ppp.txt 15 KB

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