1 /*****************************************************************************
\r
2 * ppp.c - Network Point to Point Protocol program file.
\r
4 * Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
\r
5 * portions Copyright (c) 1997 by Global Election Systems Inc.
\r
7 * The authors hereby grant permission to use, copy, modify, distribute,
\r
8 * and license this software and its documentation for any purpose, provided
\r
9 * that existing copyright notices are retained in all copies and that this
\r
10 * notice and the following disclaimer are included verbatim in any
\r
11 * distributions. No written agreement, license, or royalty fee is required
\r
12 * for any of the authorized uses.
\r
14 * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
\r
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
\r
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
\r
17 * IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
\r
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
\r
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
\r
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
\r
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
\r
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
\r
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\r
25 ******************************************************************************
\r
28 * 03-01-01 Marc Boucher <marc@mbsi.ca>
\r
30 * 97-11-05 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
\r
32 *****************************************************************************/
\r
35 * ppp_defs.h - PPP definitions.
\r
37 * if_pppvar.h - private structures and declarations for PPP.
\r
39 * Copyright (c) 1994 The Australian National University.
\r
40 * All rights reserved.
\r
42 * Permission to use, copy, modify, and distribute this software and its
\r
43 * documentation is hereby granted, provided that the above copyright
\r
44 * notice appears in all copies. This software is provided without any
\r
45 * warranty, express or implied. The Australian National University
\r
46 * makes no representations about the suitability of this software for
\r
49 * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
\r
50 * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
\r
51 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
\r
52 * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
\r
55 * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
\r
56 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
\r
57 * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
\r
58 * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
\r
59 * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
\r
64 * if_ppp.h - Point-to-Point Protocol definitions.
\r
66 * Copyright (c) 1989 Carnegie Mellon University.
\r
67 * All rights reserved.
\r
69 * Redistribution and use in source and binary forms are permitted
\r
70 * provided that the above copyright notice and this paragraph are
\r
71 * duplicated in all such forms and that any documentation,
\r
72 * advertising materials, and other materials related to such
\r
73 * distribution and use acknowledge that the software was developed
\r
74 * by Carnegie Mellon University. The name of the
\r
75 * University may not be used to endorse or promote products derived
\r
76 * from this software without specific prior written permission.
\r
77 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
\r
78 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
\r
79 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
\r
91 #if CHAP_SUPPORT > 0
\r
102 #include "pppdebug.h"
\r
104 /*************************/
\r
105 /*** LOCAL DEFINITIONS ***/
\r
106 /*************************/
\r
109 * The basic PPP frame.
\r
111 #define PPP_ADDRESS(p) (((u_char *)(p))[0])
\r
112 #define PPP_CONTROL(p) (((u_char *)(p))[1])
\r
113 #define PPP_PROTOCOL(p) ((((u_char *)(p))[2] << 8) + ((u_char *)(p))[3])
\r
115 /* PPP packet parser states. Current state indicates operation yet to be
\r
118 PDIDLE = 0, /* Idle state - waiting. */
\r
119 PDSTART, /* Process start flag. */
\r
120 PDADDRESS, /* Process address field. */
\r
121 PDCONTROL, /* Process control field. */
\r
122 PDPROTOCOL1, /* Process protocol field 1. */
\r
123 PDPROTOCOL2, /* Process protocol field 2. */
\r
124 PDDATA /* Process data byte. */
\r
127 #define ESCAPE_P(accm, c) ((accm)[(c) >> 3] & pppACCMMask[c & 0x07])
\r
129 /************************/
\r
130 /*** LOCAL DATA TYPES ***/
\r
131 /************************/
\r
133 * PPP interface control block.
\r
135 typedef struct PPPControl_s {
\r
136 char openFlag; /* True when in use. */
\r
137 char oldFrame; /* Old framing character for fd. */
\r
138 sio_fd_t fd; /* File device ID of port. */
\r
139 int kill_link; /* Shut the link down. */
\r
140 int sig_hup; /* Carrier lost. */
\r
141 int if_up; /* True when the interface is up. */
\r
142 int errCode; /* Code indicating why interface is down. */
\r
143 struct pbuf *inHead, *inTail; /* The input packet. */
\r
144 PPPDevStates inState; /* The input process state. */
\r
145 char inEscaped; /* Escape next character. */
\r
146 u16_t inProtocol; /* The input protocol code. */
\r
147 u16_t inFCS; /* Input Frame Check Sequence value. */
\r
148 int mtu; /* Peer's mru */
\r
149 int pcomp; /* Does peer accept protocol compression? */
\r
150 int accomp; /* Does peer accept addr/ctl compression? */
\r
151 u_long lastXMit; /* Time of last transmission. */
\r
152 ext_accm inACCM; /* Async-Ctl-Char-Map for input. */
\r
153 ext_accm outACCM; /* Async-Ctl-Char-Map for output. */
\r
155 int vjEnabled; /* Flag indicating VJ compression enabled. */
\r
156 struct vjcompress vjComp; /* Van Jabobsen compression header. */
\r
159 struct netif netif;
\r
161 struct ppp_addrs addrs;
\r
163 void (*linkStatusCB)(void *ctx, int errCode, void *arg);
\r
164 void *linkStatusCtx;
\r
170 * Ioctl definitions.
\r
174 int protocol; /* PPP procotol, e.g. PPP_IP */
\r
180 /***********************************/
\r
181 /*** LOCAL FUNCTION DECLARATIONS ***/
\r
182 /***********************************/
\r
183 static void pppMain(void *pd);
\r
184 static void pppDrop(PPPControl *pc);
\r
185 static void pppInProc(int pd, u_char *s, int l);
\r
188 /******************************/
\r
189 /*** PUBLIC DATA STRUCTURES ***/
\r
190 /******************************/
\r
193 static PPPControl pppControl[NUM_PPP]; /* The PPP interface control blocks. */
\r
196 * PPP Data Link Layer "protocol" table.
\r
197 * One entry per supported protocol.
\r
198 * The last entry must be NULL.
\r
200 struct protent *ppp_protocols[] = {
\r
202 #if PAP_SUPPORT > 0
\r
205 #if CHAP_SUPPORT > 0
\r
208 #if CBCP_SUPPORT > 0
\r
212 #if CCP_SUPPORT > 0
\r
220 * Buffers for outgoing packets. This must be accessed only from the appropriate
\r
221 * PPP task so that it doesn't need to be protected to avoid collisions.
\r
223 u_char outpacket_buf[NUM_PPP][PPP_MRU+PPP_HDRLEN];
\r
226 /*****************************/
\r
227 /*** LOCAL DATA STRUCTURES ***/
\r
228 /*****************************/
\r
231 * FCS lookup table as calculated by genfcstab.
\r
233 static const u_short fcstab[256] = {
\r
234 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
\r
235 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
\r
236 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
\r
237 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
\r
238 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
\r
239 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
\r
240 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
\r
241 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
\r
242 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
\r
243 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
\r
244 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
\r
245 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
\r
246 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
\r
247 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
\r
248 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
\r
249 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
\r
250 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
\r
251 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
\r
252 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
\r
253 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
\r
254 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
\r
255 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
\r
256 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
\r
257 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
\r
258 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
\r
259 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
\r
260 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
\r
261 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
\r
262 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
\r
263 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
\r
264 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
\r
265 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
\r
268 /* PPP's Asynchronous-Control-Character-Map. The mask array is used
\r
269 * to select the specific bit for a character. */
\r
270 static u_char pppACCMMask[] = {
\r
282 /***********************************/
\r
283 /*** PUBLIC FUNCTION DEFINITIONS ***/
\r
284 /***********************************/
\r
285 /* Initialize the PPP subsystem. */
\r
287 struct ppp_settings ppp_settings;
\r
291 struct protent *protp;
\r
294 memset(&ppp_settings, 0, sizeof(ppp_settings));
\r
295 ppp_settings.usepeerdns = 1;
\r
296 pppSetAuth(PPPAUTHTYPE_NONE, NULL, NULL);
\r
300 for (i = 0; i < NUM_PPP; i++) {
\r
301 pppControl[i].openFlag = 0;
\r
303 subnetMask = htonl(0xffffff00);
\r
306 * Initialize to the standard option set.
\r
308 for (j = 0; (protp = ppp_protocols[j]) != NULL; ++j)
\r
313 /* Clear the statistics. */
\r
314 memset(&lwip_stats.link, 0, sizeof(lwip_stats.link));
\r
318 void pppSetAuth(enum pppAuthType authType, const char *user, const char *passwd)
\r
321 case PPPAUTHTYPE_NONE:
\r
323 #ifdef LWIP_PPP_STRICT_PAP_REJECT
\r
324 ppp_settings.refuse_pap = 1;
\r
326 /* some providers request pap and accept an empty login/pw */
\r
327 ppp_settings.refuse_pap = 0;
\r
329 ppp_settings.refuse_chap = 1;
\r
331 case PPPAUTHTYPE_ANY:
\r
332 /* Warning: Using PPPAUTHTYPE_ANY might have security consequences.
\r
335 * In practice, within or associated with each PPP server, there is a
\r
336 * database which associates "user" names with authentication
\r
337 * information ("secrets"). It is not anticipated that a particular
\r
338 * named user would be authenticated by multiple methods. This would
\r
339 * make the user vulnerable to attacks which negotiate the least secure
\r
340 * method from among a set (such as PAP rather than CHAP). If the same
\r
341 * secret was used, PAP would reveal the secret to be used later with
\r
344 * Instead, for each user name there should be an indication of exactly
\r
345 * one method used to authenticate that user name. If a user needs to
\r
346 * make use of different authentication methods under different
\r
347 * circumstances, then distinct user names SHOULD be employed, each of
\r
348 * which identifies exactly one authentication method.
\r
351 ppp_settings.refuse_pap = 0;
\r
352 ppp_settings.refuse_chap = 0;
\r
354 case PPPAUTHTYPE_PAP:
\r
355 ppp_settings.refuse_pap = 0;
\r
356 ppp_settings.refuse_chap = 1;
\r
358 case PPPAUTHTYPE_CHAP:
\r
359 ppp_settings.refuse_pap = 1;
\r
360 ppp_settings.refuse_chap = 0;
\r
365 strncpy(ppp_settings.user, user, sizeof(ppp_settings.user)-1);
\r
366 ppp_settings.user[sizeof(ppp_settings.user)-1] = '\0';
\r
368 ppp_settings.user[0] = '\0';
\r
371 strncpy(ppp_settings.passwd, passwd, sizeof(ppp_settings.passwd)-1);
\r
372 ppp_settings.passwd[sizeof(ppp_settings.passwd)-1] = '\0';
\r
374 ppp_settings.passwd[0] = '\0';
\r
377 /* Open a new PPP connection using the given I/O device.
\r
378 * This initializes the PPP control block but does not
\r
379 * attempt to negotiate the LCP session. If this port
\r
380 * connects to a modem, the modem connection must be
\r
381 * established before calling this.
\r
382 * Return a new PPP connection descriptor on success or
\r
383 * an error code (negative) on failure. */
\r
384 int pppOpen(sio_fd_t fd, void (*linkStatusCB)(void *ctx, int errCode, void *arg), void *linkStatusCtx)
\r
389 /* Find a free PPP session descriptor. Critical region? */
\r
390 for (pd = 0; pd < NUM_PPP && pppControl[pd].openFlag != 0; pd++);
\r
394 pppControl[pd].openFlag = !0;
\r
396 /* Launch a deamon thread. */
\r
399 pppControl[pd].openFlag = 1;
\r
402 pc = &pppControl[pd];
\r
408 pc->inState = PDIDLE;
\r
416 vj_compress_init(&pc->vjComp);
\r
420 * Default the in and out accm so that escape and flag characters
\r
421 * are always escaped.
\r
423 memset(pc->inACCM, 0, sizeof(ext_accm));
\r
424 pc->inACCM[15] = 0x60;
\r
425 memset(pc->outACCM, 0, sizeof(ext_accm));
\r
426 pc->outACCM[15] = 0x60;
\r
428 pc->linkStatusCB = linkStatusCB;
\r
429 pc->linkStatusCtx = linkStatusCtx;
\r
431 sys_thread_new(pppMain, (void*)pd, PPP_THREAD_PRIO);
\r
432 if(!linkStatusCB) {
\r
433 while(pd >= 0 && !pc->if_up) {
\r
435 if (lcp_phase[pd] == PHASE_DEAD) {
\r
440 pd = PPPERR_CONNECT;
\r
448 /* Close a PPP connection and release the descriptor.
\r
449 * Any outstanding packets in the queues are dropped.
\r
450 * Return 0 on success, an error code on failure. */
\r
451 int pppClose(int pd)
\r
453 PPPControl *pc = &pppControl[pd];
\r
457 pc->kill_link = !0;
\r
460 if(!pc->linkStatusCB) {
\r
461 while(st >= 0 && lcp_phase[pd] != PHASE_DEAD) {
\r
469 /* This function is called when carrier is lost on the PPP channel. */
\r
470 void pppSigHUP(int pd)
\r
472 PPPControl *pc = &pppControl[pd];
\r
478 static void nPut(PPPControl *pc, struct pbuf *nb)
\r
483 for(b = nb; b != NULL; b = b->next) {
\r
484 if((c = sio_write(pc->fd, b->payload, b->len)) != b->len) {
\r
485 PPPDEBUG((LOG_WARNING,
\r
486 "PPP nPut: incomplete sio_write(%d,, %u) = %d\n", pc->fd, b->len, c));
\r
488 lwip_stats.link.err++;
\r
489 #endif /* LINK_STATS */
\r
490 pc->lastXMit = 0; /* prepend PPP_FLAG to next packet */
\r
497 lwip_stats.link.xmit++;
\r
498 #endif /* LINK_STATS */
\r
502 * pppAppend - append given character to end of given pbuf. If outACCM
\r
503 * is not NULL and the character needs to be escaped, do so.
\r
504 * If pbuf is full, append another.
\r
505 * Return the current pbuf.
\r
507 static struct pbuf *pppAppend(u_char c, struct pbuf *nb, ext_accm *outACCM)
\r
509 struct pbuf *tb = nb;
\r
511 /* Make sure there is room for the character and an escape code.
\r
512 * Sure we don't quite fill the buffer if the character doesn't
\r
513 * get escaped but is one character worth complicating this? */
\r
514 /* Note: We assume no packet header. */
\r
515 if (nb && (PBUF_POOL_BUFSIZE - nb->len) < 2) {
\r
516 tb = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
\r
522 lwip_stats.link.memerr++;
\r
524 #endif /* LINK_STATS */
\r
528 if (outACCM && ESCAPE_P(*outACCM, c)) {
\r
529 *((u_char*)nb->payload + nb->len++) = PPP_ESCAPE;
\r
530 *((u_char*)nb->payload + nb->len++) = c ^ PPP_TRANS;
\r
533 *((u_char*)nb->payload + nb->len++) = c;
\r
539 /* Send a packet on the given connection. */
\r
540 static err_t pppifOutput(struct netif *netif, struct pbuf *pb, struct ip_addr *ipaddr)
\r
542 int pd = (int)netif->state;
\r
543 u_short protocol = PPP_IP;
\r
544 PPPControl *pc = &pppControl[pd];
\r
545 u_int fcsOut = PPP_INITFCS;
\r
546 struct pbuf *headMB = NULL, *tailMB = NULL, *p;
\r
551 /* Validate parameters. */
\r
552 /* We let any protocol value go through - it can't hurt us
\r
553 * and the peer will just drop it if it's not accepting it. */
\r
554 if (pd < 0 || pd >= NUM_PPP || !pc->openFlag || !pb) {
\r
555 PPPDEBUG((LOG_WARNING, "pppifOutput[%d]: bad parms prot=%d pb=%p\n",
\r
556 pd, protocol, pb));
\r
558 lwip_stats.link.opterr++;
\r
559 lwip_stats.link.drop++;
\r
564 /* Check that the link is up. */
\r
565 if (lcp_phase[pd] == PHASE_DEAD) {
\r
566 PPPDEBUG((LOG_ERR, "pppifOutput[%d]: link not up\n", pd));
\r
568 lwip_stats.link.rterr++;
\r
569 lwip_stats.link.drop++;
\r
574 /* Grab an output buffer. */
\r
575 headMB = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
\r
576 if (headMB == NULL) {
\r
577 PPPDEBUG((LOG_WARNING, "pppifOutput[%d]: first alloc fail\n", pd));
\r
579 lwip_stats.link.memerr++;
\r
580 lwip_stats.link.drop++;
\r
581 #endif /* LINK_STATS */
\r
587 * Attempt Van Jacobson header compression if VJ is configured and
\r
588 * this is an IP packet.
\r
590 if (protocol == PPP_IP && pc->vjEnabled) {
\r
591 switch (vj_compress_tcp(&pc->vjComp, pb)) {
\r
594 protocol = PPP_IP_PROTOCOL;
\r
597 case TYPE_COMPRESSED_TCP:
\r
598 protocol = PPP_VJC_COMP;
\r
600 case TYPE_UNCOMPRESSED_TCP:
\r
601 protocol = PPP_VJC_UNCOMP;
\r
604 PPPDEBUG((LOG_WARNING, "pppifOutput[%d]: bad IP packet\n", pd));
\r
606 lwip_stats.link.proterr++;
\r
607 lwip_stats.link.drop++;
\r
617 /* Build the PPP header. */
\r
618 if ((sys_jiffies() - pc->lastXMit) >= PPP_MAXIDLEFLAG)
\r
619 tailMB = pppAppend(PPP_FLAG, tailMB, NULL);
\r
620 pc->lastXMit = sys_jiffies();
\r
622 fcsOut = PPP_FCS(fcsOut, PPP_ALLSTATIONS);
\r
623 tailMB = pppAppend(PPP_ALLSTATIONS, tailMB, &pc->outACCM);
\r
624 fcsOut = PPP_FCS(fcsOut, PPP_UI);
\r
625 tailMB = pppAppend(PPP_UI, tailMB, &pc->outACCM);
\r
627 if (!pc->pcomp || protocol > 0xFF) {
\r
628 c = (protocol >> 8) & 0xFF;
\r
629 fcsOut = PPP_FCS(fcsOut, c);
\r
630 tailMB = pppAppend(c, tailMB, &pc->outACCM);
\r
632 c = protocol & 0xFF;
\r
633 fcsOut = PPP_FCS(fcsOut, c);
\r
634 tailMB = pppAppend(c, tailMB, &pc->outACCM);
\r
637 for(p = pb; p; p = p->next) {
\r
641 sPtr = (u_char*)p->payload;
\r
646 /* Update FCS before checking for special characters. */
\r
647 fcsOut = PPP_FCS(fcsOut, c);
\r
649 /* Copy to output buffer escaping special characters. */
\r
650 tailMB = pppAppend(c, tailMB, &pc->outACCM);
\r
654 /* Add FCS and trailing flag. */
\r
655 c = ~fcsOut & 0xFF;
\r
656 tailMB = pppAppend(c, tailMB, &pc->outACCM);
\r
657 c = (~fcsOut >> 8) & 0xFF;
\r
658 tailMB = pppAppend(c, tailMB, &pc->outACCM);
\r
659 tailMB = pppAppend(PPP_FLAG, tailMB, NULL);
\r
661 /* If we failed to complete the packet, throw it away. */
\r
663 PPPDEBUG((LOG_WARNING,
\r
664 "pppifOutput[%d]: Alloc err - dropping proto=%d\n",
\r
668 lwip_stats.link.memerr++;
\r
669 lwip_stats.link.drop++;
\r
675 PPPDEBUG((LOG_INFO, "pppifOutput[%d]: proto=0x%04X\n", pd, protocol));
\r
682 /* Get and set parameters for the given connection.
\r
683 * Return 0 on success, an error code on failure. */
\r
684 int pppIOCtl(int pd, int cmd, void *arg)
\r
686 PPPControl *pc = &pppControl[pd];
\r
689 if (pd < 0 || pd >= NUM_PPP)
\r
693 case PPPCTLG_UPSTATUS: /* Get the PPP up status. */
\r
695 *(int *)arg = (int)(pc->if_up);
\r
699 case PPPCTLS_ERRCODE: /* Set the PPP error code. */
\r
701 pc->errCode = *(int *)arg;
\r
705 case PPPCTLG_ERRCODE: /* Get the PPP error code. */
\r
707 *(int *)arg = (int)(pc->errCode);
\r
713 *(sio_fd_t *)arg = pc->fd;
\r
727 * Return the Maximum Transmission Unit for the given PPP connection.
\r
729 u_int pppMTU(int pd)
\r
731 PPPControl *pc = &pppControl[pd];
\r
734 /* Validate parameters. */
\r
735 if (pd < 0 || pd >= NUM_PPP || !pc->openFlag)
\r
744 * Write n characters to a ppp link.
\r
745 * RETURN: >= 0 Number of characters written
\r
746 * -1 Failed to write to device
\r
748 int pppWrite(int pd, const u_char *s, int n)
\r
750 PPPControl *pc = &pppControl[pd];
\r
752 u_int fcsOut = PPP_INITFCS;
\r
753 struct pbuf *headMB = NULL, *tailMB;
\r
754 headMB = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
\r
755 if (headMB == NULL) {
\r
757 lwip_stats.link.memerr++;
\r
758 lwip_stats.link.proterr++;
\r
759 #endif /* LINK_STATS */
\r
760 return PPPERR_ALLOC;
\r
765 /* If the link has been idle, we'll send a fresh flag character to
\r
766 * flush any noise. */
\r
767 if ((sys_jiffies() - pc->lastXMit) >= PPP_MAXIDLEFLAG)
\r
768 tailMB = pppAppend(PPP_FLAG, tailMB, NULL);
\r
769 pc->lastXMit = sys_jiffies();
\r
771 /* Load output buffer. */
\r
775 /* Update FCS before checking for special characters. */
\r
776 fcsOut = PPP_FCS(fcsOut, c);
\r
778 /* Copy to output buffer escaping special characters. */
\r
779 tailMB = pppAppend(c, tailMB, &pc->outACCM);
\r
782 /* Add FCS and trailing flag. */
\r
783 c = ~fcsOut & 0xFF;
\r
784 tailMB = pppAppend(c, tailMB, &pc->outACCM);
\r
785 c = (~fcsOut >> 8) & 0xFF;
\r
786 tailMB = pppAppend(c, tailMB, &pc->outACCM);
\r
787 tailMB = pppAppend(PPP_FLAG, tailMB, NULL);
\r
789 /* If we failed to complete the packet, throw it away.
\r
790 * Otherwise send it. */
\r
792 PPPDEBUG((LOG_WARNING,
\r
793 "pppWrite[%d]: Alloc err - dropping pbuf len=%d\n", pd, headMB->len));
\r
794 /* "pppWrite[%d]: Alloc err - dropping %d:%.*H", pd, headMB->len, LWIP_MIN(headMB->len * 2, 40), headMB->payload)); */
\r
797 lwip_stats.link.memerr++;
\r
798 lwip_stats.link.proterr++;
\r
799 #endif /* LINK_STATS */
\r
800 return PPPERR_ALLOC;
\r
803 PPPDEBUG((LOG_INFO, "pppWrite[%d]: len=%d\n", pd, headMB->len));
\r
804 /* "pppWrite[%d]: %d:%.*H", pd, headMB->len, LWIP_MIN(headMB->len * 2, 40), headMB->payload)); */
\r
807 return PPPERR_NONE;
\r
811 * ppp_send_config - configure the transmit characteristics of
\r
812 * the ppp interface.
\r
814 void ppp_send_config(
\r
822 PPPControl *pc = &pppControl[unit];
\r
827 pc->accomp = accomp;
\r
829 /* Load the ACCM bits for the 32 control codes. */
\r
830 for (i = 0; i < 32/8; i++)
\r
831 pc->outACCM[i] = (u_char)((asyncmap >> (8 * i)) & 0xFF);
\r
832 PPPDEBUG((LOG_INFO, "ppp_send_config[%d]: outACCM=%X %X %X %X\n",
\r
834 pc->outACCM[0], pc->outACCM[1], pc->outACCM[2], pc->outACCM[3]));
\r
839 * ppp_set_xaccm - set the extended transmit ACCM for the interface.
\r
841 void ppp_set_xaccm(int unit, ext_accm *accm)
\r
843 memcpy(pppControl[unit].outACCM, accm, sizeof(ext_accm));
\r
844 PPPDEBUG((LOG_INFO, "ppp_set_xaccm[%d]: outACCM=%X %X %X %X\n",
\r
846 pppControl[unit].outACCM[0],
\r
847 pppControl[unit].outACCM[1],
\r
848 pppControl[unit].outACCM[2],
\r
849 pppControl[unit].outACCM[3]));
\r
854 * ppp_recv_config - configure the receive-side characteristics of
\r
855 * the ppp interface.
\r
857 void ppp_recv_config(
\r
865 PPPControl *pc = &pppControl[unit];
\r
872 /* Load the ACCM bits for the 32 control codes. */
\r
873 for (i = 0; i < 32 / 8; i++)
\r
874 pc->inACCM[i] = (u_char)(asyncmap >> (i * 8));
\r
875 PPPDEBUG((LOG_INFO, "ppp_recv_config[%d]: inACCM=%X %X %X %X\n",
\r
877 pc->inACCM[0], pc->inACCM[1], pc->inACCM[2], pc->inACCM[3]));
\r
882 * ccp_test - ask kernel whether a given compression method
\r
883 * is acceptable for use. Returns 1 if the method and parameters
\r
884 * are OK, 0 if the method is known but the parameters are not OK
\r
885 * (e.g. code size should be reduced), or -1 if the method is unknown.
\r
894 return 0; /* XXX Currently no compression. */
\r
898 * ccp_flags_set - inform kernel about the current state of CCP.
\r
900 void ccp_flags_set(int unit, int isopen, int isup)
\r
906 * ccp_fatal_error - returns 1 if decompression was disabled as a
\r
907 * result of an error detected after decompression of a packet,
\r
908 * 0 otherwise. This is necessary because of patent nonsense.
\r
910 int ccp_fatal_error(int unit)
\r
918 * get_idle_time - return how long the link has been idle.
\r
920 int get_idle_time(int u, struct ppp_idle *ip)
\r
931 * Return user specified netmask, modified by any mask we might determine
\r
932 * for address `addr' (in network byte order).
\r
933 * Here we scan through the system's list of interfaces, looking for
\r
934 * any non-point-to-point interfaces which might appear to be on the same
\r
935 * network as `addr'. If we find any, we OR in their netmask to the
\r
936 * user-specified netmask.
\r
938 u32_t GetMask(u32_t addr)
\r
943 if (IN_CLASSA(addr)) /* determine network mask for address class */
\r
944 nmask = IN_CLASSA_NET;
\r
945 else if (IN_CLASSB(addr))
\r
946 nmask = IN_CLASSB_NET;
\r
948 nmask = IN_CLASSC_NET;
\r
949 /* class D nets are disallowed by bad_ip_adrs */
\r
950 mask = subnetMask | htonl(nmask);
\r
953 * Scan through the system's network interfaces.
\r
954 * Get each netmask and OR them into our mask.
\r
961 * sifvjcomp - config tcp header compression
\r
971 PPPControl *pc = &pppControl[pd];
\r
973 pc->vjEnabled = vjcomp;
\r
974 pc->vjComp.compressSlot = cidcomp;
\r
975 pc->vjComp.maxSlotIndex = maxcid;
\r
976 PPPDEBUG((LOG_INFO, "sifvjcomp: VJ compress enable=%d slot=%d max slot=%d\n",
\r
977 vjcomp, cidcomp, maxcid));
\r
984 * pppifNetifInit - netif init callback
\r
986 static err_t pppifNetifInit(struct netif *netif)
\r
988 netif->name[0] = 'p';
\r
989 netif->name[1] = 'p';
\r
990 netif->output = pppifOutput;
\r
991 netif->mtu = pppMTU((int)netif->state);
\r
997 * sifup - Config the interface up and enable IP packets to pass.
\r
1001 PPPControl *pc = &pppControl[pd];
\r
1004 if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
\r
1006 PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd));
\r
1008 netif_remove(&pc->netif);
\r
1009 if (netif_add(&pc->netif, &pc->addrs.our_ipaddr, &pc->addrs.netmask, &pc->addrs.his_ipaddr, (void *)pd, pppifNetifInit, ip_input)) {
\r
1011 netif_set_up(&pc->netif);
\r
1013 pc->errCode = PPPERR_NONE;
\r
1015 PPPDEBUG((LOG_DEBUG, "sifup: unit %d: linkStatusCB=%lx errCode=%d\n", pd, pc->linkStatusCB, pc->errCode));
\r
1016 if(pc->linkStatusCB)
\r
1017 pc->linkStatusCB(pc->linkStatusCtx, pc->errCode, &pc->addrs);
\r
1020 PPPDEBUG((LOG_ERR, "sifup[%d]: netif_add failed\n", pd));
\r
1028 * sifnpmode - Set the mode for handling packets for a given NP.
\r
1030 int sifnpmode(int u, int proto, enum NPmode mode)
\r
1039 * sifdown - Config the interface down and disable IP.
\r
1041 int sifdown(int pd)
\r
1043 PPPControl *pc = &pppControl[pd];
\r
1046 if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
\r
1048 PPPDEBUG((LOG_WARNING, "sifdown[%d]: bad parms\n", pd));
\r
1051 netif_remove(&pc->netif);
\r
1052 PPPDEBUG((LOG_DEBUG, "sifdown: unit %d: linkStatusCB=%lx errCode=%d\n", pd, pc->linkStatusCB, pc->errCode));
\r
1053 if(pc->linkStatusCB)
\r
1054 pc->linkStatusCB(pc->linkStatusCtx, PPPERR_CONNECT, NULL);
\r
1060 * sifaddr - Config the interface IP addresses and netmask.
\r
1063 int pd, /* Interface unit ??? */
\r
1064 u32_t o, /* Our IP address ??? */
\r
1065 u32_t h, /* His IP address ??? */
\r
1066 u32_t m, /* IP subnet mask ??? */
\r
1067 u32_t ns1, /* Primary DNS */
\r
1068 u32_t ns2 /* Secondary DNS */
\r
1071 PPPControl *pc = &pppControl[pd];
\r
1074 if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
\r
1076 PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd));
\r
1078 memcpy(&pc->addrs.our_ipaddr, &o, sizeof(o));
\r
1079 memcpy(&pc->addrs.his_ipaddr, &h, sizeof(h));
\r
1080 memcpy(&pc->addrs.netmask, &m, sizeof(m));
\r
1081 memcpy(&pc->addrs.dns1, &ns1, sizeof(ns1));
\r
1082 memcpy(&pc->addrs.dns2, &ns2, sizeof(ns2));
\r
1088 * cifaddr - Clear the interface IP addresses, and delete routes
\r
1089 * through the interface if possible.
\r
1092 int pd, /* Interface unit ??? */
\r
1093 u32_t o, /* Our IP address ??? */
\r
1094 u32_t h /* IP broadcast address ??? */
\r
1097 PPPControl *pc = &pppControl[pd];
\r
1102 if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
\r
1104 PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd));
\r
1106 IP4_ADDR(&pc->addrs.our_ipaddr, 0,0,0,0);
\r
1107 IP4_ADDR(&pc->addrs.his_ipaddr, 0,0,0,0);
\r
1108 IP4_ADDR(&pc->addrs.netmask, 255,255,255,0);
\r
1109 IP4_ADDR(&pc->addrs.dns1, 0,0,0,0);
\r
1110 IP4_ADDR(&pc->addrs.dns2, 0,0,0,0);
\r
1116 * sifdefaultroute - assign a default route through the address given.
\r
1118 int sifdefaultroute(int pd, u32_t l, u32_t g)
\r
1120 PPPControl *pc = &pppControl[pd];
\r
1125 if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
\r
1127 PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd));
\r
1129 netif_set_default(&pc->netif);
\r
1132 /* TODO: check how PPP handled the netMask, previously not set by ipSetDefault */
\r
1138 * cifdefaultroute - delete a default route through the address given.
\r
1140 int cifdefaultroute(int pd, u32_t l, u32_t g)
\r
1142 PPPControl *pc = &pppControl[pd];
\r
1147 if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
\r
1149 PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd));
\r
1151 netif_set_default(NULL);
\r
1158 pppMainWakeup(int pd)
\r
1160 PPPDEBUG((LOG_DEBUG, "pppMainWakeup: unit %d\n", pd));
\r
1161 sio_read_abort(pppControl[pd].fd);
\r
1164 /* these callbacks are necessary because lcp_* functions
\r
1165 must be called in the same context as pppInput(),
\r
1166 namely the tcpip_thread(), essentially because
\r
1167 they manipulate timeouts which are thread-private
\r
1171 pppStartCB(void *arg)
\r
1173 int pd = (int)arg;
\r
1175 PPPDEBUG((LOG_DEBUG, "pppStartCB: unit %d\n", pd));
\r
1177 lcp_open(pd); /* Start protocol */
\r
1181 pppStopCB(void *arg)
\r
1183 int pd = (int)arg;
\r
1185 PPPDEBUG((LOG_DEBUG, "pppStopCB: unit %d\n", pd));
\r
1186 lcp_close(pd, "User request");
\r
1190 pppHupCB(void *arg)
\r
1192 int pd = (int)arg;
\r
1194 PPPDEBUG((LOG_DEBUG, "pppHupCB: unit %d\n", pd));
\r
1195 lcp_lowerdown(pd);
\r
1196 link_terminated(pd);
\r
1198 /**********************************/
\r
1199 /*** LOCAL FUNCTION DEFINITIONS ***/
\r
1200 /**********************************/
\r
1201 /* The main PPP process function. This implements the state machine according
\r
1202 * to section 4 of RFC 1661: The Point-To-Point Protocol. */
\r
1203 static void pppMain(void *arg)
\r
1205 int pd = (int)arg;
\r
1209 pc = &pppControl[pd];
\r
1211 p = pbuf_alloc(PBUF_RAW, PPP_MRU+PPP_HDRLEN, PBUF_RAM);
\r
1213 LWIP_ASSERT("p != NULL", p);
\r
1214 pc->errCode = PPPERR_ALLOC;
\r
1219 * Start the connection and handle incoming events (packet or timeout).
\r
1221 PPPDEBUG((LOG_INFO, "pppMain: unit %d: Connecting\n", pd));
\r
1222 tcpip_callback(pppStartCB, arg);
\r
1223 while (lcp_phase[pd] != PHASE_DEAD) {
\r
1224 if (pc->kill_link) {
\r
1225 PPPDEBUG((LOG_DEBUG, "pppMainWakeup: unit %d kill_link -> pppStopCB\n", pd));
\r
1226 pc->errCode = PPPERR_USER;
\r
1227 /* This will leave us at PHASE_DEAD. */
\r
1228 tcpip_callback(pppStopCB, arg);
\r
1229 pc->kill_link = 0;
\r
1231 else if (pc->sig_hup) {
\r
1232 PPPDEBUG((LOG_DEBUG, "pppMainWakeup: unit %d sig_hup -> pppHupCB\n", pd));
\r
1234 tcpip_callback(pppHupCB, arg);
\r
1236 int c = sio_read(pc->fd, p->payload, p->len);
\r
1238 pppInProc(pd, p->payload, c);
\r
1240 PPPDEBUG((LOG_DEBUG, "pppMainWakeup: unit %d sio_read len=%d returned %d\n", pd, p->len, c));
\r
1241 sys_msleep(1); /* give other tasks a chance to run */
\r
1245 PPPDEBUG((LOG_INFO, "pppMain: unit %d: PHASE_DEAD\n", pd));
\r
1249 PPPDEBUG((LOG_DEBUG, "pppMain: unit %d: linkStatusCB=%lx errCode=%d\n", pd, pc->linkStatusCB, pc->errCode));
\r
1250 if(pc->linkStatusCB)
\r
1251 pc->linkStatusCB(pc->linkStatusCtx, pc->errCode ? pc->errCode : PPPERR_PROTOCOL, NULL);
\r
1256 static struct pbuf *pppSingleBuf(struct pbuf *p)
\r
1258 struct pbuf *q, *b;
\r
1261 if(p->tot_len == p->len)
\r
1264 q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
\r
1266 PPPDEBUG((LOG_ERR,
\r
1267 "pppSingleBuf: unable to alloc new buf (%d)\n", p->tot_len));
\r
1268 return p; /* live dangerously */
\r
1271 for(b = p, pl = q->payload; b != NULL; b = b->next) {
\r
1272 memcpy(pl, b->payload, b->len);
\r
1281 struct pppInputHeader {
\r
1287 * Pass the processed input packet to the appropriate handler.
\r
1288 * This function and all handlers run in the context of the tcpip_thread
\r
1290 static void pppInput(void *arg)
\r
1292 struct pbuf *nb = (struct pbuf *)arg;
\r
1296 pd = ((struct pppInputHeader *)nb->payload)->unit;
\r
1297 protocol = ((struct pppInputHeader *)nb->payload)->proto;
\r
1299 pbuf_header(nb, -(int)sizeof(struct pppInputHeader));
\r
1302 lwip_stats.link.recv++;
\r
1303 #endif /* LINK_STATS */
\r
1306 * Toss all non-LCP packets unless LCP is OPEN.
\r
1307 * Until we get past the authentication phase, toss all packets
\r
1308 * except LCP, LQR and authentication packets.
\r
1310 if((lcp_phase[pd] <= PHASE_AUTHENTICATE) && (protocol != PPP_LCP)) {
\r
1311 if(!((protocol == PPP_LQR) || (protocol == PPP_PAP) || (protocol == PPP_CHAP)) ||
\r
1312 (lcp_phase[pd] != PHASE_AUTHENTICATE)) {
\r
1313 PPPDEBUG((LOG_INFO, "pppInput: discarding proto 0x%04X in phase %d\n", protocol, lcp_phase[pd]));
\r
1318 switch(protocol) {
\r
1319 case PPP_VJC_COMP: /* VJ compressed TCP */
\r
1320 #if VJ_SUPPORT > 0
\r
1321 PPPDEBUG((LOG_INFO, "pppInput[%d]: vj_comp in pbuf len=%d\n", pd, nb->len));
\r
1323 * Clip off the VJ header and prepend the rebuilt TCP/IP header and
\r
1324 * pass the result to IP.
\r
1326 if (vj_uncompress_tcp(&nb, &pppControl[pd].vjComp) >= 0) {
\r
1327 if (pppControl[pd].netif.input != NULL) {
\r
1328 pppControl[pd].netif.input(nb, &pppControl[pd].netif);
\r
1332 /* Something's wrong so drop it. */
\r
1333 PPPDEBUG((LOG_WARNING, "pppInput[%d]: Dropping VJ compressed\n", pd));
\r
1335 /* No handler for this protocol so drop the packet. */
\r
1336 PPPDEBUG((LOG_INFO, "pppInput[%d]: drop VJ Comp in %d:%s\n", pd, nb->len, nb->payload));
\r
1337 #endif /* VJ_SUPPORT > 0 */
\r
1339 case PPP_VJC_UNCOMP: /* VJ uncompressed TCP */
\r
1340 #if VJ_SUPPORT > 0
\r
1341 PPPDEBUG((LOG_INFO, "pppInput[%d]: vj_un in pbuf len=%d\n", pd, nb->len));
\r
1343 * Process the TCP/IP header for VJ header compression and then pass
\r
1344 * the packet to IP.
\r
1346 if (vj_uncompress_uncomp(nb, &pppControl[pd].vjComp) >= 0) {
\r
1347 if (pppControl[pd].netif.input != NULL) {
\r
1348 pppControl[pd].netif.input(nb, &pppControl[pd].netif);
\r
1352 /* Something's wrong so drop it. */
\r
1353 PPPDEBUG((LOG_WARNING, "pppInput[%d]: Dropping VJ uncompressed\n", pd));
\r
1355 /* No handler for this protocol so drop the packet. */
\r
1356 PPPDEBUG((LOG_INFO,
\r
1357 "pppInput[%d]: drop VJ UnComp in %d:.*H\n",
\r
1358 pd, nb->len, LWIP_MIN(nb->len * 2, 40), nb->payload));
\r
1359 #endif /* VJ_SUPPORT > 0 */
\r
1361 case PPP_IP: /* Internet Protocol */
\r
1362 PPPDEBUG((LOG_INFO, "pppInput[%d]: ip in pbuf len=%d\n", pd, nb->len));
\r
1363 if (pppControl[pd].netif.input != NULL) {
\r
1364 pppControl[pd].netif.input(nb, &pppControl[pd].netif);
\r
1369 struct protent *protp;
\r
1373 * Upcall the proper protocol input routine.
\r
1375 for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i) {
\r
1376 if (protp->protocol == protocol && protp->enabled_flag) {
\r
1377 PPPDEBUG((LOG_INFO, "pppInput[%d]: %s len=%d\n", pd, protp->name, nb->len));
\r
1378 nb = pppSingleBuf(nb);
\r
1379 (*protp->input)(pd, nb->payload, nb->len);
\r
1384 /* No handler for this protocol so reject the packet. */
\r
1385 PPPDEBUG((LOG_INFO, "pppInput[%d]: rejecting unsupported proto 0x%04X len=%d\n", pd, protocol, nb->len));
\r
1386 pbuf_header(nb, sizeof(protocol));
\r
1387 #if BYTE_ORDER == LITTLE_ENDIAN
\r
1388 protocol = htons(protocol);
\r
1389 memcpy(nb->payload, &protocol, sizeof(protocol));
\r
1391 lcp_sprotrej(pd, nb->payload, nb->len);
\r
1398 lwip_stats.link.drop++;
\r
1408 * Drop the input packet.
\r
1410 static void pppDrop(PPPControl *pc)
\r
1412 if (pc->inHead != NULL) {
\r
1414 PPPDEBUG((LOG_INFO, "pppDrop: %d:%.*H\n", pc->inHead->len, min(60, pc->inHead->len * 2), pc->inHead->payload));
\r
1416 PPPDEBUG((LOG_INFO, "pppDrop: pbuf len=%d\n", pc->inHead->len));
\r
1417 if (pc->inTail && (pc->inTail != pc->inHead))
\r
1418 pbuf_free(pc->inTail);
\r
1419 pbuf_free(pc->inHead);
\r
1420 pc->inHead = NULL;
\r
1421 pc->inTail = NULL;
\r
1423 #if VJ_SUPPORT > 0
\r
1424 vj_uncompress_err(&pc->vjComp);
\r
1428 lwip_stats.link.drop++;
\r
1429 #endif /* LINK_STATS */
\r
1434 * Process a received octet string.
\r
1436 static void pppInProc(int pd, u_char *s, int l)
\r
1438 PPPControl *pc = &pppControl[pd];
\r
1439 struct pbuf *nextNBuf;
\r
1442 PPPDEBUG((LOG_DEBUG, "pppInProc[%d]: got %d bytes\n", pd, l));
\r
1446 /* Handle special characters. */
\r
1447 if (ESCAPE_P(pc->inACCM, curChar)) {
\r
1448 /* Check for escape sequences. */
\r
1449 /* XXX Note that this does not handle an escaped 0x5d character which
\r
1450 * would appear as an escape character. Since this is an ASCII ']'
\r
1451 * and there is no reason that I know of to escape it, I won't complicate
\r
1452 * the code to handle this case. GLL */
\r
1453 if (curChar == PPP_ESCAPE)
\r
1454 pc->inEscaped = 1;
\r
1455 /* Check for the flag character. */
\r
1456 else if (curChar == PPP_FLAG) {
\r
1457 /* If this is just an extra flag character, ignore it. */
\r
1458 if (pc->inState <= PDADDRESS)
\r
1460 /* If we haven't received the packet header, drop what has come in. */
\r
1461 else if (pc->inState < PDDATA) {
\r
1462 PPPDEBUG((LOG_WARNING,
\r
1463 "pppInProc[%d]: Dropping incomplete packet %d\n",
\r
1464 pd, pc->inState));
\r
1466 lwip_stats.link.lenerr++;
\r
1470 /* If the fcs is invalid, drop the packet. */
\r
1471 else if (pc->inFCS != PPP_GOODFCS) {
\r
1472 PPPDEBUG((LOG_INFO,
\r
1473 "pppInProc[%d]: Dropping bad fcs 0x%04X proto=0x%04X\n",
\r
1474 pd, pc->inFCS, pc->inProtocol));
\r
1476 lwip_stats.link.chkerr++;
\r
1480 /* Otherwise it's a good packet so pass it on. */
\r
1483 /* Trim off the checksum. */
\r
1484 if(pc->inTail->len >= 2) {
\r
1485 pc->inTail->len -= 2;
\r
1487 pc->inTail->tot_len = pc->inTail->len;
\r
1488 if (pc->inTail != pc->inHead) {
\r
1489 pbuf_cat(pc->inHead, pc->inTail);
\r
1492 pc->inTail->tot_len = pc->inTail->len;
\r
1493 if (pc->inTail != pc->inHead) {
\r
1494 pbuf_cat(pc->inHead, pc->inTail);
\r
1497 pbuf_realloc(pc->inHead, pc->inHead->tot_len - 2);
\r
1500 /* Dispatch the packet thereby consuming it. */
\r
1501 if(tcpip_callback(pppInput, pc->inHead) != ERR_OK) {
\r
1502 PPPDEBUG((LOG_ERR,
\r
1503 "pppInProc[%d]: tcpip_callback() failed, dropping packet\n", pd));
\r
1504 pbuf_free(pc->inHead);
\r
1506 lwip_stats.link.drop++;
\r
1509 pc->inHead = NULL;
\r
1510 pc->inTail = NULL;
\r
1513 /* Prepare for a new packet. */
\r
1514 pc->inFCS = PPP_INITFCS;
\r
1515 pc->inState = PDADDRESS;
\r
1516 pc->inEscaped = 0;
\r
1518 /* Other characters are usually control characters that may have
\r
1519 * been inserted by the physical layer so here we just drop them. */
\r
1521 PPPDEBUG((LOG_WARNING,
\r
1522 "pppInProc[%d]: Dropping ACCM char <%d>\n", pd, curChar));
\r
1525 /* Process other characters. */
\r
1527 /* Unencode escaped characters. */
\r
1528 if (pc->inEscaped) {
\r
1529 pc->inEscaped = 0;
\r
1530 curChar ^= PPP_TRANS;
\r
1533 /* Process character relative to current state. */
\r
1534 switch(pc->inState) {
\r
1535 case PDIDLE: /* Idle state - waiting. */
\r
1536 /* Drop the character if it's not 0xff
\r
1537 * we would have processed a flag character above. */
\r
1538 if (curChar != PPP_ALLSTATIONS) {
\r
1542 /* Fall through */
\r
1543 case PDSTART: /* Process start flag. */
\r
1544 /* Prepare for a new packet. */
\r
1545 pc->inFCS = PPP_INITFCS;
\r
1547 /* Fall through */
\r
1548 case PDADDRESS: /* Process address field. */
\r
1549 if (curChar == PPP_ALLSTATIONS) {
\r
1550 pc->inState = PDCONTROL;
\r
1553 /* Else assume compressed address and control fields so
\r
1554 * fall through to get the protocol... */
\r
1555 case PDCONTROL: /* Process control field. */
\r
1556 /* If we don't get a valid control code, restart. */
\r
1557 if (curChar == PPP_UI) {
\r
1558 pc->inState = PDPROTOCOL1;
\r
1563 PPPDEBUG((LOG_WARNING,
\r
1564 "pppInProc[%d]: Invalid control <%d>\n", pd, curChar));
\r
1565 pc->inState = PDSTART;
\r
1568 case PDPROTOCOL1: /* Process protocol field 1. */
\r
1569 /* If the lower bit is set, this is the end of the protocol
\r
1571 if (curChar & 1) {
\r
1572 pc->inProtocol = curChar;
\r
1573 pc->inState = PDDATA;
\r
1576 pc->inProtocol = (u_int)curChar << 8;
\r
1577 pc->inState = PDPROTOCOL2;
\r
1580 case PDPROTOCOL2: /* Process protocol field 2. */
\r
1581 pc->inProtocol |= curChar;
\r
1582 pc->inState = PDDATA;
\r
1584 case PDDATA: /* Process data byte. */
\r
1585 /* Make space to receive processed data. */
\r
1586 if (pc->inTail == NULL || pc->inTail->len == PBUF_POOL_BUFSIZE) {
\r
1588 pc->inTail->tot_len = pc->inTail->len;
\r
1589 if (pc->inTail != pc->inHead) {
\r
1590 pbuf_cat(pc->inHead, pc->inTail);
\r
1593 /* If we haven't started a packet, we need a packet header. */
\r
1594 nextNBuf = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
\r
1595 if (nextNBuf == NULL) {
\r
1596 /* No free buffers. Drop the input packet and let the
\r
1597 * higher layers deal with it. Continue processing
\r
1598 * the received pbuf chain in case a new packet starts. */
\r
1599 PPPDEBUG((LOG_ERR, "pppInProc[%d]: NO FREE MBUFS!\n", pd));
\r
1601 lwip_stats.link.memerr++;
\r
1602 #endif /* LINK_STATS */
\r
1604 pc->inState = PDSTART; /* Wait for flag sequence. */
\r
1607 if (pc->inHead == NULL) {
\r
1608 struct pppInputHeader *pih = nextNBuf->payload;
\r
1611 pih->proto = pc->inProtocol;
\r
1613 nextNBuf->len += sizeof(*pih);
\r
1615 pc->inHead = nextNBuf;
\r
1617 pc->inTail = nextNBuf;
\r
1619 /* Load character into buffer. */
\r
1620 ((u_char*)pc->inTail->payload)[pc->inTail->len++] = curChar;
\r
1624 /* update the frame check sequence number. */
\r
1625 pc->inFCS = PPP_FCS(pc->inFCS, curChar);
\r
1631 #endif /* PPP_SUPPORT */
\r