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