1PPP interface for lwIP 2 3Author: Sylvain Rochet 4 5Table of Contents: 6 71 - Supported PPP protocols and features 82 - Raw API PPP example for all protocols 93 - PPPoS input path (raw API, IRQ safe API, TCPIP API) 104 - Thread safe PPP API (PPPAPI) 115 - Notify phase callback (PPP_NOTIFY_PHASE) 126 - Upgrading from lwIP <= 1.4.x to lwIP >= 2.0.x 13 14 15 161 Supported PPP protocols and features 17====================================== 18 19Supported Low level protocols: 20* PPP over serial using HDLC-like framing, such as wired dialup modems 21 or mobile telecommunications GPRS/EDGE/UMTS/HSPA+/LTE modems 22* PPP over Ethernet, such as xDSL modems 23* PPP over L2TP (Layer 2 Tunneling Protocol) LAC (L2TP Access Concentrator), 24 IP tunnel over UDP, such as VPN access 25 26Supported auth protocols: 27* PAP, Password Authentication Protocol 28* CHAP, Challenge-Handshake Authentication Protocol, also known as CHAP-MD5 29* MSCHAPv1, Microsoft version of CHAP, version 1 30* MSCHAPv2, Microsoft version of CHAP, version 2 31* EAP, Extensible Authentication Protocol 32 33Supported address protocols: 34* IPCP, IP Control Protocol, IPv4 addresses negotiation 35* IP6CP, IPv6 Control Protocol, IPv6 link-local addresses negotiation 36 37Supported encryption protocols: 38* MPPE, Microsoft Point-to-Point Encryption 39 40Supported compression or miscellaneous protocols, for serial links only: 41* PFC, Protocol Field Compression 42* ACFC, Address-and-Control-Field-Compression 43* ACCM, Asynchronous-Control-Character-Map 44* VJ, Van Jacobson TCP/IP Header Compression 45 46 47 482 Raw API PPP example for all protocols 49======================================= 50 51As usual, raw API for lwIP means the lightweight API which *MUST* only be used 52for NO_SYS=1 systems or called inside lwIP core thread for NO_SYS=0 systems. 53 54/* 55 * Globals 56 * ======= 57 */ 58 59/* The PPP control block */ 60ppp_pcb *ppp; 61 62/* The PPP IP interface */ 63struct netif ppp_netif; 64 65 66/* 67 * PPP status callback 68 * =================== 69 * 70 * PPP status callback is called on PPP status change (up, down, …) from lwIP 71 * core thread 72 */ 73 74/* PPP status callback example */ 75static void status_cb(ppp_pcb *pcb, int err_code, void *ctx) { 76 struct netif *pppif = ppp_netif(pcb); 77 LWIP_UNUSED_ARG(ctx); 78 79 switch(err_code) { 80 case PPPERR_NONE: { 81#if LWIP_DNS 82 const ip_addr_t *ns; 83#endif /* LWIP_DNS */ 84 printf("status_cb: Connected\n"); 85#if PPP_IPV4_SUPPORT 86 printf(" our_ipaddr = %s\n", ipaddr_ntoa(&pppif->ip_addr)); 87 printf(" his_ipaddr = %s\n", ipaddr_ntoa(&pppif->gw)); 88 printf(" netmask = %s\n", ipaddr_ntoa(&pppif->netmask)); 89#if LWIP_DNS 90 ns = dns_getserver(0); 91 printf(" dns1 = %s\n", ipaddr_ntoa(ns)); 92 ns = dns_getserver(1); 93 printf(" dns2 = %s\n", ipaddr_ntoa(ns)); 94#endif /* LWIP_DNS */ 95#endif /* PPP_IPV4_SUPPORT */ 96#if PPP_IPV6_SUPPORT 97 printf(" our6_ipaddr = %s\n", ip6addr_ntoa(netif_ip6_addr(pppif, 0))); 98#endif /* PPP_IPV6_SUPPORT */ 99 break; 100 } 101 case PPPERR_PARAM: { 102 printf("status_cb: Invalid parameter\n"); 103 break; 104 } 105 case PPPERR_OPEN: { 106 printf("status_cb: Unable to open PPP session\n"); 107 break; 108 } 109 case PPPERR_DEVICE: { 110 printf("status_cb: Invalid I/O device for PPP\n"); 111 break; 112 } 113 case PPPERR_ALLOC: { 114 printf("status_cb: Unable to allocate resources\n"); 115 break; 116 } 117 case PPPERR_USER: { 118 printf("status_cb: User interrupt\n"); 119 break; 120 } 121 case PPPERR_CONNECT: { 122 printf("status_cb: Connection lost\n"); 123 break; 124 } 125 case PPPERR_AUTHFAIL: { 126 printf("status_cb: Failed authentication challenge\n"); 127 break; 128 } 129 case PPPERR_PROTOCOL: { 130 printf("status_cb: Failed to meet protocol\n"); 131 break; 132 } 133 case PPPERR_PEERDEAD: { 134 printf("status_cb: Connection timeout\n"); 135 break; 136 } 137 case PPPERR_IDLETIMEOUT: { 138 printf("status_cb: Idle Timeout\n"); 139 break; 140 } 141 case PPPERR_CONNECTTIME: { 142 printf("status_cb: Max connect time reached\n"); 143 break; 144 } 145 case PPPERR_LOOPBACK: { 146 printf("status_cb: Loopback detected\n"); 147 break; 148 } 149 default: { 150 printf("status_cb: Unknown error code %d\n", err_code); 151 break; 152 } 153 } 154 155/* 156 * This should be in the switch case, this is put outside of the switch 157 * case for example readability. 158 */ 159 160 if (err_code == PPPERR_NONE) { 161 return; 162 } 163 164 /* ppp_close() was previously called, don't reconnect */ 165 if (err_code == PPPERR_USER) { 166 /* ppp_free(); -- can be called here */ 167 return; 168 } 169 170 /* 171 * Try to reconnect in 30 seconds, if you need a modem chatscript you have 172 * to do a much better signaling here ;-) 173 */ 174 ppp_connect(pcb, 30); 175 /* OR ppp_listen(pcb); */ 176} 177 178 179/* 180 * Creating a new PPPoS session 181 * ============================ 182 * 183 * In lwIP, PPPoS is not PPPoSONET, in lwIP PPPoS is PPPoSerial. 184 */ 185 186#include "netif/ppp/pppos.h" 187 188/* 189 * PPPoS serial output callback 190 * 191 * ppp_pcb, PPP control block 192 * data, buffer to write to serial port 193 * len, length of the data buffer 194 * ctx, optional user-provided callback context pointer 195 * 196 * Return value: len if write succeed 197 */ 198static u32_t output_cb(ppp_pcb *pcb, u8_t *data, u32_t len, void *ctx) { 199 return uart_write(UART, data, len); 200} 201 202/* 203 * Create a new PPPoS interface 204 * 205 * ppp_netif, netif to use for this PPP link, i.e. PPP IP interface 206 * output_cb, PPPoS serial output callback 207 * status_cb, PPP status callback, called on PPP status change (up, down, …) 208 * ctx_cb, optional user-provided callback context pointer 209 */ 210ppp = pppos_create(&ppp_netif, 211 output_cb, status_cb, ctx_cb); 212 213 214/* 215 * Creating a new PPPoE session 216 * ============================ 217 */ 218 219#include "netif/ppp/pppoe.h" 220 221/* 222 * Create a new PPPoE interface 223 * 224 * ppp_netif, netif to use for this PPP link, i.e. PPP IP interface 225 * ethif, already existing and setup Ethernet interface to use 226 * service_name, PPPoE service name discriminator (not supported yet) 227 * concentrator_name, PPPoE concentrator name discriminator (not supported yet) 228 * status_cb, PPP status callback, called on PPP status change (up, down, …) 229 * ctx_cb, optional user-provided callback context pointer 230 */ 231ppp = pppoe_create(&ppp_netif, 232 ðif, 233 service_name, concentrator_name, 234 status_cb, ctx_cb); 235 236 237/* 238 * Creating a new PPPoL2TP session 239 * =============================== 240 */ 241 242#include "netif/ppp/pppol2tp.h" 243 244/* 245 * Create a new PPPoL2TP interface 246 * 247 * ppp_netif, netif to use for this PPP link, i.e. PPP IP interface 248 * netif, optional already existing and setup output netif, necessary if you 249 * want to set this interface as default route to settle the chicken 250 * and egg problem with VPN links 251 * ipaddr, IP to connect to 252 * port, UDP port to connect to (usually 1701) 253 * secret, L2TP secret to use 254 * secret_len, size in bytes of the L2TP secret 255 * status_cb, PPP status callback, called on PPP status change (up, down, …) 256 * ctx_cb, optional user-provided callback context pointer 257 */ 258ppp = pppol2tp_create(&ppp_netif, 259 struct netif *netif, ip_addr_t *ipaddr, u16_t port, 260 u8_t *secret, u8_t secret_len, 261 ppp_link_status_cb_fn link_status_cb, void *ctx_cb); 262 263 264/* 265 * Initiate PPP client connection 266 * ============================== 267 */ 268 269/* Set this interface as default route */ 270ppp_set_default(ppp); 271 272/* 273 * Basic PPP client configuration. Can only be set if PPP session is in the 274 * dead state (i.e. disconnected). We don't need to provide thread-safe 275 * equivalents through PPPAPI because those helpers are only changing 276 * structure members while session is inactive for lwIP core. Configuration 277 * only need to be done once. 278 */ 279 280/* Ask the peer for up to 2 DNS server addresses. */ 281ppp_set_usepeerdns(ppp, 1); 282 283/* Auth configuration, this is pretty self-explanatory */ 284ppp_set_auth(ppp, PPPAUTHTYPE_ANY, "login", "password"); 285 286/* 287 * Initiate PPP negotiation, without waiting (holdoff=0), can only be called 288 * if PPP session is in the dead state (i.e. disconnected). 289 */ 290u16_t holdoff = 0; 291ppp_connect(ppp, holdoff); 292 293 294/* 295 * Initiate PPP server listener 296 * ============================ 297 */ 298 299/* 300 * Basic PPP server configuration. Can only be set if PPP session is in the 301 * dead state (i.e. disconnected). We don't need to provide thread-safe 302 * equivalents through PPPAPI because those helpers are only changing 303 * structure members while session is inactive for lwIP core. Configuration 304 * only need to be done once. 305 */ 306ip4_addr_t addr; 307 308/* Set our address */ 309IP4_ADDR(&addr, 192,168,0,1); 310ppp_set_ipcp_ouraddr(ppp, &addr); 311 312/* Set peer(his) address */ 313IP4_ADDR(&addr, 192,168,0,2); 314ppp_set_ipcp_hisaddr(ppp, &addr); 315 316/* Set primary DNS server */ 317IP4_ADDR(&addr, 192,168,10,20); 318ppp_set_ipcp_dnsaddr(ppp, 0, &addr); 319 320/* Set secondary DNS server */ 321IP4_ADDR(&addr, 192,168,10,21); 322ppp_set_ipcp_dnsaddr(ppp, 1, &addr); 323 324/* Auth configuration, this is pretty self-explanatory */ 325ppp_set_auth(ppp, PPPAUTHTYPE_ANY, "login", "password"); 326 327/* Require peer to authenticate */ 328ppp_set_auth_required(ppp, 1); 329 330/* 331 * Only for PPPoS, the PPP session should be up and waiting for input. 332 * 333 * Note: for PPPoS, ppp_connect() and ppp_listen() are actually the same thing. 334 * The listen call is meant for future support of PPPoE and PPPoL2TP server 335 * mode, where we will need to negotiate the incoming PPPoE session or L2TP 336 * session before initiating PPP itself. We need this call because there is 337 * two passive modes for PPPoS, ppp_set_passive and ppp_set_silent. 338 */ 339ppp_set_silent(pppos, 1); 340 341/* 342 * Initiate PPP listener (i.e. wait for an incoming connection), can only 343 * be called if PPP session is in the dead state (i.e. disconnected). 344 */ 345ppp_listen(ppp); 346 347 348/* 349 * Closing PPP connection 350 * ====================== 351 */ 352 353/* 354 * Initiate the end of the PPP session, without carrier lost signal 355 * (nocarrier=0), meaning a clean shutdown of PPP protocols. 356 * You can call this function at anytime. 357 */ 358u8_t nocarrier = 0; 359ppp_close(ppp, nocarrier); 360/* 361 * Then you must wait your status_cb() to be called, it may takes from a few 362 * seconds to several tens of seconds depending on the current PPP state. 363 */ 364 365/* 366 * Freeing a PPP connection 367 * ======================== 368 */ 369 370/* 371 * Free the PPP control block, can only be called if PPP session is in the 372 * dead state (i.e. disconnected). You need to call ppp_close() before. 373 */ 374ppp_free(ppp); 375 376 377 3783 PPPoS input path (raw API, IRQ safe API, TCPIP API) 379===================================================== 380 381Received data on serial port should be sent to lwIP using the pppos_input() 382function or the pppos_input_tcpip() function. 383 384If NO_SYS is 1 and if PPP_INPROC_IRQ_SAFE is 0 (the default), pppos_input() 385is not IRQ safe and then *MUST* only be called inside your main loop. 386 387Whatever the NO_SYS value, if PPP_INPROC_IRQ_SAFE is 1, pppos_input() is IRQ 388safe and can be safely called from an interrupt context, using that is going 389to reduce your need of buffer if pppos_input() is called byte after byte in 390your rx serial interrupt. 391 392if NO_SYS is 0, the thread safe way outside an interrupt context is to use 393the pppos_input_tcpip() function to pass input data to the lwIP core thread 394using the TCPIP API. This is thread safe in all cases but you should avoid 395passing data byte after byte because it uses heavy locking (mailbox) and it 396allocates pbuf, better fill them ! 397 398if NO_SYS is 0 and if PPP_INPROC_IRQ_SAFE is 1, you may also use pppos_input() 399from an RX thread, however pppos_input() is not thread safe by itself. You can 400do that *BUT* you should NEVER call pppos_connect(), pppos_listen() and 401ppp_free() if pppos_input() can still be running, doing this is NOT thread safe 402at all. Using PPP_INPROC_IRQ_SAFE from an RX thread is discouraged unless you 403really know what you are doing, your move ;-) 404 405 406/* 407 * Fonction to call for received data 408 * 409 * ppp, PPP control block 410 * buffer, input buffer 411 * buffer_len, buffer length in bytes 412 */ 413void pppos_input(ppp, buffer, buffer_len); 414 415or 416 417void pppos_input_tcpip(ppp, buffer, buffer_len); 418 419 420 4214 Thread safe PPP API (PPPAPI) 422============================== 423 424There is a thread safe API for all corresponding ppp_* functions, you have to 425enable LWIP_PPP_API in your lwipopts.h file, then see 426include/netif/ppp/pppapi.h, this is actually pretty obvious. 427 428 429 4305 Notify phase callback (PPP_NOTIFY_PHASE) 431========================================== 432 433Notify phase callback, enabled using the PPP_NOTIFY_PHASE config option, let 434you configure a callback that is called on each PPP internal state change. 435This is different from the status callback which only warns you about 436up(running) and down(dead) events. 437 438Notify phase callback can be used, for example, to set a LED pattern depending 439on the current phase of the PPP session. Here is a callback example which 440tries to mimic what we usually see on xDSL modems while they are negotiating 441the link, which should be self-explanatory: 442 443static void ppp_notify_phase_cb(ppp_pcb *pcb, u8_t phase, void *ctx) { 444 switch (phase) { 445 446 /* Session is down (either permanently or briefly) */ 447 case PPP_PHASE_DEAD: 448 led_set(PPP_LED, LED_OFF); 449 break; 450 451 /* We are between two sessions */ 452 case PPP_PHASE_HOLDOFF: 453 led_set(PPP_LED, LED_SLOW_BLINK); 454 break; 455 456 /* Session just started */ 457 case PPP_PHASE_INITIALIZE: 458 led_set(PPP_LED, LED_FAST_BLINK); 459 break; 460 461 /* Session is running */ 462 case PPP_PHASE_RUNNING: 463 led_set(PPP_LED, LED_ON); 464 break; 465 466 default: 467 break; 468 } 469} 470 471 472 4736 Upgrading from lwIP <= 1.4.x to lwIP >= 2.0.x 474=============================================== 475 476PPP API was fully reworked between 1.4.x and 2.0.x releases. However porting 477from previous lwIP version is pretty easy: 478 479* Previous PPP API used an integer to identify PPP sessions, we are now 480 using ppp_pcb* control block, therefore all functions changed from "int ppp" 481 to "ppp_pcb *ppp" 482 483* struct netif was moved outside the PPP structure, you have to provide a netif 484 for PPP interface in pppoX_create() functions 485 486* PPP session are not started automatically after you created them anymore, 487 you have to call ppp_connect(), this way you can configure the session before 488 starting it. 489 490* Previous PPP API used CamelCase, we are now using snake_case. 491 492* Previous PPP API mixed PPPoS and PPPoE calls, this isn't the case anymore, 493 PPPoS functions are now prefixed pppos_ and PPPoE functions are now prefixed 494 pppoe_, common functions are now prefixed ppp_. 495 496* New PPPERR_ error codes added, check you have all of them in your status 497 callback function 498 499* Only the following include files should now be used in user application: 500 #include "netif/ppp/pppapi.h" 501 #include "netif/ppp/pppos.h" 502 #include "netif/ppp/pppoe.h" 503 #include "netif/ppp/pppol2tp.h" 504 505 Functions from ppp.h can be used, but you don't need to include this header 506 file as it is already included by above header files. 507 508* PPP_INPROC_OWNTHREAD was broken by design and was removed, you have to create 509 your own serial rx thread 510 511* PPP_INPROC_MULTITHREADED option was misnamed and confusing and was renamed 512 PPP_INPROC_IRQ_SAFE, please read the "PPPoS input path" documentation above 513 because you might have been fooled by that 514 515* If you used tcpip_callback_with_block() on ppp_ functions you may wish to use 516 the PPPAPI API instead. 517 518* ppp_sighup and ppp_close functions were merged using an optional argument 519 "nocarrier" on ppp_close. 520 521* DNS servers are now only remotely asked if LWIP_DNS is set and if 522 ppp_set_usepeerdns() is set to true, they are now automatically registered 523 using the dns_setserver() function so you don't need to do that in the PPP 524 callback anymore. 525 526* PPPoS does not use the SIO API anymore, as such it now requires a serial 527 output callback in place of sio_write 528 529* PPP_MAXIDLEFLAG is now in ms instead of jiffies 530