]> git.sur5r.net Git - freertos/blob - Demo/Common/ethernet/lwIP/netif/ppp/ppp.c
Start to re-arrange files to include FreeRTOS+ in main download.
[freertos] / Demo / Common / ethernet / lwIP / netif / ppp / ppp.c
1 /*****************************************************************************\r
2 * ppp.c - Network Point to Point Protocol program file.\r
3 *\r
4 * Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.\r
5 * portions Copyright (c) 1997 by Global Election Systems Inc.\r
6 *\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
13 *\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
24 *\r
25 ******************************************************************************\r
26 * REVISION HISTORY\r
27 *\r
28 * 03-01-01 Marc Boucher <marc@mbsi.ca>\r
29 *   Ported to lwIP.\r
30 * 97-11-05 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.\r
31 *   Original.\r
32 *****************************************************************************/\r
33 \r
34 /*\r
35  * ppp_defs.h - PPP definitions.\r
36  *\r
37  * if_pppvar.h - private structures and declarations for PPP.\r
38  *\r
39  * Copyright (c) 1994 The Australian National University.\r
40  * All rights reserved.\r
41  *\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
47  * any purpose.\r
48  *\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
53  * OF SUCH DAMAGE.\r
54  *\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
60  * OR MODIFICATIONS.\r
61  */\r
62 \r
63 /*\r
64  * if_ppp.h - Point-to-Point Protocol definitions.\r
65  *\r
66  * Copyright (c) 1989 Carnegie Mellon University.\r
67  * All rights reserved.\r
68  *\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
80  */\r
81  \r
82 #include <string.h>\r
83  \r
84 #include "ppp.h"\r
85 #if PPP_SUPPORT > 0\r
86 #include "randm.h"\r
87 #include "fsm.h"\r
88 #if PAP_SUPPORT > 0\r
89 #include "pap.h"\r
90 #endif\r
91 #if CHAP_SUPPORT > 0\r
92 #include "chap.h"\r
93 #endif\r
94 #include "ipcp.h"\r
95 #include "lcp.h"\r
96 #include "magic.h"\r
97 #include "auth.h"\r
98 #if VJ_SUPPORT > 0\r
99 #include "vj.h"\r
100 #endif\r
101 \r
102 #include "pppdebug.h"\r
103 \r
104 /*************************/\r
105 /*** LOCAL DEFINITIONS ***/\r
106 /*************************/\r
107 \r
108 /*\r
109  * The basic PPP frame.\r
110  */\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
114 \r
115 /* PPP packet parser states.  Current state indicates operation yet to be\r
116  * completed. */\r
117 typedef enum {\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
125 } PPPDevStates;\r
126 \r
127 #define ESCAPE_P(accm, c) ((accm)[(c) >> 3] & pppACCMMask[c & 0x07])\r
128 \r
129 /************************/\r
130 /*** LOCAL DATA TYPES ***/\r
131 /************************/\r
132 /*\r
133  * PPP interface control block.\r
134  */\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
154 #if VJ_SUPPORT > 0\r
155     int  vjEnabled;                     /* Flag indicating VJ compression enabled. */\r
156     struct vjcompress vjComp;           /* Van Jabobsen compression header. */\r
157 #endif\r
158 \r
159     struct netif netif;\r
160 \r
161     struct ppp_addrs addrs;\r
162 \r
163     void (*linkStatusCB)(void *ctx, int errCode, void *arg);\r
164     void *linkStatusCtx;\r
165 \r
166 } PPPControl;\r
167 \r
168 \r
169 /*\r
170  * Ioctl definitions.\r
171  */\r
172 \r
173 struct npioctl {\r
174     int     protocol;           /* PPP procotol, e.g. PPP_IP */\r
175     enum NPmode mode;\r
176 };\r
177 \r
178 \r
179 \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
186 \r
187 \r
188 /******************************/\r
189 /*** PUBLIC DATA STRUCTURES ***/\r
190 /******************************/\r
191 u_long subnetMask;\r
192 \r
193 static PPPControl pppControl[NUM_PPP]; /* The PPP interface control blocks. */\r
194 \r
195 /*\r
196  * PPP Data Link Layer "protocol" table.\r
197  * One entry per supported protocol.\r
198  * The last entry must be NULL.\r
199  */\r
200 struct protent *ppp_protocols[] = {\r
201     &lcp_protent,\r
202 #if PAP_SUPPORT > 0\r
203     &pap_protent,\r
204 #endif\r
205 #if CHAP_SUPPORT > 0\r
206     &chap_protent,\r
207 #endif\r
208 #if CBCP_SUPPORT > 0\r
209     &cbcp_protent,\r
210 #endif\r
211     &ipcp_protent,\r
212 #if CCP_SUPPORT > 0\r
213     &ccp_protent,\r
214 #endif\r
215     NULL\r
216 };\r
217 \r
218 \r
219 /*\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
222  */\r
223 u_char outpacket_buf[NUM_PPP][PPP_MRU+PPP_HDRLEN];  \r
224 \r
225 \r
226 /*****************************/\r
227 /*** LOCAL DATA STRUCTURES ***/\r
228 /*****************************/\r
229 \r
230 /*\r
231  * FCS lookup table as calculated by genfcstab.\r
232  */\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
266 };\r
267 \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
271     0x01,\r
272     0x02,\r
273     0x04,\r
274     0x08,\r
275     0x10,\r
276     0x20,\r
277     0x40,\r
278     0x80\r
279 };\r
280 \r
281 \r
282 /***********************************/\r
283 /*** PUBLIC FUNCTION DEFINITIONS ***/\r
284 /***********************************/\r
285 /* Initialize the PPP subsystem. */\r
286 \r
287 struct ppp_settings ppp_settings;\r
288 \r
289 void pppInit(void)\r
290 {\r
291     struct protent *protp;\r
292     int i, j;\r
293     \r
294         memset(&ppp_settings, 0, sizeof(ppp_settings));\r
295         ppp_settings.usepeerdns = 1;\r
296         pppSetAuth(PPPAUTHTYPE_NONE, NULL, NULL);\r
297 \r
298         magicInit();\r
299 \r
300     for (i = 0; i < NUM_PPP; i++) {\r
301         pppControl[i].openFlag = 0;\r
302 \r
303                 subnetMask = htonl(0xffffff00);\r
304     \r
305         /*\r
306          * Initialize to the standard option set.\r
307          */\r
308         for (j = 0; (protp = ppp_protocols[j]) != NULL; ++j)\r
309             (*protp->init)(i);\r
310     }\r
311 \r
312 #if LINK_STATS\r
313     /* Clear the statistics. */\r
314     memset(&lwip_stats.link, 0, sizeof(lwip_stats.link));\r
315 #endif\r
316 }\r
317 \r
318 void pppSetAuth(enum pppAuthType authType, const char *user, const char *passwd)\r
319 {\r
320     switch(authType) {\r
321         case PPPAUTHTYPE_NONE:\r
322         default:\r
323 #ifdef LWIP_PPP_STRICT_PAP_REJECT\r
324             ppp_settings.refuse_pap = 1;\r
325 #else\r
326             /* some providers request pap and accept an empty login/pw */\r
327             ppp_settings.refuse_pap = 0;\r
328 #endif\r
329             ppp_settings.refuse_chap = 1;\r
330             break;\r
331         case PPPAUTHTYPE_ANY:\r
332 /* Warning: Using PPPAUTHTYPE_ANY might have security consequences.\r
333  * RFC 1994 says:\r
334  *\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
342  * CHAP.\r
343  *\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
349  *\r
350  */\r
351             ppp_settings.refuse_pap = 0;\r
352             ppp_settings.refuse_chap = 0;\r
353             break;\r
354         case PPPAUTHTYPE_PAP:\r
355             ppp_settings.refuse_pap = 0;\r
356             ppp_settings.refuse_chap = 1;\r
357             break;\r
358         case PPPAUTHTYPE_CHAP:\r
359             ppp_settings.refuse_pap = 1;\r
360             ppp_settings.refuse_chap = 0;\r
361             break;\r
362     }\r
363 \r
364     if(user) {\r
365         strncpy(ppp_settings.user, user, sizeof(ppp_settings.user)-1);\r
366         ppp_settings.user[sizeof(ppp_settings.user)-1] = '\0';\r
367     } else\r
368         ppp_settings.user[0] = '\0';\r
369 \r
370     if(passwd) {\r
371         strncpy(ppp_settings.passwd, passwd, sizeof(ppp_settings.passwd)-1);\r
372         ppp_settings.passwd[sizeof(ppp_settings.passwd)-1] = '\0';\r
373     } else\r
374         ppp_settings.passwd[0] = '\0';\r
375 }\r
376 \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
385 {\r
386     PPPControl *pc;\r
387     int pd;\r
388 \r
389     /* Find a free PPP session descriptor. Critical region? */\r
390     for (pd = 0; pd < NUM_PPP && pppControl[pd].openFlag != 0; pd++);\r
391     if (pd >= NUM_PPP)\r
392         pd = PPPERR_OPEN;\r
393     else\r
394         pppControl[pd].openFlag = !0;\r
395 \r
396     /* Launch a deamon thread. */\r
397     if (pd >= 0) {\r
398 \r
399         pppControl[pd].openFlag = 1;\r
400 \r
401         lcp_init(pd);\r
402         pc = &pppControl[pd];\r
403         pc->fd = fd;\r
404         pc->kill_link = 0;\r
405         pc->sig_hup = 0;\r
406         pc->if_up = 0;\r
407         pc->errCode = 0;\r
408         pc->inState = PDIDLE;\r
409         pc->inHead = NULL;\r
410         pc->inTail = NULL;\r
411         pc->inEscaped = 0;\r
412         pc->lastXMit = 0;\r
413 \r
414 #if VJ_SUPPORT > 0\r
415         pc->vjEnabled = 0;\r
416         vj_compress_init(&pc->vjComp);\r
417 #endif\r
418 \r
419         /* \r
420          * Default the in and out accm so that escape and flag characters\r
421          * are always escaped. \r
422          */\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
427 \r
428         pc->linkStatusCB = linkStatusCB;\r
429         pc->linkStatusCtx = linkStatusCtx;\r
430 \r
431         sys_thread_new(pppMain, (void*)pd, PPP_THREAD_PRIO);\r
432         if(!linkStatusCB) {\r
433                 while(pd >= 0 && !pc->if_up) {\r
434                         sys_msleep(500);\r
435                         if (lcp_phase[pd] == PHASE_DEAD) {\r
436                                 pppClose(pd);\r
437                                 if (pc->errCode)\r
438                                         pd = pc->errCode;\r
439                                 else\r
440                                         pd = PPPERR_CONNECT;\r
441                         }\r
442                 }\r
443         }\r
444     }\r
445     return pd;\r
446 }\r
447 \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
452 {\r
453     PPPControl *pc = &pppControl[pd];\r
454     int st = 0;\r
455 \r
456     /* Disconnect */\r
457     pc->kill_link = !0;\r
458     pppMainWakeup(pd);\r
459     \r
460     if(!pc->linkStatusCB) {\r
461             while(st >= 0 && lcp_phase[pd] != PHASE_DEAD) {\r
462                     sys_msleep(500);\r
463                     break;\r
464             }\r
465     }\r
466     return st;\r
467 }\r
468 \r
469 /* This function is called when carrier is lost on the PPP channel. */\r
470 void pppSigHUP(int pd)\r
471 {\r
472     PPPControl *pc = &pppControl[pd];\r
473 \r
474     pc->sig_hup = 1;\r
475     pppMainWakeup(pd);\r
476 }\r
477 \r
478 static void nPut(PPPControl *pc, struct pbuf *nb)\r
479 {\r
480         struct pbuf *b;\r
481         int c;\r
482 \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
487 #if LINK_STATS\r
488                 lwip_stats.link.err++;\r
489 #endif /* LINK_STATS */\r
490                 pc->lastXMit = 0; /* prepend PPP_FLAG to next packet */\r
491                 break;\r
492             }\r
493         }\r
494         pbuf_free(nb);\r
495 \r
496 #if LINK_STATS\r
497         lwip_stats.link.xmit++;\r
498 #endif /* LINK_STATS */\r
499 }\r
500 \r
501 /* \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
506  */\r
507 static struct pbuf *pppAppend(u_char c, struct pbuf *nb, ext_accm *outACCM)\r
508 {\r
509     struct pbuf *tb = nb;\r
510     \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
517         if (tb) {\r
518             nb->next = tb;\r
519         }\r
520 #if LINK_STATS\r
521         else {\r
522             lwip_stats.link.memerr++;\r
523         }\r
524 #endif /* LINK_STATS */\r
525         nb = tb;\r
526     }\r
527     if (nb) {\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
531         }\r
532         else\r
533             *((u_char*)nb->payload + nb->len++) = c;\r
534     }\r
535         \r
536     return tb;\r
537 }\r
538 \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
541 {\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
547     u_char c;\r
548 \r
549     (void)ipaddr;\r
550 \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
557 #if LINK_STATS\r
558                 lwip_stats.link.opterr++;\r
559                 lwip_stats.link.drop++;\r
560 #endif\r
561                 return ERR_ARG;\r
562         }\r
563 \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
567 #if LINK_STATS\r
568                 lwip_stats.link.rterr++;\r
569                 lwip_stats.link.drop++;\r
570 #endif\r
571                 return ERR_RTE;\r
572         }\r
573 \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
578 #if LINK_STATS\r
579                 lwip_stats.link.memerr++;\r
580                 lwip_stats.link.drop++;\r
581 #endif /* LINK_STATS */\r
582         return ERR_MEM;\r
583     }\r
584         \r
585 #if VJ_SUPPORT > 0\r
586     /* \r
587      * Attempt Van Jacobson header compression if VJ is configured and\r
588      * this is an IP packet. \r
589      */\r
590     if (protocol == PPP_IP && pc->vjEnabled) {\r
591         switch (vj_compress_tcp(&pc->vjComp, pb)) {\r
592         case TYPE_IP:\r
593             /* No change...\r
594             protocol = PPP_IP_PROTOCOL;\r
595              */\r
596             break;\r
597         case TYPE_COMPRESSED_TCP:\r
598             protocol = PPP_VJC_COMP;\r
599             break;\r
600         case TYPE_UNCOMPRESSED_TCP:\r
601             protocol = PPP_VJC_UNCOMP;\r
602             break;\r
603         default:\r
604             PPPDEBUG((LOG_WARNING, "pppifOutput[%d]: bad IP packet\n", pd));\r
605 #if LINK_STATS\r
606                         lwip_stats.link.proterr++;\r
607                         lwip_stats.link.drop++;\r
608 #endif\r
609                 pbuf_free(headMB);\r
610             return ERR_VAL;\r
611         }\r
612     }\r
613 #endif\r
614         \r
615     tailMB = headMB;\r
616         \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
621     if (!pc->accomp) {\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
626     }\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
631     }\r
632     c = protocol & 0xFF;\r
633     fcsOut = PPP_FCS(fcsOut, c);\r
634     tailMB = pppAppend(c, tailMB, &pc->outACCM);\r
635     \r
636     /* Load packet. */\r
637         for(p = pb; p; p = p->next) {\r
638         int n;\r
639         u_char *sPtr;\r
640 \r
641         sPtr = (u_char*)p->payload;\r
642         n = p->len;\r
643         while (n-- > 0) {\r
644             c = *sPtr++;\r
645             \r
646             /* Update FCS before checking for special characters. */\r
647             fcsOut = PPP_FCS(fcsOut, c);\r
648             \r
649             /* Copy to output buffer escaping special characters. */\r
650             tailMB = pppAppend(c, tailMB, &pc->outACCM);\r
651         }\r
652     }\r
653 \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
660         \r
661     /* If we failed to complete the packet, throw it away. */\r
662     if (!tailMB) {\r
663         PPPDEBUG((LOG_WARNING,\r
664                     "pppifOutput[%d]: Alloc err - dropping proto=%d\n", \r
665                     pd, protocol));\r
666         pbuf_free(headMB);\r
667 #if LINK_STATS\r
668                 lwip_stats.link.memerr++;\r
669                 lwip_stats.link.drop++;\r
670 #endif\r
671         return ERR_MEM;\r
672     }\r
673 \r
674         /* Send it. */\r
675     PPPDEBUG((LOG_INFO, "pppifOutput[%d]: proto=0x%04X\n", pd, protocol));\r
676 \r
677     nPut(pc, headMB);\r
678 \r
679     return ERR_OK;\r
680 }\r
681 \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
685 {\r
686     PPPControl *pc = &pppControl[pd];\r
687     int st = 0;\r
688 \r
689     if (pd < 0 || pd >= NUM_PPP)\r
690         st = PPPERR_PARAM;\r
691     else {\r
692         switch(cmd) {\r
693         case PPPCTLG_UPSTATUS:      /* Get the PPP up status. */\r
694             if (arg) \r
695                 *(int *)arg = (int)(pc->if_up);\r
696             else\r
697                 st = PPPERR_PARAM;\r
698             break;\r
699         case PPPCTLS_ERRCODE:       /* Set the PPP error code. */\r
700             if (arg) \r
701                 pc->errCode = *(int *)arg;\r
702             else\r
703                 st = PPPERR_PARAM;\r
704             break;\r
705         case PPPCTLG_ERRCODE:       /* Get the PPP error code. */\r
706             if (arg) \r
707                 *(int *)arg = (int)(pc->errCode);\r
708             else\r
709                 st = PPPERR_PARAM;\r
710             break;\r
711         case PPPCTLG_FD:\r
712             if (arg) \r
713                 *(sio_fd_t *)arg = pc->fd;\r
714             else\r
715                 st = PPPERR_PARAM;\r
716             break;\r
717         default:\r
718             st = PPPERR_PARAM;\r
719             break;\r
720         }\r
721     }\r
722     \r
723     return st;\r
724 }\r
725 \r
726 /*\r
727  * Return the Maximum Transmission Unit for the given PPP connection.\r
728  */\r
729 u_int pppMTU(int pd)\r
730 {\r
731     PPPControl *pc = &pppControl[pd];\r
732     u_int st;\r
733     \r
734     /* Validate parameters. */\r
735     if (pd < 0 || pd >= NUM_PPP || !pc->openFlag)\r
736         st = 0;\r
737     else\r
738         st = pc->mtu;\r
739         \r
740     return st;\r
741 }\r
742 \r
743 /*\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
747  */\r
748 int pppWrite(int pd, const u_char *s, int n)\r
749 {\r
750     PPPControl *pc = &pppControl[pd];\r
751     u_char c;\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
756 #if LINK_STATS\r
757                 lwip_stats.link.memerr++;\r
758                 lwip_stats.link.proterr++;\r
759 #endif /* LINK_STATS */\r
760                 return PPPERR_ALLOC;\r
761     }\r
762 \r
763     tailMB = headMB;\r
764         \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
770      \r
771     /* Load output buffer. */\r
772     while (n-- > 0) {\r
773         c = *s++;\r
774         \r
775         /* Update FCS before checking for special characters. */\r
776         fcsOut = PPP_FCS(fcsOut, c);\r
777         \r
778         /* Copy to output buffer escaping special characters. */\r
779         tailMB = pppAppend(c, tailMB, &pc->outACCM);\r
780     }\r
781     \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
788         \r
789     /* If we failed to complete the packet, throw it away.\r
790      * Otherwise send it. */\r
791     if (!tailMB) {\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
795                 pbuf_free(headMB);\r
796 #if LINK_STATS\r
797                 lwip_stats.link.memerr++;\r
798                 lwip_stats.link.proterr++;\r
799 #endif /* LINK_STATS */\r
800                 return PPPERR_ALLOC;\r
801         }\r
802 \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
805     nPut(pc, headMB);\r
806 \r
807     return PPPERR_NONE;\r
808 }\r
809 \r
810 /*\r
811  * ppp_send_config - configure the transmit characteristics of\r
812  * the ppp interface.\r
813  */\r
814 void ppp_send_config(\r
815     int unit, \r
816     int mtu,\r
817     u32_t asyncmap,\r
818     int pcomp, \r
819     int accomp\r
820 )\r
821 {\r
822     PPPControl *pc = &pppControl[unit];\r
823     int i;\r
824     \r
825     pc->mtu = mtu;\r
826     pc->pcomp = pcomp;\r
827     pc->accomp = accomp;\r
828     \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
833                 unit,\r
834                 pc->outACCM[0], pc->outACCM[1], pc->outACCM[2], pc->outACCM[3]));\r
835 }\r
836 \r
837 \r
838 /*\r
839  * ppp_set_xaccm - set the extended transmit ACCM for the interface.\r
840  */\r
841 void ppp_set_xaccm(int unit, ext_accm *accm)\r
842 {\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
845                 unit,\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
850 }\r
851 \r
852 \r
853 /*\r
854  * ppp_recv_config - configure the receive-side characteristics of\r
855  * the ppp interface.\r
856  */\r
857 void ppp_recv_config(\r
858     int unit, \r
859     int mru,\r
860     u32_t asyncmap,\r
861     int pcomp, \r
862     int accomp\r
863 )\r
864 {\r
865     PPPControl *pc = &pppControl[unit];\r
866     int i;\r
867     \r
868         (void)accomp;\r
869         (void)pcomp;\r
870         (void)mru;\r
871 \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
876                 unit,\r
877                 pc->inACCM[0], pc->inACCM[1], pc->inACCM[2], pc->inACCM[3]));\r
878 }\r
879 \r
880 #if 0\r
881 /*\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
886  */\r
887 int ccp_test(\r
888     int unit, \r
889     int opt_len, \r
890     int for_transmit,\r
891     u_char *opt_ptr\r
892 )\r
893 {\r
894     return 0;   /* XXX Currently no compression. */\r
895 }\r
896 \r
897 /*\r
898  * ccp_flags_set - inform kernel about the current state of CCP.\r
899  */\r
900 void ccp_flags_set(int unit, int isopen, int isup)\r
901 {\r
902     /* XXX */\r
903 }\r
904 \r
905 /*\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
909  */\r
910 int ccp_fatal_error(int unit)\r
911 {\r
912     /* XXX */\r
913     return 0;\r
914 }\r
915 #endif\r
916 \r
917 /*\r
918  * get_idle_time - return how long the link has been idle.\r
919  */\r
920 int get_idle_time(int u, struct ppp_idle *ip)\r
921 {   \r
922     /* XXX */\r
923         (void)u;\r
924         (void)ip;\r
925 \r
926     return 0;\r
927 }\r
928 \r
929 \r
930 /*\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
937  */\r
938 u32_t GetMask(u32_t addr)\r
939 {\r
940     u32_t mask, nmask;\r
941     \r
942     htonl(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
947     else\r
948         nmask = IN_CLASSC_NET;\r
949     /* class D nets are disallowed by bad_ip_adrs */\r
950     mask = subnetMask | htonl(nmask);\r
951     \r
952     /* XXX\r
953      * Scan through the system's network interfaces.\r
954      * Get each netmask and OR them into our mask.\r
955      */\r
956     \r
957     return mask;\r
958 }\r
959 \r
960 /*\r
961  * sifvjcomp - config tcp header compression\r
962  */\r
963 int sifvjcomp(\r
964     int pd, \r
965     int vjcomp, \r
966     int cidcomp, \r
967     int maxcid\r
968 )\r
969 {\r
970 #if VJ_SUPPORT > 0\r
971     PPPControl *pc = &pppControl[pd];\r
972     \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
978 #endif\r
979 \r
980     return 0;\r
981 }\r
982 \r
983 /*\r
984  * pppifNetifInit - netif init callback\r
985  */\r
986 static err_t pppifNetifInit(struct netif *netif)\r
987 {\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
992         return ERR_OK;\r
993 }\r
994 \r
995 \r
996 /*\r
997  * sifup - Config the interface up and enable IP packets to pass.\r
998  */\r
999 int sifup(int pd)\r
1000 {\r
1001     PPPControl *pc = &pppControl[pd];\r
1002     int st = 1;\r
1003     \r
1004     if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {\r
1005         st = 0;\r
1006         PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd));\r
1007     } else {\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
1010                 \r
1011                 netif_set_up(&pc->netif);\r
1012                 pc->if_up = 1;\r
1013                 pc->errCode = PPPERR_NONE;\r
1014 \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
1018                 } else {\r
1019                 st = 0;\r
1020                 PPPDEBUG((LOG_ERR, "sifup[%d]: netif_add failed\n", pd));\r
1021                 }\r
1022     }\r
1023 \r
1024     return st;\r
1025 }\r
1026 \r
1027 /*\r
1028  * sifnpmode - Set the mode for handling packets for a given NP.\r
1029  */\r
1030 int sifnpmode(int u, int proto, enum NPmode mode)\r
1031 {\r
1032         (void)u;\r
1033         (void)proto;\r
1034         (void)mode;\r
1035     return 0;\r
1036 }\r
1037 \r
1038 /*\r
1039  * sifdown - Config the interface down and disable IP.\r
1040  */\r
1041 int sifdown(int pd)\r
1042 {\r
1043     PPPControl *pc = &pppControl[pd];\r
1044     int st = 1;\r
1045     \r
1046     if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {\r
1047         st = 0;\r
1048         PPPDEBUG((LOG_WARNING, "sifdown[%d]: bad parms\n", pd));\r
1049     } else {\r
1050         pc->if_up = 0;\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
1055         }\r
1056     return st;\r
1057 }\r
1058 \r
1059 /*\r
1060  * sifaddr - Config the interface IP addresses and netmask.\r
1061  */\r
1062 int sifaddr(\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
1069 )\r
1070 {\r
1071     PPPControl *pc = &pppControl[pd];\r
1072     int st = 1;\r
1073     \r
1074     if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {\r
1075         st = 0;\r
1076         PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd));\r
1077     } else {\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
1083     }\r
1084     return st;\r
1085 }\r
1086 \r
1087 /*\r
1088  * cifaddr - Clear the interface IP addresses, and delete routes\r
1089  * through the interface if possible.\r
1090  */\r
1091 int cifaddr(\r
1092     int pd,         /* Interface unit ??? */\r
1093     u32_t o,    /* Our IP address ??? */\r
1094     u32_t h     /* IP broadcast address ??? */\r
1095 )\r
1096 {\r
1097     PPPControl *pc = &pppControl[pd];\r
1098     int st = 1;\r
1099     \r
1100         (void)o;\r
1101         (void)h;\r
1102     if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {\r
1103         st = 0;\r
1104         PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd));\r
1105     } else {\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
1111     }\r
1112     return st;\r
1113 }\r
1114 \r
1115 /*\r
1116  * sifdefaultroute - assign a default route through the address given.\r
1117  */\r
1118 int sifdefaultroute(int pd, u32_t l, u32_t g)\r
1119 {\r
1120     PPPControl *pc = &pppControl[pd];\r
1121     int st = 1;\r
1122     \r
1123         (void)l;\r
1124         (void)g;\r
1125     if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {\r
1126         st = 0;\r
1127         PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd));\r
1128     } else {\r
1129                 netif_set_default(&pc->netif);\r
1130     }\r
1131 \r
1132     /* TODO: check how PPP handled the netMask, previously not set by ipSetDefault */\r
1133 \r
1134     return st;\r
1135 }\r
1136 \r
1137 /*\r
1138  * cifdefaultroute - delete a default route through the address given.\r
1139  */\r
1140 int cifdefaultroute(int pd, u32_t l, u32_t g)\r
1141 {\r
1142     PPPControl *pc = &pppControl[pd];\r
1143     int st = 1;\r
1144     \r
1145         (void)l;\r
1146         (void)g;\r
1147     if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {\r
1148         st = 0;\r
1149         PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd));\r
1150     } else {\r
1151                 netif_set_default(NULL);\r
1152     }\r
1153 \r
1154     return st;\r
1155 }\r
1156 \r
1157 void\r
1158 pppMainWakeup(int pd)\r
1159 {\r
1160         PPPDEBUG((LOG_DEBUG, "pppMainWakeup: unit %d\n", pd));\r
1161         sio_read_abort(pppControl[pd].fd);\r
1162 }\r
1163 \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
1168 */\r
1169 \r
1170 static void\r
1171 pppStartCB(void *arg)\r
1172 {\r
1173     int pd = (int)arg;\r
1174 \r
1175         PPPDEBUG((LOG_DEBUG, "pppStartCB: unit %d\n", pd));\r
1176     lcp_lowerup(pd);\r
1177     lcp_open(pd);      /* Start protocol */\r
1178 }\r
1179 \r
1180 static void\r
1181 pppStopCB(void *arg)\r
1182 {\r
1183     int pd = (int)arg;\r
1184 \r
1185         PPPDEBUG((LOG_DEBUG, "pppStopCB: unit %d\n", pd));\r
1186     lcp_close(pd, "User request");\r
1187 }\r
1188 \r
1189 static void\r
1190 pppHupCB(void *arg)\r
1191 {\r
1192     int pd = (int)arg;\r
1193 \r
1194         PPPDEBUG((LOG_DEBUG, "pppHupCB: unit %d\n", pd));\r
1195     lcp_lowerdown(pd);\r
1196     link_terminated(pd);\r
1197 }\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
1204 {\r
1205     int pd = (int)arg;\r
1206     struct pbuf *p;\r
1207     PPPControl* pc;\r
1208 \r
1209     pc = &pppControl[pd];\r
1210 \r
1211     p = pbuf_alloc(PBUF_RAW, PPP_MRU+PPP_HDRLEN, PBUF_RAM);\r
1212     if(!p) {\r
1213                 LWIP_ASSERT("p != NULL", p);\r
1214                 pc->errCode = PPPERR_ALLOC;\r
1215                 goto out;\r
1216     }\r
1217 \r
1218     /*\r
1219      * Start the connection and handle incoming events (packet or timeout).\r
1220      */\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
1230         }\r
1231         else if (pc->sig_hup) {\r
1232                 PPPDEBUG((LOG_DEBUG, "pppMainWakeup: unit %d sig_hup -> pppHupCB\n", pd));\r
1233                 pc->sig_hup = 0;\r
1234                 tcpip_callback(pppHupCB, arg);\r
1235         } else {\r
1236                 int c = sio_read(pc->fd, p->payload, p->len);\r
1237                 if(c > 0) {\r
1238                         pppInProc(pd, p->payload, c);\r
1239                 } else {\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
1242                 }\r
1243         }\r
1244     }\r
1245         PPPDEBUG((LOG_INFO, "pppMain: unit %d: PHASE_DEAD\n", pd));\r
1246     pbuf_free(p);\r
1247 \r
1248 out:\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
1252 \r
1253     pc->openFlag = 0;\r
1254 }\r
1255 \r
1256 static struct pbuf *pppSingleBuf(struct pbuf *p)\r
1257 {\r
1258         struct pbuf *q, *b;\r
1259         u_char *pl;\r
1260 \r
1261         if(p->tot_len == p->len)\r
1262                 return p;\r
1263 \r
1264         q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);\r
1265         if(!q) {\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
1269         }\r
1270 \r
1271         for(b = p, pl = q->payload; b != NULL; b = b->next) {\r
1272                 memcpy(pl, b->payload, b->len);\r
1273                 pl += b->len;\r
1274         }\r
1275 \r
1276         pbuf_free(p);\r
1277 \r
1278         return q;\r
1279 }\r
1280 \r
1281 struct pppInputHeader {\r
1282         int unit;\r
1283         u16_t proto;\r
1284 };\r
1285 \r
1286 /*\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
1289  */\r
1290 static void pppInput(void *arg)\r
1291 {\r
1292         struct pbuf *nb = (struct pbuf *)arg;\r
1293     u16_t protocol;\r
1294     int pd;\r
1295 \r
1296         pd = ((struct pppInputHeader *)nb->payload)->unit;\r
1297         protocol = ((struct pppInputHeader *)nb->payload)->proto;\r
1298 \r
1299     pbuf_header(nb, -(int)sizeof(struct pppInputHeader));\r
1300 \r
1301 #if LINK_STATS\r
1302     lwip_stats.link.recv++;\r
1303 #endif /* LINK_STATS */\r
1304 \r
1305     /*\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
1309      */\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
1314                 goto drop;\r
1315             }\r
1316     }\r
1317 \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
1322         /*\r
1323          * Clip off the VJ header and prepend the rebuilt TCP/IP header and\r
1324          * pass the result to IP.\r
1325          */\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
1329             }\r
1330                         return;\r
1331         }\r
1332         /* Something's wrong so drop it. */\r
1333         PPPDEBUG((LOG_WARNING, "pppInput[%d]: Dropping VJ compressed\n", pd));\r
1334 #else\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
1338         break;\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
1342         /*\r
1343          * Process the TCP/IP header for VJ header compression and then pass\r
1344          * the packet to IP.\r
1345          */\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
1349             }\r
1350                         return;\r
1351         }\r
1352         /* Something's wrong so drop it. */\r
1353         PPPDEBUG((LOG_WARNING, "pppInput[%d]: Dropping VJ uncompressed\n", pd));\r
1354 #else\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
1360         break;\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
1365         }\r
1366                 return;\r
1367     default:\r
1368         {\r
1369                 struct protent *protp;\r
1370                 int i;\r
1371 \r
1372                 /*\r
1373                  * Upcall the proper protocol input routine.\r
1374                  */\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
1380                                 goto out;\r
1381                         }\r
1382                 }\r
1383 \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
1390 #endif\r
1391                 lcp_sprotrej(pd, nb->payload, nb->len);\r
1392         }\r
1393         break;\r
1394     }\r
1395 \r
1396 drop:\r
1397 #if LINK_STATS\r
1398     lwip_stats.link.drop++;\r
1399 #endif\r
1400 \r
1401 out:\r
1402     pbuf_free(nb);\r
1403     return;\r
1404 }\r
1405 \r
1406 \r
1407 /*\r
1408  * Drop the input packet.\r
1409  */\r
1410 static void pppDrop(PPPControl *pc)\r
1411 {\r
1412     if (pc->inHead != NULL) {\r
1413 #if 0       \r
1414         PPPDEBUG((LOG_INFO, "pppDrop: %d:%.*H\n", pc->inHead->len, min(60, pc->inHead->len * 2), pc->inHead->payload));\r
1415 #endif  \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
1422     }\r
1423 #if VJ_SUPPORT > 0\r
1424     vj_uncompress_err(&pc->vjComp);\r
1425 #endif\r
1426 \r
1427 #if LINK_STATS\r
1428     lwip_stats.link.drop++;\r
1429 #endif /* LINK_STATS */\r
1430 }\r
1431 \r
1432 \r
1433 /*\r
1434  * Process a received octet string.\r
1435  */\r
1436 static void pppInProc(int pd, u_char *s, int l)\r
1437 {\r
1438     PPPControl *pc = &pppControl[pd];\r
1439     struct pbuf *nextNBuf;\r
1440     u_char curChar;\r
1441 \r
1442     PPPDEBUG((LOG_DEBUG, "pppInProc[%d]: got %d bytes\n", pd, l));\r
1443     while (l-- > 0) {\r
1444         curChar = *s++;\r
1445         \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
1459                     ;\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
1465 #if LINK_STATS\r
1466                                         lwip_stats.link.lenerr++;\r
1467 #endif\r
1468                     pppDrop(pc);\r
1469                 }\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
1475 #if LINK_STATS\r
1476                                         lwip_stats.link.chkerr++;\r
1477 #endif\r
1478                     pppDrop(pc);\r
1479                 }\r
1480                 /* Otherwise it's a good packet so pass it on. */\r
1481                 else {\r
1482                     \r
1483                     /* Trim off the checksum. */\r
1484                     if(pc->inTail->len >= 2) {\r
1485                         pc->inTail->len -= 2;\r
1486 \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
1490                         }\r
1491                     } else {\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
1495                         }\r
1496 \r
1497                         pbuf_realloc(pc->inHead, pc->inHead->tot_len - 2);\r
1498                     }\r
1499 \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
1505 #if LINK_STATS\r
1506                         lwip_stats.link.drop++;\r
1507 #endif\r
1508                     }\r
1509                     pc->inHead = NULL;\r
1510                     pc->inTail = NULL;\r
1511                 }\r
1512                     \r
1513                 /* Prepare for a new packet. */\r
1514                 pc->inFCS = PPP_INITFCS;\r
1515                 pc->inState = PDADDRESS;\r
1516                 pc->inEscaped = 0;\r
1517             }\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
1520             else {\r
1521                 PPPDEBUG((LOG_WARNING,\r
1522                             "pppInProc[%d]: Dropping ACCM char <%d>\n", pd, curChar));\r
1523             }\r
1524         }\r
1525         /* Process other characters. */\r
1526         else {\r
1527             /* Unencode escaped characters. */\r
1528             if (pc->inEscaped) {\r
1529                 pc->inEscaped = 0;\r
1530                 curChar ^= PPP_TRANS;\r
1531             }\r
1532             \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
1539                         break;\r
1540                                 }\r
1541 \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
1546 \r
1547                                 /* Fall through */\r
1548             case PDADDRESS:                 /* Process address field. */\r
1549                 if (curChar == PPP_ALLSTATIONS) {\r
1550                     pc->inState = PDCONTROL;\r
1551                     break;\r
1552                 }\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
1559                         break;\r
1560                 }\r
1561 #if 0\r
1562                 else {\r
1563                     PPPDEBUG((LOG_WARNING,\r
1564                                 "pppInProc[%d]: Invalid control <%d>\n", pd, curChar));\r
1565                     pc->inState = PDSTART;\r
1566                 }\r
1567 #endif\r
1568             case PDPROTOCOL1:               /* Process protocol field 1. */\r
1569                 /* If the lower bit is set, this is the end of the protocol\r
1570                  * field. */\r
1571                 if (curChar & 1) {\r
1572                     pc->inProtocol = curChar;\r
1573                     pc->inState = PDDATA;\r
1574                 }\r
1575                 else {\r
1576                     pc->inProtocol = (u_int)curChar << 8;\r
1577                     pc->inState = PDPROTOCOL2;\r
1578                 }\r
1579                 break;\r
1580             case PDPROTOCOL2:               /* Process protocol field 2. */\r
1581                 pc->inProtocol |= curChar;\r
1582                 pc->inState = PDDATA;\r
1583                 break;\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
1587                     if(pc->inTail) {\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
1591                         }\r
1592                     }\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
1600 #if LINK_STATS\r
1601                                                 lwip_stats.link.memerr++;\r
1602 #endif /* LINK_STATS */\r
1603                         pppDrop(pc);\r
1604                         pc->inState = PDSTART;  /* Wait for flag sequence. */\r
1605                         break;\r
1606                     }\r
1607                     if (pc->inHead == NULL) {\r
1608                         struct pppInputHeader *pih = nextNBuf->payload;\r
1609 \r
1610                         pih->unit = pd;\r
1611                         pih->proto = pc->inProtocol;\r
1612 \r
1613                         nextNBuf->len += sizeof(*pih);\r
1614 \r
1615                         pc->inHead = nextNBuf;\r
1616                     }\r
1617                     pc->inTail = nextNBuf;\r
1618                 }\r
1619                 /* Load character into buffer. */\r
1620                 ((u_char*)pc->inTail->payload)[pc->inTail->len++] = curChar;\r
1621                 break;\r
1622             }\r
1623 \r
1624             /* update the frame check sequence number. */\r
1625             pc->inFCS = PPP_FCS(pc->inFCS, curChar);\r
1626         }\r
1627     }\r
1628         avRandomize();\r
1629 }\r
1630 \r
1631 #endif /* PPP_SUPPORT */\r