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