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.
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 12 2022 17:34:51 by
1.7.2