1 /* PPPIPInterface.cpp */
2 /* Copyright (C) 2012 mbed.org, MIT License
4 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
5 * and associated documentation files (the "Software"), to deal in the Software without restriction,
6 * including without limitation the rights to use, copy, modify, merge, publish, distribute,
7 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
8 * furnished to do so, subject to the following conditions:
10 * The above copyright notice and this permission notice shall be included in all copies or
11 * substantial portions of the Software.
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
14 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
16 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
17 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 #define __MODULE__ "PPPIPInterface.cpp"
32 #include "PPPIPInterface.h"
36 #define CONNECT_CMD_PREFIX "ATD "
37 #define CONNECT_CMD_SUFFIX "\x0D"
38 #define EXPECTED_RESP_SUFFIX "\x0D" "\x0A" "CONNECT" "\x0D" "\x0A"
39 #define EXPECTED_RESP_DATARATE_SUFFIX "\x0D" "\x0A" "CONNECT %d" "\x0D" "\x0A"
40 #define EXPECTED_RESP_MIN_LEN 20
41 #define OK_RESP "\x0D" "\x0A" "OK" "\x0D" "\x0A"
42 #define ESCAPE_SEQ "+++"
43 #define HANGUP_CMD "ATH" "\x0D"
44 #define NO_CARRIER_RESP "\x0D" "\x0A" "NO CARRIER" "\x0D" "\x0A"
46 #include "lwip/ip_addr.h"
47 #include "lwip/inet.h"
51 #include "netif/ppp/ppp.h"
54 PPPIPInterface::PPPIPInterface(IOStream
* pStream
) : LwIPInterface(), m_linkStatusSphre(1), m_pppErrCode(0), m_pStream(pStream
), m_streamAvail(true), m_pppd(-1)
56 m_linkStatusSphre
.wait();
61 /*virtual*/ PPPIPInterface::~PPPIPInterface()
65 /*virtual*/ int PPPIPInterface::init() //Init PPP-specific stuff, create the right bindings, etc
67 DBG("Initializing LwIP");
68 LwIPInterface::init(); //Init LwIP, NOT including PPP
69 DBG("Initializing PPP");
75 int PPPIPInterface::setup(const char* user
, const char* pw
, const char* msisdn
)
77 DBG("Configuring PPP authentication method");
78 pppSetAuth(PPPAUTHTYPE_ANY
, user
, pw
);
84 /*virtual*/ int PPPIPInterface::connect()
91 DBG("Trying to connect with PPP");
95 cmdLen
= sprintf(cmd
, "%s%s%s", CONNECT_CMD_PREFIX
, m_msisdn
, CONNECT_CMD_SUFFIX
);
96 DBG("Sending %s", cmd
);
97 ret
= m_pStream
->write((uint8_t*)cmd
, cmdLen
, osWaitForever
);
105 ret
= m_pStream
->read((uint8_t*)buf
+ len
, &readLen
, EXPECTED_RESP_MIN_LEN
, 10000);
111 while( (len
< EXPECTED_RESP_MIN_LEN
) || (buf
[len
-1] != LF
) )
113 ret
= m_pStream
->read((uint8_t*)buf
+ len
, &readLen
, 1, 10000);
123 DBG("Got %s[len %d]", buf
, len
);
126 strcpy(&cmd
[cmdLen
], EXPECTED_RESP_DATARATE_SUFFIX
);
127 if( (sscanf(buf
, cmd
, &datarate
) != 1))
129 strcpy(&cmd
[cmdLen
], EXPECTED_RESP_SUFFIX
);
130 if (strcmp(cmd
, buf
) != 0)
135 ret
= m_pStream
->read((uint8_t*)buf
, &len
, 32, 0);
136 } while( (ret
== OK
) && (len
> 0) );
141 DBG("Transport link open");
144 DBG("Datarate: %d bps", datarate
);
146 m_linkStatusSphre
.wait(0);
147 if((m_pppd
!= -1) && (m_pppErrCode
== 0)) //Already connected
152 ret
= pppOverSerialOpen(this, PPPIPInterface::linkStatusCb
, this);
159 return NET_FULL
; //All available resources are already used
162 m_pppd
= ret
; //PPP descriptor
163 m_linkStatusSphre
.wait(); //Block indefinitely; there should be a timeout there
164 if(m_pppErrCode
!= PPPERR_NONE
)
170 case PPPERR_NONE
: //Connected OK
172 case PPPERR_CONNECT
: //Connection lost
173 return NET_INTERRUPTED
;
174 case PPPERR_AUTHFAIL
: //Authentication failed
176 case PPPERR_PROTOCOL
: //Protocol error
183 /*virtual*/ int PPPIPInterface::disconnect()
185 int ret
= m_linkStatusSphre
.wait(0);
186 if(ret
> 0) //Already disconnected?
188 m_pppd
= -1; //Discard PPP descriptor
191 case PPPERR_CONNECT
: //Connection terminated
192 case PPPERR_AUTHFAIL
: //Authentication failed
193 case PPPERR_PROTOCOL
: //Protocol error
209 m_linkStatusSphre
.wait(); //Block indefinitely; there should be a timeout there
210 DBG("Received PPP err code %d", m_pppErrCode
);
211 } while(m_pppErrCode
!= PPPERR_USER
);
212 m_pppd
= -1; //Discard PPP descriptor
215 DBG("Sending %s", ESCAPE_SEQ
);
217 ret
= m_pStream
->write((uint8_t*)ESCAPE_SEQ
, strlen(ESCAPE_SEQ
), osWaitForever
);
229 int PPPIPInterface::cleanupLink()
237 ret
= m_pStream
->read((uint8_t*)buf
, &len
, 32, 100);
243 } while( (ret
== OK
) && (len
> 0) );
245 DBG("Sending %s", HANGUP_CMD
);
247 ret
= m_pStream
->write((uint8_t*)HANGUP_CMD
, strlen(HANGUP_CMD
), osWaitForever
);
256 DBG("Expect %s", HANGUP_CMD
);
259 while( len
< strlen(HANGUP_CMD
) )
261 ret
= m_pStream
->read((uint8_t*)buf
+ len
, &readLen
, strlen(HANGUP_CMD
) - len
, 100);
274 DBG("Got %s[len %d]", buf
, len
);
277 DBG("Expect %s", OK_RESP
);
280 while( len
< strlen(OK_RESP
) )
282 ret
= m_pStream
->read((uint8_t*)buf
+ len
, &readLen
, strlen(OK_RESP
) - len
, 100);
295 DBG("Got %s[len %d]", buf
, len
);
298 DBG("Expect %s", NO_CARRIER_RESP
);
301 while( len
< strlen(NO_CARRIER_RESP
) )
303 ret
= m_pStream
->read((uint8_t*)buf
+ len
, &readLen
, strlen(NO_CARRIER_RESP
) - len
, 100);
316 DBG("Got %s[len %d]", buf
, len
);
320 ret
= m_pStream
->read((uint8_t*)buf
, &len
, 32, 100);
326 } while( (ret
== OK
) && (len
> 0) );
332 /*static*/ void PPPIPInterface::linkStatusCb(void *ctx
, int errCode
, void *arg
) //PPP link status
334 PPPIPInterface
* pIf
= (PPPIPInterface
*)ctx
;
335 struct ppp_addrs
* addrs
= (struct ppp_addrs
*) arg
;
340 WARN("Connected via PPP.");
341 DBG("Local IP address: %s", inet_ntoa(addrs
->our_ipaddr
));
342 DBG("Netmask: %s", inet_ntoa(addrs
->netmask
));
343 DBG("Remote IP address: %s", inet_ntoa(addrs
->his_ipaddr
));
344 DBG("Primary DNS: %s", inet_ntoa(addrs
->dns1
));
345 DBG("Secondary DNS: %s", inet_ntoa(addrs
->dns2
));
347 if (addrs
->dns1
.addr
!= 0)
349 dns_setserver(0, (struct ip_addr
*)&(addrs
->dns1
));
351 if (addrs
->dns2
.addr
!= 0)
353 dns_setserver(1, (struct ip_addr
*)&(addrs
->dns1
));
356 pIf
->setConnected(true);
357 pIf
->setIPAddress(inet_ntoa(addrs
->our_ipaddr
));
359 case PPPERR_CONNECT
: //Connection lost
360 WARN("Connection lost/terminated");
361 pIf
->setConnected(false);
363 case PPPERR_AUTHFAIL
: //Authentication failed
364 WARN("Authentication failed");
365 pIf
->setConnected(false);
367 case PPPERR_PROTOCOL
: //Protocol error
368 WARN("Protocol error");
369 pIf
->setConnected(false);
372 WARN("Disconnected by user");
373 pIf
->setConnected(false);
376 WARN("Unknown error (%d)", errCode
);
377 pIf
->setConnected(false);
381 pIf
->m_linkStatusSphre
.wait(0); //If previous event has not been handled, "delete" it now
382 pIf
->m_pppErrCode
= errCode
;
383 pIf
->m_linkStatusSphre
.release();
386 //LwIP PPP implementation
391 * Writes to the serial device.
393 * @param fd serial device handle
394 * @param data pointer to data to send
395 * @param len length (in bytes) of data to send
396 * @return number of bytes actually sent
398 * @note This function will block until all data can be sent.
400 u32_t
sio_write(sio_fd_t fd
, u8_t
*data
, u32_t len
)
403 PPPIPInterface
* pIf
= (PPPIPInterface
*)fd
;
405 if(!pIf
->m_streamAvail
) //If stream is not available (it is a shared resource) don't go further
409 ret
= pIf
->m_pStream
->write(data
, len
, osWaitForever
); //Blocks until all data is sent or an error happens
418 * Reads from the serial device.
420 * @param fd serial device handle
421 * @param data pointer to data buffer for receiving
422 * @param len maximum length (in bytes) of data to receive
423 * @return number of bytes actually received - may be 0 if aborted by sio_read_abort
425 * @note This function will block until data can be received. The blocking
426 * can be cancelled by calling sio_read_abort().
428 u32_t
sio_read(sio_fd_t fd
, u8_t
*data
, u32_t len
)
431 PPPIPInterface
* pIf
= (PPPIPInterface
*)fd
;
434 if(!pIf
->m_streamAvail
) //If stream is not available (it is a shared resource) don't go further
436 WARN("EXIT NOT AVAIL");
439 ret
= pIf
->m_pStream
->read(data
, &readLen
, len
, osWaitForever
); //Blocks until some data is received or an error happens
449 * Aborts a blocking sio_read() call.
451 * @param fd serial device handle
453 void sio_read_abort(sio_fd_t fd
)
455 DBG("sio_read_abort");
456 PPPIPInterface
* pIf
= (PPPIPInterface
*)fd
;
457 if(!pIf
->m_streamAvail
) //If stream is not available (it is a shared resource) don't go further
461 pIf
->m_pStream
->abortRead();