]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/Common/ethernet/lwIP_130/src/netif/ppp/ipcp.c
Add FreeRTOS-Plus directory.
[freertos] / FreeRTOS / Demo / Common / ethernet / lwIP_130 / src / netif / ppp / ipcp.c
1 /*****************************************************************************\r
2 * ipcp.c - Network PPP IP Control 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-12-08 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.\r
31 *   Original.\r
32 *****************************************************************************/\r
33 /*\r
34  * ipcp.c - PPP IP Control Protocol.\r
35  *\r
36  * Copyright (c) 1989 Carnegie Mellon University.\r
37  * All rights reserved.\r
38  *\r
39  * Redistribution and use in source and binary forms are permitted\r
40  * provided that the above copyright notice and this paragraph are\r
41  * duplicated in all such forms and that any documentation,\r
42  * advertising materials, and other materials related to such\r
43  * distribution and use acknowledge that the software was developed\r
44  * by Carnegie Mellon University.  The name of the\r
45  * University may not be used to endorse or promote products derived\r
46  * from this software without specific prior written permission.\r
47  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR\r
48  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED\r
49  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.\r
50  */\r
51 \r
52 #include "lwip/opt.h"\r
53 \r
54 #if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */\r
55 \r
56 #include "ppp.h"\r
57 #include "pppdebug.h"\r
58 \r
59 #include "auth.h"\r
60 #include "fsm.h"\r
61 #include "vj.h"\r
62 #include "ipcp.h"\r
63 \r
64 #include <string.h>\r
65 \r
66 /*************************/\r
67 /*** LOCAL DEFINITIONS ***/\r
68 /*************************/\r
69 /* #define OLD_CI_ADDRS 1 */ /* Support deprecated address negotiation. */\r
70 \r
71 /*\r
72  * Lengths of configuration options.\r
73  */\r
74 #define CILEN_VOID     2\r
75 #define CILEN_COMPRESS 4  /* min length for compression protocol opt. */\r
76 #define CILEN_VJ       6  /* length for RFC1332 Van-Jacobson opt. */\r
77 #define CILEN_ADDR     6  /* new-style single address option */\r
78 #define CILEN_ADDRS    10 /* old-style dual address option */\r
79 \r
80 \r
81 \r
82 /***********************************/\r
83 /*** LOCAL FUNCTION DECLARATIONS ***/\r
84 /***********************************/\r
85 /*\r
86  * Callbacks for fsm code.  (CI = Configuration Information)\r
87  */\r
88 static void ipcp_resetci (fsm *);                     /* Reset our CI */\r
89 static int  ipcp_cilen (fsm *);                       /* Return length of our CI */\r
90 static void ipcp_addci (fsm *, u_char *, int *);      /* Add our CI */\r
91 static int  ipcp_ackci (fsm *, u_char *, int);        /* Peer ack'd our CI */\r
92 static int  ipcp_nakci (fsm *, u_char *, int);        /* Peer nak'd our CI */\r
93 static int  ipcp_rejci (fsm *, u_char *, int);        /* Peer rej'd our CI */\r
94 static int  ipcp_reqci (fsm *, u_char *, int *, int); /* Rcv CI */\r
95 static void ipcp_up (fsm *);                          /* We're UP */\r
96 static void ipcp_down (fsm *);                        /* We're DOWN */\r
97 #if 0\r
98 static void ipcp_script (fsm *, char *); /* Run an up/down script */\r
99 #endif\r
100 static void ipcp_finished (fsm *);                    /* Don't need lower layer */\r
101 \r
102 /*\r
103  * Protocol entry points from main code.\r
104  */\r
105 static void ipcp_init (int);\r
106 static void ipcp_open (int);\r
107 static void ipcp_close (int, char *);\r
108 static void ipcp_lowerup (int);\r
109 static void ipcp_lowerdown (int);\r
110 static void ipcp_input (int, u_char *, int);\r
111 static void ipcp_protrej (int);\r
112 \r
113 static void ipcp_clear_addrs (int);\r
114 \r
115 #define CODENAME(x) ((x) == CONFACK ? "ACK" : \\r
116                      (x) == CONFNAK ? "NAK" : "REJ")\r
117 \r
118 \r
119 \r
120 /******************************/\r
121 /*** PUBLIC DATA STRUCTURES ***/\r
122 /******************************/\r
123 /* global vars */\r
124 ipcp_options ipcp_wantoptions[NUM_PPP];  /* Options that we want to request */\r
125 ipcp_options ipcp_gotoptions[NUM_PPP];   /* Options that peer ack'd */\r
126 ipcp_options ipcp_allowoptions[NUM_PPP]; /* Options we allow peer to request */\r
127 ipcp_options ipcp_hisoptions[NUM_PPP];   /* Options that we ack'd */\r
128 \r
129 fsm ipcp_fsm[NUM_PPP]; /* IPCP fsm structure */\r
130 \r
131 struct protent ipcp_protent = {\r
132   PPP_IPCP,\r
133   ipcp_init,\r
134   ipcp_input,\r
135   ipcp_protrej,\r
136   ipcp_lowerup,\r
137   ipcp_lowerdown,\r
138   ipcp_open,\r
139   ipcp_close,\r
140 #if 0\r
141   ipcp_printpkt,\r
142   NULL,\r
143 #endif\r
144   1,\r
145   "IPCP",\r
146 #if 0\r
147   ip_check_options,\r
148   NULL,\r
149   ip_active_pkt\r
150 #endif\r
151 };\r
152 \r
153 \r
154 \r
155 /*****************************/\r
156 /*** LOCAL DATA STRUCTURES ***/\r
157 /*****************************/\r
158 /* local vars */\r
159 static int cis_received[NUM_PPP];      /* # Conf-Reqs received */\r
160 static int default_route_set[NUM_PPP]; /* Have set up a default route */\r
161 \r
162 static fsm_callbacks ipcp_callbacks = { /* IPCP callback routines */\r
163   ipcp_resetci,  /* Reset our Configuration Information */\r
164   ipcp_cilen,    /* Length of our Configuration Information */\r
165   ipcp_addci,    /* Add our Configuration Information */\r
166   ipcp_ackci,    /* ACK our Configuration Information */\r
167   ipcp_nakci,    /* NAK our Configuration Information */\r
168   ipcp_rejci,    /* Reject our Configuration Information */\r
169   ipcp_reqci,    /* Request peer's Configuration Information */\r
170   ipcp_up,       /* Called when fsm reaches LS_OPENED state */\r
171   ipcp_down,     /* Called when fsm leaves LS_OPENED state */\r
172   NULL,          /* Called when we want the lower layer up */\r
173   ipcp_finished, /* Called when we want the lower layer down */\r
174   NULL,          /* Called when Protocol-Reject received */\r
175   NULL,          /* Retransmission is necessary */\r
176   NULL,          /* Called to handle protocol-specific codes */\r
177   "IPCP"         /* String name of protocol */\r
178 };\r
179 \r
180 \r
181 \r
182 /**********************************/\r
183 /*** LOCAL FUNCTION DEFINITIONS ***/\r
184 /**********************************/\r
185 \r
186 /*\r
187  * Non-standard inet_ntoa left here for compat with original ppp\r
188  * sources. Assumes u32_t instead of struct in_addr.\r
189  */ \r
190 \r
191 char *\r
192 _inet_ntoa(u32_t n)\r
193 {\r
194   struct in_addr ia;\r
195   ia.s_addr = n;\r
196   return inet_ntoa(ia);\r
197 }\r
198 \r
199 #define inet_ntoa _inet_ntoa\r
200 \r
201 /*\r
202  * ipcp_init - Initialize IPCP.\r
203  */\r
204 static void\r
205 ipcp_init(int unit)\r
206 {\r
207   fsm           *f = &ipcp_fsm[unit];\r
208   ipcp_options *wo = &ipcp_wantoptions[unit];\r
209   ipcp_options *ao = &ipcp_allowoptions[unit];\r
210 \r
211   f->unit      = unit;\r
212   f->protocol  = PPP_IPCP;\r
213   f->callbacks = &ipcp_callbacks;\r
214   fsm_init(&ipcp_fsm[unit]);\r
215 \r
216   memset(wo, 0, sizeof(*wo));\r
217   memset(ao, 0, sizeof(*ao));\r
218 \r
219   wo->neg_addr      = 1;\r
220   wo->ouraddr       = 0;\r
221 #if VJ_SUPPORT\r
222   wo->neg_vj        = 1;\r
223 #else  /* VJ_SUPPORT */\r
224   wo->neg_vj        = 0;\r
225 #endif /* VJ_SUPPORT */\r
226   wo->vj_protocol   = IPCP_VJ_COMP;\r
227   wo->maxslotindex  = MAX_SLOTS - 1;\r
228   wo->cflag         = 0;\r
229   wo->default_route = 1;\r
230 \r
231   ao->neg_addr      = 1;\r
232 #if VJ_SUPPORT\r
233   ao->neg_vj        = 1;\r
234 #else  /* VJ_SUPPORT */\r
235   ao->neg_vj        = 0;\r
236 #endif /* VJ_SUPPORT */\r
237   ao->maxslotindex  = MAX_SLOTS - 1;\r
238   ao->cflag         = 1;\r
239   ao->default_route = 1;\r
240 }\r
241 \r
242 \r
243 /*\r
244  * ipcp_open - IPCP is allowed to come up.\r
245  */\r
246 static void\r
247 ipcp_open(int unit)\r
248 {\r
249   fsm_open(&ipcp_fsm[unit]);\r
250 }\r
251 \r
252 \r
253 /*\r
254  * ipcp_close - Take IPCP down.\r
255  */\r
256 static void\r
257 ipcp_close(int unit, char *reason)\r
258 {\r
259   fsm_close(&ipcp_fsm[unit], reason);\r
260 }\r
261 \r
262 \r
263 /*\r
264  * ipcp_lowerup - The lower layer is up.\r
265  */\r
266 static void\r
267 ipcp_lowerup(int unit)\r
268 {\r
269   fsm_lowerup(&ipcp_fsm[unit]);\r
270 }\r
271 \r
272 \r
273 /*\r
274  * ipcp_lowerdown - The lower layer is down.\r
275  */\r
276 static void\r
277 ipcp_lowerdown(int unit)\r
278 {\r
279   fsm_lowerdown(&ipcp_fsm[unit]);\r
280 }\r
281 \r
282 \r
283 /*\r
284  * ipcp_input - Input IPCP packet.\r
285  */\r
286 static void\r
287 ipcp_input(int unit, u_char *p, int len)\r
288 {\r
289   fsm_input(&ipcp_fsm[unit], p, len);\r
290 }\r
291 \r
292 \r
293 /*\r
294  * ipcp_protrej - A Protocol-Reject was received for IPCP.\r
295  *\r
296  * Pretend the lower layer went down, so we shut up.\r
297  */\r
298 static void\r
299 ipcp_protrej(int unit)\r
300 {\r
301   fsm_lowerdown(&ipcp_fsm[unit]);\r
302 }\r
303 \r
304 \r
305 /*\r
306  * ipcp_resetci - Reset our CI.\r
307  */\r
308 static void\r
309 ipcp_resetci(fsm *f)\r
310 {\r
311   ipcp_options *wo = &ipcp_wantoptions[f->unit];\r
312   \r
313   wo->req_addr = wo->neg_addr && ipcp_allowoptions[f->unit].neg_addr;\r
314   if (wo->ouraddr == 0) {\r
315     wo->accept_local = 1;\r
316   }\r
317   if (wo->hisaddr == 0) {\r
318     wo->accept_remote = 1;\r
319   }\r
320   /* Request DNS addresses from the peer */\r
321   wo->req_dns1 = ppp_settings.usepeerdns;\r
322   wo->req_dns2 = ppp_settings.usepeerdns;\r
323   ipcp_gotoptions[f->unit] = *wo;\r
324   cis_received[f->unit] = 0;\r
325 }\r
326 \r
327 \r
328 /*\r
329  * ipcp_cilen - Return length of our CI.\r
330  */\r
331 static int\r
332 ipcp_cilen(fsm *f)\r
333 {\r
334   ipcp_options *go = &ipcp_gotoptions[f->unit];\r
335   ipcp_options *wo = &ipcp_wantoptions[f->unit];\r
336   ipcp_options *ho = &ipcp_hisoptions[f->unit];\r
337 \r
338 #define LENCIVJ(neg, old)   (neg ? (old? CILEN_COMPRESS : CILEN_VJ) : 0)\r
339 #define LENCIADDR(neg, old) (neg ? (old? CILEN_ADDRS : CILEN_ADDR) : 0)\r
340 #define LENCIDNS(neg)       (neg ? (CILEN_ADDR) : 0)\r
341 \r
342   /*\r
343    * First see if we want to change our options to the old\r
344    * forms because we have received old forms from the peer.\r
345    */\r
346   if (wo->neg_addr && !go->neg_addr && !go->old_addrs) {\r
347     /* use the old style of address negotiation */\r
348     go->neg_addr = 1;\r
349     go->old_addrs = 1;\r
350   }\r
351   if (wo->neg_vj && !go->neg_vj && !go->old_vj) {\r
352     /* try an older style of VJ negotiation */\r
353     if (cis_received[f->unit] == 0) {\r
354       /* keep trying the new style until we see some CI from the peer */\r
355       go->neg_vj = 1;\r
356     } else {\r
357       /* use the old style only if the peer did */\r
358       if (ho->neg_vj && ho->old_vj) {\r
359         go->neg_vj = 1;\r
360         go->old_vj = 1;\r
361         go->vj_protocol = ho->vj_protocol;\r
362       }\r
363     }\r
364   }\r
365 \r
366   return (LENCIADDR(go->neg_addr, go->old_addrs) +\r
367           LENCIVJ(go->neg_vj, go->old_vj) +\r
368           LENCIDNS(go->req_dns1) +\r
369           LENCIDNS(go->req_dns2));\r
370 }\r
371 \r
372 \r
373 /*\r
374  * ipcp_addci - Add our desired CIs to a packet.\r
375  */\r
376 static void\r
377 ipcp_addci(fsm *f, u_char *ucp, int *lenp)\r
378 {\r
379   ipcp_options *go = &ipcp_gotoptions[f->unit];\r
380   int len = *lenp;\r
381 \r
382 #define ADDCIVJ(opt, neg, val, old, maxslotindex, cflag) \\r
383   if (neg) { \\r
384     int vjlen = old? CILEN_COMPRESS : CILEN_VJ; \\r
385     if (len >= vjlen) { \\r
386       PUTCHAR(opt, ucp); \\r
387       PUTCHAR(vjlen, ucp); \\r
388       PUTSHORT(val, ucp); \\r
389       if (!old) { \\r
390         PUTCHAR(maxslotindex, ucp); \\r
391         PUTCHAR(cflag, ucp); \\r
392       } \\r
393       len -= vjlen; \\r
394     } else { \\r
395       neg = 0; \\r
396     } \\r
397   }\r
398 \r
399 #define ADDCIADDR(opt, neg, old, val1, val2) \\r
400   if (neg) { \\r
401     int addrlen = (old? CILEN_ADDRS: CILEN_ADDR); \\r
402     if (len >= addrlen) { \\r
403       u32_t l; \\r
404       PUTCHAR(opt, ucp); \\r
405       PUTCHAR(addrlen, ucp); \\r
406       l = ntohl(val1); \\r
407       PUTLONG(l, ucp); \\r
408       if (old) { \\r
409         l = ntohl(val2); \\r
410         PUTLONG(l, ucp); \\r
411       } \\r
412       len -= addrlen; \\r
413     } else { \\r
414       neg = 0; \\r
415     } \\r
416   }\r
417 \r
418 #define ADDCIDNS(opt, neg, addr) \\r
419   if (neg) { \\r
420     if (len >= CILEN_ADDR) { \\r
421       u32_t l; \\r
422       PUTCHAR(opt, ucp); \\r
423       PUTCHAR(CILEN_ADDR, ucp); \\r
424       l = ntohl(addr); \\r
425       PUTLONG(l, ucp); \\r
426       len -= CILEN_ADDR; \\r
427     } else { \\r
428       neg = 0; \\r
429     } \\r
430   }\r
431 \r
432   ADDCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), go->neg_addr,\r
433       go->old_addrs, go->ouraddr, go->hisaddr);\r
434 \r
435   ADDCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj,\r
436       go->maxslotindex, go->cflag);\r
437 \r
438   ADDCIDNS(CI_MS_DNS1, go->req_dns1, go->dnsaddr[0]);\r
439 \r
440   ADDCIDNS(CI_MS_DNS2, go->req_dns2, go->dnsaddr[1]);\r
441 \r
442   *lenp -= len;\r
443 }\r
444 \r
445 \r
446 /*\r
447  * ipcp_ackci - Ack our CIs.\r
448  *\r
449  * Returns:\r
450  *  0 - Ack was bad.\r
451  *  1 - Ack was good.\r
452  */\r
453 static int\r
454 ipcp_ackci(fsm *f, u_char *p, int len)\r
455 {\r
456   ipcp_options *go = &ipcp_gotoptions[f->unit];\r
457   u_short cilen, citype, cishort;\r
458   u32_t cilong;\r
459   u_char cimaxslotindex, cicflag;\r
460 \r
461   /*\r
462    * CIs must be in exactly the same order that we sent...\r
463    * Check packet length and CI length at each step.\r
464    * If we find any deviations, then this packet is bad.\r
465    */\r
466 \r
467 #define ACKCIVJ(opt, neg, val, old, maxslotindex, cflag) \\r
468   if (neg) { \\r
469     int vjlen = old? CILEN_COMPRESS : CILEN_VJ; \\r
470     if ((len -= vjlen) < 0) { \\r
471       goto bad; \\r
472     } \\r
473     GETCHAR(citype, p); \\r
474     GETCHAR(cilen, p); \\r
475     if (cilen != vjlen || \\r
476         citype != opt) { \\r
477       goto bad; \\r
478     } \\r
479     GETSHORT(cishort, p); \\r
480     if (cishort != val) { \\r
481       goto bad; \\r
482     } \\r
483     if (!old) { \\r
484       GETCHAR(cimaxslotindex, p); \\r
485       if (cimaxslotindex != maxslotindex) { \\r
486         goto bad; \\r
487       } \\r
488       GETCHAR(cicflag, p); \\r
489       if (cicflag != cflag) { \\r
490         goto bad; \\r
491       } \\r
492     } \\r
493   }\r
494   \r
495 #define ACKCIADDR(opt, neg, old, val1, val2) \\r
496   if (neg) { \\r
497     int addrlen = (old? CILEN_ADDRS: CILEN_ADDR); \\r
498     u32_t l; \\r
499     if ((len -= addrlen) < 0) { \\r
500       goto bad; \\r
501     } \\r
502     GETCHAR(citype, p); \\r
503     GETCHAR(cilen, p); \\r
504     if (cilen != addrlen || \\r
505         citype != opt) { \\r
506       goto bad; \\r
507     } \\r
508     GETLONG(l, p); \\r
509     cilong = htonl(l); \\r
510     if (val1 != cilong) { \\r
511       goto bad; \\r
512     } \\r
513     if (old) { \\r
514       GETLONG(l, p); \\r
515       cilong = htonl(l); \\r
516       if (val2 != cilong) { \\r
517         goto bad; \\r
518       } \\r
519     } \\r
520   }\r
521 \r
522 #define ACKCIDNS(opt, neg, addr) \\r
523   if (neg) { \\r
524     u32_t l; \\r
525     if ((len -= CILEN_ADDR) < 0) { \\r
526       goto bad; \\r
527     } \\r
528     GETCHAR(citype, p); \\r
529     GETCHAR(cilen, p); \\r
530     if (cilen != CILEN_ADDR || \\r
531         citype != opt) { \\r
532       goto bad; \\r
533     } \\r
534     GETLONG(l, p); \\r
535     cilong = htonl(l); \\r
536     if (addr != cilong) { \\r
537       goto bad; \\r
538     } \\r
539   }\r
540 \r
541   ACKCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), go->neg_addr,\r
542         go->old_addrs, go->ouraddr, go->hisaddr);\r
543 \r
544   ACKCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj,\r
545       go->maxslotindex, go->cflag);\r
546 \r
547   ACKCIDNS(CI_MS_DNS1, go->req_dns1, go->dnsaddr[0]);\r
548 \r
549   ACKCIDNS(CI_MS_DNS2, go->req_dns2, go->dnsaddr[1]);\r
550 \r
551   /*\r
552    * If there are any remaining CIs, then this packet is bad.\r
553    */\r
554   if (len != 0) {\r
555     goto bad;\r
556   }\r
557   return (1);\r
558   \r
559 bad:\r
560   IPCPDEBUG((LOG_INFO, "ipcp_ackci: received bad Ack!\n"));\r
561   return (0);\r
562 }\r
563 \r
564 /*\r
565  * ipcp_nakci - Peer has sent a NAK for some of our CIs.\r
566  * This should not modify any state if the Nak is bad\r
567  * or if IPCP is in the LS_OPENED state.\r
568  *\r
569  * Returns:\r
570  *  0 - Nak was bad.\r
571  *  1 - Nak was good.\r
572  */\r
573 static int\r
574 ipcp_nakci(fsm *f, u_char *p, int len)\r
575 {\r
576   ipcp_options *go = &ipcp_gotoptions[f->unit];\r
577   u_char cimaxslotindex, cicflag;\r
578   u_char citype, cilen, *next;\r
579   u_short cishort;\r
580   u32_t ciaddr1, ciaddr2, l, cidnsaddr;\r
581   ipcp_options no;    /* options we've seen Naks for */\r
582   ipcp_options try;    /* options to request next time */\r
583 \r
584   BZERO(&no, sizeof(no));\r
585   try = *go;\r
586 \r
587   /*\r
588    * Any Nak'd CIs must be in exactly the same order that we sent.\r
589    * Check packet length and CI length at each step.\r
590    * If we find any deviations, then this packet is bad.\r
591    */\r
592 #define NAKCIADDR(opt, neg, old, code) \\r
593   if (go->neg && \\r
594       len >= (cilen = (old? CILEN_ADDRS: CILEN_ADDR)) && \\r
595       p[1] == cilen && \\r
596       p[0] == opt) { \\r
597     len -= cilen; \\r
598     INCPTR(2, p); \\r
599     GETLONG(l, p); \\r
600     ciaddr1 = htonl(l); \\r
601     if (old) { \\r
602       GETLONG(l, p); \\r
603       ciaddr2 = htonl(l); \\r
604       no.old_addrs = 1; \\r
605     } else { \\r
606       ciaddr2 = 0; \\r
607     } \\r
608     no.neg = 1; \\r
609     code \\r
610   }\r
611 \r
612 #define NAKCIVJ(opt, neg, code) \\r
613   if (go->neg && \\r
614       ((cilen = p[1]) == CILEN_COMPRESS || cilen == CILEN_VJ) && \\r
615       len >= cilen && \\r
616       p[0] == opt) { \\r
617     len -= cilen; \\r
618     INCPTR(2, p); \\r
619     GETSHORT(cishort, p); \\r
620     no.neg = 1; \\r
621     code \\r
622   }\r
623   \r
624 #define NAKCIDNS(opt, neg, code) \\r
625   if (go->neg && \\r
626       ((cilen = p[1]) == CILEN_ADDR) && \\r
627       len >= cilen && \\r
628       p[0] == opt) { \\r
629     len -= cilen; \\r
630     INCPTR(2, p); \\r
631     GETLONG(l, p); \\r
632     cidnsaddr = htonl(l); \\r
633     no.neg = 1; \\r
634     code \\r
635   }\r
636 \r
637   /*\r
638    * Accept the peer's idea of {our,his} address, if different\r
639    * from our idea, only if the accept_{local,remote} flag is set.\r
640    */\r
641   NAKCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), neg_addr, go->old_addrs,\r
642     if (go->accept_local && ciaddr1) { /* Do we know our address? */\r
643       try.ouraddr = ciaddr1;\r
644       IPCPDEBUG((LOG_INFO, "local IP address %s\n",\r
645            inet_ntoa(ciaddr1)));\r
646     }\r
647     if (go->accept_remote && ciaddr2) { /* Does he know his? */\r
648       try.hisaddr = ciaddr2;\r
649       IPCPDEBUG((LOG_INFO, "remote IP address %s\n",\r
650            inet_ntoa(ciaddr2)));\r
651     }\r
652   );\r
653 \r
654   /*\r
655    * Accept the peer's value of maxslotindex provided that it\r
656    * is less than what we asked for.  Turn off slot-ID compression\r
657    * if the peer wants.  Send old-style compress-type option if\r
658    * the peer wants.\r
659    */\r
660   NAKCIVJ(CI_COMPRESSTYPE, neg_vj,\r
661     if (cilen == CILEN_VJ) {\r
662       GETCHAR(cimaxslotindex, p);\r
663       GETCHAR(cicflag, p);\r
664       if (cishort == IPCP_VJ_COMP) {\r
665         try.old_vj = 0;\r
666         if (cimaxslotindex < go->maxslotindex) {\r
667           try.maxslotindex = cimaxslotindex;\r
668         }\r
669         if (!cicflag) {\r
670           try.cflag = 0;\r
671         }\r
672       } else {\r
673         try.neg_vj = 0;\r
674       }\r
675     } else {\r
676       if (cishort == IPCP_VJ_COMP || cishort == IPCP_VJ_COMP_OLD) {\r
677         try.old_vj = 1;\r
678         try.vj_protocol = cishort;\r
679       } else {\r
680         try.neg_vj = 0;\r
681       }\r
682     }\r
683   );\r
684 \r
685   NAKCIDNS(CI_MS_DNS1, req_dns1,\r
686       try.dnsaddr[0] = cidnsaddr;\r
687         IPCPDEBUG((LOG_INFO, "primary DNS address %s\n", inet_ntoa(cidnsaddr)));\r
688       );\r
689 \r
690   NAKCIDNS(CI_MS_DNS2, req_dns2,\r
691       try.dnsaddr[1] = cidnsaddr;\r
692         IPCPDEBUG((LOG_INFO, "secondary DNS address %s\n", inet_ntoa(cidnsaddr)));\r
693       );\r
694 \r
695   /*\r
696   * There may be remaining CIs, if the peer is requesting negotiation\r
697   * on an option that we didn't include in our request packet.\r
698   * If they want to negotiate about IP addresses, we comply.\r
699   * If they want us to ask for compression, we refuse.\r
700   */\r
701   while (len > CILEN_VOID) {\r
702     GETCHAR(citype, p);\r
703     GETCHAR(cilen, p);\r
704     if( (len -= cilen) < 0 ) {\r
705       goto bad;\r
706     }\r
707     next = p + cilen - 2;\r
708 \r
709     switch (citype) {\r
710       case CI_COMPRESSTYPE:\r
711         if (go->neg_vj || no.neg_vj ||\r
712             (cilen != CILEN_VJ && cilen != CILEN_COMPRESS)) {\r
713           goto bad;\r
714         }\r
715         no.neg_vj = 1;\r
716         break;\r
717       case CI_ADDRS:\r
718         if ((go->neg_addr && go->old_addrs) || no.old_addrs\r
719             || cilen != CILEN_ADDRS) {\r
720           goto bad;\r
721         }\r
722         try.neg_addr = 1;\r
723         try.old_addrs = 1;\r
724         GETLONG(l, p);\r
725         ciaddr1 = htonl(l);\r
726         if (ciaddr1 && go->accept_local) {\r
727           try.ouraddr = ciaddr1;\r
728         }\r
729         GETLONG(l, p);\r
730         ciaddr2 = htonl(l);\r
731         if (ciaddr2 && go->accept_remote) {\r
732           try.hisaddr = ciaddr2;\r
733         }\r
734         no.old_addrs = 1;\r
735         break;\r
736       case CI_ADDR:\r
737         if (go->neg_addr || no.neg_addr || cilen != CILEN_ADDR) {\r
738           goto bad;\r
739         }\r
740         try.old_addrs = 0;\r
741         GETLONG(l, p);\r
742         ciaddr1 = htonl(l);\r
743         if (ciaddr1 && go->accept_local) {\r
744           try.ouraddr = ciaddr1;\r
745         }\r
746         if (try.ouraddr != 0) {\r
747           try.neg_addr = 1;\r
748         }\r
749         no.neg_addr = 1;\r
750         break;\r
751     }\r
752     p = next;\r
753   }\r
754 \r
755   /* If there is still anything left, this packet is bad. */\r
756   if (len != 0) {\r
757     goto bad;\r
758   }\r
759 \r
760   /*\r
761    * OK, the Nak is good.  Now we can update state.\r
762    */\r
763   if (f->state != LS_OPENED) {\r
764     *go = try;\r
765   }\r
766 \r
767   return 1;\r
768 \r
769 bad:\r
770   IPCPDEBUG((LOG_INFO, "ipcp_nakci: received bad Nak!\n"));\r
771   return 0;\r
772 }\r
773 \r
774 \r
775 /*\r
776  * ipcp_rejci - Reject some of our CIs.\r
777  */\r
778 static int\r
779 ipcp_rejci(fsm *f, u_char *p, int len)\r
780 {\r
781   ipcp_options *go = &ipcp_gotoptions[f->unit];\r
782   u_char cimaxslotindex, ciflag, cilen;\r
783   u_short cishort;\r
784   u32_t cilong;\r
785   ipcp_options try;    /* options to request next time */\r
786 \r
787   try = *go;\r
788   /*\r
789    * Any Rejected CIs must be in exactly the same order that we sent.\r
790    * Check packet length and CI length at each step.\r
791    * If we find any deviations, then this packet is bad.\r
792    */\r
793 #define REJCIADDR(opt, neg, old, val1, val2) \\r
794   if (go->neg && \\r
795       len >= (cilen = old? CILEN_ADDRS: CILEN_ADDR) && \\r
796       p[1] == cilen && \\r
797       p[0] == opt) { \\r
798     u32_t l; \\r
799     len -= cilen; \\r
800     INCPTR(2, p); \\r
801     GETLONG(l, p); \\r
802     cilong = htonl(l); \\r
803     /* Check rejected value. */ \\r
804     if (cilong != val1) { \\r
805       goto bad; \\r
806     } \\r
807     if (old) { \\r
808       GETLONG(l, p); \\r
809       cilong = htonl(l); \\r
810       /* Check rejected value. */ \\r
811       if (cilong != val2) { \\r
812         goto bad; \\r
813       } \\r
814     } \\r
815     try.neg = 0; \\r
816   }\r
817 \r
818 #define REJCIVJ(opt, neg, val, old, maxslot, cflag) \\r
819   if (go->neg && \\r
820       p[1] == (old? CILEN_COMPRESS : CILEN_VJ) && \\r
821       len >= p[1] && \\r
822       p[0] == opt) { \\r
823     len -= p[1]; \\r
824     INCPTR(2, p); \\r
825     GETSHORT(cishort, p); \\r
826     /* Check rejected value. */  \\r
827     if (cishort != val) { \\r
828       goto bad; \\r
829     } \\r
830     if (!old) { \\r
831       GETCHAR(cimaxslotindex, p); \\r
832       if (cimaxslotindex != maxslot) { \\r
833         goto bad; \\r
834       } \\r
835       GETCHAR(ciflag, p); \\r
836       if (ciflag != cflag) { \\r
837         goto bad; \\r
838       } \\r
839     } \\r
840     try.neg = 0; \\r
841   }\r
842 \r
843 #define REJCIDNS(opt, neg, dnsaddr) \\r
844   if (go->neg && \\r
845       ((cilen = p[1]) == CILEN_ADDR) && \\r
846       len >= cilen && \\r
847       p[0] == opt) { \\r
848     u32_t l; \\r
849     len -= cilen; \\r
850     INCPTR(2, p); \\r
851     GETLONG(l, p); \\r
852     cilong = htonl(l); \\r
853     /* Check rejected value. */ \\r
854     if (cilong != dnsaddr) { \\r
855       goto bad; \\r
856     } \\r
857     try.neg = 0; \\r
858   }\r
859 \r
860   REJCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), neg_addr,\r
861         go->old_addrs, go->ouraddr, go->hisaddr);\r
862 \r
863   REJCIVJ(CI_COMPRESSTYPE, neg_vj, go->vj_protocol, go->old_vj,\r
864       go->maxslotindex, go->cflag);\r
865 \r
866   REJCIDNS(CI_MS_DNS1, req_dns1, go->dnsaddr[0]);\r
867 \r
868   REJCIDNS(CI_MS_DNS2, req_dns2, go->dnsaddr[1]);\r
869 \r
870   /*\r
871    * If there are any remaining CIs, then this packet is bad.\r
872    */\r
873   if (len != 0) {\r
874     goto bad;\r
875   }\r
876   /*\r
877    * Now we can update state.\r
878    */\r
879   if (f->state != LS_OPENED) {\r
880     *go = try;\r
881   }\r
882   return 1;\r
883 \r
884 bad:\r
885   IPCPDEBUG((LOG_INFO, "ipcp_rejci: received bad Reject!\n"));\r
886   return 0;\r
887 }\r
888 \r
889 \r
890 /*\r
891  * ipcp_reqci - Check the peer's requested CIs and send appropriate response.\r
892  *\r
893  * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified\r
894  * appropriately.  If reject_if_disagree is non-zero, doesn't return\r
895  * CONFNAK; returns CONFREJ if it can't return CONFACK.\r
896  */\r
897 static int\r
898 ipcp_reqci(fsm *f, u_char *inp/* Requested CIs */,int *len/* Length of requested CIs */,int reject_if_disagree)\r
899 {\r
900   ipcp_options *wo = &ipcp_wantoptions[f->unit];\r
901   ipcp_options *ho = &ipcp_hisoptions[f->unit];\r
902   ipcp_options *ao = &ipcp_allowoptions[f->unit];\r
903 #ifdef OLD_CI_ADDRS\r
904   ipcp_options *go = &ipcp_gotoptions[f->unit];\r
905 #endif\r
906   u_char *cip, *next;     /* Pointer to current and next CIs */\r
907   u_short cilen, citype;  /* Parsed len, type */\r
908   u_short cishort;        /* Parsed short value */\r
909   u32_t tl, ciaddr1;      /* Parsed address values */\r
910 #ifdef OLD_CI_ADDRS\r
911   u32_t ciaddr2;          /* Parsed address values */\r
912 #endif\r
913   int rc = CONFACK;       /* Final packet return code */\r
914   int orc;                /* Individual option return code */\r
915   u_char *p;              /* Pointer to next char to parse */\r
916   u_char *ucp = inp;      /* Pointer to current output char */\r
917   int l = *len;           /* Length left */\r
918   u_char maxslotindex, cflag;\r
919   int d;\r
920 \r
921   cis_received[f->unit] = 1;\r
922 \r
923   /*\r
924    * Reset all his options.\r
925    */\r
926   BZERO(ho, sizeof(*ho));\r
927 \r
928   /*\r
929    * Process all his options.\r
930    */\r
931   next = inp;\r
932   while (l) {\r
933     orc = CONFACK;       /* Assume success */\r
934     cip = p = next;      /* Remember begining of CI */\r
935     if (l < 2 ||         /* Not enough data for CI header or */\r
936         p[1] < 2 ||      /*  CI length too small or */\r
937         p[1] > l) {      /*  CI length too big? */\r
938       IPCPDEBUG((LOG_INFO, "ipcp_reqci: bad CI length!\n"));\r
939       orc = CONFREJ;     /* Reject bad CI */\r
940       cilen = l;         /* Reject till end of packet */\r
941       l = 0;             /* Don't loop again */\r
942       goto endswitch;\r
943     }\r
944     GETCHAR(citype, p);  /* Parse CI type */\r
945     GETCHAR(cilen, p);   /* Parse CI length */\r
946     l -= cilen;          /* Adjust remaining length */\r
947     next += cilen;       /* Step to next CI */\r
948 \r
949     switch (citype) {      /* Check CI type */\r
950 #ifdef OLD_CI_ADDRS /* Need to save space... */\r
951       case CI_ADDRS:\r
952         IPCPDEBUG((LOG_INFO, "ipcp_reqci: received ADDRS\n"));\r
953         if (!ao->neg_addr ||\r
954             cilen != CILEN_ADDRS) {  /* Check CI length */\r
955           orc = CONFREJ;    /* Reject CI */\r
956           break;\r
957         }\r
958 \r
959         /*\r
960          * If he has no address, or if we both have his address but\r
961          * disagree about it, then NAK it with our idea.\r
962          * In particular, if we don't know his address, but he does,\r
963          * then accept it.\r
964          */\r
965         GETLONG(tl, p);    /* Parse source address (his) */\r
966         ciaddr1 = htonl(tl);\r
967         IPCPDEBUG((LOG_INFO, "his addr %s\n", inet_ntoa(ciaddr1)));\r
968         if (ciaddr1 != wo->hisaddr\r
969             && (ciaddr1 == 0 || !wo->accept_remote)) {\r
970           orc = CONFNAK;\r
971           if (!reject_if_disagree) {\r
972             DECPTR(sizeof(u32_t), p);\r
973             tl = ntohl(wo->hisaddr);\r
974             PUTLONG(tl, p);\r
975           }\r
976         } else if (ciaddr1 == 0 && wo->hisaddr == 0) {\r
977           /*\r
978            * If neither we nor he knows his address, reject the option.\r
979            */\r
980           orc = CONFREJ;\r
981           wo->req_addr = 0;  /* don't NAK with 0.0.0.0 later */\r
982           break;\r
983         }\r
984 \r
985         /*\r
986          * If he doesn't know our address, or if we both have our address\r
987          * but disagree about it, then NAK it with our idea.\r
988          */\r
989         GETLONG(tl, p);    /* Parse desination address (ours) */\r
990         ciaddr2 = htonl(tl);\r
991         IPCPDEBUG((LOG_INFO, "our addr %s\n", inet_ntoa(ciaddr2)));\r
992         if (ciaddr2 != wo->ouraddr) {\r
993           if (ciaddr2 == 0 || !wo->accept_local) {\r
994             orc = CONFNAK;\r
995             if (!reject_if_disagree) {\r
996               DECPTR(sizeof(u32_t), p);\r
997               tl = ntohl(wo->ouraddr);\r
998               PUTLONG(tl, p);\r
999             }\r
1000           } else {\r
1001             go->ouraddr = ciaddr2;  /* accept peer's idea */\r
1002           }\r
1003         }\r
1004 \r
1005         ho->neg_addr = 1;\r
1006         ho->old_addrs = 1;\r
1007         ho->hisaddr = ciaddr1;\r
1008         ho->ouraddr = ciaddr2;\r
1009         break;\r
1010 #endif\r
1011 \r
1012       case CI_ADDR:\r
1013         if (!ao->neg_addr) {\r
1014           IPCPDEBUG((LOG_INFO, "ipcp_reqci: Reject ADDR not allowed\n"));\r
1015           orc = CONFREJ;        /* Reject CI */\r
1016           break;\r
1017         } else if (cilen != CILEN_ADDR) {  /* Check CI length */\r
1018           IPCPDEBUG((LOG_INFO, "ipcp_reqci: Reject ADDR bad len\n"));\r
1019           orc = CONFREJ;        /* Reject CI */\r
1020           break;\r
1021         }\r
1022 \r
1023         /*\r
1024          * If he has no address, or if we both have his address but\r
1025          * disagree about it, then NAK it with our idea.\r
1026          * In particular, if we don't know his address, but he does,\r
1027          * then accept it.\r
1028          */\r
1029         GETLONG(tl, p);  /* Parse source address (his) */\r
1030         ciaddr1 = htonl(tl);\r
1031         if (ciaddr1 != wo->hisaddr\r
1032             && (ciaddr1 == 0 || !wo->accept_remote)) {\r
1033           orc = CONFNAK;\r
1034           if (!reject_if_disagree) {\r
1035             DECPTR(sizeof(u32_t), p);\r
1036             tl = ntohl(wo->hisaddr);\r
1037             PUTLONG(tl, p);\r
1038           }\r
1039           IPCPDEBUG((LOG_INFO, "ipcp_reqci: Nak ADDR %s\n", inet_ntoa(ciaddr1)));\r
1040         } else if (ciaddr1 == 0 && wo->hisaddr == 0) {\r
1041           /*\r
1042            * Don't ACK an address of 0.0.0.0 - reject it instead.\r
1043            */\r
1044           IPCPDEBUG((LOG_INFO, "ipcp_reqci: Reject ADDR %s\n", inet_ntoa(ciaddr1)));\r
1045           orc = CONFREJ;\r
1046           wo->req_addr = 0;  /* don't NAK with 0.0.0.0 later */\r
1047           break;\r
1048         }\r
1049 \r
1050         ho->neg_addr = 1;\r
1051         ho->hisaddr = ciaddr1;\r
1052         IPCPDEBUG((LOG_INFO, "ipcp_reqci: ADDR %s\n", inet_ntoa(ciaddr1)));\r
1053         break;\r
1054 \r
1055       case CI_MS_DNS1:\r
1056       case CI_MS_DNS2:\r
1057         /* Microsoft primary or secondary DNS request */\r
1058         d = citype == CI_MS_DNS2;\r
1059 \r
1060         /* If we do not have a DNS address then we cannot send it */\r
1061         if (ao->dnsaddr[d] == 0 ||\r
1062             cilen != CILEN_ADDR) {  /* Check CI length */\r
1063           IPCPDEBUG((LOG_INFO, "ipcp_reqci: Rejecting DNS%d Request\n", d+1));\r
1064           orc = CONFREJ;        /* Reject CI */\r
1065           break;\r
1066         }\r
1067         GETLONG(tl, p);\r
1068         if (htonl(tl) != ao->dnsaddr[d]) {\r
1069           IPCPDEBUG((LOG_INFO, "ipcp_reqci: Naking DNS%d Request %d\n",\r
1070                 d+1, inet_ntoa(tl)));\r
1071           DECPTR(sizeof(u32_t), p);\r
1072           tl = ntohl(ao->dnsaddr[d]);\r
1073           PUTLONG(tl, p);\r
1074           orc = CONFNAK;\r
1075         }\r
1076         IPCPDEBUG((LOG_INFO, "ipcp_reqci: received DNS%d Request\n", d+1));\r
1077         break;\r
1078 \r
1079       case CI_MS_WINS1:\r
1080       case CI_MS_WINS2:\r
1081         /* Microsoft primary or secondary WINS request */\r
1082         d = citype == CI_MS_WINS2;\r
1083         IPCPDEBUG((LOG_INFO, "ipcp_reqci: received WINS%d Request\n", d+1));\r
1084 \r
1085         /* If we do not have a DNS address then we cannot send it */\r
1086         if (ao->winsaddr[d] == 0 ||\r
1087           cilen != CILEN_ADDR) {  /* Check CI length */\r
1088           orc = CONFREJ;      /* Reject CI */\r
1089           break;\r
1090         }\r
1091         GETLONG(tl, p);\r
1092         if (htonl(tl) != ao->winsaddr[d]) {\r
1093           DECPTR(sizeof(u32_t), p);\r
1094           tl = ntohl(ao->winsaddr[d]);\r
1095           PUTLONG(tl, p);\r
1096           orc = CONFNAK;\r
1097         }\r
1098         break;\r
1099 \r
1100       case CI_COMPRESSTYPE:\r
1101         if (!ao->neg_vj) {\r
1102           IPCPDEBUG((LOG_INFO, "ipcp_reqci: Rejecting COMPRESSTYPE not allowed\n"));\r
1103           orc = CONFREJ;\r
1104           break;\r
1105         } else if (cilen != CILEN_VJ && cilen != CILEN_COMPRESS) {\r
1106           IPCPDEBUG((LOG_INFO, "ipcp_reqci: Rejecting COMPRESSTYPE len=%d\n", cilen));\r
1107           orc = CONFREJ;\r
1108           break;\r
1109         }\r
1110         GETSHORT(cishort, p);\r
1111 \r
1112         if (!(cishort == IPCP_VJ_COMP ||\r
1113             (cishort == IPCP_VJ_COMP_OLD && cilen == CILEN_COMPRESS))) {\r
1114           IPCPDEBUG((LOG_INFO, "ipcp_reqci: Rejecting COMPRESSTYPE %d\n", cishort));\r
1115           orc = CONFREJ;\r
1116           break;\r
1117         }\r
1118 \r
1119         ho->neg_vj = 1;\r
1120         ho->vj_protocol = cishort;\r
1121         if (cilen == CILEN_VJ) {\r
1122           GETCHAR(maxslotindex, p);\r
1123           if (maxslotindex > ao->maxslotindex) { \r
1124             IPCPDEBUG((LOG_INFO, "ipcp_reqci: Naking VJ max slot %d\n", maxslotindex));\r
1125             orc = CONFNAK;\r
1126             if (!reject_if_disagree) {\r
1127               DECPTR(1, p);\r
1128               PUTCHAR(ao->maxslotindex, p);\r
1129             }\r
1130           }\r
1131           GETCHAR(cflag, p);\r
1132           if (cflag && !ao->cflag) {\r
1133             IPCPDEBUG((LOG_INFO, "ipcp_reqci: Naking VJ cflag %d\n", cflag));\r
1134             orc = CONFNAK;\r
1135             if (!reject_if_disagree) {\r
1136               DECPTR(1, p);\r
1137               PUTCHAR(wo->cflag, p);\r
1138             }\r
1139           }\r
1140           ho->maxslotindex = maxslotindex;\r
1141           ho->cflag = cflag;\r
1142         } else {\r
1143           ho->old_vj = 1;\r
1144           ho->maxslotindex = MAX_SLOTS - 1;\r
1145           ho->cflag = 1;\r
1146         }\r
1147         IPCPDEBUG((LOG_INFO, \r
1148               "ipcp_reqci: received COMPRESSTYPE p=%d old=%d maxslot=%d cflag=%d\n",\r
1149               ho->vj_protocol, ho->old_vj, ho->maxslotindex, ho->cflag));\r
1150         break;\r
1151 \r
1152       default:\r
1153         IPCPDEBUG((LOG_INFO, "ipcp_reqci: Rejecting unknown CI type %d\n", citype));\r
1154         orc = CONFREJ;\r
1155         break;\r
1156     }\r
1157 \r
1158 endswitch:\r
1159     if (orc == CONFACK &&    /* Good CI */\r
1160         rc != CONFACK) {     /*  but prior CI wasnt? */\r
1161       continue;              /* Don't send this one */\r
1162     }\r
1163 \r
1164     if (orc == CONFNAK) {    /* Nak this CI? */\r
1165       if (reject_if_disagree) {  /* Getting fed up with sending NAKs? */\r
1166         IPCPDEBUG((LOG_INFO, "ipcp_reqci: Rejecting too many naks\n"));\r
1167         orc = CONFREJ;       /* Get tough if so */\r
1168       } else {\r
1169         if (rc == CONFREJ) { /* Rejecting prior CI? */\r
1170           continue;          /* Don't send this one */\r
1171         }\r
1172         if (rc == CONFACK) { /* Ack'd all prior CIs? */\r
1173           rc = CONFNAK;      /* Not anymore... */\r
1174           ucp = inp;         /* Backup */\r
1175         }\r
1176       }\r
1177     }\r
1178 \r
1179     if (orc == CONFREJ &&    /* Reject this CI */\r
1180         rc != CONFREJ) {  /*  but no prior ones? */\r
1181       rc = CONFREJ;\r
1182       ucp = inp;        /* Backup */\r
1183     }\r
1184     \r
1185     /* Need to move CI? */\r
1186     if (ucp != cip) {\r
1187       BCOPY(cip, ucp, cilen);  /* Move it */\r
1188     }\r
1189 \r
1190     /* Update output pointer */\r
1191     INCPTR(cilen, ucp);\r
1192   }\r
1193 \r
1194   /*\r
1195    * If we aren't rejecting this packet, and we want to negotiate\r
1196    * their address, and they didn't send their address, then we\r
1197    * send a NAK with a CI_ADDR option appended.  We assume the\r
1198    * input buffer is long enough that we can append the extra\r
1199    * option safely.\r
1200    */\r
1201   if (rc != CONFREJ && !ho->neg_addr &&\r
1202       wo->req_addr && !reject_if_disagree) {\r
1203     IPCPDEBUG((LOG_INFO, "ipcp_reqci: Requesting peer address\n"));\r
1204     if (rc == CONFACK) {\r
1205       rc = CONFNAK;\r
1206       ucp = inp;        /* reset pointer */\r
1207       wo->req_addr = 0;    /* don't ask again */\r
1208     }\r
1209     PUTCHAR(CI_ADDR, ucp);\r
1210     PUTCHAR(CILEN_ADDR, ucp);\r
1211     tl = ntohl(wo->hisaddr);\r
1212     PUTLONG(tl, ucp);\r
1213   }\r
1214 \r
1215   *len = (int)(ucp - inp);    /* Compute output length */\r
1216   IPCPDEBUG((LOG_INFO, "ipcp_reqci: returning Configure-%s\n", CODENAME(rc)));\r
1217   return (rc);      /* Return final code */\r
1218 }\r
1219 \r
1220 \r
1221 #if 0\r
1222 /*\r
1223  * ip_check_options - check that any IP-related options are OK,\r
1224  * and assign appropriate defaults.\r
1225  */\r
1226 static void\r
1227 ip_check_options(u_long localAddr)\r
1228 {\r
1229   ipcp_options *wo = &ipcp_wantoptions[0];\r
1230 \r
1231   /*\r
1232    * Load our default IP address but allow the remote host to give us\r
1233    * a new address.\r
1234    */\r
1235   if (wo->ouraddr == 0 && !ppp_settings.disable_defaultip) {\r
1236     wo->accept_local = 1;  /* don't insist on this default value */\r
1237     wo->ouraddr = htonl(localAddr);\r
1238   }\r
1239 }\r
1240 #endif\r
1241 \r
1242 \r
1243 /*\r
1244  * ipcp_up - IPCP has come UP.\r
1245  *\r
1246  * Configure the IP network interface appropriately and bring it up.\r
1247  */\r
1248 static void\r
1249 ipcp_up(fsm *f)\r
1250 {\r
1251   u32_t mask;\r
1252   ipcp_options *ho = &ipcp_hisoptions[f->unit];\r
1253   ipcp_options *go = &ipcp_gotoptions[f->unit];\r
1254   ipcp_options *wo = &ipcp_wantoptions[f->unit];\r
1255 \r
1256   np_up(f->unit, PPP_IP);\r
1257   IPCPDEBUG((LOG_INFO, "ipcp: up\n"));\r
1258 \r
1259   /*\r
1260    * We must have a non-zero IP address for both ends of the link.\r
1261    */\r
1262   if (!ho->neg_addr) {\r
1263     ho->hisaddr = wo->hisaddr;\r
1264   }\r
1265 \r
1266   if (ho->hisaddr == 0) {\r
1267     IPCPDEBUG((LOG_ERR, "Could not determine remote IP address\n"));\r
1268     ipcp_close(f->unit, "Could not determine remote IP address");\r
1269     return;\r
1270   }\r
1271   if (go->ouraddr == 0) {\r
1272     IPCPDEBUG((LOG_ERR, "Could not determine local IP address\n"));\r
1273     ipcp_close(f->unit, "Could not determine local IP address");\r
1274     return;\r
1275   }\r
1276 \r
1277   if (ppp_settings.usepeerdns && (go->dnsaddr[0] || go->dnsaddr[1])) {\r
1278     /*pppGotDNSAddrs(go->dnsaddr[0], go->dnsaddr[1]);*/\r
1279   }\r
1280 \r
1281   /*\r
1282    * Check that the peer is allowed to use the IP address it wants.\r
1283    */\r
1284   if (!auth_ip_addr(f->unit, ho->hisaddr)) {\r
1285     IPCPDEBUG((LOG_ERR, "Peer is not authorized to use remote address %s\n",\r
1286         inet_ntoa(ho->hisaddr)));\r
1287     ipcp_close(f->unit, "Unauthorized remote IP address");\r
1288     return;\r
1289   }\r
1290 \r
1291   /* set tcp compression */\r
1292   sifvjcomp(f->unit, ho->neg_vj, ho->cflag, ho->maxslotindex);\r
1293 \r
1294   /*\r
1295    * Set IP addresses and (if specified) netmask.\r
1296    */\r
1297   mask = GetMask(go->ouraddr);\r
1298 \r
1299   if (!sifaddr(f->unit, go->ouraddr, ho->hisaddr, mask, go->dnsaddr[0], go->dnsaddr[1])) {\r
1300     IPCPDEBUG((LOG_WARNING, "sifaddr failed\n"));\r
1301     ipcp_close(f->unit, "Interface configuration failed");\r
1302     return;\r
1303   }\r
1304 \r
1305   /* bring the interface up for IP */\r
1306   if (!sifup(f->unit)) {\r
1307     IPCPDEBUG((LOG_WARNING, "sifup failed\n"));\r
1308     ipcp_close(f->unit, "Interface configuration failed");\r
1309     return;\r
1310   }\r
1311 \r
1312   sifnpmode(f->unit, PPP_IP, NPMODE_PASS);\r
1313 \r
1314   /* assign a default route through the interface if required */\r
1315   if (ipcp_wantoptions[f->unit].default_route) {\r
1316     if (sifdefaultroute(f->unit, go->ouraddr, ho->hisaddr)) {\r
1317       default_route_set[f->unit] = 1;\r
1318     }\r
1319   }\r
1320 \r
1321   IPCPDEBUG((LOG_NOTICE, "local  IP address %s\n", inet_ntoa(go->ouraddr)));\r
1322   IPCPDEBUG((LOG_NOTICE, "remote IP address %s\n", inet_ntoa(ho->hisaddr)));\r
1323   if (go->dnsaddr[0]) {\r
1324     IPCPDEBUG((LOG_NOTICE, "primary   DNS address %s\n", inet_ntoa(go->dnsaddr[0])));\r
1325   }\r
1326   if (go->dnsaddr[1]) {\r
1327     IPCPDEBUG((LOG_NOTICE, "secondary DNS address %s\n", inet_ntoa(go->dnsaddr[1])));\r
1328   }\r
1329 }\r
1330 \r
1331 \r
1332 /*\r
1333  * ipcp_down - IPCP has gone DOWN.\r
1334  *\r
1335  * Take the IP network interface down, clear its addresses\r
1336  * and delete routes through it.\r
1337  */\r
1338 static void\r
1339 ipcp_down(fsm *f)\r
1340 {\r
1341   IPCPDEBUG((LOG_INFO, "ipcp: down\n"));\r
1342   np_down(f->unit, PPP_IP);\r
1343   sifvjcomp(f->unit, 0, 0, 0);\r
1344 \r
1345   sifdown(f->unit);\r
1346   ipcp_clear_addrs(f->unit);\r
1347 }\r
1348 \r
1349 \r
1350 /*\r
1351  * ipcp_clear_addrs() - clear the interface addresses, routes, etc.\r
1352  */\r
1353 static void\r
1354 ipcp_clear_addrs(int unit)\r
1355 {\r
1356   u32_t ouraddr, hisaddr;\r
1357 \r
1358   ouraddr = ipcp_gotoptions[unit].ouraddr;\r
1359   hisaddr = ipcp_hisoptions[unit].hisaddr;\r
1360   if (default_route_set[unit]) {\r
1361     cifdefaultroute(unit, ouraddr, hisaddr);\r
1362     default_route_set[unit] = 0;\r
1363   }\r
1364   cifaddr(unit, ouraddr, hisaddr);\r
1365 }\r
1366 \r
1367 \r
1368 /*\r
1369  * ipcp_finished - possibly shut down the lower layers.\r
1370  */\r
1371 static void\r
1372 ipcp_finished(fsm *f)\r
1373 {\r
1374   np_finished(f->unit, PPP_IP);\r
1375 }\r
1376 \r
1377 #if 0\r
1378 static int\r
1379 ipcp_printpkt(u_char *p, int plen, void (*printer) (void *, char *, ...), void *arg)\r
1380 {\r
1381   LWIP_UNUSED_ARG(p);\r
1382   LWIP_UNUSED_ARG(plen);\r
1383   LWIP_UNUSED_ARG(printer);\r
1384   LWIP_UNUSED_ARG(arg);\r
1385   return 0;\r
1386 }\r
1387 \r
1388 /*\r
1389  * ip_active_pkt - see if this IP packet is worth bringing the link up for.\r
1390  * We don't bring the link up for IP fragments or for TCP FIN packets\r
1391  * with no data.\r
1392  */\r
1393 #define IP_HDRLEN   20  /* bytes */\r
1394 #define IP_OFFMASK  0x1fff\r
1395 #define IPPROTO_TCP 6\r
1396 #define TCP_HDRLEN  20\r
1397 #define TH_FIN      0x01\r
1398 \r
1399 /*\r
1400  * We use these macros because the IP header may be at an odd address,\r
1401  * and some compilers might use word loads to get th_off or ip_hl.\r
1402  */\r
1403 \r
1404 #define net_short(x)    (((x)[0] << 8) + (x)[1])\r
1405 #define get_iphl(x)     (((unsigned char *)(x))[0] & 0xF)\r
1406 #define get_ipoff(x)    net_short((unsigned char *)(x) + 6)\r
1407 #define get_ipproto(x)  (((unsigned char *)(x))[9])\r
1408 #define get_tcpoff(x)   (((unsigned char *)(x))[12] >> 4)\r
1409 #define get_tcpflags(x) (((unsigned char *)(x))[13])\r
1410 \r
1411 static int\r
1412 ip_active_pkt(u_char *pkt, int len)\r
1413 {\r
1414   u_char *tcp;\r
1415   int hlen;\r
1416 \r
1417   len -= PPP_HDRLEN;\r
1418   pkt += PPP_HDRLEN;\r
1419   if (len < IP_HDRLEN) {\r
1420     return 0;\r
1421   }\r
1422   if ((get_ipoff(pkt) & IP_OFFMASK) != 0) {\r
1423     return 0;\r
1424   }\r
1425   if (get_ipproto(pkt) != IPPROTO_TCP) {\r
1426     return 1;\r
1427   }\r
1428   hlen = get_iphl(pkt) * 4;\r
1429   if (len < hlen + TCP_HDRLEN) {\r
1430     return 0;\r
1431   }\r
1432   tcp = pkt + hlen;\r
1433   if ((get_tcpflags(tcp) & TH_FIN) != 0 && len == hlen + get_tcpoff(tcp) * 4) {\r
1434     return 0;\r
1435   }\r
1436   return 1;\r
1437 }\r
1438 #endif\r
1439 \r
1440 #endif /* PPP_SUPPORT */\r