Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: Socket USBHostWANDongleSprint lwip-sys lwip
Dependents: SprintUSBModemWebsocketTest SprintUSBModemHTTPClientTest SprintUSBModemNTPClientTest SprintUSBModemSMSTest ... more
Fork of SprintUSBModem_bleedingedge by
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
Generated on Wed Jul 13 2022 06:25:50 by
1.7.2
