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