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