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