]> git.gir.st - tmk_keyboard.git/blob - tool/mbed/mbed-sdk/libraries/net/lwip/lwip/netif/ppp/ppp.c
Squashed 'tmk_core/' changes from 7967731..b9e0ea0
[tmk_keyboard.git] / tool / mbed / mbed-sdk / libraries / net / lwip / lwip / netif / ppp / ppp.c
1 /*****************************************************************************
2 * ppp.c - Network Point to Point Protocol program file.
3 *
4 * Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
5 * portions Copyright (c) 1997 by Global Election Systems Inc.
6 *
7 * The authors hereby grant permission to use, copy, modify, distribute,
8 * and license this software and its documentation for any purpose, provided
9 * that existing copyright notices are retained in all copies and that this
10 * notice and the following disclaimer are included verbatim in any
11 * distributions. No written agreement, license, or royalty fee is required
12 * for any of the authorized uses.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 *
25 ******************************************************************************
26 * REVISION HISTORY
27 *
28 * 03-01-01 Marc Boucher <marc@mbsi.ca>
29 * Ported to lwIP.
30 * 97-11-05 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
31 * Original.
32 *****************************************************************************/
33
34 /*
35 * ppp_defs.h - PPP definitions.
36 *
37 * if_pppvar.h - private structures and declarations for PPP.
38 *
39 * Copyright (c) 1994 The Australian National University.
40 * All rights reserved.
41 *
42 * Permission to use, copy, modify, and distribute this software and its
43 * documentation is hereby granted, provided that the above copyright
44 * notice appears in all copies. This software is provided without any
45 * warranty, express or implied. The Australian National University
46 * makes no representations about the suitability of this software for
47 * any purpose.
48 *
49 * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
50 * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
51 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
52 * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
53 * OF SUCH DAMAGE.
54 *
55 * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
56 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
57 * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
58 * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
59 * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
60 * OR MODIFICATIONS.
61 */
62
63 /*
64 * if_ppp.h - Point-to-Point Protocol definitions.
65 *
66 * Copyright (c) 1989 Carnegie Mellon University.
67 * All rights reserved.
68 *
69 * Redistribution and use in source and binary forms are permitted
70 * provided that the above copyright notice and this paragraph are
71 * duplicated in all such forms and that any documentation,
72 * advertising materials, and other materials related to such
73 * distribution and use acknowledge that the software was developed
74 * by Carnegie Mellon University. The name of the
75 * University may not be used to endorse or promote products derived
76 * from this software without specific prior written permission.
77 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
78 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
79 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
80 */
81
82 #include "lwip/opt.h"
83
84 #if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */
85
86 #include "lwip/ip.h" /* for ip_input() */
87
88 #include "ppp.h"
89 #include "pppdebug.h"
90
91 #include "randm.h"
92 #include "fsm.h"
93 #if PAP_SUPPORT
94 #include "pap.h"
95 #endif /* PAP_SUPPORT */
96 #if CHAP_SUPPORT
97 #include "chap.h"
98 #endif /* CHAP_SUPPORT */
99 #include "ipcp.h"
100 #include "lcp.h"
101 #include "magic.h"
102 #include "auth.h"
103 #if VJ_SUPPORT
104 #include "vj.h"
105 #endif /* VJ_SUPPORT */
106 #if PPPOE_SUPPORT
107 #include "netif/ppp_oe.h"
108 #endif /* PPPOE_SUPPORT */
109
110 #include "lwip/tcpip.h"
111 #include "lwip/api.h"
112 #include "lwip/snmp.h"
113
114 #include <string.h>
115
116 /*************************/
117 /*** LOCAL DEFINITIONS ***/
118 /*************************/
119
120 /** PPP_INPROC_MULTITHREADED==1 call pppInput using tcpip_callback().
121 * Set this to 0 if pppInProc is called inside tcpip_thread or with NO_SYS==1.
122 * Default is 1 for NO_SYS==0 (multithreaded) and 0 for NO_SYS==1 (single-threaded).
123 */
124 #ifndef PPP_INPROC_MULTITHREADED
125 #define PPP_INPROC_MULTITHREADED (NO_SYS==0)
126 #endif
127
128 /** PPP_INPROC_OWNTHREAD==1: start a dedicated RX thread per PPP session.
129 * Default is 0: call pppos_input() for received raw characters, charcater
130 * reception is up to the port */
131 #ifndef PPP_INPROC_OWNTHREAD
132 #define PPP_INPROC_OWNTHREAD PPP_INPROC_MULTITHREADED
133 #endif
134
135 #if PPP_INPROC_OWNTHREAD && !PPP_INPROC_MULTITHREADED
136 #error "PPP_INPROC_OWNTHREAD needs PPP_INPROC_MULTITHREADED==1"
137 #endif
138
139 /*
140 * The basic PPP frame.
141 */
142 #define PPP_ADDRESS(p) (((u_char *)(p))[0])
143 #define PPP_CONTROL(p) (((u_char *)(p))[1])
144 #define PPP_PROTOCOL(p) ((((u_char *)(p))[2] << 8) + ((u_char *)(p))[3])
145
146 /* PPP packet parser states. Current state indicates operation yet to be
147 * completed. */
148 typedef enum {
149 PDIDLE = 0, /* Idle state - waiting. */
150 PDSTART, /* Process start flag. */
151 PDADDRESS, /* Process address field. */
152 PDCONTROL, /* Process control field. */
153 PDPROTOCOL1, /* Process protocol field 1. */
154 PDPROTOCOL2, /* Process protocol field 2. */
155 PDDATA /* Process data byte. */
156 } PPPDevStates;
157
158 #define ESCAPE_P(accm, c) ((accm)[(c) >> 3] & pppACCMMask[c & 0x07])
159
160 /************************/
161 /*** LOCAL DATA TYPES ***/
162 /************************/
163
164 /** RX buffer size: this may be configured smaller! */
165 #ifndef PPPOS_RX_BUFSIZE
166 #define PPPOS_RX_BUFSIZE (PPP_MRU + PPP_HDRLEN)
167 #endif
168
169 typedef struct PPPControlRx_s {
170 /** unit number / ppp descriptor */
171 int pd;
172 /** the rx file descriptor */
173 sio_fd_t fd;
174 /** receive buffer - encoded data is stored here */
175 u_char rxbuf[PPPOS_RX_BUFSIZE];
176
177 /* The input packet. */
178 struct pbuf *inHead, *inTail;
179
180 #if PPPOS_SUPPORT
181 u16_t inProtocol; /* The input protocol code. */
182 u16_t inFCS; /* Input Frame Check Sequence value. */
183 #endif /* PPPOS_SUPPORT */
184 PPPDevStates inState; /* The input process state. */
185 char inEscaped; /* Escape next character. */
186 ext_accm inACCM; /* Async-Ctl-Char-Map for input. */
187 } PPPControlRx;
188
189 /*
190 * PPP interface control block.
191 */
192 typedef struct PPPControl_s {
193 PPPControlRx rx;
194 char openFlag; /* True when in use. */
195 #if PPPOE_SUPPORT
196 struct netif *ethif;
197 struct pppoe_softc *pppoe_sc;
198 #endif /* PPPOE_SUPPORT */
199 int if_up; /* True when the interface is up. */
200 int errCode; /* Code indicating why interface is down. */
201 #if PPPOS_SUPPORT
202 sio_fd_t fd; /* File device ID of port. */
203 #endif /* PPPOS_SUPPORT */
204 u16_t mtu; /* Peer's mru */
205 int pcomp; /* Does peer accept protocol compression? */
206 int accomp; /* Does peer accept addr/ctl compression? */
207 u_long lastXMit; /* Time of last transmission. */
208 ext_accm outACCM; /* Async-Ctl-Char-Map for output. */
209 #if PPPOS_SUPPORT && VJ_SUPPORT
210 int vjEnabled; /* Flag indicating VJ compression enabled. */
211 struct vjcompress vjComp; /* Van Jacobson compression header. */
212 #endif /* PPPOS_SUPPORT && VJ_SUPPORT */
213
214 struct netif netif;
215
216 struct ppp_addrs addrs;
217
218 void (*linkStatusCB)(void *ctx, int errCode, void *arg);
219 void *linkStatusCtx;
220
221 } PPPControl;
222
223
224 /*
225 * Ioctl definitions.
226 */
227
228 struct npioctl {
229 int protocol; /* PPP procotol, e.g. PPP_IP */
230 enum NPmode mode;
231 };
232
233
234
235 /***********************************/
236 /*** LOCAL FUNCTION DECLARATIONS ***/
237 /***********************************/
238 #if PPPOS_SUPPORT
239 #if PPP_INPROC_OWNTHREAD
240 static void pppInputThread(void *arg);
241 #endif /* PPP_INPROC_OWNTHREAD */
242 static void pppDrop(PPPControlRx *pcrx);
243 static void pppInProc(PPPControlRx *pcrx, u_char *s, int l);
244 #endif /* PPPOS_SUPPORT */
245
246
247 /******************************/
248 /*** PUBLIC DATA STRUCTURES ***/
249 /******************************/
250 u_long subnetMask;
251
252 static PPPControl pppControl[NUM_PPP] __attribute((section("AHBSRAM1"))); /* The PPP interface control blocks. */
253
254 sys_mbox_t pppMbox; //Used to signal PPP thread that a PPP session begins
255
256 /*
257 * PPP Data Link Layer "protocol" table.
258 * One entry per supported protocol.
259 * The last entry must be NULL.
260 */
261 struct protent *ppp_protocols[] = {
262 &lcp_protent,
263 #if PAP_SUPPORT
264 &pap_protent,
265 #endif /* PAP_SUPPORT */
266 #if CHAP_SUPPORT
267 &chap_protent,
268 #endif /* CHAP_SUPPORT */
269 #if CBCP_SUPPORT
270 &cbcp_protent,
271 #endif /* CBCP_SUPPORT */
272 &ipcp_protent,
273 #if CCP_SUPPORT
274 &ccp_protent,
275 #endif /* CCP_SUPPORT */
276 NULL
277 };
278
279
280 /*
281 * Buffers for outgoing packets. This must be accessed only from the appropriate
282 * PPP task so that it doesn't need to be protected to avoid collisions.
283 */
284 u_char outpacket_buf[NUM_PPP][PPP_MRU+PPP_HDRLEN] __attribute((section("AHBSRAM1")));
285
286
287 /*****************************/
288 /*** LOCAL DATA STRUCTURES ***/
289 /*****************************/
290
291 #if PPPOS_SUPPORT
292 /*
293 * FCS lookup table as calculated by genfcstab.
294 * @todo: smaller, slower implementation for lower memory footprint?
295 */
296 static const u_short fcstab[256] = {
297 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
298 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
299 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
300 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
301 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
302 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
303 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
304 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
305 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
306 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
307 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
308 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
309 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
310 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
311 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
312 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
313 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
314 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
315 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
316 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
317 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
318 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
319 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
320 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
321 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
322 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
323 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
324 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
325 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
326 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
327 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
328 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
329 };
330
331 /* PPP's Asynchronous-Control-Character-Map. The mask array is used
332 * to select the specific bit for a character. */
333 static u_char pppACCMMask[] = {
334 0x01,
335 0x02,
336 0x04,
337 0x08,
338 0x10,
339 0x20,
340 0x40,
341 0x80
342 };
343
344 /** Wake up the task blocked in reading from serial line (if any) */
345 static void
346 pppRecvWakeup(int pd)
347 {
348 PPPDEBUG(LOG_DEBUG, ("pppRecvWakeup: unit %d\n", pd));
349 if (pppControl[pd].openFlag != 0) {
350 sio_read_abort(pppControl[pd].fd);
351 }
352 }
353 #endif /* PPPOS_SUPPORT */
354
355 void
356 pppLinkTerminated(int pd)
357 {
358 PPPDEBUG(LOG_DEBUG, ("pppLinkTerminated: unit %d\n", pd));
359
360 #if PPPOE_SUPPORT
361 if (pppControl[pd].ethif) {
362 pppoe_disconnect(pppControl[pd].pppoe_sc);
363 } else
364 #endif /* PPPOE_SUPPORT */
365 {
366 #if PPPOS_SUPPORT
367 PPPControl* pc;
368 pppRecvWakeup(pd);
369 pc = &pppControl[pd];
370
371 PPPDEBUG(LOG_DEBUG, ("pppLinkTerminated: unit %d: linkStatusCB=%p errCode=%d\n", pd, pc->linkStatusCB, pc->errCode));
372 if (pc->linkStatusCB) {
373 pc->linkStatusCB(pc->linkStatusCtx, pc->errCode ? pc->errCode : PPPERR_PROTOCOL, NULL);
374 }
375
376 pc->openFlag = 0;/**/
377 #endif /* PPPOS_SUPPORT */
378 }
379 PPPDEBUG(LOG_DEBUG, ("pppLinkTerminated: finished.\n"));
380 }
381
382 void
383 pppLinkDown(int pd)
384 {
385 PPPDEBUG(LOG_DEBUG, ("pppLinkDown: unit %d\n", pd));
386
387 #if PPPOE_SUPPORT
388 if (pppControl[pd].ethif) {
389 pppoe_disconnect(pppControl[pd].pppoe_sc);
390 } else
391 #endif /* PPPOE_SUPPORT */
392 {
393 #if PPPOS_SUPPORT
394 pppRecvWakeup(pd);
395 #endif /* PPPOS_SUPPORT */
396 }
397 }
398
399 /** Initiate LCP open request */
400 static void
401 pppStart(int pd)
402 {
403 PPPDEBUG(LOG_DEBUG, ("pppStart: unit %d\n", pd));
404 lcp_lowerup(pd);
405 lcp_open(pd); /* Start protocol */
406 PPPDEBUG(LOG_DEBUG, ("pppStart: finished\n"));
407 }
408
409 /** LCP close request */
410 static void
411 pppStop(int pd)
412 {
413 PPPDEBUG(LOG_DEBUG, ("pppStop: unit %d\n", pd));
414 lcp_close(pd, "User request");
415 }
416
417 /** Called when carrier/link is lost */
418 static void
419 pppHup(int pd)
420 {
421 PPPDEBUG(LOG_DEBUG, ("pppHupCB: unit %d\n", pd));
422 lcp_lowerdown(pd);
423 link_terminated(pd);
424 }
425
426 /***********************************/
427 /*** PUBLIC FUNCTION DEFINITIONS ***/
428 /***********************************/
429 /* Initialize the PPP subsystem. */
430
431 struct ppp_settings ppp_settings;
432
433 void
434 pppInit(void)
435 {
436 struct protent *protp;
437 int i, j;
438
439 memset(&ppp_settings, 0, sizeof(ppp_settings));
440 ppp_settings.usepeerdns = 1;
441 pppSetAuth(PPPAUTHTYPE_NONE, NULL, NULL);
442
443 magicInit();
444
445 subnetMask = PP_HTONL(0xffffff00UL);
446
447 for (i = 0; i < NUM_PPP; i++) {
448 /* Initialize each protocol to the standard option set. */
449 for (j = 0; (protp = ppp_protocols[j]) != NULL; ++j) {
450 (*protp->init)(i);
451 }
452 }
453
454 sys_mbox_new(&pppMbox, 1);
455 sys_thread_new(PPP_THREAD_NAME, pppInputThread, (void*)NULL, PPP_THREAD_STACKSIZE, PPP_THREAD_PRIO); //Create PPP thread here
456 }
457
458 void
459 pppSetAuth(enum pppAuthType authType, const char *user, const char *passwd)
460 {
461 switch(authType) {
462 case PPPAUTHTYPE_NONE:
463 default:
464 #ifdef LWIP_PPP_STRICT_PAP_REJECT
465 ppp_settings.refuse_pap = 1;
466 #else /* LWIP_PPP_STRICT_PAP_REJECT */
467 /* some providers request pap and accept an empty login/pw */
468 ppp_settings.refuse_pap = 0;
469 #endif /* LWIP_PPP_STRICT_PAP_REJECT */
470 ppp_settings.refuse_chap = 1;
471 break;
472
473 case PPPAUTHTYPE_ANY:
474 /* Warning: Using PPPAUTHTYPE_ANY might have security consequences.
475 * RFC 1994 says:
476 *
477 * In practice, within or associated with each PPP server, there is a
478 * database which associates "user" names with authentication
479 * information ("secrets"). It is not anticipated that a particular
480 * named user would be authenticated by multiple methods. This would
481 * make the user vulnerable to attacks which negotiate the least secure
482 * method from among a set (such as PAP rather than CHAP). If the same
483 * secret was used, PAP would reveal the secret to be used later with
484 * CHAP.
485 *
486 * Instead, for each user name there should be an indication of exactly
487 * one method used to authenticate that user name. If a user needs to
488 * make use of different authentication methods under different
489 * circumstances, then distinct user names SHOULD be employed, each of
490 * which identifies exactly one authentication method.
491 *
492 */
493 ppp_settings.refuse_pap = 0;
494 ppp_settings.refuse_chap = 0;
495 break;
496
497 case PPPAUTHTYPE_PAP:
498 ppp_settings.refuse_pap = 0;
499 ppp_settings.refuse_chap = 1;
500 break;
501
502 case PPPAUTHTYPE_CHAP:
503 ppp_settings.refuse_pap = 1;
504 ppp_settings.refuse_chap = 0;
505 break;
506 }
507
508 if(user) {
509 strncpy(ppp_settings.user, user, sizeof(ppp_settings.user)-1);
510 ppp_settings.user[sizeof(ppp_settings.user)-1] = '\0';
511 } else {
512 ppp_settings.user[0] = '\0';
513 }
514
515 if(passwd) {
516 strncpy(ppp_settings.passwd, passwd, sizeof(ppp_settings.passwd)-1);
517 ppp_settings.passwd[sizeof(ppp_settings.passwd)-1] = '\0';
518 } else {
519 ppp_settings.passwd[0] = '\0';
520 }
521 }
522
523 #if PPPOS_SUPPORT
524 /** Open a new PPP connection using the given I/O device.
525 * This initializes the PPP control block but does not
526 * attempt to negotiate the LCP session. If this port
527 * connects to a modem, the modem connection must be
528 * established before calling this.
529 * Return a new PPP connection descriptor on success or
530 * an error code (negative) on failure.
531 *
532 * pppOpen() is directly defined to this function.
533 */
534 int
535 pppOverSerialOpen(sio_fd_t fd, void (*linkStatusCB)(void *ctx, int errCode, void *arg), void *linkStatusCtx)
536 {
537 PPPControl *pc;
538 int pd;
539
540 if (linkStatusCB == NULL) {
541 /* PPP is single-threaded: without a callback,
542 * there is no way to know when the link is up. */
543 return PPPERR_PARAM;
544 }
545
546 /* Find a free PPP session descriptor. */
547 for (pd = 0; pd < NUM_PPP && pppControl[pd].openFlag != 0; pd++);
548
549 if (pd >= NUM_PPP) {
550 pd = PPPERR_OPEN;
551 } else {
552 pc = &pppControl[pd];
553 /* @todo: is this correct or do I overwrite something? */
554 memset(pc, 0, sizeof(PPPControl));
555 pc->rx.pd = pd;
556 pc->rx.fd = fd;
557
558 pc->openFlag = 1;
559 pc->fd = fd;
560
561 #if VJ_SUPPORT
562 vj_compress_init(&pc->vjComp);
563 #endif /* VJ_SUPPORT */
564
565 /*
566 * Default the in and out accm so that escape and flag characters
567 * are always escaped.
568 */
569 pc->rx.inACCM[15] = 0x60; /* no need to protect since RX is not running */
570 pc->outACCM[15] = 0x60;
571
572 pc->linkStatusCB = linkStatusCB;
573 pc->linkStatusCtx = linkStatusCtx;
574
575 /*
576 * Start the connection and handle incoming events (packet or timeout).
577 */
578 PPPDEBUG(LOG_INFO, ("pppOverSerialOpen: unit %d: Connecting\n", pd));
579 pppStart(pd);
580 #if PPP_INPROC_OWNTHREAD
581 sys_mbox_post(&pppMbox, (void*)&pc->rx);
582 #endif
583 }
584
585 return pd;
586 }
587 #endif /* PPPOS_SUPPORT */
588
589 #if PPPOE_SUPPORT
590 static void pppOverEthernetLinkStatusCB(int pd, int up);
591
592 void
593 pppOverEthernetClose(int pd)
594 {
595 PPPControl* pc = &pppControl[pd];
596
597 /* *TJL* There's no lcp_deinit */
598 lcp_close(pd, NULL);
599
600 pppoe_destroy(&pc->netif);
601 }
602
603 int pppOverEthernetOpen(struct netif *ethif, const char *service_name, const char *concentrator_name, void (*linkStatusCB)(void *ctx, int errCode, void *arg), void *linkStatusCtx)
604 {
605 PPPControl *pc;
606 int pd;
607
608 LWIP_UNUSED_ARG(service_name);
609 LWIP_UNUSED_ARG(concentrator_name);
610
611 if (linkStatusCB == NULL) {
612 /* PPP is single-threaded: without a callback,
613 * there is no way to know when the link is up. */
614 return PPPERR_PARAM;
615 }
616
617 /* Find a free PPP session descriptor. Critical region? */
618 for (pd = 0; pd < NUM_PPP && pppControl[pd].openFlag != 0; pd++);
619 if (pd >= NUM_PPP) {
620 pd = PPPERR_OPEN;
621 } else {
622 pc = &pppControl[pd];
623 memset(pc, 0, sizeof(PPPControl));
624 pc->openFlag = 1;
625 pc->ethif = ethif;
626
627 pc->linkStatusCB = linkStatusCB;
628 pc->linkStatusCtx = linkStatusCtx;
629
630 lcp_wantoptions[pd].mru = PPPOE_MAXMTU;
631 lcp_wantoptions[pd].neg_asyncmap = 0;
632 lcp_wantoptions[pd].neg_pcompression = 0;
633 lcp_wantoptions[pd].neg_accompression = 0;
634
635 lcp_allowoptions[pd].mru = PPPOE_MAXMTU;
636 lcp_allowoptions[pd].neg_asyncmap = 0;
637 lcp_allowoptions[pd].neg_pcompression = 0;
638 lcp_allowoptions[pd].neg_accompression = 0;
639
640 if(pppoe_create(ethif, pd, pppOverEthernetLinkStatusCB, &pc->pppoe_sc) != ERR_OK) {
641 pc->openFlag = 0;
642 return PPPERR_OPEN;
643 }
644
645 pppoe_connect(pc->pppoe_sc);
646 }
647
648 return pd;
649 }
650 #endif /* PPPOE_SUPPORT */
651
652
653 /* Close a PPP connection and release the descriptor.
654 * Any outstanding packets in the queues are dropped.
655 * Return 0 on success, an error code on failure. */
656 int
657 pppClose(int pd)
658 {
659 PPPControl *pc = &pppControl[pd];
660 int st = 0;
661
662 PPPDEBUG(LOG_DEBUG, ("pppClose() called\n"));
663
664 /* Disconnect */
665 #if PPPOE_SUPPORT
666 if(pc->ethif) {
667 PPPDEBUG(LOG_DEBUG, ("pppClose: unit %d kill_link -> pppStop\n", pd));
668 pc->errCode = PPPERR_USER;
669 /* This will leave us at PHASE_DEAD. */
670 pppStop(pd);
671 } else
672 #endif /* PPPOE_SUPPORT */
673 {
674 #if PPPOS_SUPPORT
675 PPPDEBUG(LOG_DEBUG, ("pppClose: unit %d kill_link -> pppStop\n", pd));
676 pc->errCode = PPPERR_USER;
677 /* This will leave us at PHASE_DEAD. */
678 pppStop(pd);
679 pppRecvWakeup(pd);
680 #endif /* PPPOS_SUPPORT */
681 }
682
683 return st;
684 }
685
686 /* This function is called when carrier is lost on the PPP channel. */
687 void
688 pppSigHUP(int pd)
689 {
690 PPPDEBUG(LOG_DEBUG, ("pppSigHUP: unit %d sig_hup -> pppHupCB\n", pd));
691 pppHup(pd);
692 }
693
694 #if PPPOS_SUPPORT
695 static void
696 nPut(PPPControl *pc, struct pbuf *nb)
697 {
698 struct pbuf *b;
699 int c;
700
701 for(b = nb; b != NULL; b = b->next) {
702 if((c = sio_write(pc->fd, b->payload, b->len)) != b->len) {
703 PPPDEBUG(LOG_WARNING,
704 ("PPP nPut: incomplete sio_write(fd:%"SZT_F", len:%d, c: 0x%"X8_F") c = %d\n", (size_t)pc->fd, b->len, c, c));
705 LINK_STATS_INC(link.err);
706 pc->lastXMit = 0; /* prepend PPP_FLAG to next packet */
707 snmp_inc_ifoutdiscards(&pc->netif);
708 pbuf_free(nb);
709 return;
710 }
711 }
712
713 snmp_add_ifoutoctets(&pc->netif, nb->tot_len);
714 snmp_inc_ifoutucastpkts(&pc->netif);
715 pbuf_free(nb);
716 LINK_STATS_INC(link.xmit);
717 }
718
719 /*
720 * pppAppend - append given character to end of given pbuf. If outACCM
721 * is not NULL and the character needs to be escaped, do so.
722 * If pbuf is full, append another.
723 * Return the current pbuf.
724 */
725 static struct pbuf *
726 pppAppend(u_char c, struct pbuf *nb, ext_accm *outACCM)
727 {
728 struct pbuf *tb = nb;
729
730 /* Make sure there is room for the character and an escape code.
731 * Sure we don't quite fill the buffer if the character doesn't
732 * get escaped but is one character worth complicating this? */
733 /* Note: We assume no packet header. */
734 if (nb && (PBUF_POOL_BUFSIZE - nb->len) < 2) {
735 tb = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
736 if (tb) {
737 nb->next = tb;
738 } else {
739 LINK_STATS_INC(link.memerr);
740 }
741 nb = tb;
742 }
743
744 if (nb) {
745 if (outACCM && ESCAPE_P(*outACCM, c)) {
746 *((u_char*)nb->payload + nb->len++) = PPP_ESCAPE;
747 *((u_char*)nb->payload + nb->len++) = c ^ PPP_TRANS;
748 } else {
749 *((u_char*)nb->payload + nb->len++) = c;
750 }
751 }
752
753 return tb;
754 }
755 #endif /* PPPOS_SUPPORT */
756
757 #if PPPOE_SUPPORT
758 static err_t
759 pppifOutputOverEthernet(int pd, struct pbuf *p)
760 {
761 PPPControl *pc = &pppControl[pd];
762 struct pbuf *pb;
763 u_short protocol = PPP_IP;
764 int i=0;
765 u16_t tot_len;
766
767 /* @todo: try to use pbuf_header() here! */
768 pb = pbuf_alloc(PBUF_LINK, PPPOE_HDRLEN + sizeof(protocol), PBUF_RAM);
769 if(!pb) {
770 LINK_STATS_INC(link.memerr);
771 LINK_STATS_INC(link.proterr);
772 snmp_inc_ifoutdiscards(&pc->netif);
773 return ERR_MEM;
774 }
775
776 pbuf_header(pb, -(s16_t)PPPOE_HDRLEN);
777
778 pc->lastXMit = sys_jiffies();
779
780 if (!pc->pcomp || protocol > 0xFF) {
781 *((u_char*)pb->payload + i++) = (protocol >> 8) & 0xFF;
782 }
783 *((u_char*)pb->payload + i) = protocol & 0xFF;
784
785 pbuf_chain(pb, p);
786 tot_len = pb->tot_len;
787
788 if(pppoe_xmit(pc->pppoe_sc, pb) != ERR_OK) {
789 LINK_STATS_INC(link.err);
790 snmp_inc_ifoutdiscards(&pc->netif);
791 return PPPERR_DEVICE;
792 }
793
794 snmp_add_ifoutoctets(&pc->netif, tot_len);
795 snmp_inc_ifoutucastpkts(&pc->netif);
796 LINK_STATS_INC(link.xmit);
797 return ERR_OK;
798 }
799 #endif /* PPPOE_SUPPORT */
800
801 /* Send a packet on the given connection. */
802 static err_t
803 pppifOutput(struct netif *netif, struct pbuf *pb, ip_addr_t *ipaddr)
804 {
805 int pd = (int)(size_t)netif->state;
806 PPPControl *pc = &pppControl[pd];
807 #if PPPOS_SUPPORT
808 u_short protocol = PPP_IP;
809 u_int fcsOut = PPP_INITFCS;
810 struct pbuf *headMB = NULL, *tailMB = NULL, *p;
811 u_char c;
812 #endif /* PPPOS_SUPPORT */
813
814 LWIP_UNUSED_ARG(ipaddr);
815
816 /* Validate parameters. */
817 /* We let any protocol value go through - it can't hurt us
818 * and the peer will just drop it if it's not accepting it. */
819 if (pd < 0 || pd >= NUM_PPP || !pc->openFlag || !pb) {
820 PPPDEBUG(LOG_WARNING, ("pppifOutput[%d]: bad parms prot=%d pb=%p\n",
821 pd, PPP_IP, pb));
822 LINK_STATS_INC(link.opterr);
823 LINK_STATS_INC(link.drop);
824 snmp_inc_ifoutdiscards(netif);
825 return ERR_ARG;
826 }
827
828 /* Check that the link is up. */
829 if (lcp_phase[pd] == PHASE_DEAD) {
830 PPPDEBUG(LOG_ERR, ("pppifOutput[%d]: link not up\n", pd));
831 LINK_STATS_INC(link.rterr);
832 LINK_STATS_INC(link.drop);
833 snmp_inc_ifoutdiscards(netif);
834 return ERR_RTE;
835 }
836
837 #if PPPOE_SUPPORT
838 if(pc->ethif) {
839 return pppifOutputOverEthernet(pd, pb);
840 }
841 #endif /* PPPOE_SUPPORT */
842
843 #if PPPOS_SUPPORT
844 /* Grab an output buffer. */
845 headMB = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
846 if (headMB == NULL) {
847 PPPDEBUG(LOG_WARNING, ("pppifOutput[%d]: first alloc fail\n", pd));
848 LINK_STATS_INC(link.memerr);
849 LINK_STATS_INC(link.drop);
850 snmp_inc_ifoutdiscards(netif);
851 return ERR_MEM;
852 }
853
854 #if VJ_SUPPORT
855 /*
856 * Attempt Van Jacobson header compression if VJ is configured and
857 * this is an IP packet.
858 */
859 if (protocol == PPP_IP && pc->vjEnabled) {
860 switch (vj_compress_tcp(&pc->vjComp, pb)) {
861 case TYPE_IP:
862 /* No change...
863 protocol = PPP_IP_PROTOCOL; */
864 break;
865 case TYPE_COMPRESSED_TCP:
866 protocol = PPP_VJC_COMP;
867 break;
868 case TYPE_UNCOMPRESSED_TCP:
869 protocol = PPP_VJC_UNCOMP;
870 break;
871 default:
872 PPPDEBUG(LOG_WARNING, ("pppifOutput[%d]: bad IP packet\n", pd));
873 LINK_STATS_INC(link.proterr);
874 LINK_STATS_INC(link.drop);
875 snmp_inc_ifoutdiscards(netif);
876 pbuf_free(headMB);
877 return ERR_VAL;
878 }
879 }
880 #endif /* VJ_SUPPORT */
881
882 tailMB = headMB;
883
884 /* Build the PPP header. */
885 if ((sys_jiffies() - pc->lastXMit) >= PPP_MAXIDLEFLAG) {
886 tailMB = pppAppend(PPP_FLAG, tailMB, NULL);
887 }
888
889 pc->lastXMit = sys_jiffies();
890 if (!pc->accomp) {
891 fcsOut = PPP_FCS(fcsOut, PPP_ALLSTATIONS);
892 tailMB = pppAppend(PPP_ALLSTATIONS, tailMB, &pc->outACCM);
893 fcsOut = PPP_FCS(fcsOut, PPP_UI);
894 tailMB = pppAppend(PPP_UI, tailMB, &pc->outACCM);
895 }
896 if (!pc->pcomp || protocol > 0xFF) {
897 c = (protocol >> 8) & 0xFF;
898 fcsOut = PPP_FCS(fcsOut, c);
899 tailMB = pppAppend(c, tailMB, &pc->outACCM);
900 }
901 c = protocol & 0xFF;
902 fcsOut = PPP_FCS(fcsOut, c);
903 tailMB = pppAppend(c, tailMB, &pc->outACCM);
904
905 /* Load packet. */
906 for(p = pb; p; p = p->next) {
907 int n;
908 u_char *sPtr;
909
910 sPtr = (u_char*)p->payload;
911 n = p->len;
912 while (n-- > 0) {
913 c = *sPtr++;
914
915 /* Update FCS before checking for special characters. */
916 fcsOut = PPP_FCS(fcsOut, c);
917
918 /* Copy to output buffer escaping special characters. */
919 tailMB = pppAppend(c, tailMB, &pc->outACCM);
920 }
921 }
922
923 /* Add FCS and trailing flag. */
924 c = ~fcsOut & 0xFF;
925 tailMB = pppAppend(c, tailMB, &pc->outACCM);
926 c = (~fcsOut >> 8) & 0xFF;
927 tailMB = pppAppend(c, tailMB, &pc->outACCM);
928 tailMB = pppAppend(PPP_FLAG, tailMB, NULL);
929
930 /* If we failed to complete the packet, throw it away. */
931 if (!tailMB) {
932 PPPDEBUG(LOG_WARNING,
933 ("pppifOutput[%d]: Alloc err - dropping proto=%d\n",
934 pd, protocol));
935 pbuf_free(headMB);
936 LINK_STATS_INC(link.memerr);
937 LINK_STATS_INC(link.drop);
938 snmp_inc_ifoutdiscards(netif);
939 return ERR_MEM;
940 }
941
942 /* Send it. */
943 PPPDEBUG(LOG_INFO, ("pppifOutput[%d]: proto=0x%"X16_F"\n", pd, protocol));
944
945 nPut(pc, headMB);
946 #endif /* PPPOS_SUPPORT */
947
948 return ERR_OK;
949 }
950
951 /* Get and set parameters for the given connection.
952 * Return 0 on success, an error code on failure. */
953 int
954 pppIOCtl(int pd, int cmd, void *arg)
955 {
956 PPPControl *pc = &pppControl[pd];
957 int st = 0;
958
959 if (pd < 0 || pd >= NUM_PPP) {
960 st = PPPERR_PARAM;
961 } else {
962 switch(cmd) {
963 case PPPCTLG_UPSTATUS: /* Get the PPP up status. */
964 if (arg) {
965 *(int *)arg = (int)(pc->if_up);
966 } else {
967 st = PPPERR_PARAM;
968 }
969 break;
970 case PPPCTLS_ERRCODE: /* Set the PPP error code. */
971 if (arg) {
972 pc->errCode = *(int *)arg;
973 } else {
974 st = PPPERR_PARAM;
975 }
976 break;
977 case PPPCTLG_ERRCODE: /* Get the PPP error code. */
978 if (arg) {
979 *(int *)arg = (int)(pc->errCode);
980 } else {
981 st = PPPERR_PARAM;
982 }
983 break;
984 #if PPPOS_SUPPORT
985 case PPPCTLG_FD: /* Get the fd associated with the ppp */
986 if (arg) {
987 *(sio_fd_t *)arg = pc->fd;
988 } else {
989 st = PPPERR_PARAM;
990 }
991 break;
992 #endif /* PPPOS_SUPPORT */
993 default:
994 st = PPPERR_PARAM;
995 break;
996 }
997 }
998
999 return st;
1000 }
1001
1002 /*
1003 * Return the Maximum Transmission Unit for the given PPP connection.
1004 */
1005 u_short
1006 pppMTU(int pd)
1007 {
1008 PPPControl *pc = &pppControl[pd];
1009 u_short st;
1010
1011 /* Validate parameters. */
1012 if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
1013 st = 0;
1014 } else {
1015 st = pc->mtu;
1016 }
1017
1018 return st;
1019 }
1020
1021 #if PPPOE_SUPPORT
1022 int
1023 pppWriteOverEthernet(int pd, const u_char *s, int n)
1024 {
1025 PPPControl *pc = &pppControl[pd];
1026 struct pbuf *pb;
1027
1028 /* skip address & flags */
1029 s += 2;
1030 n -= 2;
1031
1032 LWIP_ASSERT("PPPOE_HDRLEN + n <= 0xffff", PPPOE_HDRLEN + n <= 0xffff);
1033 pb = pbuf_alloc(PBUF_LINK, (u16_t)(PPPOE_HDRLEN + n), PBUF_RAM);
1034 if(!pb) {
1035 LINK_STATS_INC(link.memerr);
1036 LINK_STATS_INC(link.proterr);
1037 snmp_inc_ifoutdiscards(&pc->netif);
1038 return PPPERR_ALLOC;
1039 }
1040
1041 pbuf_header(pb, -(s16_t)PPPOE_HDRLEN);
1042
1043 pc->lastXMit = sys_jiffies();
1044
1045 MEMCPY(pb->payload, s, n);
1046
1047 if(pppoe_xmit(pc->pppoe_sc, pb) != ERR_OK) {
1048 LINK_STATS_INC(link.err);
1049 snmp_inc_ifoutdiscards(&pc->netif);
1050 return PPPERR_DEVICE;
1051 }
1052
1053 snmp_add_ifoutoctets(&pc->netif, (u16_t)n);
1054 snmp_inc_ifoutucastpkts(&pc->netif);
1055 LINK_STATS_INC(link.xmit);
1056 return PPPERR_NONE;
1057 }
1058 #endif /* PPPOE_SUPPORT */
1059
1060 /*
1061 * Write n characters to a ppp link.
1062 * RETURN: >= 0 Number of characters written
1063 * -1 Failed to write to device
1064 */
1065 int
1066 pppWrite(int pd, const u_char *s, int n)
1067 {
1068 PPPControl *pc = &pppControl[pd];
1069 #if PPPOS_SUPPORT
1070 u_char c;
1071 u_int fcsOut;
1072 struct pbuf *headMB, *tailMB;
1073 #endif /* PPPOS_SUPPORT */
1074
1075 #if PPPOE_SUPPORT
1076 if(pc->ethif) {
1077 return pppWriteOverEthernet(pd, s, n);
1078 }
1079 #endif /* PPPOE_SUPPORT */
1080
1081 #if PPPOS_SUPPORT
1082 headMB = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
1083 if (headMB == NULL) {
1084 LINK_STATS_INC(link.memerr);
1085 LINK_STATS_INC(link.proterr);
1086 snmp_inc_ifoutdiscards(&pc->netif);
1087 return PPPERR_ALLOC;
1088 }
1089
1090 tailMB = headMB;
1091
1092 /* If the link has been idle, we'll send a fresh flag character to
1093 * flush any noise. */
1094 if ((sys_jiffies() - pc->lastXMit) >= PPP_MAXIDLEFLAG) {
1095 tailMB = pppAppend(PPP_FLAG, tailMB, NULL);
1096 }
1097 pc->lastXMit = sys_jiffies();
1098
1099 fcsOut = PPP_INITFCS;
1100 /* Load output buffer. */
1101 while (n-- > 0) {
1102 c = *s++;
1103
1104 /* Update FCS before checking for special characters. */
1105 fcsOut = PPP_FCS(fcsOut, c);
1106
1107 /* Copy to output buffer escaping special characters. */
1108 tailMB = pppAppend(c, tailMB, &pc->outACCM);
1109 }
1110
1111 /* Add FCS and trailing flag. */
1112 c = ~fcsOut & 0xFF;
1113 tailMB = pppAppend(c, tailMB, &pc->outACCM);
1114 c = (~fcsOut >> 8) & 0xFF;
1115 tailMB = pppAppend(c, tailMB, &pc->outACCM);
1116 tailMB = pppAppend(PPP_FLAG, tailMB, NULL);
1117
1118 /* If we failed to complete the packet, throw it away.
1119 * Otherwise send it. */
1120 if (!tailMB) {
1121 PPPDEBUG(LOG_WARNING,
1122 ("pppWrite[%d]: Alloc err - dropping pbuf len=%d\n", pd, headMB->len));
1123 /*"pppWrite[%d]: Alloc err - dropping %d:%.*H", pd, headMB->len, LWIP_MIN(headMB->len * 2, 40), headMB->payload)); */
1124 pbuf_free(headMB);
1125 LINK_STATS_INC(link.memerr);
1126 LINK_STATS_INC(link.proterr);
1127 snmp_inc_ifoutdiscards(&pc->netif);
1128 return PPPERR_ALLOC;
1129 }
1130
1131 PPPDEBUG(LOG_INFO, ("pppWrite[%d]: len=%d\n", pd, headMB->len));
1132 /* "pppWrite[%d]: %d:%.*H", pd, headMB->len, LWIP_MIN(headMB->len * 2, 40), headMB->payload)); */
1133 nPut(pc, headMB);
1134 #endif /* PPPOS_SUPPORT */
1135
1136 return PPPERR_NONE;
1137 }
1138
1139 /*
1140 * ppp_send_config - configure the transmit characteristics of
1141 * the ppp interface.
1142 */
1143 void
1144 ppp_send_config( int unit, u16_t mtu, u32_t asyncmap, int pcomp, int accomp)
1145 {
1146 PPPControl *pc = &pppControl[unit];
1147 int i;
1148
1149 pc->mtu = mtu;
1150 pc->pcomp = pcomp;
1151 pc->accomp = accomp;
1152
1153 /* Load the ACCM bits for the 32 control codes. */
1154 for (i = 0; i < 32/8; i++) {
1155 pc->outACCM[i] = (u_char)((asyncmap >> (8 * i)) & 0xFF);
1156 }
1157 PPPDEBUG(LOG_INFO, ("ppp_send_config[%d]: outACCM=%X %X %X %X\n",
1158 unit,
1159 pc->outACCM[0], pc->outACCM[1], pc->outACCM[2], pc->outACCM[3]));
1160 }
1161
1162
1163 /*
1164 * ppp_set_xaccm - set the extended transmit ACCM for the interface.
1165 */
1166 void
1167 ppp_set_xaccm(int unit, ext_accm *accm)
1168 {
1169 SMEMCPY(pppControl[unit].outACCM, accm, sizeof(ext_accm));
1170 PPPDEBUG(LOG_INFO, ("ppp_set_xaccm[%d]: outACCM=%X %X %X %X\n",
1171 unit,
1172 pppControl[unit].outACCM[0],
1173 pppControl[unit].outACCM[1],
1174 pppControl[unit].outACCM[2],
1175 pppControl[unit].outACCM[3]));
1176 }
1177
1178
1179 /*
1180 * ppp_recv_config - configure the receive-side characteristics of
1181 * the ppp interface.
1182 */
1183 void
1184 ppp_recv_config( int unit, int mru, u32_t asyncmap, int pcomp, int accomp)
1185 {
1186 PPPControl *pc = &pppControl[unit];
1187 int i;
1188 SYS_ARCH_DECL_PROTECT(lev);
1189
1190 LWIP_UNUSED_ARG(accomp);
1191 LWIP_UNUSED_ARG(pcomp);
1192 LWIP_UNUSED_ARG(mru);
1193
1194 /* Load the ACCM bits for the 32 control codes. */
1195 SYS_ARCH_PROTECT(lev);
1196 for (i = 0; i < 32 / 8; i++) {
1197 /* @todo: does this work? ext_accm has been modified from pppd! */
1198 pc->rx.inACCM[i] = (u_char)(asyncmap >> (i * 8));
1199 }
1200 SYS_ARCH_UNPROTECT(lev);
1201 PPPDEBUG(LOG_INFO, ("ppp_recv_config[%d]: inACCM=%X %X %X %X\n",
1202 unit,
1203 pc->rx.inACCM[0], pc->rx.inACCM[1], pc->rx.inACCM[2], pc->rx.inACCM[3]));
1204 }
1205
1206 #if 0
1207 /*
1208 * ccp_test - ask kernel whether a given compression method
1209 * is acceptable for use. Returns 1 if the method and parameters
1210 * are OK, 0 if the method is known but the parameters are not OK
1211 * (e.g. code size should be reduced), or -1 if the method is unknown.
1212 */
1213 int
1214 ccp_test( int unit, int opt_len, int for_transmit, u_char *opt_ptr)
1215 {
1216 return 0; /* XXX Currently no compression. */
1217 }
1218
1219 /*
1220 * ccp_flags_set - inform kernel about the current state of CCP.
1221 */
1222 void
1223 ccp_flags_set(int unit, int isopen, int isup)
1224 {
1225 /* XXX */
1226 }
1227
1228 /*
1229 * ccp_fatal_error - returns 1 if decompression was disabled as a
1230 * result of an error detected after decompression of a packet,
1231 * 0 otherwise. This is necessary because of patent nonsense.
1232 */
1233 int
1234 ccp_fatal_error(int unit)
1235 {
1236 /* XXX */
1237 return 0;
1238 }
1239 #endif
1240
1241 /*
1242 * get_idle_time - return how long the link has been idle.
1243 */
1244 int
1245 get_idle_time(int u, struct ppp_idle *ip)
1246 {
1247 /* XXX */
1248 LWIP_UNUSED_ARG(u);
1249 LWIP_UNUSED_ARG(ip);
1250
1251 return 0;
1252 }
1253
1254
1255 /*
1256 * Return user specified netmask, modified by any mask we might determine
1257 * for address `addr' (in network byte order).
1258 * Here we scan through the system's list of interfaces, looking for
1259 * any non-point-to-point interfaces which might appear to be on the same
1260 * network as `addr'. If we find any, we OR in their netmask to the
1261 * user-specified netmask.
1262 */
1263 u32_t
1264 GetMask(u32_t addr)
1265 {
1266 u32_t mask, nmask;
1267
1268 htonl(addr);
1269 if (IP_CLASSA(addr)) { /* determine network mask for address class */
1270 nmask = IP_CLASSA_NET;
1271 } else if (IP_CLASSB(addr)) {
1272 nmask = IP_CLASSB_NET;
1273 } else {
1274 nmask = IP_CLASSC_NET;
1275 }
1276
1277 /* class D nets are disallowed by bad_ip_adrs */
1278 mask = subnetMask | htonl(nmask);
1279
1280 /* XXX
1281 * Scan through the system's network interfaces.
1282 * Get each netmask and OR them into our mask.
1283 */
1284
1285 return mask;
1286 }
1287
1288 /*
1289 * sifvjcomp - config tcp header compression
1290 */
1291 int
1292 sifvjcomp(int pd, int vjcomp, u8_t cidcomp, u8_t maxcid)
1293 {
1294 #if PPPOS_SUPPORT && VJ_SUPPORT
1295 PPPControl *pc = &pppControl[pd];
1296
1297 pc->vjEnabled = vjcomp;
1298 pc->vjComp.compressSlot = cidcomp;
1299 pc->vjComp.maxSlotIndex = maxcid;
1300 PPPDEBUG(LOG_INFO, ("sifvjcomp: VJ compress enable=%d slot=%d max slot=%d\n",
1301 vjcomp, cidcomp, maxcid));
1302 #else /* PPPOS_SUPPORT && VJ_SUPPORT */
1303 LWIP_UNUSED_ARG(pd);
1304 LWIP_UNUSED_ARG(vjcomp);
1305 LWIP_UNUSED_ARG(cidcomp);
1306 LWIP_UNUSED_ARG(maxcid);
1307 #endif /* PPPOS_SUPPORT && VJ_SUPPORT */
1308
1309 return 0;
1310 }
1311
1312 /*
1313 * pppifNetifInit - netif init callback
1314 */
1315 static err_t
1316 pppifNetifInit(struct netif *netif)
1317 {
1318 netif->name[0] = 'p';
1319 netif->name[1] = 'p';
1320 netif->output = pppifOutput;
1321 netif->mtu = pppMTU((int)(size_t)netif->state);
1322 netif->flags = NETIF_FLAG_POINTTOPOINT | NETIF_FLAG_LINK_UP;
1323 #if LWIP_NETIF_HOSTNAME
1324 /* @todo: Initialize interface hostname */
1325 /* netif_set_hostname(netif, "lwip"); */
1326 #endif /* LWIP_NETIF_HOSTNAME */
1327 return ERR_OK;
1328 }
1329
1330
1331 /*
1332 * sifup - Config the interface up and enable IP packets to pass.
1333 */
1334 int
1335 sifup(int pd)
1336 {
1337 PPPControl *pc = &pppControl[pd];
1338 int st = 1;
1339
1340 if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
1341 st = 0;
1342 PPPDEBUG(LOG_WARNING, ("sifup[%d]: bad parms\n", pd));
1343 } else {
1344 netif_remove(&pc->netif);
1345 if (netif_add(&pc->netif, &pc->addrs.our_ipaddr, &pc->addrs.netmask,
1346 &pc->addrs.his_ipaddr, (void *)(size_t)pd, pppifNetifInit, ip_input)) {
1347 netif_set_up(&pc->netif);
1348 pc->if_up = 1;
1349 pc->errCode = PPPERR_NONE;
1350
1351 PPPDEBUG(LOG_DEBUG, ("sifup: unit %d: linkStatusCB=%p errCode=%d\n", pd, pc->linkStatusCB, pc->errCode));
1352 if (pc->linkStatusCB) {
1353 pc->linkStatusCB(pc->linkStatusCtx, pc->errCode, &pc->addrs);
1354 }
1355 } else {
1356 st = 0;
1357 PPPDEBUG(LOG_ERR, ("sifup[%d]: netif_add failed\n", pd));
1358 }
1359 }
1360
1361 return st;
1362 }
1363
1364 /*
1365 * sifnpmode - Set the mode for handling packets for a given NP.
1366 */
1367 int
1368 sifnpmode(int u, int proto, enum NPmode mode)
1369 {
1370 LWIP_UNUSED_ARG(u);
1371 LWIP_UNUSED_ARG(proto);
1372 LWIP_UNUSED_ARG(mode);
1373 return 0;
1374 }
1375
1376 /*
1377 * sifdown - Config the interface down and disable IP.
1378 */
1379 int
1380 sifdown(int pd)
1381 {
1382 PPPControl *pc = &pppControl[pd];
1383 int st = 1;
1384
1385 if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
1386 st = 0;
1387 PPPDEBUG(LOG_WARNING, ("sifdown[%d]: bad parms\n", pd));
1388 } else {
1389 pc->if_up = 0;
1390 /* make sure the netif status callback is called */
1391 netif_set_down(&pc->netif);
1392 netif_remove(&pc->netif);
1393 PPPDEBUG(LOG_DEBUG, ("sifdown: unit %d: linkStatusCB=%p errCode=%d\n", pd, pc->linkStatusCB, pc->errCode));
1394 if (pc->linkStatusCB) {
1395 pc->linkStatusCB(pc->linkStatusCtx, PPPERR_CONNECT, NULL);
1396 }
1397 }
1398 return st;
1399 }
1400
1401 /**
1402 * sifaddr - Config the interface IP addresses and netmask.
1403 * @param pd Interface unit ???
1404 * @param o Our IP address ???
1405 * @param h His IP address ???
1406 * @param m IP subnet mask ???
1407 * @param ns1 Primary DNS
1408 * @param ns2 Secondary DNS
1409 */
1410 int
1411 sifaddr( int pd, u32_t o, u32_t h, u32_t m, u32_t ns1, u32_t ns2)
1412 {
1413 PPPControl *pc = &pppControl[pd];
1414 int st = 1;
1415
1416 if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
1417 st = 0;
1418 PPPDEBUG(LOG_WARNING, ("sifup[%d]: bad parms\n", pd));
1419 } else {
1420 SMEMCPY(&pc->addrs.our_ipaddr, &o, sizeof(o));
1421 SMEMCPY(&pc->addrs.his_ipaddr, &h, sizeof(h));
1422 SMEMCPY(&pc->addrs.netmask, &m, sizeof(m));
1423 SMEMCPY(&pc->addrs.dns1, &ns1, sizeof(ns1));
1424 SMEMCPY(&pc->addrs.dns2, &ns2, sizeof(ns2));
1425 }
1426 return st;
1427 }
1428
1429 /**
1430 * cifaddr - Clear the interface IP addresses, and delete routes
1431 * through the interface if possible.
1432 * @param pd Interface unit ???
1433 * @param o Our IP address ???
1434 * @param h IP broadcast address ???
1435 */
1436 int
1437 cifaddr( int pd, u32_t o, u32_t h)
1438 {
1439 PPPControl *pc = &pppControl[pd];
1440 int st = 1;
1441
1442 LWIP_UNUSED_ARG(o);
1443 LWIP_UNUSED_ARG(h);
1444 if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
1445 st = 0;
1446 PPPDEBUG(LOG_WARNING, ("sifup[%d]: bad parms\n", pd));
1447 } else {
1448 IP4_ADDR(&pc->addrs.our_ipaddr, 0,0,0,0);
1449 IP4_ADDR(&pc->addrs.his_ipaddr, 0,0,0,0);
1450 IP4_ADDR(&pc->addrs.netmask, 255,255,255,0);
1451 IP4_ADDR(&pc->addrs.dns1, 0,0,0,0);
1452 IP4_ADDR(&pc->addrs.dns2, 0,0,0,0);
1453 }
1454 return st;
1455 }
1456
1457 /*
1458 * sifdefaultroute - assign a default route through the address given.
1459 */
1460 int
1461 sifdefaultroute(int pd, u32_t l, u32_t g)
1462 {
1463 PPPControl *pc = &pppControl[pd];
1464 int st = 1;
1465
1466 LWIP_UNUSED_ARG(l);
1467 LWIP_UNUSED_ARG(g);
1468
1469 if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
1470 st = 0;
1471 PPPDEBUG(LOG_WARNING, ("sifup[%d]: bad parms\n", pd));
1472 } else {
1473 netif_set_default(&pc->netif);
1474 }
1475
1476 /* TODO: check how PPP handled the netMask, previously not set by ipSetDefault */
1477
1478 return st;
1479 }
1480
1481 /*
1482 * cifdefaultroute - delete a default route through the address given.
1483 */
1484 int
1485 cifdefaultroute(int pd, u32_t l, u32_t g)
1486 {
1487 PPPControl *pc = &pppControl[pd];
1488 int st = 1;
1489
1490 LWIP_UNUSED_ARG(l);
1491 LWIP_UNUSED_ARG(g);
1492
1493 if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
1494 st = 0;
1495 PPPDEBUG(LOG_WARNING, ("sifup[%d]: bad parms\n", pd));
1496 } else {
1497 netif_set_default(NULL);
1498 }
1499
1500 return st;
1501 }
1502
1503 /**********************************/
1504 /*** LOCAL FUNCTION DEFINITIONS ***/
1505 /**********************************/
1506
1507 #if PPPOS_SUPPORT && PPP_INPROC_OWNTHREAD
1508 /* The main PPP process function. This implements the state machine according
1509 * to section 4 of RFC 1661: The Point-To-Point Protocol. */
1510 static void
1511 pppInputThread(void *arg)
1512 {
1513 int count;
1514 PPPControlRx *pcrx = arg;
1515
1516 do
1517 {
1518 sys_arch_mbox_fetch(&pppMbox, (void**)&pcrx, 0); //Wait indefinitely
1519
1520 while (lcp_phase[pcrx->pd] != PHASE_DEAD) {
1521 count = sio_read(pcrx->fd, pcrx->rxbuf, PPPOS_RX_BUFSIZE);
1522 if(count > 0) {
1523 pppInProc(pcrx, pcrx->rxbuf, count);
1524 } else {
1525 /* nothing received, give other tasks a chance to run */
1526 sys_msleep(1);
1527 }
1528 }
1529 } while(1); //Never terminates
1530 }
1531 #endif /* PPPOS_SUPPORT && PPP_INPROC_OWNTHREAD */
1532
1533 #if PPPOE_SUPPORT
1534
1535 void
1536 pppOverEthernetInitFailed(int pd)
1537 {
1538 PPPControl* pc;
1539
1540 pppHup(pd);
1541 pppStop(pd);
1542
1543 pc = &pppControl[pd];
1544 pppoe_destroy(&pc->netif);
1545 pc->openFlag = 0;
1546
1547 if(pc->linkStatusCB) {
1548 pc->linkStatusCB(pc->linkStatusCtx, pc->errCode ? pc->errCode : PPPERR_PROTOCOL, NULL);
1549 }
1550 }
1551
1552 static void
1553 pppOverEthernetLinkStatusCB(int pd, int up)
1554 {
1555 if(up) {
1556 PPPDEBUG(LOG_INFO, ("pppOverEthernetLinkStatusCB: unit %d: Connecting\n", pd));
1557 pppStart(pd);
1558 } else {
1559 pppOverEthernetInitFailed(pd);
1560 }
1561 }
1562 #endif /* PPPOE_SUPPORT */
1563
1564 struct pbuf *
1565 pppSingleBuf(struct pbuf *p)
1566 {
1567 struct pbuf *q, *b;
1568 u_char *pl;
1569
1570 if(p->tot_len == p->len) {
1571 return p;
1572 }
1573
1574 q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
1575 if(!q) {
1576 PPPDEBUG(LOG_ERR,
1577 ("pppSingleBuf: unable to alloc new buf (%d)\n", p->tot_len));
1578 return p; /* live dangerously */
1579 }
1580
1581 for(b = p, pl = q->payload; b != NULL; b = b->next) {
1582 MEMCPY(pl, b->payload, b->len);
1583 pl += b->len;
1584 }
1585
1586 pbuf_free(p);
1587
1588 return q;
1589 }
1590
1591 struct pppInputHeader {
1592 int unit;
1593 u16_t proto;
1594 };
1595
1596 /*
1597 * Pass the processed input packet to the appropriate handler.
1598 * This function and all handlers run in the context of the tcpip_thread
1599 */
1600 static void
1601 pppInput(void *arg)
1602 {
1603 struct pbuf *nb = (struct pbuf *)arg;
1604 u16_t protocol;
1605 int pd;
1606
1607 pd = ((struct pppInputHeader *)nb->payload)->unit;
1608 protocol = ((struct pppInputHeader *)nb->payload)->proto;
1609
1610 if(pbuf_header(nb, -(int)sizeof(struct pppInputHeader))) {
1611 LWIP_ASSERT("pbuf_header failed\n", 0);
1612 goto drop;
1613 }
1614
1615 LINK_STATS_INC(link.recv);
1616 snmp_inc_ifinucastpkts(&pppControl[pd].netif);
1617 snmp_add_ifinoctets(&pppControl[pd].netif, nb->tot_len);
1618
1619 /*
1620 * Toss all non-LCP packets unless LCP is OPEN.
1621 * Until we get past the authentication phase, toss all packets
1622 * except LCP, LQR and authentication packets.
1623 */
1624 if((lcp_phase[pd] <= PHASE_AUTHENTICATE) && (protocol != PPP_LCP)) {
1625 if(!((protocol == PPP_LQR) || (protocol == PPP_PAP) || (protocol == PPP_CHAP)) ||
1626 (lcp_phase[pd] != PHASE_AUTHENTICATE)) {
1627 PPPDEBUG(LOG_INFO, ("pppInput: discarding proto 0x%"X16_F" in phase %d\n", protocol, lcp_phase[pd]));
1628 goto drop;
1629 }
1630 }
1631
1632 switch(protocol) {
1633 case PPP_VJC_COMP: /* VJ compressed TCP */
1634 #if PPPOS_SUPPORT && VJ_SUPPORT
1635 PPPDEBUG(LOG_INFO, ("pppInput[%d]: vj_comp in pbuf len=%d\n", pd, nb->len));
1636 /*
1637 * Clip off the VJ header and prepend the rebuilt TCP/IP header and
1638 * pass the result to IP.
1639 */
1640 if ((vj_uncompress_tcp(&nb, &pppControl[pd].vjComp) >= 0) && (pppControl[pd].netif.input)) {
1641 pppControl[pd].netif.input(nb, &pppControl[pd].netif);
1642 return;
1643 }
1644 /* Something's wrong so drop it. */
1645 PPPDEBUG(LOG_WARNING, ("pppInput[%d]: Dropping VJ compressed\n", pd));
1646 #else /* PPPOS_SUPPORT && VJ_SUPPORT */
1647 /* No handler for this protocol so drop the packet. */
1648 PPPDEBUG(LOG_INFO, ("pppInput[%d]: drop VJ Comp in %d:%s\n", pd, nb->len, nb->payload));
1649 #endif /* PPPOS_SUPPORT && VJ_SUPPORT */
1650 break;
1651
1652 case PPP_VJC_UNCOMP: /* VJ uncompressed TCP */
1653 #if PPPOS_SUPPORT && VJ_SUPPORT
1654 PPPDEBUG(LOG_INFO, ("pppInput[%d]: vj_un in pbuf len=%d\n", pd, nb->len));
1655 /*
1656 * Process the TCP/IP header for VJ header compression and then pass
1657 * the packet to IP.
1658 */
1659 if ((vj_uncompress_uncomp(nb, &pppControl[pd].vjComp) >= 0) && pppControl[pd].netif.input) {
1660 pppControl[pd].netif.input(nb, &pppControl[pd].netif);
1661 return;
1662 }
1663 /* Something's wrong so drop it. */
1664 PPPDEBUG(LOG_WARNING, ("pppInput[%d]: Dropping VJ uncompressed\n", pd));
1665 #else /* PPPOS_SUPPORT && VJ_SUPPORT */
1666 /* No handler for this protocol so drop the packet. */
1667 PPPDEBUG(LOG_INFO,
1668 ("pppInput[%d]: drop VJ UnComp in %d:.*H\n",
1669 pd, nb->len, LWIP_MIN(nb->len * 2, 40), nb->payload));
1670 #endif /* PPPOS_SUPPORT && VJ_SUPPORT */
1671 break;
1672
1673 case PPP_IP: /* Internet Protocol */
1674 PPPDEBUG(LOG_INFO, ("pppInput[%d]: ip in pbuf len=%d\n", pd, nb->len));
1675 if (pppControl[pd].netif.input) {
1676 pppControl[pd].netif.input(nb, &pppControl[pd].netif);
1677 return;
1678 }
1679 break;
1680
1681 default: {
1682 struct protent *protp;
1683 int i;
1684
1685 /*
1686 * Upcall the proper protocol input routine.
1687 */
1688 for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i) {
1689 if (protp->protocol == protocol && protp->enabled_flag) {
1690 PPPDEBUG(LOG_INFO, ("pppInput[%d]: %s len=%d\n", pd, protp->name, nb->len));
1691 nb = pppSingleBuf(nb);
1692 (*protp->input)(pd, nb->payload, nb->len);
1693 PPPDEBUG(LOG_DETAIL, ("pppInput[%d]: packet processed\n", pd));
1694 goto out;
1695 }
1696 }
1697
1698 /* No handler for this protocol so reject the packet. */
1699 PPPDEBUG(LOG_INFO, ("pppInput[%d]: rejecting unsupported proto 0x%"X16_F" len=%d\n", pd, protocol, nb->len));
1700 if (pbuf_header(nb, sizeof(protocol))) {
1701 LWIP_ASSERT("pbuf_header failed\n", 0);
1702 goto drop;
1703 }
1704 #if BYTE_ORDER == LITTLE_ENDIAN
1705 protocol = htons(protocol);
1706 #endif /* BYTE_ORDER == LITTLE_ENDIAN */
1707 SMEMCPY(nb->payload, &protocol, sizeof(protocol));
1708 lcp_sprotrej(pd, nb->payload, nb->len);
1709 }
1710 break;
1711 }
1712
1713 drop:
1714 LINK_STATS_INC(link.drop);
1715 snmp_inc_ifindiscards(&pppControl[pd].netif);
1716
1717 out:
1718 pbuf_free(nb);
1719 return;
1720 }
1721
1722 #if PPPOS_SUPPORT
1723 /*
1724 * Drop the input packet.
1725 */
1726 static void
1727 pppDrop(PPPControlRx *pcrx)
1728 {
1729 if (pcrx->inHead != NULL) {
1730 #if 0
1731 PPPDEBUG(LOG_INFO, ("pppDrop: %d:%.*H\n", pcrx->inHead->len, min(60, pcrx->inHead->len * 2), pcrx->inHead->payload));
1732 #endif
1733 PPPDEBUG(LOG_INFO, ("pppDrop: pbuf len=%d, addr %p\n", pcrx->inHead->len, (void*)pcrx->inHead));
1734 if (pcrx->inTail && (pcrx->inTail != pcrx->inHead)) {
1735 pbuf_free(pcrx->inTail);
1736 }
1737 pbuf_free(pcrx->inHead);
1738 pcrx->inHead = NULL;
1739 pcrx->inTail = NULL;
1740 }
1741 #if VJ_SUPPORT
1742 vj_uncompress_err(&pppControl[pcrx->pd].vjComp);
1743 #endif /* VJ_SUPPORT */
1744
1745 LINK_STATS_INC(link.drop);
1746 snmp_inc_ifindiscards(&pppControl[pcrx->pd].netif);
1747 }
1748
1749 /** Pass received raw characters to PPPoS to be decoded. This function is
1750 * thread-safe and can be called from a dedicated RX-thread or from a main-loop.
1751 *
1752 * @param pd PPP descriptor index, returned by pppOpen()
1753 * @param data received data
1754 * @param len length of received data
1755 */
1756 void
1757 pppos_input(int pd, u_char* data, int len)
1758 {
1759 pppInProc(&pppControl[pd].rx, data, len);
1760 }
1761
1762 /**
1763 * Process a received octet string.
1764 */
1765 static void
1766 pppInProc(PPPControlRx *pcrx, u_char *s, int l)
1767 {
1768 struct pbuf *nextNBuf;
1769 u_char curChar;
1770 u_char escaped;
1771 SYS_ARCH_DECL_PROTECT(lev);
1772
1773 PPPDEBUG(LOG_DEBUG, ("pppInProc[%d]: got %d bytes\n", pcrx->pd, l));
1774 while (l-- > 0) {
1775 curChar = *s++;
1776
1777 SYS_ARCH_PROTECT(lev);
1778 escaped = ESCAPE_P(pcrx->inACCM, curChar);
1779 SYS_ARCH_UNPROTECT(lev);
1780 /* Handle special characters. */
1781 if (escaped) {
1782 /* Check for escape sequences. */
1783 /* XXX Note that this does not handle an escaped 0x5d character which
1784 * would appear as an escape character. Since this is an ASCII ']'
1785 * and there is no reason that I know of to escape it, I won't complicate
1786 * the code to handle this case. GLL */
1787 if (curChar == PPP_ESCAPE) {
1788 pcrx->inEscaped = 1;
1789 /* Check for the flag character. */
1790 } else if (curChar == PPP_FLAG) {
1791 /* If this is just an extra flag character, ignore it. */
1792 if (pcrx->inState <= PDADDRESS) {
1793 /* ignore it */;
1794 /* If we haven't received the packet header, drop what has come in. */
1795 } else if (pcrx->inState < PDDATA) {
1796 PPPDEBUG(LOG_WARNING,
1797 ("pppInProc[%d]: Dropping incomplete packet %d\n",
1798 pcrx->pd, pcrx->inState));
1799 LINK_STATS_INC(link.lenerr);
1800 pppDrop(pcrx);
1801 /* If the fcs is invalid, drop the packet. */
1802 } else if (pcrx->inFCS != PPP_GOODFCS) {
1803 PPPDEBUG(LOG_INFO,
1804 ("pppInProc[%d]: Dropping bad fcs 0x%"X16_F" proto=0x%"X16_F"\n",
1805 pcrx->pd, pcrx->inFCS, pcrx->inProtocol));
1806 /* Note: If you get lots of these, check for UART frame errors or try different baud rate */
1807 LINK_STATS_INC(link.chkerr);
1808 pppDrop(pcrx);
1809 /* Otherwise it's a good packet so pass it on. */
1810 } else {
1811 struct pbuf *inp;
1812 /* Trim off the checksum. */
1813 if(pcrx->inTail->len >= 2) {
1814 pcrx->inTail->len -= 2;
1815
1816 pcrx->inTail->tot_len = pcrx->inTail->len;
1817 if (pcrx->inTail != pcrx->inHead) {
1818 pbuf_cat(pcrx->inHead, pcrx->inTail);
1819 }
1820 } else {
1821 pcrx->inTail->tot_len = pcrx->inTail->len;
1822 if (pcrx->inTail != pcrx->inHead) {
1823 pbuf_cat(pcrx->inHead, pcrx->inTail);
1824 }
1825
1826 pbuf_realloc(pcrx->inHead, pcrx->inHead->tot_len - 2);
1827 }
1828
1829 /* Dispatch the packet thereby consuming it. */
1830 inp = pcrx->inHead;
1831 /* Packet consumed, release our references. */
1832 pcrx->inHead = NULL;
1833 pcrx->inTail = NULL;
1834 #if PPP_INPROC_MULTITHREADED
1835 if(tcpip_callback_with_block(pppInput, inp, 0) != ERR_OK) {
1836 PPPDEBUG(LOG_ERR, ("pppInProc[%d]: tcpip_callback() failed, dropping packet\n", pcrx->pd));
1837 pbuf_free(inp);
1838 LINK_STATS_INC(link.drop);
1839 snmp_inc_ifindiscards(&pppControl[pcrx->pd].netif);
1840 }
1841 #else /* PPP_INPROC_MULTITHREADED */
1842 pppInput(inp);
1843 #endif /* PPP_INPROC_MULTITHREADED */
1844 }
1845
1846 /* Prepare for a new packet. */
1847 pcrx->inFCS = PPP_INITFCS;
1848 pcrx->inState = PDADDRESS;
1849 pcrx->inEscaped = 0;
1850 /* Other characters are usually control characters that may have
1851 * been inserted by the physical layer so here we just drop them. */
1852 } else {
1853 PPPDEBUG(LOG_WARNING,
1854 ("pppInProc[%d]: Dropping ACCM char <%d>\n", pcrx->pd, curChar));
1855 }
1856 /* Process other characters. */
1857 } else {
1858 /* Unencode escaped characters. */
1859 if (pcrx->inEscaped) {
1860 pcrx->inEscaped = 0;
1861 curChar ^= PPP_TRANS;
1862 }
1863
1864 /* Process character relative to current state. */
1865 switch(pcrx->inState) {
1866 case PDIDLE: /* Idle state - waiting. */
1867 /* Drop the character if it's not 0xff
1868 * we would have processed a flag character above. */
1869 if (curChar != PPP_ALLSTATIONS) {
1870 break;
1871 }
1872
1873 /* Fall through */
1874 case PDSTART: /* Process start flag. */
1875 /* Prepare for a new packet. */
1876 pcrx->inFCS = PPP_INITFCS;
1877
1878 /* Fall through */
1879 case PDADDRESS: /* Process address field. */
1880 if (curChar == PPP_ALLSTATIONS) {
1881 pcrx->inState = PDCONTROL;
1882 break;
1883 }
1884 /* Else assume compressed address and control fields so
1885 * fall through to get the protocol... */
1886 case PDCONTROL: /* Process control field. */
1887 /* If we don't get a valid control code, restart. */
1888 if (curChar == PPP_UI) {
1889 pcrx->inState = PDPROTOCOL1;
1890 break;
1891 }
1892 #if 0
1893 else {
1894 PPPDEBUG(LOG_WARNING,
1895 ("pppInProc[%d]: Invalid control <%d>\n", pcrx->pd, curChar));
1896 pcrx->inState = PDSTART;
1897 }
1898 #endif
1899 case PDPROTOCOL1: /* Process protocol field 1. */
1900 /* If the lower bit is set, this is the end of the protocol
1901 * field. */
1902 if (curChar & 1) {
1903 pcrx->inProtocol = curChar;
1904 pcrx->inState = PDDATA;
1905 } else {
1906 pcrx->inProtocol = (u_int)curChar << 8;
1907 pcrx->inState = PDPROTOCOL2;
1908 }
1909 break;
1910 case PDPROTOCOL2: /* Process protocol field 2. */
1911 pcrx->inProtocol |= curChar;
1912 pcrx->inState = PDDATA;
1913 break;
1914 case PDDATA: /* Process data byte. */
1915 /* Make space to receive processed data. */
1916 if (pcrx->inTail == NULL || pcrx->inTail->len == PBUF_POOL_BUFSIZE) {
1917 if (pcrx->inTail != NULL) {
1918 pcrx->inTail->tot_len = pcrx->inTail->len;
1919 if (pcrx->inTail != pcrx->inHead) {
1920 pbuf_cat(pcrx->inHead, pcrx->inTail);
1921 /* give up the inTail reference now */
1922 pcrx->inTail = NULL;
1923 }
1924 }
1925 /* If we haven't started a packet, we need a packet header. */
1926 nextNBuf = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
1927 if (nextNBuf == NULL) {
1928 /* No free buffers. Drop the input packet and let the
1929 * higher layers deal with it. Continue processing
1930 * the received pbuf chain in case a new packet starts. */
1931 PPPDEBUG(LOG_ERR, ("pppInProc[%d]: NO FREE MBUFS!\n", pcrx->pd));
1932 LINK_STATS_INC(link.memerr);
1933 pppDrop(pcrx);
1934 pcrx->inState = PDSTART; /* Wait for flag sequence. */
1935 break;
1936 }
1937 if (pcrx->inHead == NULL) {
1938 struct pppInputHeader *pih = nextNBuf->payload;
1939
1940 pih->unit = pcrx->pd;
1941 pih->proto = pcrx->inProtocol;
1942
1943 nextNBuf->len += sizeof(*pih);
1944
1945 pcrx->inHead = nextNBuf;
1946 }
1947 pcrx->inTail = nextNBuf;
1948 }
1949 /* Load character into buffer. */
1950 ((u_char*)pcrx->inTail->payload)[pcrx->inTail->len++] = curChar;
1951 break;
1952 }
1953
1954 /* update the frame check sequence number. */
1955 pcrx->inFCS = PPP_FCS(pcrx->inFCS, curChar);
1956 }
1957 } /* while (l-- > 0), all bytes processed */
1958
1959 avRandomize();
1960 }
1961 #endif /* PPPOS_SUPPORT */
1962
1963 #if PPPOE_SUPPORT
1964 void
1965 pppInProcOverEthernet(int pd, struct pbuf *pb)
1966 {
1967 struct pppInputHeader *pih;
1968 u16_t inProtocol;
1969
1970 if(pb->len < sizeof(inProtocol)) {
1971 PPPDEBUG(LOG_ERR, ("pppInProcOverEthernet: too small for protocol field\n"));
1972 goto drop;
1973 }
1974
1975 inProtocol = (((u8_t *)pb->payload)[0] << 8) | ((u8_t*)pb->payload)[1];
1976
1977 /* make room for pppInputHeader - should not fail */
1978 if (pbuf_header(pb, sizeof(*pih) - sizeof(inProtocol)) != 0) {
1979 PPPDEBUG(LOG_ERR, ("pppInProcOverEthernet: could not allocate room for header\n"));
1980 goto drop;
1981 }
1982
1983 pih = pb->payload;
1984
1985 pih->unit = pd;
1986 pih->proto = inProtocol;
1987
1988 /* Dispatch the packet thereby consuming it. */
1989 pppInput(pb);
1990 return;
1991
1992 drop:
1993 LINK_STATS_INC(link.drop);
1994 snmp_inc_ifindiscards(&pppControl[pd].netif);
1995 pbuf_free(pb);
1996 return;
1997 }
1998 #endif /* PPPOE_SUPPORT */
1999
2000 #if LWIP_NETIF_STATUS_CALLBACK
2001 /** Set the status callback of a PPP's netif
2002 *
2003 * @param pd The PPP descriptor returned by pppOpen()
2004 * @param status_callback pointer to the status callback function
2005 *
2006 * @see netif_set_status_callback
2007 */
2008 void
2009 ppp_set_netif_statuscallback(int pd, netif_status_callback_fn status_callback)
2010 {
2011 netif_set_status_callback(&pppControl[pd].netif, status_callback);
2012 }
2013 #endif /* LWIP_NETIF_STATUS_CALLBACK */
2014
2015 #if LWIP_NETIF_LINK_CALLBACK
2016 /** Set the link callback of a PPP's netif
2017 *
2018 * @param pd The PPP descriptor returned by pppOpen()
2019 * @param link_callback pointer to the link callback function
2020 *
2021 * @see netif_set_link_callback
2022 */
2023 void
2024 ppp_set_netif_linkcallback(int pd, netif_status_callback_fn link_callback)
2025 {
2026 netif_set_link_callback(&pppControl[pd].netif, link_callback);
2027 }
2028 #endif /* LWIP_NETIF_LINK_CALLBACK */
2029
2030 #endif /* PPP_SUPPORT */
Imprint / Impressum