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