Base library for cellular modem implementations
Dependencies: Socket lwip-sys lwip
Dependents: CellularUSBModem CellularUSBModem
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 <cstdio> 00029 using std::sscanf; 00030 using std::sprintf; 00031 00032 #include "PPPIPInterface.h" 00033 00034 #define MSISDN "*99#" 00035 00036 #define CONNECT_CMD_PREFIX "ATD " 00037 #define CONNECT_CMD_SUFFIX "\x0D" 00038 #define EXPECTED_RESP_SUFFIX "\x0D" "\x0A" "CONNECT" "\x0D" "\x0A" 00039 #define EXPECTED_RESP_DATARATE_SUFFIX "\x0D" "\x0A" "CONNECT %d" "\x0D" "\x0A" 00040 #define EXPECTED_RESP_MIN_LEN 20 00041 #define OK_RESP "\x0D" "\x0A" "OK" "\x0D" "\x0A" 00042 #define ESCAPE_SEQ "+++" 00043 #define HANGUP_CMD "ATH" "\x0D" 00044 #define NO_CARRIER_RESP "\x0D" "\x0A" "NO CARRIER" "\x0D" "\x0A" 00045 extern "C" { 00046 #include "lwip/ip_addr.h" 00047 #include "lwip/inet.h" 00048 #include "lwip/err.h" 00049 #include "lwip/dns.h" 00050 00051 #include "netif/ppp/ppp.h" 00052 } 00053 00054 PPPIPInterface::PPPIPInterface(IOStream* pStream) : LwIPInterface(), m_linkStatusSphre(1), m_pppErrCode(0), m_pStream(pStream), m_streamAvail(true), m_pppd(-1) 00055 { 00056 m_linkStatusSphre.wait(); 00057 } 00058 00059 00060 00061 /*virtual*/ PPPIPInterface::~PPPIPInterface() 00062 { 00063 } 00064 00065 /*virtual*/ int PPPIPInterface::init() //Init PPP-specific stuff, create the right bindings, etc 00066 { 00067 DBG("Initializing LwIP"); 00068 LwIPInterface::init(); //Init LwIP, NOT including PPP 00069 DBG("Initializing PPP"); 00070 pppInit(); 00071 DBG("Done"); 00072 return OK; 00073 } 00074 00075 int PPPIPInterface::setup(const char* user, const char* pw, const char* msisdn) 00076 { 00077 DBG("Configuring PPP authentication method"); 00078 pppSetAuth(PPPAUTHTYPE_ANY, user, pw); 00079 m_msisdn = msisdn; 00080 DBG("Done"); 00081 return OK; 00082 } 00083 00084 /*virtual*/ int PPPIPInterface::connect() 00085 { 00086 int ret; 00087 char cmd[32]; 00088 int cmdLen; 00089 char buf[32]; 00090 size_t len; 00091 DBG("Trying to connect with PPP"); 00092 00093 cleanupLink(); 00094 00095 cmdLen = sprintf(cmd, "%s%s%s", CONNECT_CMD_PREFIX, m_msisdn, CONNECT_CMD_SUFFIX); 00096 DBG("Sending %s", cmd); 00097 ret = m_pStream->write((uint8_t*)cmd, cmdLen, osWaitForever); 00098 if( ret != OK ) 00099 { 00100 return NET_UNKNOWN; 00101 } 00102 00103 len = 0; 00104 size_t readLen; 00105 ret = m_pStream->read((uint8_t*)buf + len, &readLen, EXPECTED_RESP_MIN_LEN, 10000); 00106 if( ret != OK ) 00107 { 00108 return NET_UNKNOWN; 00109 } 00110 len += readLen; 00111 while( (len < EXPECTED_RESP_MIN_LEN) || (buf[len-1] != LF) ) 00112 { 00113 ret = m_pStream->read((uint8_t*)buf + len, &readLen, 1, 10000); 00114 if( ret != OK ) 00115 { 00116 return NET_UNKNOWN; 00117 } 00118 len += readLen; 00119 } 00120 00121 buf[len]=0; 00122 00123 DBG("Got %s[len %d]", buf, len); 00124 00125 int datarate = 0; 00126 strcpy(&cmd[cmdLen], EXPECTED_RESP_DATARATE_SUFFIX); 00127 if( (sscanf(buf, cmd, &datarate ) != 1)) 00128 { 00129 strcpy(&cmd[cmdLen], EXPECTED_RESP_SUFFIX); 00130 if (strcmp(cmd, buf) != 0) 00131 { 00132 //Discard buffer 00133 do //Clear buf 00134 { 00135 ret = m_pStream->read((uint8_t*)buf, &len, 32, 0); 00136 } while( (ret == OK) && (len > 0) ); 00137 return NET_CONN; 00138 } 00139 } 00140 00141 DBG("Transport link open"); 00142 if(datarate != 0) 00143 { 00144 DBG("Datarate: %d bps", datarate); 00145 } 00146 m_linkStatusSphre.wait(0); 00147 if((m_pppd != -1) && (m_pppErrCode == 0)) //Already connected 00148 { 00149 return NET_INVALID; 00150 } 00151 00152 ret = pppOverSerialOpen(this, PPPIPInterface::linkStatusCb, this); 00153 if(ret < 0) 00154 { 00155 switch(ret) 00156 { 00157 case PPPERR_OPEN: 00158 default: 00159 return NET_FULL; //All available resources are already used 00160 } 00161 } 00162 m_pppd = ret; //PPP descriptor 00163 m_linkStatusSphre.wait(); //Block indefinitely; there should be a timeout there 00164 if(m_pppErrCode != PPPERR_NONE) 00165 { 00166 m_pppd = -1; 00167 } 00168 switch(m_pppErrCode) 00169 { 00170 case PPPERR_NONE: //Connected OK 00171 return OK; 00172 case PPPERR_CONNECT: //Connection lost 00173 return NET_INTERRUPTED; 00174 case PPPERR_AUTHFAIL: //Authentication failed 00175 return NET_AUTH; 00176 case PPPERR_PROTOCOL: //Protocol error 00177 return NET_PROTOCOL; 00178 default: 00179 return NET_UNKNOWN; 00180 } 00181 } 00182 00183 /*virtual*/ int PPPIPInterface::disconnect() 00184 { 00185 int ret = m_linkStatusSphre.wait(0); 00186 if(ret > 0) //Already disconnected? 00187 { 00188 m_pppd = -1; //Discard PPP descriptor 00189 switch(m_pppErrCode) 00190 { 00191 case PPPERR_CONNECT: //Connection terminated 00192 case PPPERR_AUTHFAIL: //Authentication failed 00193 case PPPERR_PROTOCOL: //Protocol error 00194 case PPPERR_USER: 00195 return OK; 00196 default: 00197 return NET_UNKNOWN; 00198 } 00199 } 00200 else 00201 { 00202 if(m_pppd == -1) 00203 { 00204 return NET_INVALID; 00205 } 00206 pppClose(m_pppd); 00207 do 00208 { 00209 m_linkStatusSphre.wait(); //Block indefinitely; there should be a timeout there 00210 DBG("Received PPP err code %d", m_pppErrCode); 00211 } while(m_pppErrCode != PPPERR_USER); 00212 m_pppd = -1; //Discard PPP descriptor 00213 } 00214 00215 DBG("Sending %s", ESCAPE_SEQ); 00216 00217 ret = m_pStream->write((uint8_t*)ESCAPE_SEQ, strlen(ESCAPE_SEQ), osWaitForever); 00218 if( ret != OK ) 00219 { 00220 return NET_UNKNOWN; 00221 } 00222 00223 cleanupLink(); 00224 00225 return OK; 00226 } 00227 00228 00229 int PPPIPInterface::cleanupLink() 00230 { 00231 int ret; 00232 char buf[32]; 00233 size_t len; 00234 00235 do //Clear buf 00236 { 00237 ret = m_pStream->read((uint8_t*)buf, &len, 32, 100); 00238 if(ret == OK) 00239 { 00240 buf[len] = '\0'; 00241 DBG("Got %s", buf); 00242 } 00243 } while( (ret == OK) && (len > 0) ); 00244 00245 DBG("Sending %s", HANGUP_CMD); 00246 00247 ret = m_pStream->write((uint8_t*)HANGUP_CMD, strlen(HANGUP_CMD), osWaitForever); 00248 if( ret != OK ) 00249 { 00250 return NET_UNKNOWN; 00251 } 00252 00253 size_t readLen; 00254 00255 //Hangup 00256 DBG("Expect %s", HANGUP_CMD); 00257 00258 len = 0; 00259 while( len < strlen(HANGUP_CMD) ) 00260 { 00261 ret = m_pStream->read((uint8_t*)buf + len, &readLen, strlen(HANGUP_CMD) - len, 100); 00262 if( ret != OK ) 00263 { 00264 break; 00265 } 00266 len += readLen; 00267 ///// 00268 buf[len]=0; 00269 DBG("Got %s", buf); 00270 } 00271 00272 buf[len]=0; 00273 00274 DBG("Got %s[len %d]", buf, len); 00275 00276 //OK response 00277 DBG("Expect %s", OK_RESP); 00278 00279 len = 0; 00280 while( len < strlen(OK_RESP) ) 00281 { 00282 ret = m_pStream->read((uint8_t*)buf + len, &readLen, strlen(OK_RESP) - len, 100); 00283 if( ret != OK ) 00284 { 00285 break; 00286 } 00287 len += readLen; 00288 ///// 00289 buf[len]=0; 00290 DBG("Got %s", buf); 00291 } 00292 00293 buf[len]=0; 00294 00295 DBG("Got %s[len %d]", buf, len); 00296 00297 //NO CARRIER event 00298 DBG("Expect %s", NO_CARRIER_RESP); 00299 00300 len = 0; 00301 while( len < strlen(NO_CARRIER_RESP) ) 00302 { 00303 ret = m_pStream->read((uint8_t*)buf + len, &readLen, strlen(NO_CARRIER_RESP) - len, 100); 00304 if( ret != OK ) 00305 { 00306 break; 00307 } 00308 len += readLen; 00309 ///// 00310 buf[len]=0; 00311 DBG("Got %s", buf); 00312 } 00313 00314 buf[len]=0; 00315 00316 DBG("Got %s[len %d]", buf, len); 00317 00318 do //Clear buf 00319 { 00320 ret = m_pStream->read((uint8_t*)buf, &len, 32, 100); 00321 if(ret == OK) 00322 { 00323 buf[len] = '\0'; 00324 DBG("Got %s", buf); 00325 } 00326 } while( (ret == OK) && (len > 0) ); 00327 00328 00329 return OK; 00330 } 00331 00332 /*static*/ void PPPIPInterface::linkStatusCb(void *ctx, int errCode, void *arg) //PPP link status 00333 { 00334 PPPIPInterface* pIf = (PPPIPInterface*)ctx; 00335 struct ppp_addrs* addrs = (struct ppp_addrs*) arg; 00336 00337 switch(errCode) 00338 { 00339 case PPPERR_NONE: 00340 WARN("Connected via PPP."); 00341 DBG("Local IP address: %s", inet_ntoa(addrs->our_ipaddr)); 00342 DBG("Netmask: %s", inet_ntoa(addrs->netmask)); 00343 DBG("Remote IP address: %s", inet_ntoa(addrs->his_ipaddr)); 00344 DBG("Primary DNS: %s", inet_ntoa(addrs->dns1)); 00345 DBG("Secondary DNS: %s", inet_ntoa(addrs->dns2)); 00346 //Setup DNS 00347 if (addrs->dns1.addr != 0) 00348 { 00349 dns_setserver(0, (struct ip_addr*)&(addrs->dns1)); 00350 } 00351 if (addrs->dns2.addr != 0) 00352 { 00353 dns_setserver(1, (struct ip_addr*)&(addrs->dns1)); 00354 } 00355 00356 pIf->setConnected(true); 00357 pIf->setIPAddress(inet_ntoa(addrs->our_ipaddr)); 00358 break; 00359 case PPPERR_CONNECT: //Connection lost 00360 WARN("Connection lost/terminated"); 00361 pIf->setConnected(false); 00362 break; 00363 case PPPERR_AUTHFAIL: //Authentication failed 00364 WARN("Authentication failed"); 00365 pIf->setConnected(false); 00366 break; 00367 case PPPERR_PROTOCOL: //Protocol error 00368 WARN("Protocol error"); 00369 pIf->setConnected(false); 00370 break; 00371 case PPPERR_USER: 00372 WARN("Disconnected by user"); 00373 pIf->setConnected(false); 00374 break; 00375 default: 00376 WARN("Unknown error (%d)", errCode); 00377 pIf->setConnected(false); 00378 break; 00379 } 00380 00381 pIf->m_linkStatusSphre.wait(0); //If previous event has not been handled, "delete" it now 00382 pIf->m_pppErrCode = errCode; 00383 pIf->m_linkStatusSphre.release(); 00384 } 00385 00386 //LwIP PPP implementation 00387 extern "C" 00388 { 00389 00390 /** 00391 * Writes to the serial device. 00392 * 00393 * @param fd serial device handle 00394 * @param data pointer to data to send 00395 * @param len length (in bytes) of data to send 00396 * @return number of bytes actually sent 00397 * 00398 * @note This function will block until all data can be sent. 00399 */ 00400 u32_t sio_write(sio_fd_t fd, u8_t *data, u32_t len) 00401 { 00402 DBG("sio_write"); 00403 PPPIPInterface* pIf = (PPPIPInterface*)fd; 00404 int ret; 00405 if(!pIf->m_streamAvail) //If stream is not available (it is a shared resource) don't go further 00406 { 00407 return 0; 00408 } 00409 ret = pIf->m_pStream->write(data, len, osWaitForever); //Blocks until all data is sent or an error happens 00410 if(ret != OK) 00411 { 00412 return 0; 00413 } 00414 return len; 00415 } 00416 00417 /** 00418 * Reads from the serial device. 00419 * 00420 * @param fd serial device handle 00421 * @param data pointer to data buffer for receiving 00422 * @param len maximum length (in bytes) of data to receive 00423 * @return number of bytes actually received - may be 0 if aborted by sio_read_abort 00424 * 00425 * @note This function will block until data can be received. The blocking 00426 * can be cancelled by calling sio_read_abort(). 00427 */ 00428 u32_t sio_read(sio_fd_t fd, u8_t *data, u32_t len) 00429 { 00430 DBG("sio_read"); 00431 PPPIPInterface* pIf = (PPPIPInterface*)fd; 00432 int ret; 00433 size_t readLen; 00434 if(!pIf->m_streamAvail) //If stream is not available (it is a shared resource) don't go further 00435 { 00436 WARN("EXIT NOT AVAIL"); 00437 return 0; 00438 } 00439 ret = pIf->m_pStream->read(data, &readLen, len, osWaitForever); //Blocks until some data is received or an error happens 00440 if(ret != OK) 00441 { 00442 return 0; 00443 } 00444 DBG("ret"); 00445 return readLen; 00446 } 00447 00448 /** 00449 * Aborts a blocking sio_read() call. 00450 * 00451 * @param fd serial device handle 00452 */ 00453 void sio_read_abort(sio_fd_t fd) 00454 { 00455 DBG("sio_read_abort"); 00456 PPPIPInterface* pIf = (PPPIPInterface*)fd; 00457 if(!pIf->m_streamAvail) //If stream is not available (it is a shared resource) don't go further 00458 { 00459 return; 00460 } 00461 pIf->m_pStream->abortRead(); 00462 DBG("ret"); 00463 } 00464 00465 } 00466
Generated on Tue Jul 26 2022 09:42:59 by 1.7.2