1 /*****************************************************************************
2 * ppp.c - Network Point to Point Protocol program file.
4 * Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
5 * portions Copyright (c) 1997 by Global Election Systems Inc.
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.
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.
25 ******************************************************************************
28 * 03-01-01 Marc Boucher <marc@mbsi.ca>
30 * 97-11-05 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
32 *****************************************************************************/
35 * ppp_defs.h - PPP definitions.
37 * if_pppvar.h - private structures and declarations for PPP.
39 * Copyright (c) 1994 The Australian National University.
40 * All rights reserved.
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
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
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,
64 * if_ppp.h - Point-to-Point Protocol definitions.
66 * Copyright (c) 1989 Carnegie Mellon University.
67 * All rights reserved.
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.
101 /*************************/
102 /*** LOCAL DEFINITIONS ***/
103 /*************************/
106 * The basic PPP frame.
108 #define PPP_ADDRESS(p) (((u_char *)(p))[0])
109 #define PPP_CONTROL(p) (((u_char *)(p))[1])
110 #define PPP_PROTOCOL(p) ((((u_char *)(p))[2] << 8) + ((u_char *)(p))[3])
112 /* PPP packet parser states. Current state indicates operation yet to be
115 PDIDLE = 0, /* Idle state - waiting. */
116 PDSTART, /* Process start flag. */
117 PDADDRESS, /* Process address field. */
118 PDCONTROL, /* Process control field. */
119 PDPROTOCOL1, /* Process protocol field 1. */
120 PDPROTOCOL2, /* Process protocol field 2. */
121 PDDATA /* Process data byte. */
124 #define ESCAPE_P(accm, c) ((accm)[(c) >> 3] & pppACCMMask[c & 0x07])
126 /************************/
127 /*** LOCAL DATA TYPES ***/
128 /************************/
130 * PPP interface control block.
132 typedef struct PPPControl_s {
133 char openFlag; /* True when in use. */
134 char oldFrame; /* Old framing character for fd. */
135 sio_fd_t fd; /* File device ID of port. */
136 int kill_link; /* Shut the link down. */
137 int sig_hup; /* Carrier lost. */
138 int if_up; /* True when the interface is up. */
139 int errCode; /* Code indicating why interface is down. */
140 struct pbuf *inHead, *inTail; /* The input packet. */
141 PPPDevStates inState; /* The input process state. */
142 char inEscaped; /* Escape next character. */
143 u16_t inProtocol; /* The input protocol code. */
144 u16_t inFCS; /* Input Frame Check Sequence value. */
145 int mtu; /* Peer's mru */
146 int pcomp; /* Does peer accept protocol compression? */
147 int accomp; /* Does peer accept addr/ctl compression? */
148 u_long lastXMit; /* Time of last transmission. */
149 ext_accm inACCM; /* Async-Ctl-Char-Map for input. */
150 ext_accm outACCM; /* Async-Ctl-Char-Map for output. */
152 int vjEnabled; /* Flag indicating VJ compression enabled. */
153 struct vjcompress vjComp; /* Van Jabobsen compression header. */
158 struct ppp_addrs addrs;
160 void (*linkStatusCB)(void *ctx, int errCode, void *arg);
171 int protocol; /* PPP procotol, e.g. PPP_IP */
177 /***********************************/
178 /*** LOCAL FUNCTION DECLARATIONS ***/
179 /***********************************/
180 static void pppMain(void *pd);
181 static void pppDrop(PPPControl *pc);
182 static void pppInProc(int pd, u_char *s, int l);
185 /******************************/
186 /*** PUBLIC DATA STRUCTURES ***/
187 /******************************/
190 static PPPControl pppControl[NUM_PPP]; /* The PPP interface control blocks. */
193 * PPP Data Link Layer "protocol" table.
194 * One entry per supported protocol.
195 * The last entry must be NULL.
197 struct protent *ppp_protocols[] = {
217 * Buffers for outgoing packets. This must be accessed only from the appropriate
218 * PPP task so that it doesn't need to be protected to avoid collisions.
220 u_char outpacket_buf[NUM_PPP][PPP_MRU+PPP_HDRLEN];
223 /*****************************/
224 /*** LOCAL DATA STRUCTURES ***/
225 /*****************************/
228 * FCS lookup table as calculated by genfcstab.
230 static const u_short fcstab[256] = {
231 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
232 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
233 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
234 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
235 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
236 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
237 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
238 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
239 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
240 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
241 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
242 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
243 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
244 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
245 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
246 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
247 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
248 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
249 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
250 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
251 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
252 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
253 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
254 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
255 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
256 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
257 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
258 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
259 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
260 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
261 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
262 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
265 /* PPP's Asynchronous-Control-Character-Map. The mask array is used
266 * to select the specific bit for a character. */
267 static u_char pppACCMMask[] = {
279 /***********************************/
280 /*** PUBLIC FUNCTION DEFINITIONS ***/
281 /***********************************/
282 /* Initialize the PPP subsystem. */
284 struct ppp_settings ppp_settings;
288 struct protent *protp;
291 memset(&ppp_settings, 0, sizeof(ppp_settings));
292 ppp_settings.usepeerdns = 1;
293 pppSetAuth(PPPAUTHTYPE_NONE, NULL, NULL);
297 for (i = 0; i < NUM_PPP; i++) {
298 pppControl[i].openFlag = 0;
299 pppControl[i].netif = NULL;
301 subnetMask = htonl(0xffffff00);
304 * Initialize to the standard option set.
306 for (j = 0; (protp = ppp_protocols[j]) != NULL; ++j)
311 /* Clear the statistics. */
312 memset(&lwip_stats.link, 0, sizeof(lwip_stats.link));
316 void pppSetAuth(enum pppAuthType authType, const char *user, const char *passwd)
319 case PPPAUTHTYPE_NONE:
321 #ifdef LWIP_PPP_STRICT_PAP_REJECT
322 ppp_settings.refuse_pap = 1;
324 /* some providers request pap and accept an empty login/pw */
325 ppp_settings.refuse_pap = 0;
327 ppp_settings.refuse_chap = 1;
329 case PPPAUTHTYPE_ANY:
330 /* Warning: Using PPPAUTHTYPE_ANY might have security consequences.
333 * In practice, within or associated with each PPP server, there is a
334 * database which associates "user" names with authentication
335 * information ("secrets"). It is not anticipated that a particular
336 * named user would be authenticated by multiple methods. This would
337 * make the user vulnerable to attacks which negotiate the least secure
338 * method from among a set (such as PAP rather than CHAP). If the same
339 * secret was used, PAP would reveal the secret to be used later with
342 * Instead, for each user name there should be an indication of exactly
343 * one method used to authenticate that user name. If a user needs to
344 * make use of different authentication methods under different
345 * circumstances, then distinct user names SHOULD be employed, each of
346 * which identifies exactly one authentication method.
349 ppp_settings.refuse_pap = 0;
350 ppp_settings.refuse_chap = 0;
352 case PPPAUTHTYPE_PAP:
353 ppp_settings.refuse_pap = 0;
354 ppp_settings.refuse_chap = 1;
356 case PPPAUTHTYPE_CHAP:
357 ppp_settings.refuse_pap = 1;
358 ppp_settings.refuse_chap = 0;
363 strncpy(ppp_settings.user, user, sizeof(ppp_settings.user)-1);
364 ppp_settings.user[sizeof(ppp_settings.user)-1] = '\0';
366 ppp_settings.user[0] = '\0';
369 strncpy(ppp_settings.passwd, passwd, sizeof(ppp_settings.passwd)-1);
370 ppp_settings.passwd[sizeof(ppp_settings.passwd)-1] = '\0';
372 ppp_settings.passwd[0] = '\0';
375 /* Open a new PPP connection using the given I/O device.
376 * This initializes the PPP control block but does not
377 * attempt to negotiate the LCP session. If this port
378 * connects to a modem, the modem connection must be
379 * established before calling this.
380 * Return a new PPP connection descriptor on success or
381 * an error code (negative) on failure. */
382 int pppOpen(sio_fd_t fd, void (*linkStatusCB)(void *ctx, int errCode, void *arg), void *linkStatusCtx)
387 /* Find a free PPP session descriptor. Critical region? */
388 for (pd = 0; pd < NUM_PPP && pppControl[pd].openFlag != 0; pd++);
392 pppControl[pd].openFlag = !0;
394 /* Launch a deamon thread. */
397 pppControl[pd].openFlag = 1;
400 pc = &pppControl[pd];
406 pc->inState = PDIDLE;
414 vj_compress_init(&pc->vjComp);
418 * Default the in and out accm so that escape and flag characters
419 * are always escaped.
421 memset(pc->inACCM, 0, sizeof(ext_accm));
422 pc->inACCM[15] = 0x60;
423 memset(pc->outACCM, 0, sizeof(ext_accm));
424 pc->outACCM[15] = 0x60;
426 pc->linkStatusCB = linkStatusCB;
427 pc->linkStatusCtx = linkStatusCtx;
429 sys_thread_new(pppMain, (void*)pd, PPP_THREAD_PRIO);
431 while(pd >= 0 && !pc->if_up) {
433 if (lcp_phase[pd] == PHASE_DEAD) {
446 /* Close a PPP connection and release the descriptor.
447 * Any outstanding packets in the queues are dropped.
448 * Return 0 on success, an error code on failure. */
451 PPPControl *pc = &pppControl[pd];
458 if(!pc->linkStatusCB) {
459 while(st >= 0 && lcp_phase[pd] != PHASE_DEAD) {
467 /* This function is called when carrier is lost on the PPP channel. */
468 void pppSigHUP(int pd)
470 PPPControl *pc = &pppControl[pd];
476 static void nPut(PPPControl *pc, struct pbuf *nb)
481 for(b = nb; b != NULL; b = b->next) {
482 if((c = sio_write(pc->fd, b->payload, b->len)) != b->len) {
483 PPPDEBUG((LOG_WARNING,
484 "PPP nPut: incomplete sio_write(%d,, %u) = %d\n", pc->fd, b->len, c));
486 lwip_stats.link.err++;
487 #endif /* LINK_STATS */
488 pc->lastXMit = 0; /* prepend PPP_FLAG to next packet */
495 lwip_stats.link.xmit++;
496 #endif /* LINK_STATS */
500 * pppAppend - append given character to end of given pbuf. If outACCM
501 * is not NULL and the character needs to be escaped, do so.
502 * If pbuf is full, append another.
503 * Return the current pbuf.
505 static struct pbuf *pppAppend(u_char c, struct pbuf *nb, ext_accm *outACCM)
507 struct pbuf *tb = nb;
509 /* Make sure there is room for the character and an escape code.
510 * Sure we don't quite fill the buffer if the character doesn't
511 * get escaped but is one character worth complicating this? */
512 /* Note: We assume no packet header. */
513 if (nb && (PBUF_POOL_BUFSIZE - nb->len) < 2) {
514 tb = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
520 lwip_stats.link.memerr++;
522 #endif /* LINK_STATS */
526 if (outACCM && ESCAPE_P(*outACCM, c)) {
527 *((u_char*)nb->payload + nb->len++) = PPP_ESCAPE;
528 *((u_char*)nb->payload + nb->len++) = c ^ PPP_TRANS;
531 *((u_char*)nb->payload + nb->len++) = c;
537 /* Send a packet on the given connection. */
538 static err_t pppifOutput(struct netif *netif, struct pbuf *pb, struct ip_addr *ipaddr)
540 int pd = (int)netif->state;
541 u_short protocol = PPP_IP;
542 PPPControl *pc = &pppControl[pd];
543 u_int fcsOut = PPP_INITFCS;
544 struct pbuf *headMB = NULL, *tailMB = NULL, *p;
549 /* Validate parameters. */
550 /* We let any protocol value go through - it can't hurt us
551 * and the peer will just drop it if it's not accepting it. */
552 if (pd < 0 || pd >= NUM_PPP || !pc->openFlag || !pb) {
553 PPPDEBUG((LOG_WARNING, "pppifOutput[%d]: bad parms prot=%d pb=%p\n",
556 lwip_stats.link.opterr++;
557 lwip_stats.link.drop++;
562 /* Check that the link is up. */
563 if (lcp_phase[pd] == PHASE_DEAD) {
564 PPPDEBUG((LOG_ERR, "pppifOutput[%d]: link not up\n", pd));
566 lwip_stats.link.rterr++;
567 lwip_stats.link.drop++;
572 /* Grab an output buffer. */
573 headMB = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
574 if (headMB == NULL) {
575 PPPDEBUG((LOG_WARNING, "pppifOutput[%d]: first alloc fail\n", pd));
577 lwip_stats.link.memerr++;
578 lwip_stats.link.drop++;
579 #endif /* LINK_STATS */
585 * Attempt Van Jacobson header compression if VJ is configured and
586 * this is an IP packet.
588 if (protocol == PPP_IP && pc->vjEnabled) {
589 switch (vj_compress_tcp(&pc->vjComp, pb)) {
592 protocol = PPP_IP_PROTOCOL;
595 case TYPE_COMPRESSED_TCP:
596 protocol = PPP_VJC_COMP;
598 case TYPE_UNCOMPRESSED_TCP:
599 protocol = PPP_VJC_UNCOMP;
602 PPPDEBUG((LOG_WARNING, "pppifOutput[%d]: bad IP packet\n", pd));
604 lwip_stats.link.proterr++;
605 lwip_stats.link.drop++;
615 /* Build the PPP header. */
616 if ((sys_jiffies() - pc->lastXMit) >= PPP_MAXIDLEFLAG)
617 tailMB = pppAppend(PPP_FLAG, tailMB, NULL);
618 pc->lastXMit = sys_jiffies();
620 fcsOut = PPP_FCS(fcsOut, PPP_ALLSTATIONS);
621 tailMB = pppAppend(PPP_ALLSTATIONS, tailMB, &pc->outACCM);
622 fcsOut = PPP_FCS(fcsOut, PPP_UI);
623 tailMB = pppAppend(PPP_UI, tailMB, &pc->outACCM);
625 if (!pc->pcomp || protocol > 0xFF) {
626 c = (protocol >> 8) & 0xFF;
627 fcsOut = PPP_FCS(fcsOut, c);
628 tailMB = pppAppend(c, tailMB, &pc->outACCM);
631 fcsOut = PPP_FCS(fcsOut, c);
632 tailMB = pppAppend(c, tailMB, &pc->outACCM);
635 for(p = pb; p; p = p->next) {
639 sPtr = (u_char*)p->payload;
644 /* Update FCS before checking for special characters. */
645 fcsOut = PPP_FCS(fcsOut, c);
647 /* Copy to output buffer escaping special characters. */
648 tailMB = pppAppend(c, tailMB, &pc->outACCM);
652 /* Add FCS and trailing flag. */
654 tailMB = pppAppend(c, tailMB, &pc->outACCM);
655 c = (~fcsOut >> 8) & 0xFF;
656 tailMB = pppAppend(c, tailMB, &pc->outACCM);
657 tailMB = pppAppend(PPP_FLAG, tailMB, NULL);
659 /* If we failed to complete the packet, throw it away. */
661 PPPDEBUG((LOG_WARNING,
662 "pppifOutput[%d]: Alloc err - dropping proto=%d\n",
666 lwip_stats.link.memerr++;
667 lwip_stats.link.drop++;
673 PPPDEBUG((LOG_INFO, "pppifOutput[%d]: proto=0x%04X\n", pd, protocol));
680 /* Get and set parameters for the given connection.
681 * Return 0 on success, an error code on failure. */
682 int pppIOCtl(int pd, int cmd, void *arg)
684 PPPControl *pc = &pppControl[pd];
687 if (pd < 0 || pd >= NUM_PPP)
691 case PPPCTLG_UPSTATUS: /* Get the PPP up status. */
693 *(int *)arg = (int)(pc->if_up);
697 case PPPCTLS_ERRCODE: /* Set the PPP error code. */
699 pc->errCode = *(int *)arg;
703 case PPPCTLG_ERRCODE: /* Get the PPP error code. */
705 *(int *)arg = (int)(pc->errCode);
711 *(sio_fd_t *)arg = pc->fd;
725 * Return the Maximum Transmission Unit for the given PPP connection.
729 PPPControl *pc = &pppControl[pd];
732 /* Validate parameters. */
733 if (pd < 0 || pd >= NUM_PPP || !pc->openFlag)
742 * Write n characters to a ppp link.
743 * RETURN: >= 0 Number of characters written
744 * -1 Failed to write to device
746 int pppWrite(int pd, const u_char *s, int n)
748 PPPControl *pc = &pppControl[pd];
750 u_int fcsOut = PPP_INITFCS;
751 struct pbuf *headMB = NULL, *tailMB;
752 headMB = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
753 if (headMB == NULL) {
755 lwip_stats.link.memerr++;
756 lwip_stats.link.proterr++;
757 #endif /* LINK_STATS */
763 /* If the link has been idle, we'll send a fresh flag character to
764 * flush any noise. */
765 if ((sys_jiffies() - pc->lastXMit) >= PPP_MAXIDLEFLAG)
766 tailMB = pppAppend(PPP_FLAG, tailMB, NULL);
767 pc->lastXMit = sys_jiffies();
769 /* Load output buffer. */
773 /* Update FCS before checking for special characters. */
774 fcsOut = PPP_FCS(fcsOut, c);
776 /* Copy to output buffer escaping special characters. */
777 tailMB = pppAppend(c, tailMB, &pc->outACCM);
780 /* Add FCS and trailing flag. */
782 tailMB = pppAppend(c, tailMB, &pc->outACCM);
783 c = (~fcsOut >> 8) & 0xFF;
784 tailMB = pppAppend(c, tailMB, &pc->outACCM);
785 tailMB = pppAppend(PPP_FLAG, tailMB, NULL);
787 /* If we failed to complete the packet, throw it away.
788 * Otherwise send it. */
790 PPPDEBUG((LOG_WARNING,
791 "pppWrite[%d]: Alloc err - dropping pbuf len=%d\n", pd, headMB->len));
792 /* "pppWrite[%d]: Alloc err - dropping %d:%.*H", pd, headMB->len, LWIP_MIN(headMB->len * 2, 40), headMB->payload)); */
795 lwip_stats.link.memerr++;
796 lwip_stats.link.proterr++;
797 #endif /* LINK_STATS */
801 PPPDEBUG((LOG_INFO, "pppWrite[%d]: len=%d\n", pd, headMB->len));
802 /* "pppWrite[%d]: %d:%.*H", pd, headMB->len, LWIP_MIN(headMB->len * 2, 40), headMB->payload)); */
809 * ppp_send_config - configure the transmit characteristics of
812 void ppp_send_config(
820 PPPControl *pc = &pppControl[unit];
827 /* Load the ACCM bits for the 32 control codes. */
828 for (i = 0; i < 32/8; i++)
829 pc->outACCM[i] = (u_char)((asyncmap >> (8 * i)) & 0xFF);
830 PPPDEBUG((LOG_INFO, "ppp_send_config[%d]: outACCM=%X %X %X %X\n",
832 pc->outACCM[0], pc->outACCM[1], pc->outACCM[2], pc->outACCM[3]));
837 * ppp_set_xaccm - set the extended transmit ACCM for the interface.
839 void ppp_set_xaccm(int unit, ext_accm *accm)
841 memcpy(pppControl[unit].outACCM, accm, sizeof(ext_accm));
842 PPPDEBUG((LOG_INFO, "ppp_set_xaccm[%d]: outACCM=%X %X %X %X\n",
844 pppControl[unit].outACCM[0],
845 pppControl[unit].outACCM[1],
846 pppControl[unit].outACCM[2],
847 pppControl[unit].outACCM[3]));
852 * ppp_recv_config - configure the receive-side characteristics of
855 void ppp_recv_config(
863 PPPControl *pc = &pppControl[unit];
870 /* Load the ACCM bits for the 32 control codes. */
871 for (i = 0; i < 32 / 8; i++)
872 pc->inACCM[i] = (u_char)(asyncmap >> (i * 8));
873 PPPDEBUG((LOG_INFO, "ppp_recv_config[%d]: inACCM=%X %X %X %X\n",
875 pc->inACCM[0], pc->inACCM[1], pc->inACCM[2], pc->inACCM[3]));
880 * ccp_test - ask kernel whether a given compression method
881 * is acceptable for use. Returns 1 if the method and parameters
882 * are OK, 0 if the method is known but the parameters are not OK
883 * (e.g. code size should be reduced), or -1 if the method is unknown.
892 return 0; /* XXX Currently no compression. */
896 * ccp_flags_set - inform kernel about the current state of CCP.
898 void ccp_flags_set(int unit, int isopen, int isup)
904 * ccp_fatal_error - returns 1 if decompression was disabled as a
905 * result of an error detected after decompression of a packet,
906 * 0 otherwise. This is necessary because of patent nonsense.
908 int ccp_fatal_error(int unit)
916 * get_idle_time - return how long the link has been idle.
918 int get_idle_time(int u, struct ppp_idle *ip)
929 * Return user specified netmask, modified by any mask we might determine
930 * for address `addr' (in network byte order).
931 * Here we scan through the system's list of interfaces, looking for
932 * any non-point-to-point interfaces which might appear to be on the same
933 * network as `addr'. If we find any, we OR in their netmask to the
934 * user-specified netmask.
936 u32_t GetMask(u32_t addr)
941 if (IN_CLASSA(addr)) /* determine network mask for address class */
942 nmask = IN_CLASSA_NET;
943 else if (IN_CLASSB(addr))
944 nmask = IN_CLASSB_NET;
946 nmask = IN_CLASSC_NET;
947 /* class D nets are disallowed by bad_ip_adrs */
948 mask = subnetMask | htonl(nmask);
951 * Scan through the system's network interfaces.
952 * Get each netmask and OR them into our mask.
959 * sifvjcomp - config tcp header compression
969 PPPControl *pc = &pppControl[pd];
971 pc->vjEnabled = vjcomp;
972 pc->vjComp.compressSlot = cidcomp;
973 pc->vjComp.maxSlotIndex = maxcid;
974 PPPDEBUG((LOG_INFO, "sifvjcomp: VJ compress enable=%d slot=%d max slot=%d\n",
975 vjcomp, cidcomp, maxcid));
982 * pppifNetifInit - netif init callback
984 static err_t pppifNetifInit(struct netif *netif)
986 netif->name[0] = 'p';
987 netif->name[1] = 'p';
988 netif->output = pppifOutput;
989 netif->mtu = pppMTU((int)netif->state);
995 * sifup - Config the interface up and enable IP packets to pass.
999 PPPControl *pc = &pppControl[pd];
1002 if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
1004 PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd));
1007 netif_remove(pc->netif);
1008 pc->netif = netif_add(&pc->addrs.our_ipaddr, &pc->addrs.netmask, &pc->addrs.his_ipaddr, (void *)pd, pppifNetifInit, ip_input);
1011 pc->errCode = PPPERR_NONE;
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);
1018 PPPDEBUG((LOG_ERR, "sifup[%d]: netif_add failed\n", pd));
1026 * sifnpmode - Set the mode for handling packets for a given NP.
1028 int sifnpmode(int u, int proto, enum NPmode mode)
1037 * sifdown - Config the interface down and disable IP.
1041 PPPControl *pc = &pppControl[pd];
1044 if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
1046 PPPDEBUG((LOG_WARNING, "sifdown[%d]: bad parms\n", pd));
1050 netif_remove(pc->netif);
1052 PPPDEBUG((LOG_DEBUG, "sifdown: unit %d: linkStatusCB=%lx errCode=%d\n", pd, pc->linkStatusCB, pc->errCode));
1053 if(pc->linkStatusCB)
1054 pc->linkStatusCB(pc->linkStatusCtx, PPPERR_CONNECT, NULL);
1060 * sifaddr - Config the interface IP addresses and netmask.
1063 int pd, /* Interface unit ??? */
1064 u32_t o, /* Our IP address ??? */
1065 u32_t h, /* His IP address ??? */
1066 u32_t m, /* IP subnet mask ??? */
1067 u32_t ns1, /* Primary DNS */
1068 u32_t ns2 /* Secondary DNS */
1071 PPPControl *pc = &pppControl[pd];
1074 if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
1076 PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd));
1078 memcpy(&pc->addrs.our_ipaddr, &o, sizeof(o));
1079 memcpy(&pc->addrs.his_ipaddr, &h, sizeof(h));
1080 memcpy(&pc->addrs.netmask, &m, sizeof(m));
1081 memcpy(&pc->addrs.dns1, &ns1, sizeof(ns1));
1082 memcpy(&pc->addrs.dns2, &ns2, sizeof(ns2));
1088 * cifaddr - Clear the interface IP addresses, and delete routes
1089 * through the interface if possible.
1092 int pd, /* Interface unit ??? */
1093 u32_t o, /* Our IP address ??? */
1094 u32_t h /* IP broadcast address ??? */
1097 PPPControl *pc = &pppControl[pd];
1102 if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
1104 PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd));
1106 IP4_ADDR(&pc->addrs.our_ipaddr, 0,0,0,0);
1107 IP4_ADDR(&pc->addrs.his_ipaddr, 0,0,0,0);
1108 IP4_ADDR(&pc->addrs.netmask, 255,255,255,0);
1109 IP4_ADDR(&pc->addrs.dns1, 0,0,0,0);
1110 IP4_ADDR(&pc->addrs.dns2, 0,0,0,0);
1116 * sifdefaultroute - assign a default route through the address given.
1118 int sifdefaultroute(int pd, u32_t l, u32_t g)
1120 PPPControl *pc = &pppControl[pd];
1125 if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
1127 PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd));
1129 netif_set_default(pc->netif);
1132 /* TODO: check how PPP handled the netMask, previously not set by ipSetDefault */
1138 * cifdefaultroute - delete a default route through the address given.
1140 int cifdefaultroute(int pd, u32_t l, u32_t g)
1142 PPPControl *pc = &pppControl[pd];
1147 if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {
1149 PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd));
1151 netif_set_default(NULL);
1158 pppMainWakeup(int pd)
1160 PPPDEBUG((LOG_DEBUG, "pppMainWakeup: unit %d\n", pd));
1161 sio_read_abort(pppControl[pd].fd);
1164 /* these callbacks are necessary because lcp_* functions
1165 must be called in the same context as pppInput(),
1166 namely the tcpip_thread(), essentially because
1167 they manipulate timeouts which are thread-private
1171 pppStartCB(void *arg)
1175 PPPDEBUG((LOG_DEBUG, "pppStartCB: unit %d\n", pd));
1177 lcp_open(pd); /* Start protocol */
1181 pppStopCB(void *arg)
1185 PPPDEBUG((LOG_DEBUG, "pppStopCB: unit %d\n", pd));
1186 lcp_close(pd, "User request");
1194 PPPDEBUG((LOG_DEBUG, "pppHupCB: unit %d\n", pd));
1196 link_terminated(pd);
1198 /**********************************/
1199 /*** LOCAL FUNCTION DEFINITIONS ***/
1200 /**********************************/
1201 /* The main PPP process function. This implements the state machine according
1202 * to section 4 of RFC 1661: The Point-To-Point Protocol. */
1203 static void pppMain(void *arg)
1209 pc = &pppControl[pd];
1211 p = pbuf_alloc(PBUF_RAW, PPP_MRU+PPP_HDRLEN, PBUF_RAM);
1213 LWIP_ASSERT("p != NULL", p);
1214 pc->errCode = PPPERR_ALLOC;
1219 * Start the connection and handle incoming events (packet or timeout).
1221 PPPDEBUG((LOG_INFO, "pppMain: unit %d: Connecting\n", pd));
1222 tcpip_callback(pppStartCB, arg);
1223 while (lcp_phase[pd] != PHASE_DEAD) {
1224 if (pc->kill_link) {
1225 PPPDEBUG((LOG_DEBUG, "pppMainWakeup: unit %d kill_link -> pppStopCB\n", pd));
1226 pc->errCode = PPPERR_USER;
1227 /* This will leave us at PHASE_DEAD. */
1228 tcpip_callback(pppStopCB, arg);
1231 else if (pc->sig_hup) {
1232 PPPDEBUG((LOG_DEBUG, "pppMainWakeup: unit %d sig_hup -> pppHupCB\n", pd));
1234 tcpip_callback(pppHupCB, arg);
1236 int c = sio_read(pc->fd, p->payload, p->len);
1238 pppInProc(pd, p->payload, c);
1240 PPPDEBUG((LOG_DEBUG, "pppMainWakeup: unit %d sio_read len=%d returned %d\n", pd, p->len, c));
1241 sys_msleep(250); /* give other tasks a chance to run */
1245 PPPDEBUG((LOG_INFO, "pppMain: unit %d: PHASE_DEAD\n", pd));
1249 PPPDEBUG((LOG_DEBUG, "pppMain: unit %d: linkStatusCB=%lx errCode=%d\n", pd, pc->linkStatusCB, pc->errCode));
1250 if(pc->linkStatusCB)
1251 pc->linkStatusCB(pc->linkStatusCtx, pc->errCode ? pc->errCode : PPPERR_PROTOCOL, NULL);
1256 static struct pbuf *pppSingleBuf(struct pbuf *p)
1261 if(p->tot_len == p->len)
1264 q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
1267 "pppSingleBuf: unable to alloc new buf (%d)\n", p->tot_len));
1268 return p; /* live dangerously */
1271 for(b = p, pl = q->payload; b != NULL; b = b->next) {
1272 memcpy(pl, b->payload, b->len);
1281 struct pppInputHeader {
1287 * Pass the processed input packet to the appropriate handler.
1288 * This function and all handlers run in the context of the tcpip_thread
1290 static void pppInput(void *arg)
1292 struct pbuf *nb = (struct pbuf *)arg;
1296 pd = ((struct pppInputHeader *)nb->payload)->unit;
1297 protocol = ((struct pppInputHeader *)nb->payload)->proto;
1299 pbuf_header(nb, -(int)sizeof(struct pppInputHeader));
1302 lwip_stats.link.recv++;
1303 #endif /* LINK_STATS */
1306 * Toss all non-LCP packets unless LCP is OPEN.
1307 * Until we get past the authentication phase, toss all packets
1308 * except LCP, LQR and authentication packets.
1310 if((lcp_phase[pd] <= PHASE_AUTHENTICATE) && (protocol != PPP_LCP)) {
1311 if(!((protocol == PPP_LQR) || (protocol == PPP_PAP) || (protocol == PPP_CHAP)) ||
1312 (lcp_phase[pd] != PHASE_AUTHENTICATE)) {
1313 PPPDEBUG((LOG_INFO, "pppInput: discarding proto 0x%04X in phase %d\n", protocol, lcp_phase[pd]));
1319 case PPP_VJC_COMP: /* VJ compressed TCP */
1321 PPPDEBUG((LOG_INFO, "pppInput[%d]: vj_comp in pbuf len=%d\n", pd, nb->len));
1323 * Clip off the VJ header and prepend the rebuilt TCP/IP header and
1324 * pass the result to IP.
1326 if (vj_uncompress_tcp(&nb, &pppControl[pd].vjComp) >= 0) {
1327 pppControl[pd].netif->input(nb, pppControl[pd].netif);
1330 /* Something's wrong so drop it. */
1331 PPPDEBUG((LOG_WARNING, "pppInput[%d]: Dropping VJ compressed\n", pd));
1333 /* No handler for this protocol so drop the packet. */
1334 PPPDEBUG((LOG_INFO, "pppInput[%d]: drop VJ Comp in %d:%s\n", pd, nb->len, nb->payload));
1335 #endif /* VJ_SUPPORT > 0 */
1337 case PPP_VJC_UNCOMP: /* VJ uncompressed TCP */
1339 PPPDEBUG((LOG_INFO, "pppInput[%d]: vj_un in pbuf len=%d\n", pd, nb->len));
1341 * Process the TCP/IP header for VJ header compression and then pass
1344 if (vj_uncompress_uncomp(nb, &pppControl[pd].vjComp) >= 0) {
1345 pppControl[pd].netif->input(nb, pppControl[pd].netif);
1348 /* Something's wrong so drop it. */
1349 PPPDEBUG((LOG_WARNING, "pppInput[%d]: Dropping VJ uncompressed\n", pd));
1351 /* No handler for this protocol so drop the packet. */
1353 "pppInput[%d]: drop VJ UnComp in %d:.*H\n",
1354 pd, nb->len, LWIP_MIN(nb->len * 2, 40), nb->payload));
1355 #endif /* VJ_SUPPORT > 0 */
1357 case PPP_IP: /* Internet Protocol */
1358 PPPDEBUG((LOG_INFO, "pppInput[%d]: ip in pbuf len=%d\n", pd, nb->len));
1359 pppControl[pd].netif->input(nb, pppControl[pd].netif);
1363 struct protent *protp;
1367 * Upcall the proper protocol input routine.
1369 for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i) {
1370 if (protp->protocol == protocol && protp->enabled_flag) {
1371 PPPDEBUG((LOG_INFO, "pppInput[%d]: %s len=%d\n", pd, protp->name, nb->len));
1372 nb = pppSingleBuf(nb);
1373 (*protp->input)(pd, nb->payload, nb->len);
1378 /* No handler for this protocol so reject the packet. */
1379 PPPDEBUG((LOG_INFO, "pppInput[%d]: rejecting unsupported proto 0x%04X len=%d\n", pd, protocol, nb->len));
1380 pbuf_header(nb, sizeof(protocol));
1381 #if BYTE_ORDER == LITTLE_ENDIAN
1382 protocol = htons(protocol);
1383 memcpy(nb->payload, &protocol, sizeof(protocol));
1385 lcp_sprotrej(pd, nb->payload, nb->len);
1392 lwip_stats.link.drop++;
1402 * Drop the input packet.
1404 static void pppDrop(PPPControl *pc)
1406 if (pc->inHead != NULL) {
1408 PPPDEBUG((LOG_INFO, "pppDrop: %d:%.*H\n", pc->inHead->len, min(60, pc->inHead->len * 2), pc->inHead->payload));
1410 PPPDEBUG((LOG_INFO, "pppDrop: pbuf len=%d\n", pc->inHead->len));
1411 if (pc->inTail && (pc->inTail != pc->inHead))
1412 pbuf_free(pc->inTail);
1413 pbuf_free(pc->inHead);
1418 vj_uncompress_err(&pc->vjComp);
1422 lwip_stats.link.drop++;
1423 #endif /* LINK_STATS */
1428 * Process a received octet string.
1430 static void pppInProc(int pd, u_char *s, int l)
1432 PPPControl *pc = &pppControl[pd];
1433 struct pbuf *nextNBuf;
1436 PPPDEBUG((LOG_DEBUG, "pppInProc[%d]: got %d bytes\n", pd, l));
1440 /* Handle special characters. */
1441 if (ESCAPE_P(pc->inACCM, curChar)) {
1442 /* Check for escape sequences. */
1443 /* XXX Note that this does not handle an escaped 0x5d character which
1444 * would appear as an escape character. Since this is an ASCII ']'
1445 * and there is no reason that I know of to escape it, I won't complicate
1446 * the code to handle this case. GLL */
1447 if (curChar == PPP_ESCAPE)
1449 /* Check for the flag character. */
1450 else if (curChar == PPP_FLAG) {
1451 /* If this is just an extra flag character, ignore it. */
1452 if (pc->inState <= PDADDRESS)
1454 /* If we haven't received the packet header, drop what has come in. */
1455 else if (pc->inState < PDDATA) {
1456 PPPDEBUG((LOG_WARNING,
1457 "pppInProc[%d]: Dropping incomplete packet %d\n",
1460 lwip_stats.link.lenerr++;
1464 /* If the fcs is invalid, drop the packet. */
1465 else if (pc->inFCS != PPP_GOODFCS) {
1467 "pppInProc[%d]: Dropping bad fcs 0x%04X proto=0x%04X\n",
1468 pd, pc->inFCS, pc->inProtocol));
1470 lwip_stats.link.chkerr++;
1474 /* Otherwise it's a good packet so pass it on. */
1477 /* Trim off the checksum. */
1478 if(pc->inTail->len >= 2) {
1479 pc->inTail->len -= 2;
1481 pc->inTail->tot_len = pc->inTail->len;
1482 if (pc->inTail != pc->inHead) {
1483 pbuf_cat(pc->inHead, pc->inTail);
1486 pc->inTail->tot_len = pc->inTail->len;
1487 if (pc->inTail != pc->inHead) {
1488 pbuf_cat(pc->inHead, pc->inTail);
1491 pbuf_realloc(pc->inHead, pc->inHead->tot_len - 2);
1494 /* Dispatch the packet thereby consuming it. */
1495 if(tcpip_callback(pppInput, pc->inHead) != ERR_OK) {
1497 "pppInProc[%d]: tcpip_callback() failed, dropping packet\n", pd));
1498 pbuf_free(pc->inHead);
1500 lwip_stats.link.drop++;
1507 /* Prepare for a new packet. */
1508 pc->inFCS = PPP_INITFCS;
1509 pc->inState = PDADDRESS;
1512 /* Other characters are usually control characters that may have
1513 * been inserted by the physical layer so here we just drop them. */
1515 PPPDEBUG((LOG_WARNING,
1516 "pppInProc[%d]: Dropping ACCM char <%d>\n", pd, curChar));
1519 /* Process other characters. */
1521 /* Unencode escaped characters. */
1522 if (pc->inEscaped) {
1524 curChar ^= PPP_TRANS;
1527 /* Process character relative to current state. */
1528 switch(pc->inState) {
1529 case PDIDLE: /* Idle state - waiting. */
1530 /* Drop the character if it's not 0xff
1531 * we would have processed a flag character above. */
1532 if (curChar != PPP_ALLSTATIONS) {
1537 case PDSTART: /* Process start flag. */
1538 /* Prepare for a new packet. */
1539 pc->inFCS = PPP_INITFCS;
1542 case PDADDRESS: /* Process address field. */
1543 if (curChar == PPP_ALLSTATIONS) {
1544 pc->inState = PDCONTROL;
1547 /* Else assume compressed address and control fields so
1548 * fall through to get the protocol... */
1549 case PDCONTROL: /* Process control field. */
1550 /* If we don't get a valid control code, restart. */
1551 if (curChar == PPP_UI) {
1552 pc->inState = PDPROTOCOL1;
1557 PPPDEBUG((LOG_WARNING,
1558 "pppInProc[%d]: Invalid control <%d>\n", pd, curChar));
1559 pc->inState = PDSTART;
1562 case PDPROTOCOL1: /* Process protocol field 1. */
1563 /* If the lower bit is set, this is the end of the protocol
1566 pc->inProtocol = curChar;
1567 pc->inState = PDDATA;
1570 pc->inProtocol = (u_int)curChar << 8;
1571 pc->inState = PDPROTOCOL2;
1574 case PDPROTOCOL2: /* Process protocol field 2. */
1575 pc->inProtocol |= curChar;
1576 pc->inState = PDDATA;
1578 case PDDATA: /* Process data byte. */
1579 /* Make space to receive processed data. */
1580 if (pc->inTail == NULL || pc->inTail->len == PBUF_POOL_BUFSIZE) {
1582 pc->inTail->tot_len = pc->inTail->len;
1583 if (pc->inTail != pc->inHead) {
1584 pbuf_cat(pc->inHead, pc->inTail);
1587 /* If we haven't started a packet, we need a packet header. */
1588 nextNBuf = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
1589 if (nextNBuf == NULL) {
1590 /* No free buffers. Drop the input packet and let the
1591 * higher layers deal with it. Continue processing
1592 * the received pbuf chain in case a new packet starts. */
1593 PPPDEBUG((LOG_ERR, "pppInProc[%d]: NO FREE MBUFS!\n", pd));
1595 lwip_stats.link.memerr++;
1596 #endif /* LINK_STATS */
1598 pc->inState = PDSTART; /* Wait for flag sequence. */
1601 if (pc->inHead == NULL) {
1602 struct pppInputHeader *pih = nextNBuf->payload;
1605 pih->proto = pc->inProtocol;
1607 nextNBuf->len += sizeof(*pih);
1609 pc->inHead = nextNBuf;
1611 pc->inTail = nextNBuf;
1613 /* Load character into buffer. */
1614 ((u_char*)pc->inTail->payload)[pc->inTail->len++] = curChar;
1618 /* update the frame check sequence number. */
1619 pc->inFCS = PPP_FCS(pc->inFCS, curChar);
1625 #endif /* PPP_SUPPORT */