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