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