]> git.donarmstrong.com Git - qmk_firmware.git/blob - tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/ip/PPPIPInterface.cpp
Squashed 'tmk_core/' changes from 7967731..b9e0ea0
[qmk_firmware.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