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