]> git.ozlabs.org Git - ppp.git/blob - pppd/ipcp.c
Patch from Frank Cusack to add support for MSCHAPv2.
[ppp.git] / 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
20 #define RCSID   "$Id: ipcp.c,v 1.60 2002/01/22 16:02:58 dfs Exp $"
21
22 /*
23  * TODO:
24  */
25
26 #include <stdio.h>
27 #include <string.h>
28 #include <stdlib.h>
29 #include <netdb.h>
30 #include <sys/param.h>
31 #include <sys/types.h>
32 #include <sys/socket.h>
33 #include <netinet/in.h>
34 #include <arpa/inet.h>
35
36 #include "pppd.h"
37 #include "fsm.h"
38 #include "ipcp.h"
39 #include "pathnames.h"
40
41 static const char rcsid[] = RCSID;
42
43 /* global vars */
44 ipcp_options ipcp_wantoptions[NUM_PPP]; /* Options that we want to request */
45 ipcp_options ipcp_gotoptions[NUM_PPP];  /* Options that peer ack'd */
46 ipcp_options ipcp_allowoptions[NUM_PPP]; /* Options we allow peer to request */
47 ipcp_options ipcp_hisoptions[NUM_PPP];  /* Options that we ack'd */
48
49 u_int32_t netmask = 0;          /* IP netmask to set on interface */
50
51 bool    disable_defaultip = 0;  /* Don't use hostname for default IP adrs */
52
53 /* Hook for a plugin to know when IP protocol has come up */
54 void (*ip_up_hook) __P((void)) = NULL;
55
56 /* Hook for a plugin to know when IP protocol has come down */
57 void (*ip_down_hook) __P((void)) = NULL;
58
59 /* Hook for a plugin to choose the remote IP address */
60 void (*ip_choose_hook) __P((u_int32_t *)) = NULL;
61
62 /* Notifiers for when IPCP goes up and down */
63 struct notifier *ip_up_notifier = NULL;
64 struct notifier *ip_down_notifier = NULL;
65
66 /* local vars */
67 static int default_route_set[NUM_PPP];  /* Have set up a default route */
68 static int proxy_arp_set[NUM_PPP];      /* Have created proxy arp entry */
69 static bool usepeerdns;                 /* Ask peer for DNS addrs */
70 static int ipcp_is_up;                  /* have called np_up() */
71 static bool ask_for_local;              /* request our address from peer */
72 static char vj_value[8];                /* string form of vj option value */
73 static char netmask_str[20];            /* string form of netmask value */
74
75 /*
76  * Callbacks for fsm code.  (CI = Configuration Information)
77  */
78 static void ipcp_resetci __P((fsm *));  /* Reset our CI */
79 static int  ipcp_cilen __P((fsm *));            /* Return length of our CI */
80 static void ipcp_addci __P((fsm *, u_char *, int *)); /* Add our CI */
81 static int  ipcp_ackci __P((fsm *, u_char *, int));     /* Peer ack'd our CI */
82 static int  ipcp_nakci __P((fsm *, u_char *, int));     /* Peer nak'd our CI */
83 static int  ipcp_rejci __P((fsm *, u_char *, int));     /* Peer rej'd our CI */
84 static int  ipcp_reqci __P((fsm *, u_char *, int *, int)); /* Rcv CI */
85 static void ipcp_up __P((fsm *));               /* We're UP */
86 static void ipcp_down __P((fsm *));             /* We're DOWN */
87 static void ipcp_finished __P((fsm *)); /* Don't need lower layer */
88
89 fsm ipcp_fsm[NUM_PPP];          /* IPCP fsm structure */
90
91 static fsm_callbacks ipcp_callbacks = { /* IPCP callback routines */
92     ipcp_resetci,               /* Reset our Configuration Information */
93     ipcp_cilen,                 /* Length of our Configuration Information */
94     ipcp_addci,                 /* Add our Configuration Information */
95     ipcp_ackci,                 /* ACK our Configuration Information */
96     ipcp_nakci,                 /* NAK our Configuration Information */
97     ipcp_rejci,                 /* Reject our Configuration Information */
98     ipcp_reqci,                 /* Request peer's Configuration Information */
99     ipcp_up,                    /* Called when fsm reaches OPENED state */
100     ipcp_down,                  /* Called when fsm leaves OPENED state */
101     NULL,                       /* Called when we want the lower layer up */
102     ipcp_finished,              /* Called when we want the lower layer down */
103     NULL,                       /* Called when Protocol-Reject received */
104     NULL,                       /* Retransmission is necessary */
105     NULL,                       /* Called to handle protocol-specific codes */
106     "IPCP"                      /* String name of protocol */
107 };
108
109 /*
110  * Command-line options.
111  */
112 static int setvjslots __P((char **));
113 static int setdnsaddr __P((char **));
114 static int setwinsaddr __P((char **));
115 static int setnetmask __P((char **));
116 int setipaddr __P((char *, char **, int));
117 static void printipaddr __P((option_t *, void (*)(void *, char *,...),void *));
118
119 static option_t ipcp_option_list[] = {
120     { "noip", o_bool, &ipcp_protent.enabled_flag,
121       "Disable IP and IPCP" },
122     { "-ip", o_bool, &ipcp_protent.enabled_flag,
123       "Disable IP and IPCP", OPT_ALIAS },
124
125     { "novj", o_bool, &ipcp_wantoptions[0].neg_vj,
126       "Disable VJ compression", OPT_A2CLR, &ipcp_allowoptions[0].neg_vj },
127     { "-vj", o_bool, &ipcp_wantoptions[0].neg_vj,
128       "Disable VJ compression", OPT_ALIAS | OPT_A2CLR,
129       &ipcp_allowoptions[0].neg_vj },
130
131     { "novjccomp", o_bool, &ipcp_wantoptions[0].cflag,
132       "Disable VJ connection-ID compression", OPT_A2CLR,
133       &ipcp_allowoptions[0].cflag },
134     { "-vjccomp", o_bool, &ipcp_wantoptions[0].cflag,
135       "Disable VJ connection-ID compression", OPT_ALIAS | OPT_A2CLR,
136       &ipcp_allowoptions[0].cflag },
137
138     { "vj-max-slots", o_special, (void *)setvjslots,
139       "Set maximum VJ header slots",
140       OPT_PRIO | OPT_A2STRVAL | OPT_STATIC, vj_value },
141
142     { "ipcp-accept-local", o_bool, &ipcp_wantoptions[0].accept_local,
143       "Accept peer's address for us", 1 },
144     { "ipcp-accept-remote", o_bool, &ipcp_wantoptions[0].accept_remote,
145       "Accept peer's address for it", 1 },
146
147     { "ipparam", o_string, &ipparam,
148       "Set ip script parameter", OPT_PRIO },
149
150     { "noipdefault", o_bool, &disable_defaultip,
151       "Don't use name for default IP adrs", 1 },
152
153     { "ms-dns", 1, (void *)setdnsaddr,
154       "DNS address for the peer's use" },
155     { "ms-wins", 1, (void *)setwinsaddr,
156       "Nameserver for SMB over TCP/IP for peer" },
157
158     { "ipcp-restart", o_int, &ipcp_fsm[0].timeouttime,
159       "Set timeout for IPCP", OPT_PRIO },
160     { "ipcp-max-terminate", o_int, &ipcp_fsm[0].maxtermtransmits,
161       "Set max #xmits for term-reqs", OPT_PRIO },
162     { "ipcp-max-configure", o_int, &ipcp_fsm[0].maxconfreqtransmits,
163       "Set max #xmits for conf-reqs", OPT_PRIO },
164     { "ipcp-max-failure", o_int, &ipcp_fsm[0].maxnakloops,
165       "Set max #conf-naks for IPCP", OPT_PRIO },
166
167     { "defaultroute", o_bool, &ipcp_wantoptions[0].default_route,
168       "Add default route", OPT_ENABLE|1, &ipcp_allowoptions[0].default_route },
169     { "nodefaultroute", o_bool, &ipcp_allowoptions[0].default_route,
170       "disable defaultroute option", OPT_A2CLR,
171       &ipcp_wantoptions[0].default_route },
172     { "-defaultroute", o_bool, &ipcp_allowoptions[0].default_route,
173       "disable defaultroute option", OPT_ALIAS | OPT_A2CLR,
174       &ipcp_wantoptions[0].default_route },
175
176     { "proxyarp", o_bool, &ipcp_wantoptions[0].proxy_arp,
177       "Add proxy ARP entry", OPT_ENABLE|1, &ipcp_allowoptions[0].proxy_arp },
178     { "noproxyarp", o_bool, &ipcp_allowoptions[0].proxy_arp,
179       "disable proxyarp option", OPT_A2CLR,
180       &ipcp_wantoptions[0].proxy_arp },
181     { "-proxyarp", o_bool, &ipcp_allowoptions[0].proxy_arp,
182       "disable proxyarp option", OPT_ALIAS | OPT_A2CLR,
183       &ipcp_wantoptions[0].proxy_arp },
184
185     { "usepeerdns", o_bool, &usepeerdns,
186       "Ask peer for DNS address(es)", 1 },
187
188     { "netmask", o_special, (void *)setnetmask,
189       "set netmask", OPT_PRIO | OPT_A2STRVAL | OPT_STATIC, netmask_str },
190
191     { "IP addresses", o_wild, (void *) &setipaddr,
192       "set local and remote IP addresses",
193       OPT_NOARG | OPT_A2PRINTER, (void *) &printipaddr },
194
195     { NULL }
196 };
197
198 /*
199  * Protocol entry points from main code.
200  */
201 static void ipcp_init __P((int));
202 static void ipcp_open __P((int));
203 static void ipcp_close __P((int, char *));
204 static void ipcp_lowerup __P((int));
205 static void ipcp_lowerdown __P((int));
206 static void ipcp_input __P((int, u_char *, int));
207 static void ipcp_protrej __P((int));
208 static int  ipcp_printpkt __P((u_char *, int,
209                                void (*) __P((void *, char *, ...)), void *));
210 static void ip_check_options __P((void));
211 static int  ip_demand_conf __P((int));
212 static int  ip_active_pkt __P((u_char *, int));
213 static void create_resolv __P((u_int32_t, u_int32_t));
214
215 struct protent ipcp_protent = {
216     PPP_IPCP,
217     ipcp_init,
218     ipcp_input,
219     ipcp_protrej,
220     ipcp_lowerup,
221     ipcp_lowerdown,
222     ipcp_open,
223     ipcp_close,
224     ipcp_printpkt,
225     NULL,
226     1,
227     "IPCP",
228     "IP",
229     ipcp_option_list,
230     ip_check_options,
231     ip_demand_conf,
232     ip_active_pkt
233 };
234
235 static void ipcp_clear_addrs __P((int, u_int32_t, u_int32_t));
236 static void ipcp_script __P((char *));          /* Run an up/down script */
237 static void ipcp_script_done __P((void *));
238
239 /*
240  * Lengths of configuration options.
241  */
242 #define CILEN_VOID      2
243 #define CILEN_COMPRESS  4       /* min length for compression protocol opt. */
244 #define CILEN_VJ        6       /* length for RFC1332 Van-Jacobson opt. */
245 #define CILEN_ADDR      6       /* new-style single address option */
246 #define CILEN_ADDRS     10      /* old-style dual address option */
247
248
249 #define CODENAME(x)     ((x) == CONFACK ? "ACK" : \
250                          (x) == CONFNAK ? "NAK" : "REJ")
251
252 /*
253  * This state variable is used to ensure that we don't
254  * run an ipcp-up/down script while one is already running.
255  */
256 static enum script_state {
257     s_down,
258     s_up,
259 } ipcp_script_state;
260 static pid_t ipcp_script_pid;
261
262 /*
263  * Make a string representation of a network IP address.
264  */
265 char *
266 ip_ntoa(ipaddr)
267 u_int32_t ipaddr;
268 {
269     static char b[64];
270
271     slprintf(b, sizeof(b), "%I", ipaddr);
272     return b;
273 }
274
275 /*
276  * Option parsing.
277  */
278
279 /*
280  * setvjslots - set maximum number of connection slots for VJ compression
281  */
282 static int
283 setvjslots(argv)
284     char **argv;
285 {
286     int value;
287
288     if (!int_option(*argv, &value))
289         return 0;
290     if (value < 2 || value > 16) {
291         option_error("vj-max-slots value must be between 2 and 16");
292         return 0;
293     }
294     ipcp_wantoptions [0].maxslotindex =
295         ipcp_allowoptions[0].maxslotindex = value - 1;
296     slprintf(vj_value, sizeof(vj_value), "%d", value);
297     return 1;
298 }
299
300 /*
301  * setdnsaddr - set the dns address(es)
302  */
303 static int
304 setdnsaddr(argv)
305     char **argv;
306 {
307     u_int32_t dns;
308     struct hostent *hp;
309
310     dns = inet_addr(*argv);
311     if (dns == (u_int32_t) -1) {
312         if ((hp = gethostbyname(*argv)) == NULL) {
313             option_error("invalid address parameter '%s' for ms-dns option",
314                          *argv);
315             return 0;
316         }
317         dns = *(u_int32_t *)hp->h_addr;
318     }
319
320     /* We take the last 2 values given, the 2nd-last as the primary
321        and the last as the secondary.  If only one is given it
322        becomes both primary and secondary. */
323     if (ipcp_allowoptions[0].dnsaddr[1] == 0)
324         ipcp_allowoptions[0].dnsaddr[0] = dns;
325     else
326         ipcp_allowoptions[0].dnsaddr[0] = ipcp_allowoptions[0].dnsaddr[1];
327
328     /* always set the secondary address value. */
329     ipcp_allowoptions[0].dnsaddr[1] = dns;
330
331     return (1);
332 }
333
334 /*
335  * setwinsaddr - set the wins address(es)
336  * This is primrarly used with the Samba package under UNIX or for pointing
337  * the caller to the existing WINS server on a Windows NT platform.
338  */
339 static int
340 setwinsaddr(argv)
341     char **argv;
342 {
343     u_int32_t wins;
344     struct hostent *hp;
345
346     wins = inet_addr(*argv);
347     if (wins == (u_int32_t) -1) {
348         if ((hp = gethostbyname(*argv)) == NULL) {
349             option_error("invalid address parameter '%s' for ms-wins option",
350                          *argv);
351             return 0;
352         }
353         wins = *(u_int32_t *)hp->h_addr;
354     }
355
356     /* We take the last 2 values given, the 2nd-last as the primary
357        and the last as the secondary.  If only one is given it
358        becomes both primary and secondary. */
359     if (ipcp_allowoptions[0].winsaddr[1] == 0)
360         ipcp_allowoptions[0].winsaddr[0] = wins;
361     else
362         ipcp_allowoptions[0].winsaddr[0] = ipcp_allowoptions[0].winsaddr[1];
363
364     /* always set the secondary address value. */
365     ipcp_allowoptions[0].winsaddr[1] = wins;
366
367     return (1);
368 }
369
370 /*
371  * setipaddr - Set the IP address
372  * If doit is 0, the call is to check whether this option is
373  * potentially an IP address specification.
374  * Not static so that plugins can call it to set the addresses
375  */
376 int
377 setipaddr(arg, argv, doit)
378     char *arg;
379     char **argv;
380     int doit;
381 {
382     struct hostent *hp;
383     char *colon;
384     u_int32_t local, remote;
385     ipcp_options *wo = &ipcp_wantoptions[0];
386     static int prio_local = 0, prio_remote = 0;
387
388     /*
389      * IP address pair separated by ":".
390      */
391     if ((colon = strchr(arg, ':')) == NULL)
392         return 0;
393     if (!doit)
394         return 1;
395   
396     /*
397      * If colon first character, then no local addr.
398      */
399     if (colon != arg && option_priority >= prio_local) {
400         *colon = '\0';
401         if ((local = inet_addr(arg)) == (u_int32_t) -1) {
402             if ((hp = gethostbyname(arg)) == NULL) {
403                 option_error("unknown host: %s", arg);
404                 return 0;
405             }
406             local = *(u_int32_t *)hp->h_addr;
407         }
408         if (bad_ip_adrs(local)) {
409             option_error("bad local IP address %s", ip_ntoa(local));
410             return 0;
411         }
412         if (local != 0)
413             wo->ouraddr = local;
414         *colon = ':';
415         prio_local = option_priority;
416     }
417   
418     /*
419      * If colon last character, then no remote addr.
420      */
421     if (*++colon != '\0' && option_priority >= prio_remote) {
422         if ((remote = inet_addr(colon)) == (u_int32_t) -1) {
423             if ((hp = gethostbyname(colon)) == NULL) {
424                 option_error("unknown host: %s", colon);
425                 return 0;
426             }
427             remote = *(u_int32_t *)hp->h_addr;
428             if (remote_name[0] == 0)
429                 strlcpy(remote_name, colon, sizeof(remote_name));
430         }
431         if (bad_ip_adrs(remote)) {
432             option_error("bad remote IP address %s", ip_ntoa(remote));
433             return 0;
434         }
435         if (remote != 0)
436             wo->hisaddr = remote;
437         prio_remote = option_priority;
438     }
439
440     return 1;
441 }
442
443 static void
444 printipaddr(opt, printer, arg)
445     option_t *opt;
446     void (*printer) __P((void *, char *, ...));
447     void *arg;
448 {
449         ipcp_options *wo = &ipcp_wantoptions[0];
450
451         if (wo->ouraddr != 0)
452                 printer(arg, "%I", wo->ouraddr);
453         printer(arg, ":");
454         if (wo->hisaddr != 0)
455                 printer(arg, "%I", wo->hisaddr);
456 }
457
458 /*
459  * setnetmask - set the netmask to be used on the interface.
460  */
461 static int
462 setnetmask(argv)
463     char **argv;
464 {
465     u_int32_t mask;
466     int n;
467     char *p;
468
469     /*
470      * Unfortunately, if we use inet_addr, we can't tell whether
471      * a result of all 1s is an error or a valid 255.255.255.255.
472      */
473     p = *argv;
474     n = parse_dotted_ip(p, &mask);
475
476     mask = htonl(mask);
477
478     if (n == 0 || p[n] != 0 || (netmask & ~mask) != 0) {
479         option_error("invalid netmask value '%s'", *argv);
480         return 0;
481     }
482
483     netmask = mask;
484     slprintf(netmask_str, sizeof(netmask_str), "%I", mask);
485
486     return (1);
487 }
488
489 int
490 parse_dotted_ip(p, vp)
491     char *p;
492     u_int32_t *vp;
493 {
494     int n;
495     u_int32_t v, b;
496     char *endp, *p0 = p;
497
498     v = 0;
499     for (n = 3;; --n) {
500         b = strtoul(p, &endp, 0);
501         if (endp == p)
502             return 0;
503         if (b > 255) {
504             if (n < 3)
505                 return 0;
506             /* accept e.g. 0xffffff00 */
507             *vp = b;
508             return endp - p0;
509         }
510         v |= b << (n * 8);
511         p = endp;
512         if (n == 0)
513             break;
514         if (*p != '.')
515             return 0;
516         ++p;
517     }
518     *vp = v;
519     return p - p0;
520 }
521
522
523 /*
524  * ipcp_init - Initialize IPCP.
525  */
526 static void
527 ipcp_init(unit)
528     int unit;
529 {
530     fsm *f = &ipcp_fsm[unit];
531     ipcp_options *wo = &ipcp_wantoptions[unit];
532     ipcp_options *ao = &ipcp_allowoptions[unit];
533
534     f->unit = unit;
535     f->protocol = PPP_IPCP;
536     f->callbacks = &ipcp_callbacks;
537     fsm_init(&ipcp_fsm[unit]);
538
539     memset(wo, 0, sizeof(*wo));
540     memset(ao, 0, sizeof(*ao));
541
542     wo->neg_addr = 1;
543     wo->neg_vj = 1;
544     wo->vj_protocol = IPCP_VJ_COMP;
545     wo->maxslotindex = MAX_STATES - 1; /* really max index */
546     wo->cflag = 1;
547
548
549     /* max slots and slot-id compression are currently hardwired in */
550     /* ppp_if.c to 16 and 1, this needs to be changed (among other */
551     /* things) gmc */
552
553     ao->neg_addr = 1;
554     ao->neg_vj = 1;
555     ao->maxslotindex = MAX_STATES - 1;
556     ao->cflag = 1;
557
558     /*
559      * XXX These control whether the user may use the proxyarp
560      * and defaultroute options.
561      */
562     ao->proxy_arp = 1;
563     ao->default_route = 1;
564 }
565
566
567 /*
568  * ipcp_open - IPCP is allowed to come up.
569  */
570 static void
571 ipcp_open(unit)
572     int unit;
573 {
574     fsm_open(&ipcp_fsm[unit]);
575 }
576
577
578 /*
579  * ipcp_close - Take IPCP down.
580  */
581 static void
582 ipcp_close(unit, reason)
583     int unit;
584     char *reason;
585 {
586     fsm_close(&ipcp_fsm[unit], reason);
587 }
588
589
590 /*
591  * ipcp_lowerup - The lower layer is up.
592  */
593 static void
594 ipcp_lowerup(unit)
595     int unit;
596 {
597     fsm_lowerup(&ipcp_fsm[unit]);
598 }
599
600
601 /*
602  * ipcp_lowerdown - The lower layer is down.
603  */
604 static void
605 ipcp_lowerdown(unit)
606     int unit;
607 {
608     fsm_lowerdown(&ipcp_fsm[unit]);
609 }
610
611
612 /*
613  * ipcp_input - Input IPCP packet.
614  */
615 static void
616 ipcp_input(unit, p, len)
617     int unit;
618     u_char *p;
619     int len;
620 {
621     fsm_input(&ipcp_fsm[unit], p, len);
622 }
623
624
625 /*
626  * ipcp_protrej - A Protocol-Reject was received for IPCP.
627  *
628  * Pretend the lower layer went down, so we shut up.
629  */
630 static void
631 ipcp_protrej(unit)
632     int unit;
633 {
634     fsm_lowerdown(&ipcp_fsm[unit]);
635 }
636
637
638 /*
639  * ipcp_resetci - Reset our CI.
640  * Called by fsm_sconfreq, Send Configure Request.
641  */
642 static void
643 ipcp_resetci(f)
644     fsm *f;
645 {
646     ipcp_options *wo = &ipcp_wantoptions[f->unit];
647     ipcp_options *go = &ipcp_gotoptions[f->unit];
648
649     wo->req_addr = wo->neg_addr && ipcp_allowoptions[f->unit].neg_addr;
650     if (wo->ouraddr == 0)
651         wo->accept_local = 1;
652     if (wo->hisaddr == 0)
653         wo->accept_remote = 1;
654     wo->req_dns1 = usepeerdns;  /* Request DNS addresses from the peer */
655     wo->req_dns2 = usepeerdns;
656     *go = *wo;
657     if (!ask_for_local)
658         go->ouraddr = 0;
659     if (ip_choose_hook) {
660         ip_choose_hook(&wo->hisaddr);
661         if (wo->hisaddr) {
662             wo->accept_remote = 0;
663         }
664     }
665 }
666
667
668 /*
669  * ipcp_cilen - Return length of our CI.
670  * Called by fsm_sconfreq, Send Configure Request.
671  */
672 static int
673 ipcp_cilen(f)
674     fsm *f;
675 {
676     ipcp_options *go = &ipcp_gotoptions[f->unit];
677     ipcp_options *wo = &ipcp_wantoptions[f->unit];
678     ipcp_options *ho = &ipcp_hisoptions[f->unit];
679
680 #define LENCIVJ(neg, old)       (neg ? (old? CILEN_COMPRESS : CILEN_VJ) : 0)
681 #define LENCIADDR(neg, old)     (neg ? (old? CILEN_ADDRS : CILEN_ADDR) : 0)
682 #define LENCIDNS(neg)           (neg ? (CILEN_ADDR) : 0)
683
684     /*
685      * First see if we want to change our options to the old
686      * forms because we have received old forms from the peer.
687      */
688     if (wo->neg_addr && !go->neg_addr && !go->old_addrs) {
689         /* use the old style of address negotiation */
690         go->neg_addr = 1;
691         go->old_addrs = 1;
692     }
693     if (wo->neg_vj && !go->neg_vj && !go->old_vj) {
694         /* try an older style of VJ negotiation */
695         /* use the old style only if the peer did */
696         if (ho->neg_vj && ho->old_vj) {
697             go->neg_vj = 1;
698             go->old_vj = 1;
699             go->vj_protocol = ho->vj_protocol;
700         }
701     }
702
703     return (LENCIADDR(go->neg_addr, go->old_addrs) +
704             LENCIVJ(go->neg_vj, go->old_vj) +
705             LENCIDNS(go->req_dns1) +
706             LENCIDNS(go->req_dns2)) ;
707 }
708
709
710 /*
711  * ipcp_addci - Add our desired CIs to a packet.
712  * Called by fsm_sconfreq, Send Configure Request.
713  */
714 static void
715 ipcp_addci(f, ucp, lenp)
716     fsm *f;
717     u_char *ucp;
718     int *lenp;
719 {
720     ipcp_options *go = &ipcp_gotoptions[f->unit];
721     int len = *lenp;
722
723 #define ADDCIVJ(opt, neg, val, old, maxslotindex, cflag) \
724     if (neg) { \
725         int vjlen = old? CILEN_COMPRESS : CILEN_VJ; \
726         if (len >= vjlen) { \
727             PUTCHAR(opt, ucp); \
728             PUTCHAR(vjlen, ucp); \
729             PUTSHORT(val, ucp); \
730             if (!old) { \
731                 PUTCHAR(maxslotindex, ucp); \
732                 PUTCHAR(cflag, ucp); \
733             } \
734             len -= vjlen; \
735         } else \
736             neg = 0; \
737     }
738
739 #define ADDCIADDR(opt, neg, old, val1, val2) \
740     if (neg) { \
741         int addrlen = (old? CILEN_ADDRS: CILEN_ADDR); \
742         if (len >= addrlen) { \
743             u_int32_t l; \
744             PUTCHAR(opt, ucp); \
745             PUTCHAR(addrlen, ucp); \
746             l = ntohl(val1); \
747             PUTLONG(l, ucp); \
748             if (old) { \
749                 l = ntohl(val2); \
750                 PUTLONG(l, ucp); \
751             } \
752             len -= addrlen; \
753         } else \
754             neg = 0; \
755     }
756
757 #define ADDCIDNS(opt, neg, addr) \
758     if (neg) { \
759         if (len >= CILEN_ADDR) { \
760             u_int32_t l; \
761             PUTCHAR(opt, ucp); \
762             PUTCHAR(CILEN_ADDR, ucp); \
763             l = ntohl(addr); \
764             PUTLONG(l, ucp); \
765             len -= CILEN_ADDR; \
766         } else \
767             neg = 0; \
768     }
769
770     ADDCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), go->neg_addr,
771               go->old_addrs, go->ouraddr, go->hisaddr);
772
773     ADDCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj,
774             go->maxslotindex, go->cflag);
775
776     ADDCIDNS(CI_MS_DNS1, go->req_dns1, go->dnsaddr[0]);
777
778     ADDCIDNS(CI_MS_DNS2, go->req_dns2, go->dnsaddr[1]);
779
780     *lenp -= len;
781 }
782
783
784 /*
785  * ipcp_ackci - Ack our CIs.
786  * Called by fsm_rconfack, Receive Configure ACK.
787  *
788  * Returns:
789  *      0 - Ack was bad.
790  *      1 - Ack was good.
791  */
792 static int
793 ipcp_ackci(f, p, len)
794     fsm *f;
795     u_char *p;
796     int len;
797 {
798     ipcp_options *go = &ipcp_gotoptions[f->unit];
799     u_short cilen, citype, cishort;
800     u_int32_t cilong;
801     u_char cimaxslotindex, cicflag;
802
803     /*
804      * CIs must be in exactly the same order that we sent...
805      * Check packet length and CI length at each step.
806      * If we find any deviations, then this packet is bad.
807      */
808
809 #define ACKCIVJ(opt, neg, val, old, maxslotindex, cflag) \
810     if (neg) { \
811         int vjlen = old? CILEN_COMPRESS : CILEN_VJ; \
812         if ((len -= vjlen) < 0) \
813             goto bad; \
814         GETCHAR(citype, p); \
815         GETCHAR(cilen, p); \
816         if (cilen != vjlen || \
817             citype != opt)  \
818             goto bad; \
819         GETSHORT(cishort, p); \
820         if (cishort != val) \
821             goto bad; \
822         if (!old) { \
823             GETCHAR(cimaxslotindex, p); \
824             if (cimaxslotindex != maxslotindex) \
825                 goto bad; \
826             GETCHAR(cicflag, p); \
827             if (cicflag != cflag) \
828                 goto bad; \
829         } \
830     }
831
832 #define ACKCIADDR(opt, neg, old, val1, val2) \
833     if (neg) { \
834         int addrlen = (old? CILEN_ADDRS: CILEN_ADDR); \
835         u_int32_t l; \
836         if ((len -= addrlen) < 0) \
837             goto bad; \
838         GETCHAR(citype, p); \
839         GETCHAR(cilen, p); \
840         if (cilen != addrlen || \
841             citype != opt) \
842             goto bad; \
843         GETLONG(l, p); \
844         cilong = htonl(l); \
845         if (val1 != cilong) \
846             goto bad; \
847         if (old) { \
848             GETLONG(l, p); \
849             cilong = htonl(l); \
850             if (val2 != cilong) \
851                 goto bad; \
852         } \
853     }
854
855 #define ACKCIDNS(opt, neg, addr) \
856     if (neg) { \
857         u_int32_t l; \
858         if ((len -= CILEN_ADDR) < 0) \
859             goto bad; \
860         GETCHAR(citype, p); \
861         GETCHAR(cilen, p); \
862         if (cilen != CILEN_ADDR || citype != opt) \
863             goto bad; \
864         GETLONG(l, p); \
865         cilong = htonl(l); \
866         if (addr != cilong) \
867             goto bad; \
868     }
869
870     ACKCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), go->neg_addr,
871               go->old_addrs, go->ouraddr, go->hisaddr);
872
873     ACKCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj,
874             go->maxslotindex, go->cflag);
875
876     ACKCIDNS(CI_MS_DNS1, go->req_dns1, go->dnsaddr[0]);
877
878     ACKCIDNS(CI_MS_DNS2, go->req_dns2, go->dnsaddr[1]);
879
880     /*
881      * If there are any remaining CIs, then this packet is bad.
882      */
883     if (len != 0)
884         goto bad;
885     return (1);
886
887 bad:
888     IPCPDEBUG(("ipcp_ackci: received bad Ack!"));
889     return (0);
890 }
891
892 /*
893  * ipcp_nakci - Peer has sent a NAK for some of our CIs.
894  * This should not modify any state if the Nak is bad
895  * or if IPCP is in the OPENED state.
896  * Calback from fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject.
897  *
898  * Returns:
899  *      0 - Nak was bad.
900  *      1 - Nak was good.
901  */
902 static int
903 ipcp_nakci(f, p, len)
904     fsm *f;
905     u_char *p;
906     int len;
907 {
908     ipcp_options *go = &ipcp_gotoptions[f->unit];
909     u_char cimaxslotindex, cicflag;
910     u_char citype, cilen, *next;
911     u_short cishort;
912     u_int32_t ciaddr1, ciaddr2, l, cidnsaddr;
913     ipcp_options no;            /* options we've seen Naks for */
914     ipcp_options try;           /* options to request next time */
915
916     BZERO(&no, sizeof(no));
917     try = *go;
918
919     /*
920      * Any Nak'd CIs must be in exactly the same order that we sent.
921      * Check packet length and CI length at each step.
922      * If we find any deviations, then this packet is bad.
923      */
924 #define NAKCIADDR(opt, neg, old, code) \
925     if (go->neg && \
926         len >= (cilen = (old? CILEN_ADDRS: CILEN_ADDR)) && \
927         p[1] == cilen && \
928         p[0] == opt) { \
929         len -= cilen; \
930         INCPTR(2, p); \
931         GETLONG(l, p); \
932         ciaddr1 = htonl(l); \
933         if (old) { \
934             GETLONG(l, p); \
935             ciaddr2 = htonl(l); \
936             no.old_addrs = 1; \
937         } else \
938             ciaddr2 = 0; \
939         no.neg = 1; \
940         code \
941     }
942
943 #define NAKCIVJ(opt, neg, code) \
944     if (go->neg && \
945         ((cilen = p[1]) == CILEN_COMPRESS || cilen == CILEN_VJ) && \
946         len >= cilen && \
947         p[0] == opt) { \
948         len -= cilen; \
949         INCPTR(2, p); \
950         GETSHORT(cishort, p); \
951         no.neg = 1; \
952         code \
953     }
954
955 #define NAKCIDNS(opt, neg, code) \
956     if (go->neg && \
957         ((cilen = p[1]) == CILEN_ADDR) && \
958         len >= cilen && \
959         p[0] == opt) { \
960         len -= cilen; \
961         INCPTR(2, p); \
962         GETLONG(l, p); \
963         cidnsaddr = htonl(l); \
964         no.neg = 1; \
965         code \
966     }
967
968     /*
969      * Accept the peer's idea of {our,his} address, if different
970      * from our idea, only if the accept_{local,remote} flag is set.
971      */
972     NAKCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), neg_addr, go->old_addrs,
973               if (go->accept_local && ciaddr1) { /* Do we know our address? */
974                   try.ouraddr = ciaddr1;
975               }
976               if (go->accept_remote && ciaddr2) { /* Does he know his? */
977                   try.hisaddr = ciaddr2;
978               }
979               );
980
981     /*
982      * Accept the peer's value of maxslotindex provided that it
983      * is less than what we asked for.  Turn off slot-ID compression
984      * if the peer wants.  Send old-style compress-type option if
985      * the peer wants.
986      */
987     NAKCIVJ(CI_COMPRESSTYPE, neg_vj,
988             if (cilen == CILEN_VJ) {
989                 GETCHAR(cimaxslotindex, p);
990                 GETCHAR(cicflag, p);
991                 if (cishort == IPCP_VJ_COMP) {
992                     try.old_vj = 0;
993                     if (cimaxslotindex < go->maxslotindex)
994                         try.maxslotindex = cimaxslotindex;
995                     if (!cicflag)
996                         try.cflag = 0;
997                 } else {
998                     try.neg_vj = 0;
999                 }
1000             } else {
1001                 if (cishort == IPCP_VJ_COMP || cishort == IPCP_VJ_COMP_OLD) {
1002                     try.old_vj = 1;
1003                     try.vj_protocol = cishort;
1004                 } else {
1005                     try.neg_vj = 0;
1006                 }
1007             }
1008             );
1009
1010     NAKCIDNS(CI_MS_DNS1, req_dns1,
1011             try.dnsaddr[0] = cidnsaddr;
1012             );
1013
1014     NAKCIDNS(CI_MS_DNS2, req_dns2,
1015             try.dnsaddr[1] = cidnsaddr;
1016             );
1017
1018     /*
1019      * There may be remaining CIs, if the peer is requesting negotiation
1020      * on an option that we didn't include in our request packet.
1021      * If they want to negotiate about IP addresses, we comply.
1022      * If they want us to ask for compression, we refuse.
1023      */
1024     while (len > CILEN_VOID) {
1025         GETCHAR(citype, p);
1026         GETCHAR(cilen, p);
1027         if( (len -= cilen) < 0 )
1028             goto bad;
1029         next = p + cilen - 2;
1030
1031         switch (citype) {
1032         case CI_COMPRESSTYPE:
1033             if (go->neg_vj || no.neg_vj ||
1034                 (cilen != CILEN_VJ && cilen != CILEN_COMPRESS))
1035                 goto bad;
1036             no.neg_vj = 1;
1037             break;
1038         case CI_ADDRS:
1039             if ((go->neg_addr && go->old_addrs) || no.old_addrs
1040                 || cilen != CILEN_ADDRS)
1041                 goto bad;
1042             try.neg_addr = 1;
1043             try.old_addrs = 1;
1044             GETLONG(l, p);
1045             ciaddr1 = htonl(l);
1046             if (ciaddr1 && go->accept_local)
1047                 try.ouraddr = ciaddr1;
1048             GETLONG(l, p);
1049             ciaddr2 = htonl(l);
1050             if (ciaddr2 && go->accept_remote)
1051                 try.hisaddr = ciaddr2;
1052             no.old_addrs = 1;
1053             break;
1054         case CI_ADDR:
1055             if (go->neg_addr || no.neg_addr || cilen != CILEN_ADDR)
1056                 goto bad;
1057             try.old_addrs = 0;
1058             GETLONG(l, p);
1059             ciaddr1 = htonl(l);
1060             if (ciaddr1 && go->accept_local)
1061                 try.ouraddr = ciaddr1;
1062             if (try.ouraddr != 0)
1063                 try.neg_addr = 1;
1064             no.neg_addr = 1;
1065             break;
1066         }
1067         p = next;
1068     }
1069
1070     /*
1071      * OK, the Nak is good.  Now we can update state.
1072      * If there are any remaining options, we ignore them.
1073      */
1074     if (f->state != OPENED)
1075         *go = try;
1076
1077     return 1;
1078
1079 bad:
1080     IPCPDEBUG(("ipcp_nakci: received bad Nak!"));
1081     return 0;
1082 }
1083
1084
1085 /*
1086  * ipcp_rejci - Reject some of our CIs.
1087  * Callback from fsm_rconfnakrej.
1088  */
1089 static int
1090 ipcp_rejci(f, p, len)
1091     fsm *f;
1092     u_char *p;
1093     int len;
1094 {
1095     ipcp_options *go = &ipcp_gotoptions[f->unit];
1096     u_char cimaxslotindex, ciflag, cilen;
1097     u_short cishort;
1098     u_int32_t cilong;
1099     ipcp_options try;           /* options to request next time */
1100
1101     try = *go;
1102     /*
1103      * Any Rejected CIs must be in exactly the same order that we sent.
1104      * Check packet length and CI length at each step.
1105      * If we find any deviations, then this packet is bad.
1106      */
1107 #define REJCIADDR(opt, neg, old, val1, val2) \
1108     if (go->neg && \
1109         len >= (cilen = old? CILEN_ADDRS: CILEN_ADDR) && \
1110         p[1] == cilen && \
1111         p[0] == opt) { \
1112         u_int32_t l; \
1113         len -= cilen; \
1114         INCPTR(2, p); \
1115         GETLONG(l, p); \
1116         cilong = htonl(l); \
1117         /* Check rejected value. */ \
1118         if (cilong != val1) \
1119             goto bad; \
1120         if (old) { \
1121             GETLONG(l, p); \
1122             cilong = htonl(l); \
1123             /* Check rejected value. */ \
1124             if (cilong != val2) \
1125                 goto bad; \
1126         } \
1127         try.neg = 0; \
1128     }
1129
1130 #define REJCIVJ(opt, neg, val, old, maxslot, cflag) \
1131     if (go->neg && \
1132         p[1] == (old? CILEN_COMPRESS : CILEN_VJ) && \
1133         len >= p[1] && \
1134         p[0] == opt) { \
1135         len -= p[1]; \
1136         INCPTR(2, p); \
1137         GETSHORT(cishort, p); \
1138         /* Check rejected value. */  \
1139         if (cishort != val) \
1140             goto bad; \
1141         if (!old) { \
1142            GETCHAR(cimaxslotindex, p); \
1143            if (cimaxslotindex != maxslot) \
1144              goto bad; \
1145            GETCHAR(ciflag, p); \
1146            if (ciflag != cflag) \
1147              goto bad; \
1148         } \
1149         try.neg = 0; \
1150      }
1151
1152 #define REJCIDNS(opt, neg, dnsaddr) \
1153     if (go->neg && \
1154         ((cilen = p[1]) == CILEN_ADDR) && \
1155         len >= cilen && \
1156         p[0] == opt) { \
1157         u_int32_t l; \
1158         len -= cilen; \
1159         INCPTR(2, p); \
1160         GETLONG(l, p); \
1161         cilong = htonl(l); \
1162         /* Check rejected value. */ \
1163         if (cilong != dnsaddr) \
1164             goto bad; \
1165         try.neg = 0; \
1166     }
1167
1168
1169     REJCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), neg_addr,
1170               go->old_addrs, go->ouraddr, go->hisaddr);
1171
1172     REJCIVJ(CI_COMPRESSTYPE, neg_vj, go->vj_protocol, go->old_vj,
1173             go->maxslotindex, go->cflag);
1174
1175     REJCIDNS(CI_MS_DNS1, req_dns1, go->dnsaddr[0]);
1176
1177     REJCIDNS(CI_MS_DNS2, req_dns2, go->dnsaddr[1]);
1178
1179     /*
1180      * If there are any remaining CIs, then this packet is bad.
1181      */
1182     if (len != 0)
1183         goto bad;
1184     /*
1185      * Now we can update state.
1186      */
1187     if (f->state != OPENED)
1188         *go = try;
1189     return 1;
1190
1191 bad:
1192     IPCPDEBUG(("ipcp_rejci: received bad Reject!"));
1193     return 0;
1194 }
1195
1196
1197 /*
1198  * ipcp_reqci - Check the peer's requested CIs and send appropriate response.
1199  * Callback from fsm_rconfreq, Receive Configure Request
1200  *
1201  * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified
1202  * appropriately.  If reject_if_disagree is non-zero, doesn't return
1203  * CONFNAK; returns CONFREJ if it can't return CONFACK.
1204  */
1205 static int
1206 ipcp_reqci(f, inp, len, reject_if_disagree)
1207     fsm *f;
1208     u_char *inp;                /* Requested CIs */
1209     int *len;                   /* Length of requested CIs */
1210     int reject_if_disagree;
1211 {
1212     ipcp_options *wo = &ipcp_wantoptions[f->unit];
1213     ipcp_options *ho = &ipcp_hisoptions[f->unit];
1214     ipcp_options *ao = &ipcp_allowoptions[f->unit];
1215     ipcp_options *go = &ipcp_gotoptions[f->unit];
1216     u_char *cip, *next;         /* Pointer to current and next CIs */
1217     u_short cilen, citype;      /* Parsed len, type */
1218     u_short cishort;            /* Parsed short value */
1219     u_int32_t tl, ciaddr1, ciaddr2;/* Parsed address values */
1220     int rc = CONFACK;           /* Final packet return code */
1221     int orc;                    /* Individual option return code */
1222     u_char *p;                  /* Pointer to next char to parse */
1223     u_char *ucp = inp;          /* Pointer to current output char */
1224     int l = *len;               /* Length left */
1225     u_char maxslotindex, cflag;
1226     int d;
1227
1228     /*
1229      * Reset all his options.
1230      */
1231     BZERO(ho, sizeof(*ho));
1232     
1233     /*
1234      * Process all his options.
1235      */
1236     next = inp;
1237     while (l) {
1238         orc = CONFACK;                  /* Assume success */
1239         cip = p = next;                 /* Remember begining of CI */
1240         if (l < 2 ||                    /* Not enough data for CI header or */
1241             p[1] < 2 ||                 /*  CI length too small or */
1242             p[1] > l) {                 /*  CI length too big? */
1243             IPCPDEBUG(("ipcp_reqci: bad CI length!"));
1244             orc = CONFREJ;              /* Reject bad CI */
1245             cilen = l;                  /* Reject till end of packet */
1246             l = 0;                      /* Don't loop again */
1247             goto endswitch;
1248         }
1249         GETCHAR(citype, p);             /* Parse CI type */
1250         GETCHAR(cilen, p);              /* Parse CI length */
1251         l -= cilen;                     /* Adjust remaining length */
1252         next += cilen;                  /* Step to next CI */
1253
1254         switch (citype) {               /* Check CI type */
1255         case CI_ADDRS:
1256             if (!ao->neg_addr ||
1257                 cilen != CILEN_ADDRS) { /* Check CI length */
1258                 orc = CONFREJ;          /* Reject CI */
1259                 break;
1260             }
1261
1262             /*
1263              * If he has no address, or if we both have his address but
1264              * disagree about it, then NAK it with our idea.
1265              * In particular, if we don't know his address, but he does,
1266              * then accept it.
1267              */
1268             GETLONG(tl, p);             /* Parse source address (his) */
1269             ciaddr1 = htonl(tl);
1270             if (ciaddr1 != wo->hisaddr
1271                 && (ciaddr1 == 0 || !wo->accept_remote)) {
1272                 orc = CONFNAK;
1273                 if (!reject_if_disagree) {
1274                     DECPTR(sizeof(u_int32_t), p);
1275                     tl = ntohl(wo->hisaddr);
1276                     PUTLONG(tl, p);
1277                 }
1278             } else if (ciaddr1 == 0 && wo->hisaddr == 0) {
1279                 /*
1280                  * If neither we nor he knows his address, reject the option.
1281                  */
1282                 orc = CONFREJ;
1283                 wo->req_addr = 0;       /* don't NAK with 0.0.0.0 later */
1284                 break;
1285             }
1286
1287             /*
1288              * If he doesn't know our address, or if we both have our address
1289              * but disagree about it, then NAK it with our idea.
1290              */
1291             GETLONG(tl, p);             /* Parse desination address (ours) */
1292             ciaddr2 = htonl(tl);
1293             if (ciaddr2 != wo->ouraddr) {
1294                 if (ciaddr2 == 0 || !wo->accept_local) {
1295                     orc = CONFNAK;
1296                     if (!reject_if_disagree) {
1297                         DECPTR(sizeof(u_int32_t), p);
1298                         tl = ntohl(wo->ouraddr);
1299                         PUTLONG(tl, p);
1300                     }
1301                 } else {
1302                     go->ouraddr = ciaddr2;      /* accept peer's idea */
1303                 }
1304             }
1305
1306             ho->neg_addr = 1;
1307             ho->old_addrs = 1;
1308             ho->hisaddr = ciaddr1;
1309             ho->ouraddr = ciaddr2;
1310             break;
1311
1312         case CI_ADDR:
1313             if (!ao->neg_addr ||
1314                 cilen != CILEN_ADDR) {  /* Check CI length */
1315                 orc = CONFREJ;          /* Reject CI */
1316                 break;
1317             }
1318
1319             /*
1320              * If he has no address, or if we both have his address but
1321              * disagree about it, then NAK it with our idea.
1322              * In particular, if we don't know his address, but he does,
1323              * then accept it.
1324              */
1325             GETLONG(tl, p);     /* Parse source address (his) */
1326             ciaddr1 = htonl(tl);
1327             if (ciaddr1 != wo->hisaddr
1328                 && (ciaddr1 == 0 || !wo->accept_remote)) {
1329                 orc = CONFNAK;
1330                 if (!reject_if_disagree) {
1331                     DECPTR(sizeof(u_int32_t), p);
1332                     tl = ntohl(wo->hisaddr);
1333                     PUTLONG(tl, p);
1334                 }
1335             } else if (ciaddr1 == 0 && wo->hisaddr == 0) {
1336                 /*
1337                  * Don't ACK an address of 0.0.0.0 - reject it instead.
1338                  */
1339                 orc = CONFREJ;
1340                 wo->req_addr = 0;       /* don't NAK with 0.0.0.0 later */
1341                 break;
1342             }
1343         
1344             ho->neg_addr = 1;
1345             ho->hisaddr = ciaddr1;
1346             break;
1347
1348         case CI_MS_DNS1:
1349         case CI_MS_DNS2:
1350             /* Microsoft primary or secondary DNS request */
1351             d = citype == CI_MS_DNS2;
1352
1353             /* If we do not have a DNS address then we cannot send it */
1354             if (ao->dnsaddr[d] == 0 ||
1355                 cilen != CILEN_ADDR) {  /* Check CI length */
1356                 orc = CONFREJ;          /* Reject CI */
1357                 break;
1358             }
1359             GETLONG(tl, p);
1360             if (htonl(tl) != ao->dnsaddr[d]) {
1361                 DECPTR(sizeof(u_int32_t), p);
1362                 tl = ntohl(ao->dnsaddr[d]);
1363                 PUTLONG(tl, p);
1364                 orc = CONFNAK;
1365             }
1366             break;
1367
1368         case CI_MS_WINS1:
1369         case CI_MS_WINS2:
1370             /* Microsoft primary or secondary WINS request */
1371             d = citype == CI_MS_WINS2;
1372
1373             /* If we do not have a DNS address then we cannot send it */
1374             if (ao->winsaddr[d] == 0 ||
1375                 cilen != CILEN_ADDR) {  /* Check CI length */
1376                 orc = CONFREJ;          /* Reject CI */
1377                 break;
1378             }
1379             GETLONG(tl, p);
1380             if (htonl(tl) != ao->winsaddr[d]) {
1381                 DECPTR(sizeof(u_int32_t), p);
1382                 tl = ntohl(ao->winsaddr[d]);
1383                 PUTLONG(tl, p);
1384                 orc = CONFNAK;
1385             }
1386             break;
1387         
1388         case CI_COMPRESSTYPE:
1389             if (!ao->neg_vj ||
1390                 (cilen != CILEN_VJ && cilen != CILEN_COMPRESS)) {
1391                 orc = CONFREJ;
1392                 break;
1393             }
1394             GETSHORT(cishort, p);
1395
1396             if (!(cishort == IPCP_VJ_COMP ||
1397                   (cishort == IPCP_VJ_COMP_OLD && cilen == CILEN_COMPRESS))) {
1398                 orc = CONFREJ;
1399                 break;
1400             }
1401
1402             ho->neg_vj = 1;
1403             ho->vj_protocol = cishort;
1404             if (cilen == CILEN_VJ) {
1405                 GETCHAR(maxslotindex, p);
1406                 if (maxslotindex > ao->maxslotindex) { 
1407                     orc = CONFNAK;
1408                     if (!reject_if_disagree){
1409                         DECPTR(1, p);
1410                         PUTCHAR(ao->maxslotindex, p);
1411                     }
1412                 }
1413                 GETCHAR(cflag, p);
1414                 if (cflag && !ao->cflag) {
1415                     orc = CONFNAK;
1416                     if (!reject_if_disagree){
1417                         DECPTR(1, p);
1418                         PUTCHAR(wo->cflag, p);
1419                     }
1420                 }
1421                 ho->maxslotindex = maxslotindex;
1422                 ho->cflag = cflag;
1423             } else {
1424                 ho->old_vj = 1;
1425                 ho->maxslotindex = MAX_STATES - 1;
1426                 ho->cflag = 1;
1427             }
1428             break;
1429
1430         default:
1431             orc = CONFREJ;
1432             break;
1433         }
1434 endswitch:
1435         if (orc == CONFACK &&           /* Good CI */
1436             rc != CONFACK)              /*  but prior CI wasnt? */
1437             continue;                   /* Don't send this one */
1438
1439         if (orc == CONFNAK) {           /* Nak this CI? */
1440             if (reject_if_disagree)     /* Getting fed up with sending NAKs? */
1441                 orc = CONFREJ;          /* Get tough if so */
1442             else {
1443                 if (rc == CONFREJ)      /* Rejecting prior CI? */
1444                     continue;           /* Don't send this one */
1445                 if (rc == CONFACK) {    /* Ack'd all prior CIs? */
1446                     rc = CONFNAK;       /* Not anymore... */
1447                     ucp = inp;          /* Backup */
1448                 }
1449             }
1450         }
1451
1452         if (orc == CONFREJ &&           /* Reject this CI */
1453             rc != CONFREJ) {            /*  but no prior ones? */
1454             rc = CONFREJ;
1455             ucp = inp;                  /* Backup */
1456         }
1457
1458         /* Need to move CI? */
1459         if (ucp != cip)
1460             BCOPY(cip, ucp, cilen);     /* Move it */
1461
1462         /* Update output pointer */
1463         INCPTR(cilen, ucp);
1464     }
1465
1466     /*
1467      * If we aren't rejecting this packet, and we want to negotiate
1468      * their address, and they didn't send their address, then we
1469      * send a NAK with a CI_ADDR option appended.  We assume the
1470      * input buffer is long enough that we can append the extra
1471      * option safely.
1472      */
1473     if (rc != CONFREJ && !ho->neg_addr &&
1474         wo->req_addr && !reject_if_disagree) {
1475         if (rc == CONFACK) {
1476             rc = CONFNAK;
1477             ucp = inp;                  /* reset pointer */
1478             wo->req_addr = 0;           /* don't ask again */
1479         }
1480         PUTCHAR(CI_ADDR, ucp);
1481         PUTCHAR(CILEN_ADDR, ucp);
1482         tl = ntohl(wo->hisaddr);
1483         PUTLONG(tl, ucp);
1484     }
1485
1486     *len = ucp - inp;                   /* Compute output length */
1487     IPCPDEBUG(("ipcp: returning Configure-%s", CODENAME(rc)));
1488     return (rc);                        /* Return final code */
1489 }
1490
1491
1492 /*
1493  * ip_check_options - check that any IP-related options are OK,
1494  * and assign appropriate defaults.
1495  */
1496 static void
1497 ip_check_options()
1498 {
1499     struct hostent *hp;
1500     u_int32_t local;
1501     ipcp_options *wo = &ipcp_wantoptions[0];
1502
1503     /*
1504      * Default our local IP address based on our hostname.
1505      * If local IP address already given, don't bother.
1506      */
1507     if (wo->ouraddr == 0 && !disable_defaultip) {
1508         /*
1509          * Look up our hostname (possibly with domain name appended)
1510          * and take the first IP address as our local IP address.
1511          * If there isn't an IP address for our hostname, too bad.
1512          */
1513         wo->accept_local = 1;   /* don't insist on this default value */
1514         if ((hp = gethostbyname(hostname)) != NULL) {
1515             local = *(u_int32_t *)hp->h_addr;
1516             if (local != 0 && !bad_ip_adrs(local))
1517                 wo->ouraddr = local;
1518         }
1519     }
1520     ask_for_local = wo->ouraddr != 0 || !disable_defaultip;
1521 }
1522
1523
1524 /*
1525  * ip_demand_conf - configure the interface as though
1526  * IPCP were up, for use with dial-on-demand.
1527  */
1528 static int
1529 ip_demand_conf(u)
1530     int u;
1531 {
1532     ipcp_options *wo = &ipcp_wantoptions[u];
1533
1534     if (wo->hisaddr == 0) {
1535         /* make up an arbitrary address for the peer */
1536         wo->hisaddr = htonl(0x0a707070 + ifunit);
1537         wo->accept_remote = 1;
1538     }
1539     if (wo->ouraddr == 0) {
1540         /* make up an arbitrary address for us */
1541         wo->ouraddr = htonl(0x0a404040 + ifunit);
1542         wo->accept_local = 1;
1543         ask_for_local = 0;      /* don't tell the peer this address */
1544     }
1545     if (!sifaddr(u, wo->ouraddr, wo->hisaddr, GetMask(wo->ouraddr)))
1546         return 0;
1547     if (!sifup(u))
1548         return 0;
1549     if (!sifnpmode(u, PPP_IP, NPMODE_QUEUE))
1550         return 0;
1551     if (wo->default_route)
1552         if (sifdefaultroute(u, wo->ouraddr, wo->hisaddr))
1553             default_route_set[u] = 1;
1554     if (wo->proxy_arp)
1555         if (sifproxyarp(u, wo->hisaddr))
1556             proxy_arp_set[u] = 1;
1557
1558     notice("local  IP address %I", wo->ouraddr);
1559     notice("remote IP address %I", wo->hisaddr);
1560
1561     return 1;
1562 }
1563
1564
1565 /*
1566  * ipcp_up - IPCP has come UP.
1567  *
1568  * Configure the IP network interface appropriately and bring it up.
1569  */
1570 static void
1571 ipcp_up(f)
1572     fsm *f;
1573 {
1574     u_int32_t mask;
1575     ipcp_options *ho = &ipcp_hisoptions[f->unit];
1576     ipcp_options *go = &ipcp_gotoptions[f->unit];
1577     ipcp_options *wo = &ipcp_wantoptions[f->unit];
1578
1579     IPCPDEBUG(("ipcp: up"));
1580
1581     /*
1582      * We must have a non-zero IP address for both ends of the link.
1583      */
1584     if (!ho->neg_addr)
1585         ho->hisaddr = wo->hisaddr;
1586
1587     if (go->ouraddr == 0) {
1588         error("Could not determine local IP address");
1589         ipcp_close(f->unit, "Could not determine local IP address");
1590         return;
1591     }
1592     if (ho->hisaddr == 0) {
1593         ho->hisaddr = htonl(0x0a404040 + ifunit);
1594         warn("Could not determine remote IP address: defaulting to %I",
1595              ho->hisaddr);
1596     }
1597     script_setenv("IPLOCAL", ip_ntoa(go->ouraddr), 0);
1598     script_setenv("IPREMOTE", ip_ntoa(ho->hisaddr), 1);
1599
1600     if (usepeerdns && (go->dnsaddr[0] || go->dnsaddr[1])) {
1601         script_setenv("USEPEERDNS", "1", 0);
1602         if (go->dnsaddr[0])
1603             script_setenv("DNS1", ip_ntoa(go->dnsaddr[0]), 0);
1604         if (go->dnsaddr[1])
1605             script_setenv("DNS2", ip_ntoa(go->dnsaddr[1]), 0);
1606         create_resolv(go->dnsaddr[0], go->dnsaddr[1]);
1607     }
1608
1609     /*
1610      * Check that the peer is allowed to use the IP address it wants.
1611      */
1612     if (!auth_ip_addr(f->unit, ho->hisaddr)) {
1613         error("Peer is not authorized to use remote address %I", ho->hisaddr);
1614         ipcp_close(f->unit, "Unauthorized remote IP address");
1615         return;
1616     }
1617
1618     /* set tcp compression */
1619     sifvjcomp(f->unit, ho->neg_vj, ho->cflag, ho->maxslotindex);
1620
1621     /*
1622      * If we are doing dial-on-demand, the interface is already
1623      * configured, so we put out any saved-up packets, then set the
1624      * interface to pass IP packets.
1625      */
1626     if (demand) {
1627         if (go->ouraddr != wo->ouraddr || ho->hisaddr != wo->hisaddr) {
1628             ipcp_clear_addrs(f->unit, wo->ouraddr, wo->hisaddr);
1629             if (go->ouraddr != wo->ouraddr) {
1630                 warn("Local IP address changed to %I", go->ouraddr);
1631                 script_setenv("OLDIPLOCAL", ip_ntoa(wo->ouraddr), 0);
1632                 wo->ouraddr = go->ouraddr;
1633             } else
1634                 script_unsetenv("OLDIPLOCAL");
1635             if (ho->hisaddr != wo->hisaddr) {
1636                 warn("Remote IP address changed to %I", ho->hisaddr);
1637                 script_setenv("OLDIPREMOTE", ip_ntoa(wo->hisaddr), 0);
1638                 wo->hisaddr = ho->hisaddr;
1639             } else
1640                 script_unsetenv("OLDIPREMOTE");
1641
1642             /* Set the interface to the new addresses */
1643             mask = GetMask(go->ouraddr);
1644             if (!sifaddr(f->unit, go->ouraddr, ho->hisaddr, mask)) {
1645                 if (debug)
1646                     warn("Interface configuration failed");
1647                 ipcp_close(f->unit, "Interface configuration failed");
1648                 return;
1649             }
1650
1651             /* assign a default route through the interface if required */
1652             if (ipcp_wantoptions[f->unit].default_route) 
1653                 if (sifdefaultroute(f->unit, go->ouraddr, ho->hisaddr))
1654                     default_route_set[f->unit] = 1;
1655
1656             /* Make a proxy ARP entry if requested. */
1657             if (ipcp_wantoptions[f->unit].proxy_arp)
1658                 if (sifproxyarp(f->unit, ho->hisaddr))
1659                     proxy_arp_set[f->unit] = 1;
1660
1661         }
1662         demand_rexmit(PPP_IP);
1663         sifnpmode(f->unit, PPP_IP, NPMODE_PASS);
1664
1665     } else {
1666         /*
1667          * Set IP addresses and (if specified) netmask.
1668          */
1669         mask = GetMask(go->ouraddr);
1670
1671 #if !(defined(SVR4) && (defined(SNI) || defined(__USLC__)))
1672         if (!sifaddr(f->unit, go->ouraddr, ho->hisaddr, mask)) {
1673             if (debug)
1674                 warn("Interface configuration failed");
1675             ipcp_close(f->unit, "Interface configuration failed");
1676             return;
1677         }
1678 #endif
1679
1680         /* bring the interface up for IP */
1681         if (!sifup(f->unit)) {
1682             if (debug)
1683                 warn("Interface failed to come up");
1684             ipcp_close(f->unit, "Interface configuration failed");
1685             return;
1686         }
1687
1688 #if (defined(SVR4) && (defined(SNI) || defined(__USLC__)))
1689         if (!sifaddr(f->unit, go->ouraddr, ho->hisaddr, mask)) {
1690             if (debug)
1691                 warn("Interface configuration failed");
1692             ipcp_close(f->unit, "Interface configuration failed");
1693             return;
1694         }
1695 #endif
1696         sifnpmode(f->unit, PPP_IP, NPMODE_PASS);
1697
1698         /* assign a default route through the interface if required */
1699         if (ipcp_wantoptions[f->unit].default_route) 
1700             if (sifdefaultroute(f->unit, go->ouraddr, ho->hisaddr))
1701                 default_route_set[f->unit] = 1;
1702
1703         /* Make a proxy ARP entry if requested. */
1704         if (ipcp_wantoptions[f->unit].proxy_arp)
1705             if (sifproxyarp(f->unit, ho->hisaddr))
1706                 proxy_arp_set[f->unit] = 1;
1707
1708         ipcp_wantoptions[0].ouraddr = go->ouraddr;
1709
1710         notice("local  IP address %I", go->ouraddr);
1711         notice("remote IP address %I", ho->hisaddr);
1712         if (go->dnsaddr[0])
1713             notice("primary   DNS address %I", go->dnsaddr[0]);
1714         if (go->dnsaddr[1])
1715             notice("secondary DNS address %I", go->dnsaddr[1]);
1716     }
1717
1718     np_up(f->unit, PPP_IP);
1719     ipcp_is_up = 1;
1720
1721     notify(ip_up_notifier, 0);
1722     if (ip_up_hook)
1723         ip_up_hook();
1724
1725     /*
1726      * Execute the ip-up script, like this:
1727      *  /etc/ppp/ip-up interface tty speed local-IP remote-IP
1728      */
1729     if (ipcp_script_state == s_down && ipcp_script_pid == 0) {
1730         ipcp_script_state = s_up;
1731         ipcp_script(_PATH_IPUP);
1732     }
1733 }
1734
1735
1736 /*
1737  * ipcp_down - IPCP has gone DOWN.
1738  *
1739  * Take the IP network interface down, clear its addresses
1740  * and delete routes through it.
1741  */
1742 static void
1743 ipcp_down(f)
1744     fsm *f;
1745 {
1746     IPCPDEBUG(("ipcp: down"));
1747     /* XXX a bit IPv4-centric here, we only need to get the stats
1748      * before the interface is marked down. */
1749     update_link_stats(f->unit);
1750     notify(ip_down_notifier, 0);
1751     if (ip_down_hook)
1752         ip_down_hook();
1753     if (ipcp_is_up) {
1754         ipcp_is_up = 0;
1755         np_down(f->unit, PPP_IP);
1756     }
1757     sifvjcomp(f->unit, 0, 0, 0);
1758
1759     /*
1760      * If we are doing dial-on-demand, set the interface
1761      * to queue up outgoing packets (for now).
1762      */
1763     if (demand) {
1764         sifnpmode(f->unit, PPP_IP, NPMODE_QUEUE);
1765     } else {
1766         sifnpmode(f->unit, PPP_IP, NPMODE_DROP);
1767         sifdown(f->unit);
1768         ipcp_clear_addrs(f->unit, ipcp_gotoptions[f->unit].ouraddr,
1769                          ipcp_hisoptions[f->unit].hisaddr);
1770     }
1771
1772     /* Execute the ip-down script */
1773     if (ipcp_script_state == s_up && ipcp_script_pid == 0) {
1774         ipcp_script_state = s_down;
1775         ipcp_script(_PATH_IPDOWN);
1776     }
1777 }
1778
1779
1780 /*
1781  * ipcp_clear_addrs() - clear the interface addresses, routes,
1782  * proxy arp entries, etc.
1783  */
1784 static void
1785 ipcp_clear_addrs(unit, ouraddr, hisaddr)
1786     int unit;
1787     u_int32_t ouraddr;  /* local address */
1788     u_int32_t hisaddr;  /* remote address */
1789 {
1790     if (proxy_arp_set[unit]) {
1791         cifproxyarp(unit, hisaddr);
1792         proxy_arp_set[unit] = 0;
1793     }
1794     if (default_route_set[unit]) {
1795         cifdefaultroute(unit, ouraddr, hisaddr);
1796         default_route_set[unit] = 0;
1797     }
1798     cifaddr(unit, ouraddr, hisaddr);
1799 }
1800
1801
1802 /*
1803  * ipcp_finished - possibly shut down the lower layers.
1804  */
1805 static void
1806 ipcp_finished(f)
1807     fsm *f;
1808 {
1809     np_finished(f->unit, PPP_IP);
1810 }
1811
1812
1813 /*
1814  * ipcp_script_done - called when the ip-up or ip-down script
1815  * has finished.
1816  */
1817 static void
1818 ipcp_script_done(arg)
1819     void *arg;
1820 {
1821     ipcp_script_pid = 0;
1822     switch (ipcp_script_state) {
1823     case s_up:
1824         if (ipcp_fsm[0].state != OPENED) {
1825             ipcp_script_state = s_down;
1826             ipcp_script(_PATH_IPDOWN);
1827         }
1828         break;
1829     case s_down:
1830         if (ipcp_fsm[0].state == OPENED) {
1831             ipcp_script_state = s_up;
1832             ipcp_script(_PATH_IPUP);
1833         }
1834         break;
1835     }
1836 }
1837
1838
1839 /*
1840  * ipcp_script - Execute a script with arguments
1841  * interface-name tty-name speed local-IP remote-IP.
1842  */
1843 static void
1844 ipcp_script(script)
1845     char *script;
1846 {
1847     char strspeed[32], strlocal[32], strremote[32];
1848     char *argv[8];
1849
1850     slprintf(strspeed, sizeof(strspeed), "%d", baud_rate);
1851     slprintf(strlocal, sizeof(strlocal), "%I", ipcp_gotoptions[0].ouraddr);
1852     slprintf(strremote, sizeof(strremote), "%I", ipcp_hisoptions[0].hisaddr);
1853
1854     argv[0] = script;
1855     argv[1] = ifname;
1856     argv[2] = devnam;
1857     argv[3] = strspeed;
1858     argv[4] = strlocal;
1859     argv[5] = strremote;
1860     argv[6] = ipparam;
1861     argv[7] = NULL;
1862     ipcp_script_pid = run_program(script, argv, 0, ipcp_script_done, NULL);
1863 }
1864
1865 /*
1866  * create_resolv - create the replacement resolv.conf file
1867  */
1868 static void
1869 create_resolv(peerdns1, peerdns2)
1870     u_int32_t peerdns1, peerdns2;
1871 {
1872     FILE *f;
1873
1874     f = fopen(_PATH_RESOLV, "w");
1875     if (f == NULL) {
1876         error("Failed to create %s: %m", _PATH_RESOLV);
1877         return;
1878     }
1879
1880     if (peerdns1)
1881         fprintf(f, "nameserver %s\n", ip_ntoa(peerdns1));
1882
1883     if (peerdns2)
1884         fprintf(f, "nameserver %s\n", ip_ntoa(peerdns2));
1885
1886     if (ferror(f))
1887         error("Write failed to %s: %m", _PATH_RESOLV);
1888
1889     fclose(f);
1890 }
1891
1892 /*
1893  * ipcp_printpkt - print the contents of an IPCP packet.
1894  */
1895 static char *ipcp_codenames[] = {
1896     "ConfReq", "ConfAck", "ConfNak", "ConfRej",
1897     "TermReq", "TermAck", "CodeRej"
1898 };
1899
1900 static int
1901 ipcp_printpkt(p, plen, printer, arg)
1902     u_char *p;
1903     int plen;
1904     void (*printer) __P((void *, char *, ...));
1905     void *arg;
1906 {
1907     int code, id, len, olen;
1908     u_char *pstart, *optend;
1909     u_short cishort;
1910     u_int32_t cilong;
1911
1912     if (plen < HEADERLEN)
1913         return 0;
1914     pstart = p;
1915     GETCHAR(code, p);
1916     GETCHAR(id, p);
1917     GETSHORT(len, p);
1918     if (len < HEADERLEN || len > plen)
1919         return 0;
1920
1921     if (code >= 1 && code <= sizeof(ipcp_codenames) / sizeof(char *))
1922         printer(arg, " %s", ipcp_codenames[code-1]);
1923     else
1924         printer(arg, " code=0x%x", code);
1925     printer(arg, " id=0x%x", id);
1926     len -= HEADERLEN;
1927     switch (code) {
1928     case CONFREQ:
1929     case CONFACK:
1930     case CONFNAK:
1931     case CONFREJ:
1932         /* print option list */
1933         while (len >= 2) {
1934             GETCHAR(code, p);
1935             GETCHAR(olen, p);
1936             p -= 2;
1937             if (olen < 2 || olen > len) {
1938                 break;
1939             }
1940             printer(arg, " <");
1941             len -= olen;
1942             optend = p + olen;
1943             switch (code) {
1944             case CI_ADDRS:
1945                 if (olen == CILEN_ADDRS) {
1946                     p += 2;
1947                     GETLONG(cilong, p);
1948                     printer(arg, "addrs %I", htonl(cilong));
1949                     GETLONG(cilong, p);
1950                     printer(arg, " %I", htonl(cilong));
1951                 }
1952                 break;
1953             case CI_COMPRESSTYPE:
1954                 if (olen >= CILEN_COMPRESS) {
1955                     p += 2;
1956                     GETSHORT(cishort, p);
1957                     printer(arg, "compress ");
1958                     switch (cishort) {
1959                     case IPCP_VJ_COMP:
1960                         printer(arg, "VJ");
1961                         break;
1962                     case IPCP_VJ_COMP_OLD:
1963                         printer(arg, "old-VJ");
1964                         break;
1965                     default:
1966                         printer(arg, "0x%x", cishort);
1967                     }
1968                 }
1969                 break;
1970             case CI_ADDR:
1971                 if (olen == CILEN_ADDR) {
1972                     p += 2;
1973                     GETLONG(cilong, p);
1974                     printer(arg, "addr %I", htonl(cilong));
1975                 }
1976                 break;
1977             case CI_MS_DNS1:
1978             case CI_MS_DNS2:
1979                 p += 2;
1980                 GETLONG(cilong, p);
1981                 printer(arg, "ms-dns%d %I", code - CI_MS_DNS1 + 1,
1982                         htonl(cilong));
1983                 break;
1984             case CI_MS_WINS1:
1985             case CI_MS_WINS2:
1986                 p += 2;
1987                 GETLONG(cilong, p);
1988                 printer(arg, "ms-wins %I", htonl(cilong));
1989                 break;
1990             }
1991             while (p < optend) {
1992                 GETCHAR(code, p);
1993                 printer(arg, " %.2x", code);
1994             }
1995             printer(arg, ">");
1996         }
1997         break;
1998
1999     case TERMACK:
2000     case TERMREQ:
2001         if (len > 0 && *p >= ' ' && *p < 0x7f) {
2002             printer(arg, " ");
2003             print_string((char *)p, len, printer, arg);
2004             p += len;
2005             len = 0;
2006         }
2007         break;
2008     }
2009
2010     /* print the rest of the bytes in the packet */
2011     for (; len > 0; --len) {
2012         GETCHAR(code, p);
2013         printer(arg, " %.2x", code);
2014     }
2015
2016     return p - pstart;
2017 }
2018
2019 /*
2020  * ip_active_pkt - see if this IP packet is worth bringing the link up for.
2021  * We don't bring the link up for IP fragments or for TCP FIN packets
2022  * with no data.
2023  */
2024 #define IP_HDRLEN       20      /* bytes */
2025 #define IP_OFFMASK      0x1fff
2026 #ifndef IPPROTO_TCP
2027 #define IPPROTO_TCP     6
2028 #endif
2029 #define TCP_HDRLEN      20
2030 #define TH_FIN          0x01
2031
2032 /*
2033  * We use these macros because the IP header may be at an odd address,
2034  * and some compilers might use word loads to get th_off or ip_hl.
2035  */
2036
2037 #define net_short(x)    (((x)[0] << 8) + (x)[1])
2038 #define get_iphl(x)     (((unsigned char *)(x))[0] & 0xF)
2039 #define get_ipoff(x)    net_short((unsigned char *)(x) + 6)
2040 #define get_ipproto(x)  (((unsigned char *)(x))[9])
2041 #define get_tcpoff(x)   (((unsigned char *)(x))[12] >> 4)
2042 #define get_tcpflags(x) (((unsigned char *)(x))[13])
2043
2044 static int
2045 ip_active_pkt(pkt, len)
2046     u_char *pkt;
2047     int len;
2048 {
2049     u_char *tcp;
2050     int hlen;
2051
2052     len -= PPP_HDRLEN;
2053     pkt += PPP_HDRLEN;
2054     if (len < IP_HDRLEN)
2055         return 0;
2056     if ((get_ipoff(pkt) & IP_OFFMASK) != 0)
2057         return 0;
2058     if (get_ipproto(pkt) != IPPROTO_TCP)
2059         return 1;
2060     hlen = get_iphl(pkt) * 4;
2061     if (len < hlen + TCP_HDRLEN)
2062         return 0;
2063     tcp = pkt + hlen;
2064     if ((get_tcpflags(tcp) & TH_FIN) != 0 && len == hlen + get_tcpoff(tcp) * 4)
2065         return 0;
2066     return 1;
2067 }