PPPIPInterface.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  1. /* PPPIPInterface.cpp */
  2. /* Copyright (C) 2012 mbed.org, MIT License
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
  5. * and associated documentation files (the "Software"), to deal in the Software without restriction,
  6. * including without limitation the rights to use, copy, modify, merge, publish, distribute,
  7. * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
  8. * furnished to do so, subject to the following conditions:
  9. *
  10. * The above copyright notice and this permission notice shall be included in all copies or
  11. * substantial portions of the Software.
  12. *
  13. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
  14. * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  15. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
  16. * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  17. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  18. */
  19. #define __DEBUG__ 0
  20. #ifndef __MODULE__
  21. #define __MODULE__ "PPPIPInterface.cpp"
  22. #endif
  23. #include "core/fwk.h"
  24. #include "rtos.h"
  25. #include <cstdio>
  26. using std::sscanf;
  27. using std::sprintf;
  28. #include "PPPIPInterface.h"
  29. #define MSISDN "*99#"
  30. #define CONNECT_CMD_PREFIX "ATD "
  31. #define CONNECT_CMD_SUFFIX "\x0D"
  32. #define EXPECTED_RESP_SUFFIX "\x0D" "\x0A" "CONNECT" "\x0D" "\x0A"
  33. #define EXPECTED_RESP_DATARATE_SUFFIX "\x0D" "\x0A" "CONNECT %d" "\x0D" "\x0A"
  34. #define EXPECTED_RESP_MIN_LEN 20
  35. #define OK_RESP "\x0D" "\x0A" "OK" "\x0D" "\x0A"
  36. #define ESCAPE_SEQ "+++"
  37. #define HANGUP_CMD "ATH" "\x0D"
  38. #define NO_CARRIER_RESP "\x0D" "\x0A" "NO CARRIER" "\x0D" "\x0A"
  39. extern "C" {
  40. #include "lwip/ip_addr.h"
  41. #include "lwip/inet.h"
  42. #include "lwip/err.h"
  43. #include "lwip/dns.h"
  44. #include "netif/ppp/ppp.h"
  45. }
  46. PPPIPInterface::PPPIPInterface(IOStream* pStream) : LwIPInterface(), m_linkStatusSphre(1), m_pppErrCode(0), m_pStream(pStream), m_streamAvail(true), m_pppd(-1)
  47. {
  48. m_linkStatusSphre.wait();
  49. }
  50. /*virtual*/ PPPIPInterface::~PPPIPInterface()
  51. {
  52. }
  53. /*virtual*/ int PPPIPInterface::init() //Init PPP-specific stuff, create the right bindings, etc
  54. {
  55. DBG("Initializing LwIP");
  56. LwIPInterface::init(); //Init LwIP, NOT including PPP
  57. DBG("Initializing PPP");
  58. pppInit();
  59. DBG("Done");
  60. return OK;
  61. }
  62. int PPPIPInterface::setup(const char* user, const char* pw, const char* msisdn)
  63. {
  64. DBG("Configuring PPP authentication method");
  65. pppSetAuth(PPPAUTHTYPE_ANY, user, pw);
  66. m_msisdn = msisdn;
  67. DBG("Done");
  68. return OK;
  69. }
  70. /*virtual*/ int PPPIPInterface::connect()
  71. {
  72. int ret;
  73. char cmd[32];
  74. int cmdLen;
  75. char buf[32];
  76. size_t len;
  77. DBG("Trying to connect with PPP");
  78. cleanupLink();
  79. cmdLen = sprintf(cmd, "%s%s%s", CONNECT_CMD_PREFIX, m_msisdn, CONNECT_CMD_SUFFIX);
  80. DBG("Sending %s", cmd);
  81. ret = m_pStream->write((uint8_t*)cmd, cmdLen, osWaitForever);
  82. if( ret != OK )
  83. {
  84. return NET_UNKNOWN;
  85. }
  86. len = 0;
  87. size_t readLen;
  88. ret = m_pStream->read((uint8_t*)buf + len, &readLen, EXPECTED_RESP_MIN_LEN, 10000);
  89. if( ret != OK )
  90. {
  91. return NET_UNKNOWN;
  92. }
  93. len += readLen;
  94. while( (len < EXPECTED_RESP_MIN_LEN) || (buf[len-1] != LF) )
  95. {
  96. ret = m_pStream->read((uint8_t*)buf + len, &readLen, 1, 10000);
  97. if( ret != OK )
  98. {
  99. return NET_UNKNOWN;
  100. }
  101. len += readLen;
  102. }
  103. buf[len]=0;
  104. DBG("Got %s[len %d]", buf, len);
  105. int datarate = 0;
  106. strcpy(&cmd[cmdLen], EXPECTED_RESP_DATARATE_SUFFIX);
  107. if( (sscanf(buf, cmd, &datarate ) != 1))
  108. {
  109. strcpy(&cmd[cmdLen], EXPECTED_RESP_SUFFIX);
  110. if (strcmp(cmd, buf) != 0)
  111. {
  112. //Discard buffer
  113. do //Clear buf
  114. {
  115. ret = m_pStream->read((uint8_t*)buf, &len, 32, 0);
  116. } while( (ret == OK) && (len > 0) );
  117. return NET_CONN;
  118. }
  119. }
  120. DBG("Transport link open");
  121. if(datarate != 0)
  122. {
  123. DBG("Datarate: %d bps", datarate);
  124. }
  125. m_linkStatusSphre.wait(0);
  126. if((m_pppd != -1) && (m_pppErrCode == 0)) //Already connected
  127. {
  128. return NET_INVALID;
  129. }
  130. ret = pppOverSerialOpen(this, PPPIPInterface::linkStatusCb, this);
  131. if(ret < 0)
  132. {
  133. switch(ret)
  134. {
  135. case PPPERR_OPEN:
  136. default:
  137. return NET_FULL; //All available resources are already used
  138. }
  139. }
  140. m_pppd = ret; //PPP descriptor
  141. m_linkStatusSphre.wait(); //Block indefinitely; there should be a timeout there
  142. if(m_pppErrCode != PPPERR_NONE)
  143. {
  144. m_pppd = -1;
  145. }
  146. switch(m_pppErrCode)
  147. {
  148. case PPPERR_NONE: //Connected OK
  149. return OK;
  150. case PPPERR_CONNECT: //Connection lost
  151. return NET_INTERRUPTED;
  152. case PPPERR_AUTHFAIL: //Authentication failed
  153. return NET_AUTH;
  154. case PPPERR_PROTOCOL: //Protocol error
  155. return NET_PROTOCOL;
  156. default:
  157. return NET_UNKNOWN;
  158. }
  159. }
  160. /*virtual*/ int PPPIPInterface::disconnect()
  161. {
  162. int ret = m_linkStatusSphre.wait(0);
  163. if(ret > 0) //Already disconnected?
  164. {
  165. m_pppd = -1; //Discard PPP descriptor
  166. switch(m_pppErrCode)
  167. {
  168. case PPPERR_CONNECT: //Connection terminated
  169. case PPPERR_AUTHFAIL: //Authentication failed
  170. case PPPERR_PROTOCOL: //Protocol error
  171. case PPPERR_USER:
  172. return OK;
  173. default:
  174. return NET_UNKNOWN;
  175. }
  176. }
  177. else
  178. {
  179. if(m_pppd == -1)
  180. {
  181. return NET_INVALID;
  182. }
  183. pppClose(m_pppd);
  184. do
  185. {
  186. m_linkStatusSphre.wait(); //Block indefinitely; there should be a timeout there
  187. DBG("Received PPP err code %d", m_pppErrCode);
  188. } while(m_pppErrCode != PPPERR_USER);
  189. m_pppd = -1; //Discard PPP descriptor
  190. }
  191. DBG("Sending %s", ESCAPE_SEQ);
  192. ret = m_pStream->write((uint8_t*)ESCAPE_SEQ, strlen(ESCAPE_SEQ), osWaitForever);
  193. if( ret != OK )
  194. {
  195. return NET_UNKNOWN;
  196. }
  197. cleanupLink();
  198. return OK;
  199. }
  200. int PPPIPInterface::cleanupLink()
  201. {
  202. int ret;
  203. char buf[32];
  204. size_t len;
  205. do //Clear buf
  206. {
  207. ret = m_pStream->read((uint8_t*)buf, &len, 32, 100);
  208. if(ret == OK)
  209. {
  210. buf[len] = '\0';
  211. DBG("Got %s", buf);
  212. }
  213. } while( (ret == OK) && (len > 0) );
  214. DBG("Sending %s", HANGUP_CMD);
  215. ret = m_pStream->write((uint8_t*)HANGUP_CMD, strlen(HANGUP_CMD), osWaitForever);
  216. if( ret != OK )
  217. {
  218. return NET_UNKNOWN;
  219. }
  220. size_t readLen;
  221. //Hangup
  222. DBG("Expect %s", HANGUP_CMD);
  223. len = 0;
  224. while( len < strlen(HANGUP_CMD) )
  225. {
  226. ret = m_pStream->read((uint8_t*)buf + len, &readLen, strlen(HANGUP_CMD) - len, 100);
  227. if( ret != OK )
  228. {
  229. break;
  230. }
  231. len += readLen;
  232. /////
  233. buf[len]=0;
  234. DBG("Got %s", buf);
  235. }
  236. buf[len]=0;
  237. DBG("Got %s[len %d]", buf, len);
  238. //OK response
  239. DBG("Expect %s", OK_RESP);
  240. len = 0;
  241. while( len < strlen(OK_RESP) )
  242. {
  243. ret = m_pStream->read((uint8_t*)buf + len, &readLen, strlen(OK_RESP) - len, 100);
  244. if( ret != OK )
  245. {
  246. break;
  247. }
  248. len += readLen;
  249. /////
  250. buf[len]=0;
  251. DBG("Got %s", buf);
  252. }
  253. buf[len]=0;
  254. DBG("Got %s[len %d]", buf, len);
  255. //NO CARRIER event
  256. DBG("Expect %s", NO_CARRIER_RESP);
  257. len = 0;
  258. while( len < strlen(NO_CARRIER_RESP) )
  259. {
  260. ret = m_pStream->read((uint8_t*)buf + len, &readLen, strlen(NO_CARRIER_RESP) - len, 100);
  261. if( ret != OK )
  262. {
  263. break;
  264. }
  265. len += readLen;
  266. /////
  267. buf[len]=0;
  268. DBG("Got %s", buf);
  269. }
  270. buf[len]=0;
  271. DBG("Got %s[len %d]", buf, len);
  272. do //Clear buf
  273. {
  274. ret = m_pStream->read((uint8_t*)buf, &len, 32, 100);
  275. if(ret == OK)
  276. {
  277. buf[len] = '\0';
  278. DBG("Got %s", buf);
  279. }
  280. } while( (ret == OK) && (len > 0) );
  281. return OK;
  282. }
  283. /*static*/ void PPPIPInterface::linkStatusCb(void *ctx, int errCode, void *arg) //PPP link status
  284. {
  285. PPPIPInterface* pIf = (PPPIPInterface*)ctx;
  286. struct ppp_addrs* addrs = (struct ppp_addrs*) arg;
  287. switch(errCode)
  288. {
  289. case PPPERR_NONE:
  290. WARN("Connected via PPP.");
  291. DBG("Local IP address: %s", inet_ntoa(addrs->our_ipaddr));
  292. DBG("Netmask: %s", inet_ntoa(addrs->netmask));
  293. DBG("Remote IP address: %s", inet_ntoa(addrs->his_ipaddr));
  294. DBG("Primary DNS: %s", inet_ntoa(addrs->dns1));
  295. DBG("Secondary DNS: %s", inet_ntoa(addrs->dns2));
  296. //Setup DNS
  297. if (addrs->dns1.addr != 0)
  298. {
  299. dns_setserver(0, (struct ip_addr*)&(addrs->dns1));
  300. }
  301. if (addrs->dns2.addr != 0)
  302. {
  303. dns_setserver(1, (struct ip_addr*)&(addrs->dns1));
  304. }
  305. pIf->setConnected(true);
  306. pIf->setIPAddress(inet_ntoa(addrs->our_ipaddr));
  307. break;
  308. case PPPERR_CONNECT: //Connection lost
  309. WARN("Connection lost/terminated");
  310. pIf->setConnected(false);
  311. break;
  312. case PPPERR_AUTHFAIL: //Authentication failed
  313. WARN("Authentication failed");
  314. pIf->setConnected(false);
  315. break;
  316. case PPPERR_PROTOCOL: //Protocol error
  317. WARN("Protocol error");
  318. pIf->setConnected(false);
  319. break;
  320. case PPPERR_USER:
  321. WARN("Disconnected by user");
  322. pIf->setConnected(false);
  323. break;
  324. default:
  325. WARN("Unknown error (%d)", errCode);
  326. pIf->setConnected(false);
  327. break;
  328. }
  329. pIf->m_linkStatusSphre.wait(0); //If previous event has not been handled, "delete" it now
  330. pIf->m_pppErrCode = errCode;
  331. pIf->m_linkStatusSphre.release();
  332. }
  333. //LwIP PPP implementation
  334. extern "C"
  335. {
  336. /**
  337. * Writes to the serial device.
  338. *
  339. * @param fd serial device handle
  340. * @param data pointer to data to send
  341. * @param len length (in bytes) of data to send
  342. * @return number of bytes actually sent
  343. *
  344. * @note This function will block until all data can be sent.
  345. */
  346. u32_t sio_write(sio_fd_t fd, u8_t *data, u32_t len)
  347. {
  348. DBG("sio_write");
  349. PPPIPInterface* pIf = (PPPIPInterface*)fd;
  350. int ret;
  351. if(!pIf->m_streamAvail) //If stream is not available (it is a shared resource) don't go further
  352. {
  353. return 0;
  354. }
  355. ret = pIf->m_pStream->write(data, len, osWaitForever); //Blocks until all data is sent or an error happens
  356. if(ret != OK)
  357. {
  358. return 0;
  359. }
  360. return len;
  361. }
  362. /**
  363. * Reads from the serial device.
  364. *
  365. * @param fd serial device handle
  366. * @param data pointer to data buffer for receiving
  367. * @param len maximum length (in bytes) of data to receive
  368. * @return number of bytes actually received - may be 0 if aborted by sio_read_abort
  369. *
  370. * @note This function will block until data can be received. The blocking
  371. * can be cancelled by calling sio_read_abort().
  372. */
  373. u32_t sio_read(sio_fd_t fd, u8_t *data, u32_t len)
  374. {
  375. DBG("sio_read");
  376. PPPIPInterface* pIf = (PPPIPInterface*)fd;
  377. int ret;
  378. size_t readLen;
  379. if(!pIf->m_streamAvail) //If stream is not available (it is a shared resource) don't go further
  380. {
  381. WARN("EXIT NOT AVAIL");
  382. return 0;
  383. }
  384. ret = pIf->m_pStream->read(data, &readLen, len, osWaitForever); //Blocks until some data is received or an error happens
  385. if(ret != OK)
  386. {
  387. return 0;
  388. }
  389. DBG("ret");
  390. return readLen;
  391. }
  392. /**
  393. * Aborts a blocking sio_read() call.
  394. *
  395. * @param fd serial device handle
  396. */
  397. void sio_read_abort(sio_fd_t fd)
  398. {
  399. DBG("sio_read_abort");
  400. PPPIPInterface* pIf = (PPPIPInterface*)fd;
  401. if(!pIf->m_streamAvail) //If stream is not available (it is a shared resource) don't go further
  402. {
  403. return;
  404. }
  405. pIf->m_pStream->abortRead();
  406. DBG("ret");
  407. }
  408. }