• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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       &ethif,
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