mbed official / SprintUSBModem

Dependencies:   Socket USBHostWANDongleSprint lwip-sys lwip

Dependents:   SprintUSBModemWebsocketTest SprintUSBModemHTTPClientTest SprintUSBModemNTPClientTest SprintUSBModemSMSTest ... more

Fork of SprintUSBModem_bleedingedge by Donatien Garnier

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers PPPIPInterface.cpp Source File

PPPIPInterface.cpp

00001 /* PPPIPInterface.cpp */
00002 /* Copyright (C) 2012 mbed.org, MIT License
00003  *
00004  * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
00005  * and associated documentation files (the "Software"), to deal in the Software without restriction,
00006  * including without limitation the rights to use, copy, modify, merge, publish, distribute,
00007  * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
00008  * furnished to do so, subject to the following conditions:
00009  *
00010  * The above copyright notice and this permission notice shall be included in all copies or
00011  * substantial portions of the Software.
00012  *
00013  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
00014  * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00015  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
00016  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00017  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00018  */
00019 
00020 #define __DEBUG__ 0
00021 #ifndef __MODULE__
00022 #define __MODULE__ "PPPIPInterface.cpp"
00023 #endif
00024 
00025 #include "core/fwk.h"
00026 #include "rtos.h"
00027 
00028 #include "PPPIPInterface.h"
00029 
00030 #define MSISDN "#777"
00031 //TODO Pass this as parameter (*99# is used by GSM systems, #777 by CDMA systems--well at least Sprint!) 
00032 
00033 #define CONNECT_CMD "ATD " MSISDN "\x0D"
00034 #define EXPECTED_RESP CONNECT_CMD "\x0D" "\x0A" "CONNECT" "\x0D" "\x0A"
00035 #define EXPECTED_RESP_DATARATE CONNECT_CMD "\x0D" "\x0A" "CONNECT %d" "\x0D" "\x0A"
00036 #define EXPECTED_RESP_MIN_LEN 20
00037 #define OK_RESP "\x0D" "\x0A" "OK" "\x0D" "\x0A"
00038 #define ESCAPE_SEQ "+++"
00039 #define HANGUP_CMD "ATH" "\x0D"
00040 #define NO_CARRIER_RESP "\x0D" "\x0A" "NO CARRIER" "\x0D" "\x0A"
00041 extern "C" {
00042 #include "lwip/ip_addr.h"
00043 #include "lwip/inet.h"
00044 #include "netif/ppp/ppp.h"
00045 }
00046 
00047 PPPIPInterface::PPPIPInterface(IOStream* pStream) : LwIPInterface(), m_linkStatusSphre(1), m_pppErrCode(0), m_pStream(pStream), m_streamAvail(true), m_pppd(-1)
00048 {
00049   m_linkStatusSphre.wait();
00050 }
00051 
00052 /*virtual*/ PPPIPInterface::~PPPIPInterface()
00053 {
00054 
00055 }
00056 
00057 /*virtual*/ int PPPIPInterface::init() //Init PPP-specific stuff, create the right bindings, etc
00058 {
00059   DBG("Initializing LwIP");
00060   LwIPInterface::init(); //Init LwIP, NOT including PPP
00061   DBG("Initializing PPP");
00062   pppInit();
00063   DBG("Done");
00064   return OK;
00065 }
00066 
00067 int PPPIPInterface::setup(const char* user, const char* pw)
00068 {
00069   DBG("Configuring PPP authentication method");
00070   pppSetAuth(PPPAUTHTYPE_ANY, user, pw);
00071   DBG("Done");
00072   return OK;
00073 }
00074 
00075 /*virtual*/ int PPPIPInterface::connect()
00076 {
00077   int ret;
00078   char buf[32];
00079   size_t len;
00080   DBG("Trying to connect with PPP");
00081   
00082   cleanupLink();
00083   
00084   DBG("Sending %s", CONNECT_CMD);
00085   
00086   ret = m_pStream->write((uint8_t*)CONNECT_CMD, strlen(CONNECT_CMD), osWaitForever);
00087   if( ret != OK )
00088   {
00089     return NET_UNKNOWN;
00090   }
00091   
00092   DBG("Expect %s", EXPECTED_RESP);
00093     
00094   len = 0;
00095   size_t readLen;
00096   ret = m_pStream->read((uint8_t*)buf + len, &readLen, EXPECTED_RESP_MIN_LEN, 10000);
00097   if( ret != OK )
00098   {
00099     return NET_UNKNOWN;
00100   }
00101   len += readLen;
00102   while( (len < EXPECTED_RESP_MIN_LEN) || (buf[len-1] != LF) )
00103   {
00104     ret = m_pStream->read((uint8_t*)buf + len, &readLen, 1, 10000);
00105     if( ret != OK )
00106     {
00107       return NET_UNKNOWN;
00108     }
00109     len += readLen;
00110   }
00111   
00112   buf[len]=0;
00113   
00114   DBG("Got %s[len %d]", buf, len);
00115   
00116   int datarate = 0;
00117   if( (sscanf( buf, EXPECTED_RESP_DATARATE, &datarate ) != 1) && (strcmp(EXPECTED_RESP, buf) != 0) )
00118   {
00119     //Discard buffer
00120     do //Clear buf
00121     {
00122       ret = m_pStream->read((uint8_t*)buf, &len, 32, 0);
00123     } while( (ret == OK) && (len > 0) );
00124     return NET_CONN;
00125   }
00126       
00127   DBG("Transport link open");
00128   if(datarate != 0)
00129   {
00130     DBG("Datarate: %d bps", datarate);
00131   }
00132   m_linkStatusSphre.wait(0);
00133   if((m_pppd != -1) && (m_pppErrCode == 0)) //Already connected
00134   {
00135     return NET_INVALID;
00136   }
00137   
00138   ret = pppOverSerialOpen(this, PPPIPInterface::linkStatusCb, this);
00139   if(ret < 0)
00140   {
00141     switch(ret)
00142     {
00143     case PPPERR_OPEN:
00144     default:
00145       return NET_FULL; //All available resources are already used
00146     }
00147   }
00148   m_pppd = ret; //PPP descriptor
00149   m_linkStatusSphre.wait(); //Block indefinitely; there should be a timeout there
00150   if(m_pppErrCode != PPPERR_NONE)
00151   {
00152     m_pppd = -1;
00153   }
00154   switch(m_pppErrCode)
00155   {
00156   case PPPERR_NONE: //Connected OK
00157     return OK;
00158   case PPPERR_CONNECT: //Connection lost
00159     return NET_INTERRUPTED;
00160   case PPPERR_AUTHFAIL: //Authentication failed
00161     return NET_AUTH;
00162   case PPPERR_PROTOCOL: //Protocol error
00163     return NET_PROTOCOL;
00164   default:
00165     return NET_UNKNOWN;
00166   }
00167 }
00168 
00169 /*virtual*/ int PPPIPInterface::disconnect()
00170 {
00171   int ret = m_linkStatusSphre.wait(0);
00172   if(ret > 0) //Already disconnected?
00173   {
00174     m_pppd = -1; //Discard PPP descriptor
00175     switch(m_pppErrCode)
00176       {
00177       case PPPERR_CONNECT: //Connection terminated
00178       case PPPERR_AUTHFAIL: //Authentication failed
00179       case PPPERR_PROTOCOL: //Protocol error
00180       case PPPERR_USER:
00181         return OK;
00182       default:
00183         return NET_UNKNOWN;
00184       }
00185   }
00186   else
00187   {
00188     if(m_pppd == -1)
00189     {
00190       return NET_INVALID;
00191     }
00192     pppClose(m_pppd);
00193     do
00194     {
00195       m_linkStatusSphre.wait(); //Block indefinitely; there should be a timeout there
00196       DBG("Received PPP err code %d", m_pppErrCode);
00197     } while(m_pppErrCode != PPPERR_USER);
00198     m_pppd = -1; //Discard PPP descriptor
00199   }
00200   
00201   Thread::wait(500);
00202   
00203   DBG("Sending %s", ESCAPE_SEQ);
00204   
00205   ret = m_pStream->write((uint8_t*)ESCAPE_SEQ, strlen(ESCAPE_SEQ), osWaitForever);
00206   if( ret != OK )
00207   {
00208     return NET_UNKNOWN;
00209   }
00210   
00211   Thread::wait(500);
00212   
00213   cleanupLink();
00214   
00215   return OK;
00216 }
00217 
00218 
00219 int PPPIPInterface::cleanupLink()
00220 {
00221   int ret;
00222   char buf[32];
00223   size_t len;
00224   
00225   do //Clear buf
00226   {
00227     ret = m_pStream->read((uint8_t*)buf, &len, 32, 100);
00228     if(ret == OK)
00229     {
00230       buf[len] = '\0';
00231       DBG("Got %s", buf);
00232     }
00233   } while( (ret == OK) && (len > 0) );
00234   
00235   DBG("Sending %s", HANGUP_CMD);
00236   
00237   ret = m_pStream->write((uint8_t*)HANGUP_CMD, strlen(HANGUP_CMD), osWaitForever);
00238   if( ret != OK )
00239   {
00240     return NET_UNKNOWN;
00241   }
00242      
00243   size_t readLen;
00244   
00245   //Hangup
00246   DBG("Expect %s", HANGUP_CMD);
00247 
00248   len = 0;
00249   while( len < strlen(HANGUP_CMD) )
00250   {
00251     ret = m_pStream->read((uint8_t*)buf + len, &readLen, strlen(HANGUP_CMD) - len, 100);
00252     if( ret != OK )
00253     {
00254       break;
00255     }
00256     len += readLen;
00257     /////
00258     buf[len]=0;
00259     DBG("Got %s", buf);
00260   }
00261   
00262   buf[len]=0;
00263   
00264   DBG("Got %s[len %d]", buf, len);
00265   
00266   //OK response
00267   DBG("Expect %s", OK_RESP);
00268 
00269   len = 0;
00270   while( len < strlen(OK_RESP) )
00271   {
00272     ret = m_pStream->read((uint8_t*)buf + len, &readLen, strlen(OK_RESP) - len, 100);
00273     if( ret != OK )
00274     {
00275       break;
00276     }
00277     len += readLen;
00278     /////
00279     buf[len]=0;
00280     DBG("Got %s", buf);
00281   }
00282   
00283   buf[len]=0;
00284   
00285   DBG("Got %s[len %d]", buf, len);
00286   
00287   //NO CARRIER event
00288   DBG("Expect %s", NO_CARRIER_RESP);
00289 
00290   len = 0;
00291   while( len < strlen(NO_CARRIER_RESP) )
00292   {
00293     ret = m_pStream->read((uint8_t*)buf + len, &readLen, strlen(NO_CARRIER_RESP) - len, 100);
00294     if( ret != OK )
00295     {
00296       break;
00297     }
00298     len += readLen;
00299     /////
00300     buf[len]=0;
00301     DBG("Got %s", buf);
00302   }
00303   
00304   buf[len]=0;
00305   
00306   DBG("Got %s[len %d]", buf, len);
00307   
00308   do //Clear buf
00309   {
00310     ret = m_pStream->read((uint8_t*)buf, &len, 32, 100);
00311     if(ret == OK)
00312     {
00313       buf[len] = '\0';
00314       DBG("Got %s", buf);
00315     }
00316   } while( (ret == OK) && (len > 0) );
00317   
00318   
00319   return OK;
00320 }
00321 
00322 /*static*/ void PPPIPInterface::linkStatusCb(void *ctx, int errCode, void *arg) //PPP link status
00323 {
00324   PPPIPInterface* pIf = (PPPIPInterface*)ctx;
00325   struct ppp_addrs* addrs = (struct ppp_addrs*) arg;
00326 
00327   switch(errCode)
00328   {
00329   case PPPERR_NONE:
00330     WARN("Connected via PPP.");
00331     DBG("Local IP address: %s", inet_ntoa(addrs->our_ipaddr));
00332     DBG("Netmask: %s", inet_ntoa(addrs->netmask));
00333     DBG("Remote IP address: %s", inet_ntoa(addrs->his_ipaddr));
00334     DBG("Primary DNS: %s", inet_ntoa(addrs->dns1));
00335     DBG("Secondary DNS: %s", inet_ntoa(addrs->dns2));
00336     pIf->setConnected(true);
00337     pIf->setIPAddress(inet_ntoa(addrs->our_ipaddr));
00338     break;
00339   case PPPERR_CONNECT: //Connection lost
00340     WARN("Connection lost/terminated");
00341     pIf->setConnected(false);
00342     break;
00343   case PPPERR_AUTHFAIL: //Authentication failed
00344     WARN("Authentication failed");
00345     pIf->setConnected(false);
00346     break;
00347   case PPPERR_PROTOCOL: //Protocol error
00348     WARN("Protocol error");
00349     pIf->setConnected(false);
00350     break;
00351   case PPPERR_USER:
00352     WARN("Disconnected by user");
00353     pIf->setConnected(false);
00354     break;
00355   default:
00356     WARN("Unknown error (%d)", errCode);
00357     pIf->setConnected(false);
00358     break;
00359   }
00360 
00361   pIf->m_linkStatusSphre.wait(0); //If previous event has not been handled, "delete" it now
00362   pIf->m_pppErrCode = errCode;
00363   pIf->m_linkStatusSphre.release();
00364 }
00365 
00366 //LwIP PPP implementation
00367 extern "C"
00368 {
00369 
00370 /**
00371  * Writes to the serial device.
00372  *
00373  * @param fd serial device handle
00374  * @param data pointer to data to send
00375  * @param len length (in bytes) of data to send
00376  * @return number of bytes actually sent
00377  *
00378  * @note This function will block until all data can be sent.
00379  */
00380 u32_t sio_write(sio_fd_t fd, u8_t *data, u32_t len)
00381 {
00382   DBG("sio_write");
00383   PPPIPInterface* pIf = (PPPIPInterface*)fd;
00384   int ret;
00385   if(!pIf->m_streamAvail) //If stream is not available (it is a shared resource) don't go further
00386   {
00387     return 0;
00388   }
00389   ret = pIf->m_pStream->write(data, len, osWaitForever); //Blocks until all data is sent or an error happens
00390   if(ret != OK)
00391   {
00392     return 0;
00393   }
00394   return len;
00395 }
00396 
00397 /**
00398  * Reads from the serial device.
00399  *
00400  * @param fd serial device handle
00401  * @param data pointer to data buffer for receiving
00402  * @param len maximum length (in bytes) of data to receive
00403  * @return number of bytes actually received - may be 0 if aborted by sio_read_abort
00404  *
00405  * @note This function will block until data can be received. The blocking
00406  * can be cancelled by calling sio_read_abort().
00407  */
00408 u32_t sio_read(sio_fd_t fd, u8_t *data, u32_t len)
00409 {
00410   DBG("sio_read");
00411   PPPIPInterface* pIf = (PPPIPInterface*)fd;
00412   int ret;
00413   size_t readLen;
00414   if(!pIf->m_streamAvail) //If stream is not available (it is a shared resource) don't go further
00415   {
00416     WARN("EXIT NOT AVAIL");
00417     return 0;
00418   }
00419   ret = pIf->m_pStream->read(data, &readLen, len, osWaitForever); //Blocks until some data is received or an error happens
00420   if(ret != OK)
00421   {
00422     return 0;
00423   }
00424   DBG("ret");
00425   return readLen;
00426 }
00427 
00428 /**
00429  * Aborts a blocking sio_read() call.
00430  *
00431  * @param fd serial device handle
00432  */
00433 void sio_read_abort(sio_fd_t fd)
00434 {
00435   DBG("sio_read_abort");
00436   PPPIPInterface* pIf = (PPPIPInterface*)fd;
00437   if(!pIf->m_streamAvail) //If stream is not available (it is a shared resource) don't go further
00438   {
00439     return;
00440   }
00441   pIf->m_pStream->abortRead();
00442   DBG("ret");
00443 }
00444 
00445 }
00446