blob: df402189e9710f10566af9c775888ae26b026baa [file] [log] [blame]
Travis Geiselbrecht1d0df692008-09-01 02:26:09 -07001/*****************************************************************************
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 <string.h>
83
84#include "ppp.h"
85#if PPP_SUPPORT > 0
86#include "randm.h"
87#include "fsm.h"
88#if PAP_SUPPORT > 0
89#include "pap.h"
90#endif
91#if CHAP_SUPPORT > 0
92#include "chap.h"
93#endif
94#include "ipcp.h"
95#include "lcp.h"
96#include "magic.h"
97#include "auth.h"
98#if VJ_SUPPORT > 0
99#include "vj.h"
100#endif
101
102#include "pppdebug.h"
103
104/*************************/
105/*** LOCAL DEFINITIONS ***/
106/*************************/
107
108/*
109 * The basic PPP frame.
110 */
111#define PPP_ADDRESS(p) (((u_char *)(p))[0])
112#define PPP_CONTROL(p) (((u_char *)(p))[1])
113#define PPP_PROTOCOL(p) ((((u_char *)(p))[2] << 8) + ((u_char *)(p))[3])
114
115/* PPP packet parser states. Current state indicates operation yet to be
116 * completed. */
117typedef enum {
118 PDIDLE = 0, /* Idle state - waiting. */
119 PDSTART, /* Process start flag. */
120 PDADDRESS, /* Process address field. */
121 PDCONTROL, /* Process control field. */
122 PDPROTOCOL1, /* Process protocol field 1. */
123 PDPROTOCOL2, /* Process protocol field 2. */
124 PDDATA /* Process data byte. */
125} PPPDevStates;
126
127#define ESCAPE_P(accm, c) ((accm)[(c) >> 3] & pppACCMMask[c & 0x07])
128
129/************************/
130/*** LOCAL DATA TYPES ***/
131/************************/
132/*
133 * PPP interface control block.
134 */
135typedef struct PPPControl_s {
136 char openFlag; /* True when in use. */
137 char oldFrame; /* Old framing character for fd. */
138 sio_fd_t fd; /* File device ID of port. */
139 int kill_link; /* Shut the link down. */
140 int sig_hup; /* Carrier lost. */
141 int if_up; /* True when the interface is up. */
142 int errCode; /* Code indicating why interface is down. */
143 struct pbuf *inHead, *inTail; /* The input packet. */
144 PPPDevStates inState; /* The input process state. */
145 char inEscaped; /* Escape next character. */
146 u16_t inProtocol; /* The input protocol code. */
147 u16_t inFCS; /* Input Frame Check Sequence value. */
148 int mtu; /* Peer's mru */
149 int pcomp; /* Does peer accept protocol compression? */
150 int accomp; /* Does peer accept addr/ctl compression? */
151 u_long lastXMit; /* Time of last transmission. */
152 ext_accm inACCM; /* Async-Ctl-Char-Map for input. */
153 ext_accm outACCM; /* Async-Ctl-Char-Map for output. */
154#if VJ_SUPPORT > 0
155 int vjEnabled; /* Flag indicating VJ compression enabled. */
156 struct vjcompress vjComp; /* Van Jabobsen compression header. */
157#endif
158
159 struct netif netif;
160
161 struct ppp_addrs addrs;
162
163 void (*linkStatusCB)(void *ctx, int errCode, void *arg);
164 void *linkStatusCtx;
165
166} PPPControl;
167
168
169/*
170 * Ioctl definitions.
171 */
172
173struct npioctl {
174 int protocol; /* PPP procotol, e.g. PPP_IP */
175 enum NPmode mode;
176};
177
178
179
180/***********************************/
181/*** LOCAL FUNCTION DECLARATIONS ***/
182/***********************************/
183static void pppMain(void *pd);
184static void pppDrop(PPPControl *pc);
185static void pppInProc(int pd, u_char *s, int l);
186
187
188/******************************/
189/*** PUBLIC DATA STRUCTURES ***/
190/******************************/
191u_long subnetMask;
192
193static PPPControl pppControl[NUM_PPP]; /* The PPP interface control blocks. */
194
195/*
196 * PPP Data Link Layer "protocol" table.
197 * One entry per supported protocol.
198 * The last entry must be NULL.
199 */
200struct protent *ppp_protocols[] = {
201 &lcp_protent,
202#if PAP_SUPPORT > 0
203 &pap_protent,
204#endif
205#if CHAP_SUPPORT > 0
206 &chap_protent,
207#endif
208#if CBCP_SUPPORT > 0
209 &cbcp_protent,
210#endif
211 &ipcp_protent,
212#if CCP_SUPPORT > 0
213 &ccp_protent,
214#endif
215 NULL
216};
217
218
219/*
220 * Buffers for outgoing packets. This must be accessed only from the appropriate
221 * PPP task so that it doesn't need to be protected to avoid collisions.
222 */
223u_char outpacket_buf[NUM_PPP][PPP_MRU+PPP_HDRLEN];
224
225
226/*****************************/
227/*** LOCAL DATA STRUCTURES ***/
228/*****************************/
229
230/*
231 * FCS lookup table as calculated by genfcstab.
232 */
233static const u_short fcstab[256] = {
234 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
235 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
236 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
237 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
238 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
239 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
240 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
241 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
242 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
243 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
244 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
245 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
246 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
247 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
248 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
249 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
250 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
251 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
252 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
253 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
254 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
255 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
256 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
257 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
258 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
259 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
260 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
261 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
262 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
263 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
264 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
265 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
266};
267
268/* PPP's Asynchronous-Control-Character-Map. The mask array is used
269 * to select the specific bit for a character. */
270static u_char pppACCMMask[] = {
271 0x01,
272 0x02,
273 0x04,
274 0x08,
275 0x10,
276 0x20,
277 0x40,
278 0x80
279};
280
281
282/***********************************/
283/*** PUBLIC FUNCTION DEFINITIONS ***/
284/***********************************/
285/* Initialize the PPP subsystem. */
286
287struct ppp_settings ppp_settings;
288
289void pppInit(void)
290{
291 struct protent *protp;
292 int i, j;
293
294 memset(&ppp_settings, 0, sizeof(ppp_settings));
295 ppp_settings.usepeerdns = 1;
296 pppSetAuth(PPPAUTHTYPE_NONE, NULL, NULL);
297
298 magicInit();
299
300 for (i = 0; i < NUM_PPP; i++) {
301 pppControl[i].openFlag = 0;
302
303 subnetMask = htonl(0xffffff00);
304
305 /*
306 * Initialize to the standard option set.
307 */
308 for (j = 0; (protp = ppp_protocols[j]) != NULL; ++j)
309 (*protp->init)(i);
310 }
311
312#if LINK_STATS
313 /* Clear the statistics. */
314 memset(&lwip_stats.link, 0, sizeof(lwip_stats.link));
315#endif
316}
317
318void pppSetAuth(enum pppAuthType authType, const char *user, const char *passwd)
319{
320 switch(authType) {
321 case PPPAUTHTYPE_NONE:
322 default:
323#ifdef LWIP_PPP_STRICT_PAP_REJECT
324 ppp_settings.refuse_pap = 1;
325#else
326 /* some providers request pap and accept an empty login/pw */
327 ppp_settings.refuse_pap = 0;
328#endif
329 ppp_settings.refuse_chap = 1;
330 break;
331 case PPPAUTHTYPE_ANY:
332/* Warning: Using PPPAUTHTYPE_ANY might have security consequences.
333 * RFC 1994 says:
334 *
335 * In practice, within or associated with each PPP server, there is a
336 * database which associates "user" names with authentication
337 * information ("secrets"). It is not anticipated that a particular
338 * named user would be authenticated by multiple methods. This would
339 * make the user vulnerable to attacks which negotiate the least secure
340 * method from among a set (such as PAP rather than CHAP). If the same
341 * secret was used, PAP would reveal the secret to be used later with
342 * CHAP.
343 *
344 * Instead, for each user name there should be an indication of exactly
345 * one method used to authenticate that user name. If a user needs to
346 * make use of different authentication methods under different
347 * circumstances, then distinct user names SHOULD be employed, each of
348 * which identifies exactly one authentication method.
349 *
350 */
351 ppp_settings.refuse_pap = 0;
352 ppp_settings.refuse_chap = 0;
353 break;
354 case PPPAUTHTYPE_PAP:
355 ppp_settings.refuse_pap = 0;
356 ppp_settings.refuse_chap = 1;
357 break;
358 case PPPAUTHTYPE_CHAP:
359 ppp_settings.refuse_pap = 1;
360 ppp_settings.refuse_chap = 0;
361 break;
362 }
363
364 if(user) {
365 strncpy(ppp_settings.user, user, sizeof(ppp_settings.user)-1);
366 ppp_settings.user[sizeof(ppp_settings.user)-1] = '\0';
367 } else
368 ppp_settings.user[0] = '\0';
369
370 if(passwd) {
371 strncpy(ppp_settings.passwd, passwd, sizeof(ppp_settings.passwd)-1);
372 ppp_settings.passwd[sizeof(ppp_settings.passwd)-1] = '\0';
373 } else
374 ppp_settings.passwd[0] = '\0';
375}
376
377/* Open a new PPP connection using the given I/O device.
378 * This initializes the PPP control block but does not
379 * attempt to negotiate the LCP session. If this port
380 * connects to a modem, the modem connection must be
381 * established before calling this.
382 * Return a new PPP connection descriptor on success or
383 * an error code (negative) on failure. */
384int pppOpen(sio_fd_t fd, void (*linkStatusCB)(void *ctx, int errCode, void *arg), void *linkStatusCtx)
385{
386 PPPControl *pc;
387 int pd;
388
389 /* Find a free PPP session descriptor. Critical region? */
390 for (pd = 0; pd < NUM_PPP && pppControl[pd].openFlag != 0; pd++);
391 if (pd >= NUM_PPP)
392 pd = PPPERR_OPEN;
393 else
394 pppControl[pd].openFlag = !0;
395
396 /* Launch a deamon thread. */
397 if (pd >= 0) {
398
399 pppControl[pd].openFlag = 1;
400
401 lcp_init(pd);
402 pc = &pppControl[pd];
403 pc->fd = fd;
404 pc->kill_link = 0;
405 pc->sig_hup = 0;
406 pc->if_up = 0;
407 pc->errCode = 0;
408 pc->inState = PDIDLE;
409 pc->inHead = NULL;
410 pc->inTail = NULL;
411 pc->inEscaped = 0;
412 pc->lastXMit = 0;
413
414#if VJ_SUPPORT > 0
415 pc->vjEnabled = 0;
416 vj_compress_init(&pc->vjComp);
417#endif
418
419 /*
420 * Default the in and out accm so that escape and flag characters
421 * are always escaped.
422 */
423 memset(pc->inACCM, 0, sizeof(ext_accm));
424 pc->inACCM[15] = 0x60;
425 memset(pc->outACCM, 0, sizeof(ext_accm));
426 pc->outACCM[15] = 0x60;
427
428 pc->linkStatusCB = linkStatusCB;
429 pc->linkStatusCtx = linkStatusCtx;
430
431 sys_thread_new(pppMain, (void*)pd, PPP_THREAD_PRIO);
432 if(!linkStatusCB) {
433 while(pd >= 0 && !pc->if_up) {
434 sys_msleep(500);
435 if (lcp_phase[pd] == PHASE_DEAD) {
436 pppClose(pd);
437 if (pc->errCode)
438 pd = pc->errCode;
439 else
440 pd = PPPERR_CONNECT;
441 }
442 }
443 }
444 }
445 return pd;
446}
447
448/* Close a PPP connection and release the descriptor.
449 * Any outstanding packets in the queues are dropped.
450 * Return 0 on success, an error code on failure. */
451int pppClose(int pd)
452{
453 PPPControl *pc = &pppControl[pd];
454 int st = 0;
455
456 /* Disconnect */
457 pc->kill_link = !0;
458 pppMainWakeup(pd);
459
460 if(!pc->linkStatusCB) {
461 while(st >= 0 && lcp_phase[pd] != PHASE_DEAD) {
462 sys_msleep(500);
463 break;
464 }
465 }
466 return st;
467}
468
469/* This function is called when carrier is lost on the PPP channel. */
470void pppSigHUP(int pd)
471{
472 PPPControl *pc = &pppControl[pd];
473
474 pc->sig_hup = 1;
475 pppMainWakeup(pd);
476}
477
478static void nPut(PPPControl *pc, struct pbuf *nb)
479{
480 struct pbuf *b;
481 int c;
482
483 for(b = nb; b != NULL; b = b->next) {
484 if((c = sio_write(pc->fd, b->payload, b->len)) != b->len) {
485 PPPDEBUG((LOG_WARNING,
486 "PPP nPut: incomplete sio_write(%d,, %u) = %d\n", pc->fd, b->len, c));
487#if LINK_STATS
488 lwip_stats.link.err++;
489#endif /* LINK_STATS */
490 pc->lastXMit = 0; /* prepend PPP_FLAG to next packet */
491 break;
492 }
493 }
494 pbuf_free(nb);
495
496#if LINK_STATS
497 lwip_stats.link.xmit++;
498#endif /* LINK_STATS */
499}
500
501/*
502 * pppAppend - append given character to end of given pbuf. If outACCM
503 * is not NULL and the character needs to be escaped, do so.
504 * If pbuf is full, append another.
505 * Return the current pbuf.
506 */
507static struct pbuf *pppAppend(u_char c, struct pbuf *nb, ext_accm *outACCM)
508{
509 struct pbuf *tb = nb;
510
511 /* Make sure there is room for the character and an escape code.
512 * Sure we don't quite fill the buffer if the character doesn't
513 * get escaped but is one character worth complicating this? */
514 /* Note: We assume no packet header. */
515 if (nb && (PBUF_POOL_BUFSIZE - nb->len) < 2) {
516 tb = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
517 if (tb) {
518 nb->next = tb;
519 }
520#if LINK_STATS
521 else {
522 lwip_stats.link.memerr++;
523 }
524#endif /* LINK_STATS */
525 nb = tb;
526 }
527 if (nb) {
528 if (outACCM && ESCAPE_P(*outACCM, c)) {
529 *((u_char*)nb->payload + nb->len++) = PPP_ESCAPE;
530 *((u_char*)nb->payload + nb->len++) = c ^ PPP_TRANS;
531 }
532 else
533 *((u_char*)nb->payload + nb->len++) = c;
534 }
535
536 return tb;
537}
538
539/* Send a packet on the given connection. */
540static err_t pppifOutput(struct netif *netif, struct pbuf *pb, struct ip_addr *ipaddr)
541{
542 int pd = (int)netif->state;
543 u_short protocol = PPP_IP;
544 PPPControl *pc = &pppControl[pd];
545 u_int fcsOut = PPP_INITFCS;
546 struct pbuf *headMB = NULL, *tailMB = NULL, *p;
547 u_char c;
548
549 (void)ipaddr;
550
551 /* Validate parameters. */
552 /* We let any protocol value go through - it can't hurt us
553 * and the peer will just drop it if it's not accepting it. */
554 if (pd < 0 || pd >= NUM_PPP || !pc->openFlag || !pb) {
555 PPPDEBUG((LOG_WARNING, "pppifOutput[%d]: bad parms prot=%d pb=%p\n",
556 pd, protocol, pb));
557#if LINK_STATS
558 lwip_stats.link.opterr++;
559 lwip_stats.link.drop++;
560#endif
561 return ERR_ARG;
562 }
563
564 /* Check that the link is up. */
565 if (lcp_phase[pd] == PHASE_DEAD) {
566 PPPDEBUG((LOG_ERR, "pppifOutput[%d]: link not up\n", pd));
567#if LINK_STATS
568 lwip_stats.link.rterr++;
569 lwip_stats.link.drop++;
570#endif
571 return ERR_RTE;
572 }
573
574 /* Grab an output buffer. */
575 headMB = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
576 if (headMB == NULL) {
577 PPPDEBUG((LOG_WARNING, "pppifOutput[%d]: first alloc fail\n", pd));
578#if LINK_STATS
579 lwip_stats.link.memerr++;
580 lwip_stats.link.drop++;
581#endif /* LINK_STATS */
582 return ERR_MEM;
583 }
584
585#if VJ_SUPPORT > 0
586 /*
587 * Attempt Van Jacobson header compression if VJ is configured and
588 * this is an IP packet.
589 */
590 if (protocol == PPP_IP && pc->vjEnabled) {
591 switch (vj_compress_tcp(&pc->vjComp, pb)) {
592 case TYPE_IP:
593 /* No change...
594 protocol = PPP_IP_PROTOCOL;
595 */
596 break;
597 case TYPE_COMPRESSED_TCP:
598 protocol = PPP_VJC_COMP;
599 break;
600 case TYPE_UNCOMPRESSED_TCP:
601 protocol = PPP_VJC_UNCOMP;
602 break;
603 default:
604 PPPDEBUG((LOG_WARNING, "pppifOutput[%d]: bad IP packet\n", pd));
605#if LINK_STATS
606 lwip_stats.link.proterr++;
607 lwip_stats.link.drop++;
608#endif
609 pbuf_free(headMB);
610 return ERR_VAL;
611 }
612 }
613#endif
614
615 tailMB = headMB;
616
617 /* Build the PPP header. */
618 if ((sys_jiffies() - pc->lastXMit) >= PPP_MAXIDLEFLAG)
619 tailMB = pppAppend(PPP_FLAG, tailMB, NULL);
620 pc->lastXMit = sys_jiffies();
621 if (!pc->accomp) {
622 fcsOut = PPP_FCS(fcsOut, PPP_ALLSTATIONS);
623 tailMB = pppAppend(PPP_ALLSTATIONS, tailMB, &pc->outACCM);
624 fcsOut = PPP_FCS(fcsOut, PPP_UI);
625 tailMB = pppAppend(PPP_UI, tailMB, &pc->outACCM);
626 }
627 if (!pc->pcomp || protocol > 0xFF) {
628 c = (protocol >> 8) & 0xFF;
629 fcsOut = PPP_FCS(fcsOut, c);
630 tailMB = pppAppend(c, tailMB, &pc->outACCM);
631 }
632 c = protocol & 0xFF;
633 fcsOut = PPP_FCS(fcsOut, c);
634 tailMB = pppAppend(c, tailMB, &pc->outACCM);
635
636 /* Load packet. */
637 for(p = pb; p; p = p->next) {
638 int n;
639 u_char *sPtr;
640
641 sPtr = (u_char*)p->payload;
642 n = p->len;
643 while (n-- > 0) {
644 c = *sPtr++;
645
646 /* Update FCS before checking for special characters. */
647 fcsOut = PPP_FCS(fcsOut, c);
648
649 /* Copy to output buffer escaping special characters. */
650 tailMB = pppAppend(c, tailMB, &pc->outACCM);
651 }
652 }
653
654 /* Add FCS and trailing flag. */
655 c = ~fcsOut & 0xFF;
656 tailMB = pppAppend(c, tailMB, &pc->outACCM);
657 c = (~fcsOut >> 8) & 0xFF;
658 tailMB = pppAppend(c, tailMB, &pc->outACCM);
659 tailMB = pppAppend(PPP_FLAG, tailMB, NULL);
660
661 /* If we failed to complete the packet, throw it away. */
662 if (!tailMB) {
663 PPPDEBUG((LOG_WARNING,
664 "pppifOutput[%d]: Alloc err - dropping proto=%d\n",
665 pd, protocol));
666 pbuf_free(headMB);
667#if LINK_STATS
668 lwip_stats.link.memerr++;
669 lwip_stats.link.drop++;
670#endif
671 return ERR_MEM;
672 }
673
674 /* Send it. */
675 PPPDEBUG((LOG_INFO, "pppifOutput[%d]: proto=0x%04X\n", pd, protocol));
676
677 nPut(pc, headMB);
678
679 return ERR_OK;
680}
681
682/* Get and set parameters for the given connection.
683 * Return 0 on success, an error code on failure. */
684int pppIOCtl(int pd, int cmd, void *arg)
685{
686 PPPControl *pc = &pppControl[pd];
687 int st = 0;
688
689 if (pd < 0 || pd >= NUM_PPP)
690 st = PPPERR_PARAM;
691 else {
692 switch(cmd) {
693 case PPPCTLG_UPSTATUS: /* Get the PPP up status. */
694 if (arg)
695 *(int *)arg = (int)(pc->if_up);
696 else
697 st = PPPERR_PARAM;
698 break;
699 case PPPCTLS_ERRCODE: /* Set the PPP error code. */
700 if (arg)
701 pc->errCode = *(int *)arg;
702 else
703 st = PPPERR_PARAM;
704 break;
705 case PPPCTLG_ERRCODE: /* Get the PPP error code. */
706 if (arg)
707 *(int *)arg = (int)(pc->errCode);
708 else
709 st = PPPERR_PARAM;
710 break;
711 case PPPCTLG_FD:
712 if (arg)
713 *(sio_fd_t *)arg = pc->fd;
714 else
715 st = PPPERR_PARAM;
716 break;
717 default:
718 st = PPPERR_PARAM;
719 break;
720 }
721 }
722
723 return st;
724}
725
726/*
727 * Return the Maximum Transmission Unit for the given PPP connection.
728 */
729u_int pppMTU(int pd)
730{
731 PPPControl *pc = &pppControl[pd];
732 u_int st;
733
734 /* Validate parameters. */
735 if (pd < 0 || pd >= NUM_PPP || !pc->openFlag)
736 st = 0;
737 else
738 st = pc->mtu;
739
740 return st;
741}
742
743/*
744 * Write n characters to a ppp link.
745 * RETURN: >= 0 Number of characters written
746 * -1 Failed to write to device
747 */
748int pppWrite(int pd, const u_char *s, int n)
749{
750 PPPControl *pc = &pppControl[pd];
751 u_char c;
752 u_int fcsOut = PPP_INITFCS;
753 struct pbuf *headMB = NULL, *tailMB;
754 headMB = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
755 if (headMB == NULL) {
756#if LINK_STATS
757 lwip_stats.link.memerr++;
758 lwip_stats.link.proterr++;
759#endif /* LINK_STATS */
760 return PPPERR_ALLOC;
761 }
762
763 tailMB = headMB;
764
765 /* If the link has been idle, we'll send a fresh flag character to
766 * flush any noise. */
767 if ((sys_jiffies() - pc->lastXMit) >= PPP_MAXIDLEFLAG)
768 tailMB = pppAppend(PPP_FLAG, tailMB, NULL);
769 pc->lastXMit = sys_jiffies();
770
771 /* Load output buffer. */
772 while (n-- > 0) {
773 c = *s++;
774
775 /* Update FCS before checking for special characters. */
776 fcsOut = PPP_FCS(fcsOut, c);
777
778 /* Copy to output buffer escaping special characters. */
779 tailMB = pppAppend(c, tailMB, &pc->outACCM);
780 }
781
782 /* Add FCS and trailing flag. */
783 c = ~fcsOut & 0xFF;
784 tailMB = pppAppend(c, tailMB, &pc->outACCM);
785 c = (~fcsOut >> 8) & 0xFF;
786 tailMB = pppAppend(c, tailMB, &pc->outACCM);
787 tailMB = pppAppend(PPP_FLAG, tailMB, NULL);
788
789 /* If we failed to complete the packet, throw it away.
790 * Otherwise send it. */
791 if (!tailMB) {
792 PPPDEBUG((LOG_WARNING,
793 "pppWrite[%d]: Alloc err - dropping pbuf len=%d\n", pd, headMB->len));
794/* "pppWrite[%d]: Alloc err - dropping %d:%.*H", pd, headMB->len, LWIP_MIN(headMB->len * 2, 40), headMB->payload)); */
795 pbuf_free(headMB);
796#if LINK_STATS
797 lwip_stats.link.memerr++;
798 lwip_stats.link.proterr++;
799#endif /* LINK_STATS */
800 return PPPERR_ALLOC;
801 }
802
803 PPPDEBUG((LOG_INFO, "pppWrite[%d]: len=%d\n", pd, headMB->len));
804/* "pppWrite[%d]: %d:%.*H", pd, headMB->len, LWIP_MIN(headMB->len * 2, 40), headMB->payload)); */
805 nPut(pc, headMB);
806
807 return PPPERR_NONE;
808}
809
810/*
811 * ppp_send_config - configure the transmit characteristics of
812 * the ppp interface.
813 */
814void ppp_send_config(
815 int unit,
816 int mtu,
817 u32_t asyncmap,
818 int pcomp,
819 int accomp
820)
821{
822 PPPControl *pc = &pppControl[unit];
823 int i;
824
825 pc->mtu = mtu;
826 pc->pcomp = pcomp;
827 pc->accomp = accomp;
828
829 /* Load the ACCM bits for the 32 control codes. */
830 for (i = 0; i < 32/8; i++)
831 pc->outACCM[i] = (u_char)((asyncmap >> (8 * i)) & 0xFF);
832 PPPDEBUG((LOG_INFO, "ppp_send_config[%d]: outACCM=%X %X %X %X\n",
833 unit,
834 pc->outACCM[0], pc->outACCM[1], pc->outACCM[2], pc->outACCM[3]));
835}
836
837
838/*
839 * ppp_set_xaccm - set the extended transmit ACCM for the interface.
840 */
841void ppp_set_xaccm(int unit, ext_accm *accm)
842{
843 memcpy(pppControl[unit].outACCM, accm, sizeof(ext_accm));
844 PPPDEBUG((LOG_INFO, "ppp_set_xaccm[%d]: outACCM=%X %X %X %X\n",
845 unit,
846 pppControl[unit].outACCM[0],
847 pppControl[unit].outACCM[1],
848 pppControl[unit].outACCM[2],
849 pppControl[unit].outACCM[3]));
850}
851
852
853/*
854 * ppp_recv_config - configure the receive-side characteristics of
855 * the ppp interface.
856 */
857void ppp_recv_config(
858 int unit,
859 int mru,
860 u32_t asyncmap,
861 int pcomp,
862 int accomp
863)
864{
865 PPPControl *pc = &pppControl[unit];
866 int i;
867
868 (void)accomp;
869 (void)pcomp;
870 (void)mru;
871
872 /* Load the ACCM bits for the 32 control codes. */
873 for (i = 0; i < 32 / 8; i++)
874 pc->inACCM[i] = (u_char)(asyncmap >> (i * 8));
875 PPPDEBUG((LOG_INFO, "ppp_recv_config[%d]: inACCM=%X %X %X %X\n",
876 unit,
877 pc->inACCM[0], pc->inACCM[1], pc->inACCM[2], pc->inACCM[3]));
878}
879
880#if 0
881/*
882 * ccp_test - ask kernel whether a given compression method
883 * is acceptable for use. Returns 1 if the method and parameters
884 * are OK, 0 if the method is known but the parameters are not OK
885 * (e.g. code size should be reduced), or -1 if the method is unknown.
886 */
887int ccp_test(
888 int unit,
889 int opt_len,
890 int for_transmit,
891 u_char *opt_ptr
892)
893{
894 return 0; /* XXX Currently no compression. */
895}
896
897/*
898 * ccp_flags_set - inform kernel about the current state of CCP.
899 */
900void ccp_flags_set(int unit, int isopen, int isup)
901{
902 /* XXX */
903}
904
905/*
906 * ccp_fatal_error - returns 1 if decompression was disabled as a
907 * result of an error detected after decompression of a packet,
908 * 0 otherwise. This is necessary because of patent nonsense.
909 */
910int ccp_fatal_error(int unit)
911{
912 /* XXX */
913 return 0;
914}
915#endif
916
917/*
918 * get_idle_time - return how long the link has been idle.
919 */
920int get_idle_time(int u, struct ppp_idle *ip)
921{
922 /* XXX */
923 (void)u;
924 (void)ip;
925
926 return 0;
927}
928
929
930/*
931 * Return user specified netmask, modified by any mask we might determine
932 * for address `addr' (in network byte order).
933 * Here we scan through the system's list of interfaces, looking for
934 * any non-point-to-point interfaces which might appear to be on the same
935 * network as `addr'. If we find any, we OR in their netmask to the
936 * user-specified netmask.
937 */
938u32_t GetMask(u32_t addr)
939{
940 u32_t mask, nmask;
941
942 htonl(addr);
943 if (IN_CLASSA(addr)) /* determine network mask for address class */
944 nmask = IN_CLASSA_NET;
945 else if (IN_CLASSB(addr))
946 nmask = IN_CLASSB_NET;
947 else
948 nmask = IN_CLASSC_NET;
949 /* class D nets are disallowed by bad_ip_adrs */
950 mask = subnetMask | htonl(nmask);
951
952 /* XXX
953 * Scan through the system's network interfaces.
954 * Get each netmask and OR them into our mask.
955 */
956
957 return mask;
958}
959
960/*
961 * sifvjcomp - config tcp header compression
962 */
963int sifvjcomp(
964 int pd,
965 int vjcomp,
966 int cidcomp,
967 int maxcid
968)
969{
970#if VJ_SUPPORT > 0
971 PPPControl *pc = &pppControl[pd];
972
973 pc->vjEnabled = vjcomp;
974 pc->vjComp.compressSlot = cidcomp;
975 pc->vjComp.maxSlotIndex = maxcid;
976 PPPDEBUG((LOG_INFO, "sifvjcomp: VJ compress enable=%d slot=%d max slot=%d\n",
977 vjcomp, cidcomp, maxcid));
978#endif
979
980 return 0;
981}
982
983/*
984 * pppifNetifInit - netif init callback
985 */
986static err_t pppifNetifInit(struct netif *netif)
987{
988 netif->name[0] = 'p';
989 netif->name[1] = 'p';
990 netif->output = pppifOutput;
991 netif->mtu = pppMTU((int)netif->state);
992 return ERR_OK;
993}
994
995
996/*
997 * sifup - Config the interface up and enable IP packets to pass.
998 */
999int sifup(int pd)
1000{
1001 PPPControl *pc = &pppControl[pd];
1002 int st = 1;
1003
1004 if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
1005 st = 0;
1006 PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd));
1007 } else {
1008 netif_remove(&pc->netif);
1009 if (netif_add(&pc->netif, &pc->addrs.our_ipaddr, &pc->addrs.netmask, &pc->addrs.his_ipaddr, (void *)pd, pppifNetifInit, ip_input)) {
1010 pc->if_up = 1;
1011 pc->errCode = PPPERR_NONE;
1012
1013 PPPDEBUG((LOG_DEBUG, "sifup: unit %d: linkStatusCB=%lx errCode=%d\n", pd, pc->linkStatusCB, pc->errCode));
1014 if(pc->linkStatusCB)
1015 pc->linkStatusCB(pc->linkStatusCtx, pc->errCode, &pc->addrs);
1016 } else {
1017 st = 0;
1018 PPPDEBUG((LOG_ERR, "sifup[%d]: netif_add failed\n", pd));
1019 }
1020 }
1021
1022 return st;
1023}
1024
1025/*
1026 * sifnpmode - Set the mode for handling packets for a given NP.
1027 */
1028int sifnpmode(int u, int proto, enum NPmode mode)
1029{
1030 (void)u;
1031 (void)proto;
1032 (void)mode;
1033 return 0;
1034}
1035
1036/*
1037 * sifdown - Config the interface down and disable IP.
1038 */
1039int sifdown(int pd)
1040{
1041 PPPControl *pc = &pppControl[pd];
1042 int st = 1;
1043
1044 if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
1045 st = 0;
1046 PPPDEBUG((LOG_WARNING, "sifdown[%d]: bad parms\n", pd));
1047 } else {
1048 pc->if_up = 0;
1049 netif_remove(&pc->netif);
1050 PPPDEBUG((LOG_DEBUG, "sifdown: unit %d: linkStatusCB=%lx errCode=%d\n", pd, pc->linkStatusCB, pc->errCode));
1051 if(pc->linkStatusCB)
1052 pc->linkStatusCB(pc->linkStatusCtx, PPPERR_CONNECT, NULL);
1053 }
1054 return st;
1055}
1056
1057/*
1058 * sifaddr - Config the interface IP addresses and netmask.
1059 */
1060int sifaddr(
1061 int pd, /* Interface unit ??? */
1062 u32_t o, /* Our IP address ??? */
1063 u32_t h, /* His IP address ??? */
1064 u32_t m, /* IP subnet mask ??? */
1065 u32_t ns1, /* Primary DNS */
1066 u32_t ns2 /* Secondary DNS */
1067)
1068{
1069 PPPControl *pc = &pppControl[pd];
1070 int st = 1;
1071
1072 if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
1073 st = 0;
1074 PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd));
1075 } else {
1076 memcpy(&pc->addrs.our_ipaddr, &o, sizeof(o));
1077 memcpy(&pc->addrs.his_ipaddr, &h, sizeof(h));
1078 memcpy(&pc->addrs.netmask, &m, sizeof(m));
1079 memcpy(&pc->addrs.dns1, &ns1, sizeof(ns1));
1080 memcpy(&pc->addrs.dns2, &ns2, sizeof(ns2));
1081 }
1082 return st;
1083}
1084
1085/*
1086 * cifaddr - Clear the interface IP addresses, and delete routes
1087 * through the interface if possible.
1088 */
1089int cifaddr(
1090 int pd, /* Interface unit ??? */
1091 u32_t o, /* Our IP address ??? */
1092 u32_t h /* IP broadcast address ??? */
1093)
1094{
1095 PPPControl *pc = &pppControl[pd];
1096 int st = 1;
1097
1098 (void)o;
1099 (void)h;
1100 if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
1101 st = 0;
1102 PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd));
1103 } else {
1104 IP4_ADDR(&pc->addrs.our_ipaddr, 0,0,0,0);
1105 IP4_ADDR(&pc->addrs.his_ipaddr, 0,0,0,0);
1106 IP4_ADDR(&pc->addrs.netmask, 255,255,255,0);
1107 IP4_ADDR(&pc->addrs.dns1, 0,0,0,0);
1108 IP4_ADDR(&pc->addrs.dns2, 0,0,0,0);
1109 }
1110 return st;
1111}
1112
1113/*
1114 * sifdefaultroute - assign a default route through the address given.
1115 */
1116int sifdefaultroute(int pd, u32_t l, u32_t g)
1117{
1118 PPPControl *pc = &pppControl[pd];
1119 int st = 1;
1120
1121 (void)l;
1122 (void)g;
1123 if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
1124 st = 0;
1125 PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd));
1126 } else {
1127 netif_set_default(&pc->netif);
1128 }
1129
1130 /* TODO: check how PPP handled the netMask, previously not set by ipSetDefault */
1131
1132 return st;
1133}
1134
1135/*
1136 * cifdefaultroute - delete a default route through the address given.
1137 */
1138int cifdefaultroute(int pd, u32_t l, u32_t g)
1139{
1140 PPPControl *pc = &pppControl[pd];
1141 int st = 1;
1142
1143 (void)l;
1144 (void)g;
1145 if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
1146 st = 0;
1147 PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd));
1148 } else {
1149 netif_set_default(NULL);
1150 }
1151
1152 return st;
1153}
1154
1155void
1156pppMainWakeup(int pd)
1157{
1158 PPPDEBUG((LOG_DEBUG, "pppMainWakeup: unit %d\n", pd));
1159 sio_read_abort(pppControl[pd].fd);
1160}
1161
1162/* these callbacks are necessary because lcp_* functions
1163 must be called in the same context as pppInput(),
1164 namely the tcpip_thread(), essentially because
1165 they manipulate timeouts which are thread-private
1166*/
1167
1168static void
1169pppStartCB(void *arg)
1170{
1171 int pd = (int)arg;
1172
1173 PPPDEBUG((LOG_DEBUG, "pppStartCB: unit %d\n", pd));
1174 lcp_lowerup(pd);
1175 lcp_open(pd); /* Start protocol */
1176}
1177
1178static void
1179pppStopCB(void *arg)
1180{
1181 int pd = (int)arg;
1182
1183 PPPDEBUG((LOG_DEBUG, "pppStopCB: unit %d\n", pd));
1184 lcp_close(pd, "User request");
1185}
1186
1187static void
1188pppHupCB(void *arg)
1189{
1190 int pd = (int)arg;
1191
1192 PPPDEBUG((LOG_DEBUG, "pppHupCB: unit %d\n", pd));
1193 lcp_lowerdown(pd);
1194 link_terminated(pd);
1195}
1196/**********************************/
1197/*** LOCAL FUNCTION DEFINITIONS ***/
1198/**********************************/
1199/* The main PPP process function. This implements the state machine according
1200 * to section 4 of RFC 1661: The Point-To-Point Protocol. */
1201static void pppMain(void *arg)
1202{
1203 int pd = (int)arg;
1204 struct pbuf *p;
1205 PPPControl* pc;
1206
1207 pc = &pppControl[pd];
1208
1209 p = pbuf_alloc(PBUF_RAW, PPP_MRU+PPP_HDRLEN, PBUF_RAM);
1210 if(!p) {
1211 LWIP_ASSERT("p != NULL", p);
1212 pc->errCode = PPPERR_ALLOC;
1213 goto out;
1214 }
1215
1216 /*
1217 * Start the connection and handle incoming events (packet or timeout).
1218 */
1219 PPPDEBUG((LOG_INFO, "pppMain: unit %d: Connecting\n", pd));
1220 tcpip_callback(pppStartCB, arg);
1221 while (lcp_phase[pd] != PHASE_DEAD) {
1222 if (pc->kill_link) {
1223 PPPDEBUG((LOG_DEBUG, "pppMainWakeup: unit %d kill_link -> pppStopCB\n", pd));
1224 pc->errCode = PPPERR_USER;
1225 /* This will leave us at PHASE_DEAD. */
1226 tcpip_callback(pppStopCB, arg);
1227 pc->kill_link = 0;
1228 }
1229 else if (pc->sig_hup) {
1230 PPPDEBUG((LOG_DEBUG, "pppMainWakeup: unit %d sig_hup -> pppHupCB\n", pd));
1231 pc->sig_hup = 0;
1232 tcpip_callback(pppHupCB, arg);
1233 } else {
1234 int c = sio_read(pc->fd, p->payload, p->len);
1235 if(c > 0) {
1236 pppInProc(pd, p->payload, c);
1237 } else {
1238 PPPDEBUG((LOG_DEBUG, "pppMainWakeup: unit %d sio_read len=%d returned %d\n", pd, p->len, c));
1239 sys_msleep(1); /* give other tasks a chance to run */
1240 }
1241 }
1242 }
1243 PPPDEBUG((LOG_INFO, "pppMain: unit %d: PHASE_DEAD\n", pd));
1244 pbuf_free(p);
1245
1246out:
1247 PPPDEBUG((LOG_DEBUG, "pppMain: unit %d: linkStatusCB=%lx errCode=%d\n", pd, pc->linkStatusCB, pc->errCode));
1248 if(pc->linkStatusCB)
1249 pc->linkStatusCB(pc->linkStatusCtx, pc->errCode ? pc->errCode : PPPERR_PROTOCOL, NULL);
1250
1251 pc->openFlag = 0;
1252}
1253
1254static struct pbuf *pppSingleBuf(struct pbuf *p)
1255{
1256 struct pbuf *q, *b;
1257 u_char *pl;
1258
1259 if(p->tot_len == p->len)
1260 return p;
1261
1262 q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
1263 if(!q) {
1264 PPPDEBUG((LOG_ERR,
1265 "pppSingleBuf: unable to alloc new buf (%d)\n", p->tot_len));
1266 return p; /* live dangerously */
1267 }
1268
1269 for(b = p, pl = q->payload; b != NULL; b = b->next) {
1270 memcpy(pl, b->payload, b->len);
1271 pl += b->len;
1272 }
1273
1274 pbuf_free(p);
1275
1276 return q;
1277}
1278
1279struct pppInputHeader {
1280 int unit;
1281 u16_t proto;
1282};
1283
1284/*
1285 * Pass the processed input packet to the appropriate handler.
1286 * This function and all handlers run in the context of the tcpip_thread
1287 */
1288static void pppInput(void *arg)
1289{
1290 struct pbuf *nb = (struct pbuf *)arg;
1291 u16_t protocol;
1292 int pd;
1293
1294 pd = ((struct pppInputHeader *)nb->payload)->unit;
1295 protocol = ((struct pppInputHeader *)nb->payload)->proto;
1296
1297 pbuf_header(nb, -(int)sizeof(struct pppInputHeader));
1298
1299#if LINK_STATS
1300 lwip_stats.link.recv++;
1301#endif /* LINK_STATS */
1302
1303 /*
1304 * Toss all non-LCP packets unless LCP is OPEN.
1305 * Until we get past the authentication phase, toss all packets
1306 * except LCP, LQR and authentication packets.
1307 */
1308 if((lcp_phase[pd] <= PHASE_AUTHENTICATE) && (protocol != PPP_LCP)) {
1309 if(!((protocol == PPP_LQR) || (protocol == PPP_PAP) || (protocol == PPP_CHAP)) ||
1310 (lcp_phase[pd] != PHASE_AUTHENTICATE)) {
1311 PPPDEBUG((LOG_INFO, "pppInput: discarding proto 0x%04X in phase %d\n", protocol, lcp_phase[pd]));
1312 goto drop;
1313 }
1314 }
1315
1316 switch(protocol) {
1317 case PPP_VJC_COMP: /* VJ compressed TCP */
1318#if VJ_SUPPORT > 0
1319 PPPDEBUG((LOG_INFO, "pppInput[%d]: vj_comp in pbuf len=%d\n", pd, nb->len));
1320 /*
1321 * Clip off the VJ header and prepend the rebuilt TCP/IP header and
1322 * pass the result to IP.
1323 */
1324 if (vj_uncompress_tcp(&nb, &pppControl[pd].vjComp) >= 0) {
1325 pppControl[pd].netif.input(nb, &pppControl[pd].netif);
1326 return;
1327 }
1328 /* Something's wrong so drop it. */
1329 PPPDEBUG((LOG_WARNING, "pppInput[%d]: Dropping VJ compressed\n", pd));
1330#else
1331 /* No handler for this protocol so drop the packet. */
1332 PPPDEBUG((LOG_INFO, "pppInput[%d]: drop VJ Comp in %d:%s\n", pd, nb->len, nb->payload));
1333#endif /* VJ_SUPPORT > 0 */
1334 break;
1335 case PPP_VJC_UNCOMP: /* VJ uncompressed TCP */
1336#if VJ_SUPPORT > 0
1337 PPPDEBUG((LOG_INFO, "pppInput[%d]: vj_un in pbuf len=%d\n", pd, nb->len));
1338 /*
1339 * Process the TCP/IP header for VJ header compression and then pass
1340 * the packet to IP.
1341 */
1342 if (vj_uncompress_uncomp(nb, &pppControl[pd].vjComp) >= 0) {
1343 pppControl[pd].netif.input(nb, &pppControl[pd].netif);
1344 return;
1345 }
1346 /* Something's wrong so drop it. */
1347 PPPDEBUG((LOG_WARNING, "pppInput[%d]: Dropping VJ uncompressed\n", pd));
1348#else
1349 /* No handler for this protocol so drop the packet. */
1350 PPPDEBUG((LOG_INFO,
1351 "pppInput[%d]: drop VJ UnComp in %d:.*H\n",
1352 pd, nb->len, LWIP_MIN(nb->len * 2, 40), nb->payload));
1353#endif /* VJ_SUPPORT > 0 */
1354 break;
1355 case PPP_IP: /* Internet Protocol */
1356 PPPDEBUG((LOG_INFO, "pppInput[%d]: ip in pbuf len=%d\n", pd, nb->len));
1357 pppControl[pd].netif.input(nb, &pppControl[pd].netif);
1358 return;
1359 default:
1360 {
1361 struct protent *protp;
1362 int i;
1363
1364 /*
1365 * Upcall the proper protocol input routine.
1366 */
1367 for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i) {
1368 if (protp->protocol == protocol && protp->enabled_flag) {
1369 PPPDEBUG((LOG_INFO, "pppInput[%d]: %s len=%d\n", pd, protp->name, nb->len));
1370 nb = pppSingleBuf(nb);
1371 (*protp->input)(pd, nb->payload, nb->len);
1372 goto out;
1373 }
1374 }
1375
1376 /* No handler for this protocol so reject the packet. */
1377 PPPDEBUG((LOG_INFO, "pppInput[%d]: rejecting unsupported proto 0x%04X len=%d\n", pd, protocol, nb->len));
1378 pbuf_header(nb, sizeof(protocol));
1379#if BYTE_ORDER == LITTLE_ENDIAN
1380 protocol = htons(protocol);
1381 memcpy(nb->payload, &protocol, sizeof(protocol));
1382#endif
1383 lcp_sprotrej(pd, nb->payload, nb->len);
1384 }
1385 break;
1386 }
1387
1388drop:
1389#if LINK_STATS
1390 lwip_stats.link.drop++;
1391#endif
1392
1393out:
1394 pbuf_free(nb);
1395 return;
1396}
1397
1398
1399/*
1400 * Drop the input packet.
1401 */
1402static void pppDrop(PPPControl *pc)
1403{
1404 if (pc->inHead != NULL) {
1405#if 0
1406 PPPDEBUG((LOG_INFO, "pppDrop: %d:%.*H\n", pc->inHead->len, min(60, pc->inHead->len * 2), pc->inHead->payload));
1407#endif
1408 PPPDEBUG((LOG_INFO, "pppDrop: pbuf len=%d\n", pc->inHead->len));
1409 if (pc->inTail && (pc->inTail != pc->inHead))
1410 pbuf_free(pc->inTail);
1411 pbuf_free(pc->inHead);
1412 pc->inHead = NULL;
1413 pc->inTail = NULL;
1414 }
1415#if VJ_SUPPORT > 0
1416 vj_uncompress_err(&pc->vjComp);
1417#endif
1418
1419#if LINK_STATS
1420 lwip_stats.link.drop++;
1421#endif /* LINK_STATS */
1422}
1423
1424
1425/*
1426 * Process a received octet string.
1427 */
1428static void pppInProc(int pd, u_char *s, int l)
1429{
1430 PPPControl *pc = &pppControl[pd];
1431 struct pbuf *nextNBuf;
1432 u_char curChar;
1433
1434 PPPDEBUG((LOG_DEBUG, "pppInProc[%d]: got %d bytes\n", pd, l));
1435 while (l-- > 0) {
1436 curChar = *s++;
1437
1438 /* Handle special characters. */
1439 if (ESCAPE_P(pc->inACCM, curChar)) {
1440 /* Check for escape sequences. */
1441 /* XXX Note that this does not handle an escaped 0x5d character which
1442 * would appear as an escape character. Since this is an ASCII ']'
1443 * and there is no reason that I know of to escape it, I won't complicate
1444 * the code to handle this case. GLL */
1445 if (curChar == PPP_ESCAPE)
1446 pc->inEscaped = 1;
1447 /* Check for the flag character. */
1448 else if (curChar == PPP_FLAG) {
1449 /* If this is just an extra flag character, ignore it. */
1450 if (pc->inState <= PDADDRESS)
1451 ;
1452 /* If we haven't received the packet header, drop what has come in. */
1453 else if (pc->inState < PDDATA) {
1454 PPPDEBUG((LOG_WARNING,
1455 "pppInProc[%d]: Dropping incomplete packet %d\n",
1456 pd, pc->inState));
1457#if LINK_STATS
1458 lwip_stats.link.lenerr++;
1459#endif
1460 pppDrop(pc);
1461 }
1462 /* If the fcs is invalid, drop the packet. */
1463 else if (pc->inFCS != PPP_GOODFCS) {
1464 PPPDEBUG((LOG_INFO,
1465 "pppInProc[%d]: Dropping bad fcs 0x%04X proto=0x%04X\n",
1466 pd, pc->inFCS, pc->inProtocol));
1467#if LINK_STATS
1468 lwip_stats.link.chkerr++;
1469#endif
1470 pppDrop(pc);
1471 }
1472 /* Otherwise it's a good packet so pass it on. */
1473 else {
1474
1475 /* Trim off the checksum. */
1476 if(pc->inTail->len >= 2) {
1477 pc->inTail->len -= 2;
1478
1479 pc->inTail->tot_len = pc->inTail->len;
1480 if (pc->inTail != pc->inHead) {
1481 pbuf_cat(pc->inHead, pc->inTail);
1482 }
1483 } else {
1484 pc->inTail->tot_len = pc->inTail->len;
1485 if (pc->inTail != pc->inHead) {
1486 pbuf_cat(pc->inHead, pc->inTail);
1487 }
1488
1489 pbuf_realloc(pc->inHead, pc->inHead->tot_len - 2);
1490 }
1491
1492 /* Dispatch the packet thereby consuming it. */
1493 if(tcpip_callback(pppInput, pc->inHead) != ERR_OK) {
1494 PPPDEBUG((LOG_ERR,
1495 "pppInProc[%d]: tcpip_callback() failed, dropping packet\n", pd));
1496 pbuf_free(pc->inHead);
1497#if LINK_STATS
1498 lwip_stats.link.drop++;
1499#endif
1500 }
1501 pc->inHead = NULL;
1502 pc->inTail = NULL;
1503 }
1504
1505 /* Prepare for a new packet. */
1506 pc->inFCS = PPP_INITFCS;
1507 pc->inState = PDADDRESS;
1508 pc->inEscaped = 0;
1509 }
1510 /* Other characters are usually control characters that may have
1511 * been inserted by the physical layer so here we just drop them. */
1512 else {
1513 PPPDEBUG((LOG_WARNING,
1514 "pppInProc[%d]: Dropping ACCM char <%d>\n", pd, curChar));
1515 }
1516 }
1517 /* Process other characters. */
1518 else {
1519 /* Unencode escaped characters. */
1520 if (pc->inEscaped) {
1521 pc->inEscaped = 0;
1522 curChar ^= PPP_TRANS;
1523 }
1524
1525 /* Process character relative to current state. */
1526 switch(pc->inState) {
1527 case PDIDLE: /* Idle state - waiting. */
1528 /* Drop the character if it's not 0xff
1529 * we would have processed a flag character above. */
1530 if (curChar != PPP_ALLSTATIONS) {
1531 break;
1532 }
1533
1534 /* Fall through */
1535 case PDSTART: /* Process start flag. */
1536 /* Prepare for a new packet. */
1537 pc->inFCS = PPP_INITFCS;
1538
1539 /* Fall through */
1540 case PDADDRESS: /* Process address field. */
1541 if (curChar == PPP_ALLSTATIONS) {
1542 pc->inState = PDCONTROL;
1543 break;
1544 }
1545 /* Else assume compressed address and control fields so
1546 * fall through to get the protocol... */
1547 case PDCONTROL: /* Process control field. */
1548 /* If we don't get a valid control code, restart. */
1549 if (curChar == PPP_UI) {
1550 pc->inState = PDPROTOCOL1;
1551 break;
1552 }
1553#if 0
1554 else {
1555 PPPDEBUG((LOG_WARNING,
1556 "pppInProc[%d]: Invalid control <%d>\n", pd, curChar));
1557 pc->inState = PDSTART;
1558 }
1559#endif
1560 case PDPROTOCOL1: /* Process protocol field 1. */
1561 /* If the lower bit is set, this is the end of the protocol
1562 * field. */
1563 if (curChar & 1) {
1564 pc->inProtocol = curChar;
1565 pc->inState = PDDATA;
1566 }
1567 else {
1568 pc->inProtocol = (u_int)curChar << 8;
1569 pc->inState = PDPROTOCOL2;
1570 }
1571 break;
1572 case PDPROTOCOL2: /* Process protocol field 2. */
1573 pc->inProtocol |= curChar;
1574 pc->inState = PDDATA;
1575 break;
1576 case PDDATA: /* Process data byte. */
1577 /* Make space to receive processed data. */
1578 if (pc->inTail == NULL || pc->inTail->len == PBUF_POOL_BUFSIZE) {
1579 if(pc->inTail) {
1580 pc->inTail->tot_len = pc->inTail->len;
1581 if (pc->inTail != pc->inHead) {
1582 pbuf_cat(pc->inHead, pc->inTail);
1583 }
1584 }
1585 /* If we haven't started a packet, we need a packet header. */
1586 nextNBuf = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
1587 if (nextNBuf == NULL) {
1588 /* No free buffers. Drop the input packet and let the
1589 * higher layers deal with it. Continue processing
1590 * the received pbuf chain in case a new packet starts. */
1591 PPPDEBUG((LOG_ERR, "pppInProc[%d]: NO FREE MBUFS!\n", pd));
1592#if LINK_STATS
1593 lwip_stats.link.memerr++;
1594#endif /* LINK_STATS */
1595 pppDrop(pc);
1596 pc->inState = PDSTART; /* Wait for flag sequence. */
1597 break;
1598 }
1599 if (pc->inHead == NULL) {
1600 struct pppInputHeader *pih = nextNBuf->payload;
1601
1602 pih->unit = pd;
1603 pih->proto = pc->inProtocol;
1604
1605 nextNBuf->len += sizeof(*pih);
1606
1607 pc->inHead = nextNBuf;
1608 }
1609 pc->inTail = nextNBuf;
1610 }
1611 /* Load character into buffer. */
1612 ((u_char*)pc->inTail->payload)[pc->inTail->len++] = curChar;
1613 break;
1614 }
1615
1616 /* update the frame check sequence number. */
1617 pc->inFCS = PPP_FCS(pc->inFCS, curChar);
1618 }
1619 }
1620 avRandomize();
1621}
1622
1623#endif /* PPP_SUPPORT */