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