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