• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*****************************************************************************
2 * ppp.c - Network Point to Point Protocol program file.
3 *
4 * Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
5 * portions Copyright (c) 1997 by Global Election Systems Inc.
6 *
7 * The authors hereby grant permission to use, copy, modify, distribute,
8 * and license this software and its documentation for any purpose, provided
9 * that existing copyright notices are retained in all copies and that this
10 * notice and the following disclaimer are included verbatim in any
11 * distributions. No written agreement, license, or royalty fee is required
12 * for any of the authorized uses.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 *
25 ******************************************************************************
26 * REVISION HISTORY
27 *
28 * 03-01-01 Marc Boucher <marc@mbsi.ca>
29 *   Ported to lwIP.
30 * 97-11-05 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
31 *   Original.
32 *****************************************************************************/
33 
34 /*
35  * ppp_defs.h - PPP definitions.
36  *
37  * if_pppvar.h - private structures and declarations for PPP.
38  *
39  * Copyright (c) 1994 The Australian National University.
40  * All rights reserved.
41  *
42  * Permission to use, copy, modify, and distribute this software and its
43  * documentation is hereby granted, provided that the above copyright
44  * notice appears in all copies.  This software is provided without any
45  * warranty, express or implied. The Australian National University
46  * makes no representations about the suitability of this software for
47  * any purpose.
48  *
49  * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
50  * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
51  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
52  * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
53  * OF SUCH DAMAGE.
54  *
55  * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
56  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
57  * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
58  * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
59  * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
60  * OR MODIFICATIONS.
61  */
62 
63 /*
64  * if_ppp.h - Point-to-Point Protocol definitions.
65  *
66  * Copyright (c) 1989 Carnegie Mellon University.
67  * All rights reserved.
68  *
69  * Redistribution and use in source and binary forms are permitted
70  * provided that the above copyright notice and this paragraph are
71  * duplicated in all such forms and that any documentation,
72  * advertising materials, and other materials related to such
73  * distribution and use acknowledge that the software was developed
74  * by Carnegie Mellon University.  The name of the
75  * University may not be used to endorse or promote products derived
76  * from this software without specific prior written permission.
77  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
78  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
79  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
80  */
81 
82 #include "lwip/opt.h"
83 
84 #if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */
85 
86 #include "lwip/ip.h" /* for ip_input() */
87 
88 #include "ppp.h"
89 #include "pppdebug.h"
90 
91 #include "randm.h"
92 #include "fsm.h"
93 #if PAP_SUPPORT
94 #include "pap.h"
95 #endif /* PAP_SUPPORT */
96 #if CHAP_SUPPORT
97 #include "chap.h"
98 #endif /* CHAP_SUPPORT */
99 #include "ipcp.h"
100 #include "lcp.h"
101 #include "magic.h"
102 #include "auth.h"
103 #if VJ_SUPPORT
104 #include "vj.h"
105 #endif /* VJ_SUPPORT */
106 #if PPPOE_SUPPORT
107 #include "netif/ppp_oe.h"
108 #endif /* PPPOE_SUPPORT */
109 
110 #include "lwip/tcpip.h"
111 #include "lwip/api.h"
112 #include "lwip/snmp.h"
113 
114 #include <string.h>
115 
116 /*************************/
117 /*** LOCAL DEFINITIONS ***/
118 /*************************/
119 
120 /** PPP_INPROC_MULTITHREADED==1 call pppInput using tcpip_callback().
121  * Set this to 0 if pppInProc is called inside tcpip_thread or with NO_SYS==1.
122  * Default is 1 for NO_SYS==0 (multithreaded) and 0 for NO_SYS==1 (single-threaded).
123  */
124 #ifndef PPP_INPROC_MULTITHREADED
125 #define PPP_INPROC_MULTITHREADED (NO_SYS==0)
126 #endif
127 
128 /** PPP_INPROC_OWNTHREAD==1: start a dedicated RX thread per PPP session.
129  * Default is 0: call pppos_input() for received raw characters, charcater
130  * reception is up to the port */
131 #ifndef PPP_INPROC_OWNTHREAD
132 #define PPP_INPROC_OWNTHREAD      PPP_INPROC_MULTITHREADED
133 #endif
134 
135 #if PPP_INPROC_OWNTHREAD && !PPP_INPROC_MULTITHREADED
136   #error "PPP_INPROC_OWNTHREAD needs PPP_INPROC_MULTITHREADED==1"
137 #endif
138 
139 /*
140  * The basic PPP frame.
141  */
142 #define PPP_ADDRESS(p)  (((u_char *)(p))[0])
143 #define PPP_CONTROL(p)  (((u_char *)(p))[1])
144 #define PPP_PROTOCOL(p) ((((u_char *)(p))[2] << 8) + ((u_char *)(p))[3])
145 
146 /* PPP packet parser states.  Current state indicates operation yet to be
147  * completed. */
148 typedef enum {
149   PDIDLE = 0,  /* Idle state - waiting. */
150   PDSTART,     /* Process start flag. */
151   PDADDRESS,   /* Process address field. */
152   PDCONTROL,   /* Process control field. */
153   PDPROTOCOL1, /* Process protocol field 1. */
154   PDPROTOCOL2, /* Process protocol field 2. */
155   PDDATA       /* Process data byte. */
156 } PPPDevStates;
157 
158 #define ESCAPE_P(accm, c) ((accm)[(c) >> 3] & pppACCMMask[c & 0x07])
159 
160 /************************/
161 /*** LOCAL DATA TYPES ***/
162 /************************/
163 
164 /** RX buffer size: this may be configured smaller! */
165 #ifndef PPPOS_RX_BUFSIZE
166 #define PPPOS_RX_BUFSIZE    (PPP_MRU + PPP_HDRLEN)
167 #endif
168 
169 typedef struct PPPControlRx_s {
170   /** unit number / ppp descriptor */
171   int pd;
172   /** the rx file descriptor */
173   sio_fd_t fd;
174   /** receive buffer - encoded data is stored here */
175   u_char rxbuf[PPPOS_RX_BUFSIZE];
176 
177   /* The input packet. */
178   struct pbuf *inHead, *inTail;
179 
180 #if PPPOS_SUPPORT
181   u16_t inProtocol;             /* The input protocol code. */
182   u16_t inFCS;                  /* Input Frame Check Sequence value. */
183 #endif /* PPPOS_SUPPORT */
184   PPPDevStates inState;         /* The input process state. */
185   char inEscaped;               /* Escape next character. */
186   ext_accm inACCM;              /* Async-Ctl-Char-Map for input. */
187 } PPPControlRx;
188 
189 /*
190  * PPP interface control block.
191  */
192 typedef struct PPPControl_s {
193   PPPControlRx rx;
194   char openFlag;                /* True when in use. */
195 #if PPPOE_SUPPORT
196   struct netif *ethif;
197   struct pppoe_softc *pppoe_sc;
198 #endif /* PPPOE_SUPPORT */
199   int  if_up;                   /* True when the interface is up. */
200   int  errCode;                 /* Code indicating why interface is down. */
201 #if PPPOS_SUPPORT
202   sio_fd_t fd;                  /* File device ID of port. */
203 #endif /* PPPOS_SUPPORT */
204   u16_t mtu;                    /* Peer's mru */
205   int  pcomp;                   /* Does peer accept protocol compression? */
206   int  accomp;                  /* Does peer accept addr/ctl compression? */
207   u_long lastXMit;              /* Time of last transmission. */
208   ext_accm outACCM;             /* Async-Ctl-Char-Map for output. */
209 #if PPPOS_SUPPORT && VJ_SUPPORT
210   int  vjEnabled;               /* Flag indicating VJ compression enabled. */
211   struct vjcompress vjComp;     /* Van Jacobson compression header. */
212 #endif /* PPPOS_SUPPORT && VJ_SUPPORT */
213 
214   struct netif netif;
215 
216   struct ppp_addrs addrs;
217 
218   void (*linkStatusCB)(void *ctx, int errCode, void *arg);
219   void *linkStatusCtx;
220 
221 } PPPControl;
222 
223 
224 /*
225  * Ioctl definitions.
226  */
227 
228 struct npioctl {
229   int         protocol; /* PPP procotol, e.g. PPP_IP */
230   enum NPmode mode;
231 };
232 
233 
234 
235 /***********************************/
236 /*** LOCAL FUNCTION DECLARATIONS ***/
237 /***********************************/
238 #if PPPOS_SUPPORT
239 #if PPP_INPROC_OWNTHREAD
240 static void pppInputThread(void *arg);
241 #endif /* PPP_INPROC_OWNTHREAD */
242 static void pppDrop(PPPControlRx *pcrx);
243 static void pppInProc(PPPControlRx *pcrx, u_char *s, int l);
244 #endif /* PPPOS_SUPPORT */
245 
246 
247 /******************************/
248 /*** PUBLIC DATA STRUCTURES ***/
249 /******************************/
250 u_long subnetMask;
251 
252 static PPPControl pppControl[NUM_PPP]; /* 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 
342 /** Wake up the task blocked in reading from serial line (if any) */
343 static void
pppRecvWakeup(int pd)344 pppRecvWakeup(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 
353 void
pppLinkTerminated(int pd)354 pppLinkTerminated(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 
380 void
pppLinkDown(int pd)381 pppLinkDown(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 */
398 static void
pppStart(int pd)399 pppStart(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 */
408 static void
pppStop(int pd)409 pppStop(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 */
416 static void
pppHup(int pd)417 pppHup(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 
429 struct ppp_settings ppp_settings;
430 
431 void
pppInit(void)432 pppInit(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 
453 void
pppSetAuth(enum pppAuthType authType,const char * user,const char * passwd)454 pppSetAuth(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  */
529 int
pppOverSerialOpen(sio_fd_t fd,void (* linkStatusCB)(void * ctx,int errCode,void * arg),void * linkStatusCtx)530 pppOverSerialOpen(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
585 static void pppOverEthernetLinkStatusCB(int pd, int up);
586 
587 void
pppOverEthernetClose(int pd)588 pppOverEthernetClose(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 
pppOverEthernetOpen(struct netif * ethif,const char * service_name,const char * concentrator_name,void (* linkStatusCB)(void * ctx,int errCode,void * arg),void * linkStatusCtx)598 int 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. */
651 int
pppClose(int pd)652 pppClose(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. */
682 void
pppSigHUP(int pd)683 pppSigHUP(int pd)
684 {
685   PPPDEBUG(LOG_DEBUG, ("pppSigHUP: unit %d sig_hup -> pppHupCB\n", pd));
686   pppHup(pd);
687 }
688 
689 #if PPPOS_SUPPORT
690 static void
nPut(PPPControl * pc,struct pbuf * nb)691 nPut(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  */
720 static struct pbuf *
pppAppend(u_char c,struct pbuf * nb,ext_accm * outACCM)721 pppAppend(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
753 static err_t
pppifOutputOverEthernet(int pd,struct pbuf * p)754 pppifOutputOverEthernet(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. */
797 static err_t
pppifOutput(struct netif * netif,struct pbuf * pb,ip_addr_t * ipaddr)798 pppifOutput(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. */
948 int
pppIOCtl(int pd,int cmd,void * arg)949 pppIOCtl(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  */
1000 u_short
pppMTU(int pd)1001 pppMTU(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
1017 int
pppWriteOverEthernet(int pd,const u_char * s,int n)1018 pppWriteOverEthernet(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  */
1060 int
pppWrite(int pd,const u_char * s,int n)1061 pppWrite(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  */
1138 void
ppp_send_config(int unit,u16_t mtu,u32_t asyncmap,int pcomp,int accomp)1139 ppp_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  */
1161 void
ppp_set_xaccm(int unit,ext_accm * accm)1162 ppp_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  */
1178 void
ppp_recv_config(int unit,int mru,u32_t asyncmap,int pcomp,int accomp)1179 ppp_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  */
1208 int
1209 ccp_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  */
1217 void
1218 ccp_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  */
1228 int
1229 ccp_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  */
1239 int
get_idle_time(int u,struct ppp_idle * ip)1240 get_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  */
1258 u32_t
GetMask(u32_t addr)1259 GetMask(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  */
1286 int
sifvjcomp(int pd,int vjcomp,u8_t cidcomp,u8_t maxcid)1287 sifvjcomp(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  */
1310 static err_t
pppifNetifInit(struct netif * netif)1311 pppifNetifInit(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  */
1329 int
sifup(int pd)1330 sifup(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  */
1362 int
sifnpmode(int u,int proto,enum NPmode mode)1363 sifnpmode(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  */
1374 int
sifdown(int pd)1375 sifdown(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  */
1405 int
sifaddr(int pd,u32_t o,u32_t h,u32_t m,u32_t ns1,u32_t ns2)1406 sifaddr( 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  */
1431 int
cifaddr(int pd,u32_t o,u32_t h)1432 cifaddr( 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  */
1455 int
sifdefaultroute(int pd,u32_t l,u32_t g)1456 sifdefaultroute(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  */
1479 int
cifdefaultroute(int pd,u32_t l,u32_t g)1480 cifdefaultroute(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. */
1505 static void
pppInputThread(void * arg)1506 pppInputThread(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 
1525 void
pppOverEthernetInitFailed(int pd)1526 pppOverEthernetInitFailed(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 
1542 static void
pppOverEthernetLinkStatusCB(int pd,int up)1543 pppOverEthernetLinkStatusCB(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 
1554 struct pbuf *
pppSingleBuf(struct pbuf * p)1555 pppSingleBuf(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 
1581 struct 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  */
1590 static void
pppInput(void * arg)1591 pppInput(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 
1703 drop:
1704   LINK_STATS_INC(link.drop);
1705   snmp_inc_ifindiscards(&pppControl[pd].netif);
1706 
1707 out:
1708   pbuf_free(nb);
1709   return;
1710 }
1711 
1712 #if PPPOS_SUPPORT
1713 /*
1714  * Drop the input packet.
1715  */
1716 static void
pppDrop(PPPControlRx * pcrx)1717 pppDrop(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  */
1746 void
pppos_input(int pd,u_char * data,int len)1747 pppos_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  */
1755 static void
pppInProc(PPPControlRx * pcrx,u_char * s,int l)1756 pppInProc(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
1954 void
pppInProcOverEthernet(int pd,struct pbuf * pb)1955 pppInProcOverEthernet(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 
1982 drop:
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  */
1998 void
ppp_set_netif_statuscallback(int pd,netif_status_callback_fn status_callback)1999 ppp_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  */
2013 void
ppp_set_netif_linkcallback(int pd,netif_status_callback_fn link_callback)2014 ppp_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