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