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