]> git.gir.st - tmk_keyboard.git/blob - tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/ip/PPPIPInterface.cpp
Squashed 'tmk_core/' changes from 7967731..b9e0ea0
[tmk_keyboard.git] / tool / mbed / mbed-sdk / libraries / net / cellular / CellularModem / ip / PPPIPInterface.cpp
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
20 #define __DEBUG__ 0
21 #ifndef __MODULE__
22 #define __MODULE__ "PPPIPInterface.cpp"
23 #endif
24
25 #include "core/fwk.h"
26 #include "rtos.h"
27
28 #include <cstdio>
29 using std::sscanf;
30 using std::sprintf;
31
32 #include "PPPIPInterface.h"
33
34 #define MSISDN "*99#"
35
36 #define CONNECT_CMD_PREFIX "ATD "
37 #define CONNECT_CMD_SUFFIX "\x0D"
38 #define EXPECTED_RESP_SUFFIX "\x0D" "\x0A" "CONNECT" "\x0D" "\x0A"
39 #define EXPECTED_RESP_DATARATE_SUFFIX "\x0D" "\x0A" "CONNECT %d" "\x0D" "\x0A"
40 #define EXPECTED_RESP_MIN_LEN 20
41 #define OK_RESP "\x0D" "\x0A" "OK" "\x0D" "\x0A"
42 #define ESCAPE_SEQ "+++"
43 #define HANGUP_CMD "ATH" "\x0D"
44 #define NO_CARRIER_RESP "\x0D" "\x0A" "NO CARRIER" "\x0D" "\x0A"
45 extern "C" {
46 #include "lwip/ip_addr.h"
47 #include "lwip/inet.h"
48 #include "lwip/err.h"
49 #include "lwip/dns.h"
50
51 #include "netif/ppp/ppp.h"
52 }
53
54 PPPIPInterface::PPPIPInterface(IOStream* pStream) : LwIPInterface(), m_linkStatusSphre(1), m_pppErrCode(0), m_pStream(pStream), m_streamAvail(true), m_pppd(-1)
55 {
56 m_linkStatusSphre.wait();
57 }
58
59
60
61 /*virtual*/ PPPIPInterface::~PPPIPInterface()
62 {
63 }
64
65 /*virtual*/ int PPPIPInterface::init() //Init PPP-specific stuff, create the right bindings, etc
66 {
67 DBG("Initializing LwIP");
68 LwIPInterface::init(); //Init LwIP, NOT including PPP
69 DBG("Initializing PPP");
70 pppInit();
71 DBG("Done");
72 return OK;
73 }
74
75 int PPPIPInterface::setup(const char* user, const char* pw, const char* msisdn)
76 {
77 DBG("Configuring PPP authentication method");
78 pppSetAuth(PPPAUTHTYPE_ANY, user, pw);
79 m_msisdn = msisdn;
80 DBG("Done");
81 return OK;
82 }
83
84 /*virtual*/ int PPPIPInterface::connect()
85 {
86 int ret;
87 char cmd[32];
88 int cmdLen;
89 char buf[32];
90 size_t len;
91 DBG("Trying to connect with PPP");
92
93 cleanupLink();
94
95 cmdLen = sprintf(cmd, "%s%s%s", CONNECT_CMD_PREFIX, m_msisdn, CONNECT_CMD_SUFFIX);
96 DBG("Sending %s", cmd);
97 ret = m_pStream->write((uint8_t*)cmd, cmdLen, osWaitForever);
98 if( ret != OK )
99 {
100 return NET_UNKNOWN;
101 }
102
103 len = 0;
104 size_t readLen;
105 ret = m_pStream->read((uint8_t*)buf + len, &readLen, EXPECTED_RESP_MIN_LEN, 10000);
106 if( ret != OK )
107 {
108 return NET_UNKNOWN;
109 }
110 len += readLen;
111 while( (len < EXPECTED_RESP_MIN_LEN) || (buf[len-1] != LF) )
112 {
113 ret = m_pStream->read((uint8_t*)buf + len, &readLen, 1, 10000);
114 if( ret != OK )
115 {
116 return NET_UNKNOWN;
117 }
118 len += readLen;
119 }
120
121 buf[len]=0;
122
123 DBG("Got %s[len %d]", buf, len);
124
125 int datarate = 0;
126 strcpy(&cmd[cmdLen], EXPECTED_RESP_DATARATE_SUFFIX);
127 if( (sscanf(buf, cmd, &datarate ) != 1))
128 {
129 strcpy(&cmd[cmdLen], EXPECTED_RESP_SUFFIX);
130 if (strcmp(cmd, buf) != 0)
131 {
132 //Discard buffer
133 do //Clear buf
134 {
135 ret = m_pStream->read((uint8_t*)buf, &len, 32, 0);
136 } while( (ret == OK) && (len > 0) );
137 return NET_CONN;
138 }
139 }
140
141 DBG("Transport link open");
142 if(datarate != 0)
143 {
144 DBG("Datarate: %d bps", datarate);
145 }
146 m_linkStatusSphre.wait(0);
147 if((m_pppd != -1) && (m_pppErrCode == 0)) //Already connected
148 {
149 return NET_INVALID;
150 }
151
152 ret = pppOverSerialOpen(this, PPPIPInterface::linkStatusCb, this);
153 if(ret < 0)
154 {
155 switch(ret)
156 {
157 case PPPERR_OPEN:
158 default:
159 return NET_FULL; //All available resources are already used
160 }
161 }
162 m_pppd = ret; //PPP descriptor
163 m_linkStatusSphre.wait(); //Block indefinitely; there should be a timeout there
164 if(m_pppErrCode != PPPERR_NONE)
165 {
166 m_pppd = -1;
167 }
168 switch(m_pppErrCode)
169 {
170 case PPPERR_NONE: //Connected OK
171 return OK;
172 case PPPERR_CONNECT: //Connection lost
173 return NET_INTERRUPTED;
174 case PPPERR_AUTHFAIL: //Authentication failed
175 return NET_AUTH;
176 case PPPERR_PROTOCOL: //Protocol error
177 return NET_PROTOCOL;
178 default:
179 return NET_UNKNOWN;
180 }
181 }
182
183 /*virtual*/ int PPPIPInterface::disconnect()
184 {
185 int ret = m_linkStatusSphre.wait(0);
186 if(ret > 0) //Already disconnected?
187 {
188 m_pppd = -1; //Discard PPP descriptor
189 switch(m_pppErrCode)
190 {
191 case PPPERR_CONNECT: //Connection terminated
192 case PPPERR_AUTHFAIL: //Authentication failed
193 case PPPERR_PROTOCOL: //Protocol error
194 case PPPERR_USER:
195 return OK;
196 default:
197 return NET_UNKNOWN;
198 }
199 }
200 else
201 {
202 if(m_pppd == -1)
203 {
204 return NET_INVALID;
205 }
206 pppClose(m_pppd);
207 do
208 {
209 m_linkStatusSphre.wait(); //Block indefinitely; there should be a timeout there
210 DBG("Received PPP err code %d", m_pppErrCode);
211 } while(m_pppErrCode != PPPERR_USER);
212 m_pppd = -1; //Discard PPP descriptor
213 }
214
215 DBG("Sending %s", ESCAPE_SEQ);
216
217 ret = m_pStream->write((uint8_t*)ESCAPE_SEQ, strlen(ESCAPE_SEQ), osWaitForever);
218 if( ret != OK )
219 {
220 return NET_UNKNOWN;
221 }
222
223 cleanupLink();
224
225 return OK;
226 }
227
228
229 int PPPIPInterface::cleanupLink()
230 {
231 int ret;
232 char buf[32];
233 size_t len;
234
235 do //Clear buf
236 {
237 ret = m_pStream->read((uint8_t*)buf, &len, 32, 100);
238 if(ret == OK)
239 {
240 buf[len] = '\0';
241 DBG("Got %s", buf);
242 }
243 } while( (ret == OK) && (len > 0) );
244
245 DBG("Sending %s", HANGUP_CMD);
246
247 ret = m_pStream->write((uint8_t*)HANGUP_CMD, strlen(HANGUP_CMD), osWaitForever);
248 if( ret != OK )
249 {
250 return NET_UNKNOWN;
251 }
252
253 size_t readLen;
254
255 //Hangup
256 DBG("Expect %s", HANGUP_CMD);
257
258 len = 0;
259 while( len < strlen(HANGUP_CMD) )
260 {
261 ret = m_pStream->read((uint8_t*)buf + len, &readLen, strlen(HANGUP_CMD) - len, 100);
262 if( ret != OK )
263 {
264 break;
265 }
266 len += readLen;
267 /////
268 buf[len]=0;
269 DBG("Got %s", buf);
270 }
271
272 buf[len]=0;
273
274 DBG("Got %s[len %d]", buf, len);
275
276 //OK response
277 DBG("Expect %s", OK_RESP);
278
279 len = 0;
280 while( len < strlen(OK_RESP) )
281 {
282 ret = m_pStream->read((uint8_t*)buf + len, &readLen, strlen(OK_RESP) - len, 100);
283 if( ret != OK )
284 {
285 break;
286 }
287 len += readLen;
288 /////
289 buf[len]=0;
290 DBG("Got %s", buf);
291 }
292
293 buf[len]=0;
294
295 DBG("Got %s[len %d]", buf, len);
296
297 //NO CARRIER event
298 DBG("Expect %s", NO_CARRIER_RESP);
299
300 len = 0;
301 while( len < strlen(NO_CARRIER_RESP) )
302 {
303 ret = m_pStream->read((uint8_t*)buf + len, &readLen, strlen(NO_CARRIER_RESP) - len, 100);
304 if( ret != OK )
305 {
306 break;
307 }
308 len += readLen;
309 /////
310 buf[len]=0;
311 DBG("Got %s", buf);
312 }
313
314 buf[len]=0;
315
316 DBG("Got %s[len %d]", buf, len);
317
318 do //Clear buf
319 {
320 ret = m_pStream->read((uint8_t*)buf, &len, 32, 100);
321 if(ret == OK)
322 {
323 buf[len] = '\0';
324 DBG("Got %s", buf);
325 }
326 } while( (ret == OK) && (len > 0) );
327
328
329 return OK;
330 }
331
332 /*static*/ void PPPIPInterface::linkStatusCb(void *ctx, int errCode, void *arg) //PPP link status
333 {
334 PPPIPInterface* pIf = (PPPIPInterface*)ctx;
335 struct ppp_addrs* addrs = (struct ppp_addrs*) arg;
336
337 switch(errCode)
338 {
339 case PPPERR_NONE:
340 WARN("Connected via PPP.");
341 DBG("Local IP address: %s", inet_ntoa(addrs->our_ipaddr));
342 DBG("Netmask: %s", inet_ntoa(addrs->netmask));
343 DBG("Remote IP address: %s", inet_ntoa(addrs->his_ipaddr));
344 DBG("Primary DNS: %s", inet_ntoa(addrs->dns1));
345 DBG("Secondary DNS: %s", inet_ntoa(addrs->dns2));
346 //Setup DNS
347 if (addrs->dns1.addr != 0)
348 {
349 dns_setserver(0, (struct ip_addr*)&(addrs->dns1));
350 }
351 if (addrs->dns2.addr != 0)
352 {
353 dns_setserver(1, (struct ip_addr*)&(addrs->dns1));
354 }
355
356 pIf->setConnected(true);
357 pIf->setIPAddress(inet_ntoa(addrs->our_ipaddr));
358 break;
359 case PPPERR_CONNECT: //Connection lost
360 WARN("Connection lost/terminated");
361 pIf->setConnected(false);
362 break;
363 case PPPERR_AUTHFAIL: //Authentication failed
364 WARN("Authentication failed");
365 pIf->setConnected(false);
366 break;
367 case PPPERR_PROTOCOL: //Protocol error
368 WARN("Protocol error");
369 pIf->setConnected(false);
370 break;
371 case PPPERR_USER:
372 WARN("Disconnected by user");
373 pIf->setConnected(false);
374 break;
375 default:
376 WARN("Unknown error (%d)", errCode);
377 pIf->setConnected(false);
378 break;
379 }
380
381 pIf->m_linkStatusSphre.wait(0); //If previous event has not been handled, "delete" it now
382 pIf->m_pppErrCode = errCode;
383 pIf->m_linkStatusSphre.release();
384 }
385
386 //LwIP PPP implementation
387 extern "C"
388 {
389
390 /**
391 * Writes to the serial device.
392 *
393 * @param fd serial device handle
394 * @param data pointer to data to send
395 * @param len length (in bytes) of data to send
396 * @return number of bytes actually sent
397 *
398 * @note This function will block until all data can be sent.
399 */
400 u32_t sio_write(sio_fd_t fd, u8_t *data, u32_t len)
401 {
402 DBG("sio_write");
403 PPPIPInterface* pIf = (PPPIPInterface*)fd;
404 int ret;
405 if(!pIf->m_streamAvail) //If stream is not available (it is a shared resource) don't go further
406 {
407 return 0;
408 }
409 ret = pIf->m_pStream->write(data, len, osWaitForever); //Blocks until all data is sent or an error happens
410 if(ret != OK)
411 {
412 return 0;
413 }
414 return len;
415 }
416
417 /**
418 * Reads from the serial device.
419 *
420 * @param fd serial device handle
421 * @param data pointer to data buffer for receiving
422 * @param len maximum length (in bytes) of data to receive
423 * @return number of bytes actually received - may be 0 if aborted by sio_read_abort
424 *
425 * @note This function will block until data can be received. The blocking
426 * can be cancelled by calling sio_read_abort().
427 */
428 u32_t sio_read(sio_fd_t fd, u8_t *data, u32_t len)
429 {
430 DBG("sio_read");
431 PPPIPInterface* pIf = (PPPIPInterface*)fd;
432 int ret;
433 size_t readLen;
434 if(!pIf->m_streamAvail) //If stream is not available (it is a shared resource) don't go further
435 {
436 WARN("EXIT NOT AVAIL");
437 return 0;
438 }
439 ret = pIf->m_pStream->read(data, &readLen, len, osWaitForever); //Blocks until some data is received or an error happens
440 if(ret != OK)
441 {
442 return 0;
443 }
444 DBG("ret");
445 return readLen;
446 }
447
448 /**
449 * Aborts a blocking sio_read() call.
450 *
451 * @param fd serial device handle
452 */
453 void sio_read_abort(sio_fd_t fd)
454 {
455 DBG("sio_read_abort");
456 PPPIPInterface* pIf = (PPPIPInterface*)fd;
457 if(!pIf->m_streamAvail) //If stream is not available (it is a shared resource) don't go further
458 {
459 return;
460 }
461 pIf->m_pStream->abortRead();
462 DBG("ret");
463 }
464
465 }
466
Imprint / Impressum