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