]> git.ozlabs.org Git - ppp.git/blob - pppd/ipcp.c
Fix MKDEV and RMDEV.
[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 #ifndef lint
21 static char rcsid[] = "$Id: ipcp.c,v 1.22 1995/12/18 03:45:56 paulus Exp $";
22 #endif
23
24 /*
25  * TODO:
26  */
27
28 #include <stdio.h>
29 #include <string.h>
30 #include <syslog.h>
31 #include <sys/types.h>
32 #include <sys/socket.h>
33 #include <netinet/in.h>
34
35 #include "pppd.h"
36 #include "fsm.h"
37 #include "ipcp.h"
38 #include "pathnames.h"
39
40 /* global vars */
41 ipcp_options ipcp_wantoptions[NUM_PPP]; /* Options that we want to request */
42 ipcp_options ipcp_gotoptions[NUM_PPP];  /* Options that peer ack'd */
43 ipcp_options ipcp_allowoptions[NUM_PPP];        /* Options we allow peer to request */
44 ipcp_options ipcp_hisoptions[NUM_PPP];  /* Options that we ack'd */
45
46 /* local vars */
47 static int cis_received[NUM_PPP];               /* # Conf-Reqs received */
48
49 /*
50  * Callbacks for fsm code.  (CI = Configuration Information)
51  */
52 static void ipcp_resetci __P((fsm *));  /* Reset our CI */
53 static int  ipcp_cilen __P((fsm *));            /* Return length of our CI */
54 static void ipcp_addci __P((fsm *, u_char *, int *)); /* Add our CI */
55 static int  ipcp_ackci __P((fsm *, u_char *, int));     /* Peer ack'd our CI */
56 static int  ipcp_nakci __P((fsm *, u_char *, int));     /* Peer nak'd our CI */
57 static int  ipcp_rejci __P((fsm *, u_char *, int));     /* Peer rej'd our CI */
58 static int  ipcp_reqci __P((fsm *, u_char *, int *, int)); /* Rcv CI */
59 static void ipcp_up __P((fsm *));               /* We're UP */
60 static void ipcp_down __P((fsm *));             /* We're DOWN */
61 static void ipcp_script __P((fsm *, char *)); /* Run an up/down script */
62
63 fsm ipcp_fsm[NUM_PPP];          /* IPCP fsm structure */
64
65 static fsm_callbacks ipcp_callbacks = { /* IPCP callback routines */
66     ipcp_resetci,               /* Reset our Configuration Information */
67     ipcp_cilen,                 /* Length of our Configuration Information */
68     ipcp_addci,                 /* Add our Configuration Information */
69     ipcp_ackci,                 /* ACK our Configuration Information */
70     ipcp_nakci,                 /* NAK our Configuration Information */
71     ipcp_rejci,                 /* Reject our Configuration Information */
72     ipcp_reqci,                 /* Request peer's Configuration Information */
73     ipcp_up,                    /* Called when fsm reaches OPENED state */
74     ipcp_down,                  /* Called when fsm leaves OPENED state */
75     NULL,                       /* Called when we want the lower layer up */
76     NULL,                       /* Called when we want the lower layer down */
77     NULL,                       /* Called when Protocol-Reject received */
78     NULL,                       /* Retransmission is necessary */
79     NULL,                       /* Called to handle protocol-specific codes */
80     "IPCP"                      /* String name of protocol */
81 };
82
83 struct protent ipcp_protent = {
84     PPP_IPCP, ipcp_init, ipcp_input, ipcp_protrej,
85     ipcp_lowerup, ipcp_lowerdown, ipcp_open, ipcp_close,
86     ipcp_printpkt, NULL, 1, "IPCP"
87 };
88
89 /*
90  * Lengths of configuration options.
91  */
92 #define CILEN_VOID      2
93 #define CILEN_COMPRESS  4       /* min length for compression protocol opt. */
94 #define CILEN_VJ        6       /* length for RFC1332 Van-Jacobson opt. */
95 #define CILEN_ADDR      6       /* new-style single address option */
96 #define CILEN_ADDRS     10      /* old-style dual address option */
97
98
99 #define CODENAME(x)     ((x) == CONFACK ? "ACK" : \
100                          (x) == CONFNAK ? "NAK" : "REJ")
101
102
103 /*
104  * Make a string representation of a network IP address.
105  */
106 char *
107 ip_ntoa(ipaddr)
108 u_int32_t ipaddr;
109 {
110     static char b[64];
111
112     ipaddr = ntohl(ipaddr);
113
114     sprintf(b, "%d.%d.%d.%d",
115             (u_char)(ipaddr >> 24),
116             (u_char)(ipaddr >> 16),
117             (u_char)(ipaddr >> 8),
118             (u_char)(ipaddr));
119     return b;
120 }
121
122
123 /*
124  * ipcp_init - Initialize IPCP.
125  */
126 void
127 ipcp_init(unit)
128     int unit;
129 {
130     fsm *f = &ipcp_fsm[unit];
131     ipcp_options *wo = &ipcp_wantoptions[unit];
132     ipcp_options *ao = &ipcp_allowoptions[unit];
133
134     f->unit = unit;
135     f->protocol = PPP_IPCP;
136     f->callbacks = &ipcp_callbacks;
137     fsm_init(&ipcp_fsm[unit]);
138
139     memset(wo, 0, sizeof(*wo));
140     memset(ao, 0, sizeof(*ao));
141
142     wo->neg_addr = 1;
143     wo->neg_vj = 1;
144     wo->vj_protocol = IPCP_VJ_COMP;
145     wo->maxslotindex = MAX_STATES - 1; /* really max index */
146     wo->cflag = 1;
147
148     /* max slots and slot-id compression are currently hardwired in */
149     /* ppp_if.c to 16 and 1, this needs to be changed (among other */
150     /* things) gmc */
151
152     ao->neg_addr = 1;
153     ao->neg_vj = 1;
154     ao->maxslotindex = MAX_STATES - 1;
155     ao->cflag = 1;
156
157     /*
158      * XXX These control whether the user may use the proxyarp
159      * and defaultroute options.
160      */
161     ao->proxy_arp = 1;
162     ao->default_route = 1;
163 }
164
165
166 /*
167  * ipcp_open - IPCP is allowed to come up.
168  */
169 void
170 ipcp_open(unit)
171     int unit;
172 {
173     fsm_open(&ipcp_fsm[unit]);
174 }
175
176
177 /*
178  * ipcp_close - Take IPCP down.
179  */
180 void
181 ipcp_close(unit, reason)
182     int unit;
183     char *reason;
184 {
185     fsm_close(&ipcp_fsm[unit], reason);
186 }
187
188
189 /*
190  * ipcp_lowerup - The lower layer is up.
191  */
192 void
193 ipcp_lowerup(unit)
194     int unit;
195 {
196     fsm_lowerup(&ipcp_fsm[unit]);
197 }
198
199
200 /*
201  * ipcp_lowerdown - The lower layer is down.
202  */
203 void
204 ipcp_lowerdown(unit)
205     int unit;
206 {
207     fsm_lowerdown(&ipcp_fsm[unit]);
208 }
209
210
211 /*
212  * ipcp_input - Input IPCP packet.
213  */
214 void
215 ipcp_input(unit, p, len)
216     int unit;
217     u_char *p;
218     int len;
219 {
220     fsm_input(&ipcp_fsm[unit], p, len);
221 }
222
223
224 /*
225  * ipcp_protrej - A Protocol-Reject was received for IPCP.
226  *
227  * Pretend the lower layer went down, so we shut up.
228  */
229 void
230 ipcp_protrej(unit)
231     int unit;
232 {
233     fsm_lowerdown(&ipcp_fsm[unit]);
234 }
235
236
237 /*
238  * ipcp_resetci - Reset our CI.
239  */
240 static void
241 ipcp_resetci(f)
242     fsm *f;
243 {
244     ipcp_options *wo = &ipcp_wantoptions[f->unit];
245
246     wo->req_addr = wo->neg_addr && ipcp_allowoptions[f->unit].neg_addr;
247     if (wo->ouraddr == 0)
248         wo->accept_local = 1;
249     if (wo->hisaddr == 0)
250         wo->accept_remote = 1;
251     ipcp_gotoptions[f->unit] = *wo;
252     cis_received[f->unit] = 0;
253 }
254
255
256 /*
257  * ipcp_cilen - Return length of our CI.
258  */
259 static int
260 ipcp_cilen(f)
261     fsm *f;
262 {
263     ipcp_options *go = &ipcp_gotoptions[f->unit];
264
265 #define LENCIVJ(neg, old)       (neg ? (old? CILEN_COMPRESS : CILEN_VJ) : 0)
266 #define LENCIADDR(neg, old)     (neg ? (old? CILEN_ADDRS : CILEN_ADDR) : 0)
267
268     return (LENCIADDR(go->neg_addr, go->old_addrs) +
269             LENCIVJ(go->neg_vj, go->old_vj));
270 }
271
272
273 /*
274  * ipcp_addci - Add our desired CIs to a packet.
275  */
276 static void
277 ipcp_addci(f, ucp, lenp)
278     fsm *f;
279     u_char *ucp;
280     int *lenp;
281 {
282     ipcp_options *wo = &ipcp_wantoptions[f->unit];
283     ipcp_options *go = &ipcp_gotoptions[f->unit];
284     ipcp_options *ho = &ipcp_hisoptions[f->unit];
285     int len = *lenp;
286
287 #define ADDCIVJ(opt, neg, val, old, maxslotindex, cflag) \
288     if (neg) { \
289         int vjlen = old? CILEN_COMPRESS : CILEN_VJ; \
290         if (len >= vjlen) { \
291             PUTCHAR(opt, ucp); \
292             PUTCHAR(vjlen, ucp); \
293             PUTSHORT(val, ucp); \
294             if (!old) { \
295                 PUTCHAR(maxslotindex, ucp); \
296                 PUTCHAR(cflag, ucp); \
297             } \
298             len -= vjlen; \
299         } else \
300             neg = 0; \
301     }
302
303 #define ADDCIADDR(opt, neg, old, val1, val2) \
304     if (neg) { \
305         int addrlen = (old? CILEN_ADDRS: CILEN_ADDR); \
306         if (len >= addrlen) { \
307             u_int32_t l; \
308             PUTCHAR(opt, ucp); \
309             PUTCHAR(addrlen, ucp); \
310             l = ntohl(val1); \
311             PUTLONG(l, ucp); \
312             if (old) { \
313                 l = ntohl(val2); \
314                 PUTLONG(l, ucp); \
315             } \
316             len -= addrlen; \
317         } else \
318             neg = 0; \
319     }
320
321     /*
322      * First see if we want to change our options to the old
323      * forms because we have received old forms from the peer.
324      */
325     if (wo->neg_addr && !go->neg_addr && !go->old_addrs) {
326         /* use the old style of address negotiation */
327         go->neg_addr = 1;
328         go->old_addrs = 1;
329     }
330     if (wo->neg_vj && !go->neg_vj && !go->old_vj) {
331         /* try an older style of VJ negotiation */
332         if (cis_received[f->unit] == 0) {
333             /* keep trying the new style until we see some CI from the peer */
334             go->neg_vj = 1;
335         } else {
336             /* use the old style only if the peer did */
337             if (ho->neg_vj && ho->old_vj) {
338                 go->neg_vj = 1;
339                 go->old_vj = 1;
340                 go->vj_protocol = ho->vj_protocol;
341             }
342         }
343     }
344
345     ADDCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), go->neg_addr,
346               go->old_addrs, go->ouraddr, go->hisaddr);
347
348     ADDCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj,
349             go->maxslotindex, go->cflag);
350
351     *lenp -= len;
352 }
353
354
355 /*
356  * ipcp_ackci - Ack our CIs.
357  *
358  * Returns:
359  *      0 - Ack was bad.
360  *      1 - Ack was good.
361  */
362 static int
363 ipcp_ackci(f, p, len)
364     fsm *f;
365     u_char *p;
366     int len;
367 {
368     ipcp_options *go = &ipcp_gotoptions[f->unit];
369     u_short cilen, citype, cishort;
370     u_int32_t cilong;
371     u_char cimaxslotindex, cicflag;
372
373     /*
374      * CIs must be in exactly the same order that we sent...
375      * Check packet length and CI length at each step.
376      * If we find any deviations, then this packet is bad.
377      */
378
379 #define ACKCIVJ(opt, neg, val, old, maxslotindex, cflag) \
380     if (neg) { \
381         int vjlen = old? CILEN_COMPRESS : CILEN_VJ; \
382         if ((len -= vjlen) < 0) \
383             goto bad; \
384         GETCHAR(citype, p); \
385         GETCHAR(cilen, p); \
386         if (cilen != vjlen || \
387             citype != opt)  \
388             goto bad; \
389         GETSHORT(cishort, p); \
390         if (cishort != val) \
391             goto bad; \
392         if (!old) { \
393             GETCHAR(cimaxslotindex, p); \
394             if (cimaxslotindex != maxslotindex) \
395                 goto bad; \
396             GETCHAR(cicflag, p); \
397             if (cicflag != cflag) \
398                 goto bad; \
399         } \
400     }
401
402 #define ACKCIADDR(opt, neg, old, val1, val2) \
403     if (neg) { \
404         int addrlen = (old? CILEN_ADDRS: CILEN_ADDR); \
405         u_int32_t l; \
406         if ((len -= addrlen) < 0) \
407             goto bad; \
408         GETCHAR(citype, p); \
409         GETCHAR(cilen, p); \
410         if (cilen != addrlen || \
411             citype != opt) \
412             goto bad; \
413         GETLONG(l, p); \
414         cilong = htonl(l); \
415         if (val1 != cilong) \
416             goto bad; \
417         if (old) { \
418             GETLONG(l, p); \
419             cilong = htonl(l); \
420             if (val2 != cilong) \
421                 goto bad; \
422         } \
423     }
424
425     ACKCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), go->neg_addr,
426               go->old_addrs, go->ouraddr, go->hisaddr);
427
428     ACKCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj,
429             go->maxslotindex, go->cflag);
430
431     /*
432      * If there are any remaining CIs, then this packet is bad.
433      */
434     if (len != 0)
435         goto bad;
436     return (1);
437
438 bad:
439     IPCPDEBUG((LOG_INFO, "ipcp_ackci: received bad Ack!"));
440     return (0);
441 }
442
443 /*
444  * ipcp_nakci - Peer has sent a NAK for some of our CIs.
445  * This should not modify any state if the Nak is bad
446  * or if IPCP is in the OPENED state.
447  *
448  * Returns:
449  *      0 - Nak was bad.
450  *      1 - Nak was good.
451  */
452 static int
453 ipcp_nakci(f, p, len)
454     fsm *f;
455     u_char *p;
456     int len;
457 {
458     ipcp_options *go = &ipcp_gotoptions[f->unit];
459     u_char cimaxslotindex, cicflag;
460     u_char citype, cilen, *next;
461     u_short cishort;
462     u_int32_t ciaddr1, ciaddr2, l;
463     ipcp_options no;            /* options we've seen Naks for */
464     ipcp_options try;           /* options to request next time */
465
466     BZERO(&no, sizeof(no));
467     try = *go;
468
469     /*
470      * Any Nak'd CIs must be in exactly the same order that we sent.
471      * Check packet length and CI length at each step.
472      * If we find any deviations, then this packet is bad.
473      */
474 #define NAKCIADDR(opt, neg, old, code) \
475     if (go->neg && \
476         len >= (cilen = (old? CILEN_ADDRS: CILEN_ADDR)) && \
477         p[1] == cilen && \
478         p[0] == opt) { \
479         len -= cilen; \
480         INCPTR(2, p); \
481         GETLONG(l, p); \
482         ciaddr1 = htonl(l); \
483         if (old) { \
484             GETLONG(l, p); \
485             ciaddr2 = htonl(l); \
486             no.old_addrs = 1; \
487         } else \
488             ciaddr2 = 0; \
489         no.neg = 1; \
490         code \
491     }
492
493 #define NAKCIVJ(opt, neg, code) \
494     if (go->neg && \
495         ((cilen = p[1]) == CILEN_COMPRESS || cilen == CILEN_VJ) && \
496         len >= cilen && \
497         p[0] == opt) { \
498         len -= cilen; \
499         INCPTR(2, p); \
500         GETSHORT(cishort, p); \
501         no.neg = 1; \
502         code \
503     }
504
505     /*
506      * Accept the peer's idea of {our,his} address, if different
507      * from our idea, only if the accept_{local,remote} flag is set.
508      */
509     NAKCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), neg_addr, go->old_addrs,
510               if (go->accept_local && ciaddr1) { /* Do we know our address? */
511                   try.ouraddr = ciaddr1;
512                   IPCPDEBUG((LOG_INFO, "local IP address %s",
513                              ip_ntoa(ciaddr1)));
514               }
515               if (go->accept_remote && ciaddr2) { /* Does he know his? */
516                   try.hisaddr = ciaddr2;
517                   IPCPDEBUG((LOG_INFO, "remote IP address %s",
518                              ip_ntoa(ciaddr2)));
519               }
520               );
521
522     /*
523      * Accept the peer's value of maxslotindex provided that it
524      * is less than what we asked for.  Turn off slot-ID compression
525      * if the peer wants.  Send old-style compress-type option if
526      * the peer wants.
527      */
528     NAKCIVJ(CI_COMPRESSTYPE, neg_vj,
529             if (cilen == CILEN_VJ) {
530                 GETCHAR(cimaxslotindex, p);
531                 GETCHAR(cicflag, p);
532                 if (cishort == IPCP_VJ_COMP) {
533                     try.old_vj = 0;
534                     if (cimaxslotindex < go->maxslotindex)
535                         try.maxslotindex = cimaxslotindex;
536                     if (!cicflag)
537                         try.cflag = 0;
538                 } else {
539                     try.neg_vj = 0;
540                 }
541             } else {
542                 if (cishort == IPCP_VJ_COMP || cishort == IPCP_VJ_COMP_OLD) {
543                     try.old_vj = 1;
544                     try.vj_protocol = cishort;
545                 } else {
546                     try.neg_vj = 0;
547                 }
548             }
549             );
550
551     /*
552      * There may be remaining CIs, if the peer is requesting negotiation
553      * on an option that we didn't include in our request packet.
554      * If they want to negotiate about IP addresses, we comply.
555      * If they want us to ask for compression, we refuse.
556      */
557     while (len > CILEN_VOID) {
558         GETCHAR(citype, p);
559         GETCHAR(cilen, p);
560         if( (len -= cilen) < 0 )
561             goto bad;
562         next = p + cilen - 2;
563
564         switch (citype) {
565         case CI_COMPRESSTYPE:
566             if (go->neg_vj || no.neg_vj ||
567                 (cilen != CILEN_VJ && cilen != CILEN_COMPRESS))
568                 goto bad;
569             no.neg_vj = 1;
570             break;
571         case CI_ADDRS:
572             if (go->neg_addr && go->old_addrs || no.old_addrs
573                 || cilen != CILEN_ADDRS)
574                 goto bad;
575             try.neg_addr = 1;
576             try.old_addrs = 1;
577             GETLONG(l, p);
578             ciaddr1 = htonl(l);
579             if (ciaddr1 && go->accept_local)
580                 try.ouraddr = ciaddr1;
581             GETLONG(l, p);
582             ciaddr2 = htonl(l);
583             if (ciaddr2 && go->accept_remote)
584                 try.hisaddr = ciaddr2;
585             no.old_addrs = 1;
586             break;
587         case CI_ADDR:
588             if (go->neg_addr || no.neg_addr || cilen != CILEN_ADDR)
589                 goto bad;
590             try.old_addrs = 0;
591             GETLONG(l, p);
592             ciaddr1 = htonl(l);
593             if (ciaddr1 && go->accept_local)
594                 try.ouraddr = ciaddr1;
595             if (try.ouraddr != 0)
596                 try.neg_addr = 1;
597             no.neg_addr = 1;
598             break;
599         }
600         p = next;
601     }
602
603     /* If there is still anything left, this packet is bad. */
604     if (len != 0)
605         goto bad;
606
607     /*
608      * OK, the Nak is good.  Now we can update state.
609      */
610     if (f->state != OPENED)
611         *go = try;
612
613     return 1;
614
615 bad:
616     IPCPDEBUG((LOG_INFO, "ipcp_nakci: received bad Nak!"));
617     return 0;
618 }
619
620
621 /*
622  * ipcp_rejci - Reject some of our CIs.
623  */
624 static int
625 ipcp_rejci(f, p, len)
626     fsm *f;
627     u_char *p;
628     int len;
629 {
630     ipcp_options *go = &ipcp_gotoptions[f->unit];
631     u_char cimaxslotindex, ciflag, cilen;
632     u_short cishort;
633     u_int32_t cilong;
634     ipcp_options try;           /* options to request next time */
635
636     try = *go;
637     /*
638      * Any Rejected CIs must be in exactly the same order that we sent.
639      * Check packet length and CI length at each step.
640      * If we find any deviations, then this packet is bad.
641      */
642 #define REJCIADDR(opt, neg, old, val1, val2) \
643     if (go->neg && \
644         len >= (cilen = old? CILEN_ADDRS: CILEN_ADDR) && \
645         p[1] == cilen && \
646         p[0] == opt) { \
647         u_int32_t l; \
648         len -= cilen; \
649         INCPTR(2, p); \
650         GETLONG(l, p); \
651         cilong = htonl(l); \
652         /* Check rejected value. */ \
653         if (cilong != val1) \
654             goto bad; \
655         if (old) { \
656             GETLONG(l, p); \
657             cilong = htonl(l); \
658             /* Check rejected value. */ \
659             if (cilong != val2) \
660                 goto bad; \
661         } \
662         try.neg = 0; \
663     }
664
665 #define REJCIVJ(opt, neg, val, old, maxslot, cflag) \
666     if (go->neg && \
667         p[1] == (old? CILEN_COMPRESS : CILEN_VJ) && \
668         len >= p[1] && \
669         p[0] == opt) { \
670         len -= p[1]; \
671         INCPTR(2, p); \
672         GETSHORT(cishort, p); \
673         /* Check rejected value. */  \
674         if (cishort != val) \
675             goto bad; \
676         if (!old) { \
677            GETCHAR(cimaxslotindex, p); \
678            if (cimaxslotindex != maxslot) \
679              goto bad; \
680            GETCHAR(ciflag, p); \
681            if (ciflag != cflag) \
682              goto bad; \
683         } \
684         try.neg = 0; \
685      }
686
687     REJCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), neg_addr,
688               go->old_addrs, go->ouraddr, go->hisaddr);
689
690     REJCIVJ(CI_COMPRESSTYPE, neg_vj, go->vj_protocol, go->old_vj,
691             go->maxslotindex, go->cflag);
692
693     /*
694      * If there are any remaining CIs, then this packet is bad.
695      */
696     if (len != 0)
697         goto bad;
698     /*
699      * Now we can update state.
700      */
701     if (f->state != OPENED)
702         *go = try;
703     return 1;
704
705 bad:
706     IPCPDEBUG((LOG_INFO, "ipcp_rejci: received bad Reject!"));
707     return 0;
708 }
709
710
711 /*
712  * ipcp_reqci - Check the peer's requested CIs and send appropriate response.
713  *
714  * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified
715  * appropriately.  If reject_if_disagree is non-zero, doesn't return
716  * CONFNAK; returns CONFREJ if it can't return CONFACK.
717  */
718 static int
719 ipcp_reqci(f, inp, len, reject_if_disagree)
720     fsm *f;
721     u_char *inp;                /* Requested CIs */
722     int *len;                   /* Length of requested CIs */
723     int reject_if_disagree;
724 {
725     ipcp_options *wo = &ipcp_wantoptions[f->unit];
726     ipcp_options *ho = &ipcp_hisoptions[f->unit];
727     ipcp_options *ao = &ipcp_allowoptions[f->unit];
728     ipcp_options *go = &ipcp_gotoptions[f->unit];
729     u_char *cip, *next;         /* Pointer to current and next CIs */
730     u_short cilen, citype;      /* Parsed len, type */
731     u_short cishort;            /* Parsed short value */
732     u_int32_t tl, ciaddr1, ciaddr2;/* Parsed address values */
733     int rc = CONFACK;           /* Final packet return code */
734     int orc;                    /* Individual option return code */
735     u_char *p;                  /* Pointer to next char to parse */
736     u_char *ucp = inp;          /* Pointer to current output char */
737     int l = *len;               /* Length left */
738     u_char maxslotindex, cflag;
739
740     /*
741      * Reset all his options.
742      */
743     BZERO(ho, sizeof(*ho));
744     
745     /*
746      * Process all his options.
747      */
748     next = inp;
749     while (l) {
750         orc = CONFACK;                  /* Assume success */
751         cip = p = next;                 /* Remember begining of CI */
752         if (l < 2 ||                    /* Not enough data for CI header or */
753             p[1] < 2 ||                 /*  CI length too small or */
754             p[1] > l) {                 /*  CI length too big? */
755             IPCPDEBUG((LOG_INFO, "ipcp_reqci: bad CI length!"));
756             orc = CONFREJ;              /* Reject bad CI */
757             cilen = l;                  /* Reject till end of packet */
758             l = 0;                      /* Don't loop again */
759             goto endswitch;
760         }
761         GETCHAR(citype, p);             /* Parse CI type */
762         GETCHAR(cilen, p);              /* Parse CI length */
763         l -= cilen;                     /* Adjust remaining length */
764         next += cilen;                  /* Step to next CI */
765
766         switch (citype) {               /* Check CI type */
767         case CI_ADDRS:
768             IPCPDEBUG((LOG_INFO, "ipcp: received ADDRS "));
769             if (!ao->neg_addr ||
770                 cilen != CILEN_ADDRS) { /* Check CI length */
771                 orc = CONFREJ;          /* Reject CI */
772                 break;
773             }
774
775             /*
776              * If he has no address, or if we both have his address but
777              * disagree about it, then NAK it with our idea.
778              * In particular, if we don't know his address, but he does,
779              * then accept it.
780              */
781             GETLONG(tl, p);             /* Parse source address (his) */
782             ciaddr1 = htonl(tl);
783             IPCPDEBUG((LOG_INFO, "(%s:", ip_ntoa(ciaddr1)));
784             if (ciaddr1 != wo->hisaddr
785                 && (ciaddr1 == 0 || !wo->accept_remote)) {
786                 orc = CONFNAK;
787                 if (!reject_if_disagree) {
788                     DECPTR(sizeof(u_int32_t), p);
789                     tl = ntohl(wo->hisaddr);
790                     PUTLONG(tl, p);
791                 }
792             } else if (ciaddr1 == 0 && wo->hisaddr == 0) {
793                 /*
794                  * If neither we nor he knows his address, reject the option.
795                  */
796                 orc = CONFREJ;
797                 wo->req_addr = 0;       /* don't NAK with 0.0.0.0 later */
798                 break;
799             }
800
801             /*
802              * If he doesn't know our address, or if we both have our address
803              * but disagree about it, then NAK it with our idea.
804              */
805             GETLONG(tl, p);             /* Parse desination address (ours) */
806             ciaddr2 = htonl(tl);
807             IPCPDEBUG((LOG_INFO, "%s)", ip_ntoa(ciaddr2)));
808             if (ciaddr2 != wo->ouraddr) {
809                 if (ciaddr2 == 0 || !wo->accept_local) {
810                     orc = CONFNAK;
811                     if (!reject_if_disagree) {
812                         DECPTR(sizeof(u_int32_t), p);
813                         tl = ntohl(wo->ouraddr);
814                         PUTLONG(tl, p);
815                     }
816                 } else {
817                     go->ouraddr = ciaddr2;      /* accept peer's idea */
818                 }
819             }
820
821             ho->neg_addr = 1;
822             ho->old_addrs = 1;
823             ho->hisaddr = ciaddr1;
824             ho->ouraddr = ciaddr2;
825             break;
826
827         case CI_ADDR:
828             IPCPDEBUG((LOG_INFO, "ipcp: received ADDR "));
829
830             if (!ao->neg_addr ||
831                 cilen != CILEN_ADDR) {  /* Check CI length */
832                 orc = CONFREJ;          /* Reject CI */
833                 break;
834             }
835
836             /*
837              * If he has no address, or if we both have his address but
838              * disagree about it, then NAK it with our idea.
839              * In particular, if we don't know his address, but he does,
840              * then accept it.
841              */
842             GETLONG(tl, p);     /* Parse source address (his) */
843             ciaddr1 = htonl(tl);
844             IPCPDEBUG((LOG_INFO, "(%s)", ip_ntoa(ciaddr1)));
845             if (ciaddr1 != wo->hisaddr
846                 && (ciaddr1 == 0 || !wo->accept_remote)) {
847                 orc = CONFNAK;
848                 if (!reject_if_disagree) {
849                     DECPTR(sizeof(u_int32_t), p);
850                     tl = ntohl(wo->hisaddr);
851                     PUTLONG(tl, p);
852                 }
853             } else if (ciaddr1 == 0 && wo->hisaddr == 0) {
854                 /*
855                  * Don't ACK an address of 0.0.0.0 - reject it instead.
856                  */
857                 orc = CONFREJ;
858                 wo->req_addr = 0;       /* don't NAK with 0.0.0.0 later */
859                 break;
860             }
861         
862             ho->neg_addr = 1;
863             ho->hisaddr = ciaddr1;
864             break;
865
866 #ifdef USE_MS_DNS
867         case CI_MS_DNS1:
868             /* Microsoft primary DNS request */
869             IPCPDEBUG((LOG_INFO, "ipcp: received DNS1 Request "));
870
871             /* If we do not have a DNS address then we cannot send it */
872             if (ao->dnsaddr[0] == 0 ||
873                 cilen != CILEN_ADDR) {  /* Check CI length */
874                 orc = CONFREJ;          /* Reject CI */
875                 break;
876             }
877             GETLONG(tl, p);
878             if (htonl(tl) != ao->dnsaddr[0]) {
879                 DECPTR(sizeof(u_int32_t), p);
880                 tl = ntohl(ao->dnsaddr[0]);
881                 PUTLONG(tl, p);
882                 orc = CONFNAK;
883             }
884             break;
885
886         case CI_MS_DNS2:
887             /* Microsoft secondary DNS request */
888             IPCPDEBUG((LOG_INFO, "ipcp: received DNS2 Request "));
889
890             /* If we do not have a DNS address then we cannot send it */
891             if (ao->dnsaddr[1] == 0 ||  /* Yes, this is the first one! */
892                 cilen != CILEN_ADDR) {  /* Check CI length */
893                 orc = CONFREJ;          /* Reject CI */
894                 break;
895             }
896             GETLONG(tl, p);
897             if (htonl(tl) != ao->dnsaddr[1]) { /* and this is the 2nd one */
898                 DECPTR(sizeof(u_int32_t), p);
899                 tl = ntohl(ao->dnsaddr[1]);
900                 PUTLONG(tl, p);
901                 orc = CONFNAK;
902             }
903             break;
904 #endif
905         
906         case CI_COMPRESSTYPE:
907             IPCPDEBUG((LOG_INFO, "ipcp: received COMPRESSTYPE "));
908             if (!ao->neg_vj ||
909                 (cilen != CILEN_VJ && cilen != CILEN_COMPRESS)) {
910                 orc = CONFREJ;
911                 break;
912             }
913             GETSHORT(cishort, p);
914             IPCPDEBUG((LOG_INFO, "(%d)", cishort));
915
916             if (!(cishort == IPCP_VJ_COMP ||
917                   (cishort == IPCP_VJ_COMP_OLD && cilen == CILEN_COMPRESS))) {
918                 orc = CONFREJ;
919                 break;
920             }
921
922             ho->neg_vj = 1;
923             ho->vj_protocol = cishort;
924             if (cilen == CILEN_VJ) {
925                 GETCHAR(maxslotindex, p);
926                 if (maxslotindex > ao->maxslotindex) { 
927                     orc = CONFNAK;
928                     if (!reject_if_disagree){
929                         DECPTR(1, p);
930                         PUTCHAR(ao->maxslotindex, p);
931                     }
932                 }
933                 GETCHAR(cflag, p);
934                 if (cflag && !ao->cflag) {
935                     orc = CONFNAK;
936                     if (!reject_if_disagree){
937                         DECPTR(1, p);
938                         PUTCHAR(wo->cflag, p);
939                     }
940                 }
941                 ho->maxslotindex = maxslotindex;
942                 ho->cflag = cflag;
943             } else {
944                 ho->old_vj = 1;
945                 ho->maxslotindex = MAX_STATES - 1;
946                 ho->cflag = 1;
947             }
948             break;
949
950         default:
951             orc = CONFREJ;
952             break;
953         }
954
955 endswitch:
956         IPCPDEBUG((LOG_INFO, " (%s)\n", CODENAME(orc)));
957
958         if (orc == CONFACK &&           /* Good CI */
959             rc != CONFACK)              /*  but prior CI wasnt? */
960             continue;                   /* Don't send this one */
961
962         if (orc == CONFNAK) {           /* Nak this CI? */
963             if (reject_if_disagree)     /* Getting fed up with sending NAKs? */
964                 orc = CONFREJ;          /* Get tough if so */
965             else {
966                 if (rc == CONFREJ)      /* Rejecting prior CI? */
967                     continue;           /* Don't send this one */
968                 if (rc == CONFACK) {    /* Ack'd all prior CIs? */
969                     rc = CONFNAK;       /* Not anymore... */
970                     ucp = inp;          /* Backup */
971                 }
972             }
973         }
974
975         if (orc == CONFREJ &&           /* Reject this CI */
976             rc != CONFREJ) {            /*  but no prior ones? */
977             rc = CONFREJ;
978             ucp = inp;                  /* Backup */
979         }
980
981         /* Need to move CI? */
982         if (ucp != cip)
983             BCOPY(cip, ucp, cilen);     /* Move it */
984
985         /* Update output pointer */
986         INCPTR(cilen, ucp);
987     }
988
989     /*
990      * If we aren't rejecting this packet, and we want to negotiate
991      * their address, and they didn't send their address, then we
992      * send a NAK with a CI_ADDR option appended.  We assume the
993      * input buffer is long enough that we can append the extra
994      * option safely.
995      */
996     if (rc != CONFREJ && !ho->neg_addr &&
997         wo->req_addr && !reject_if_disagree) {
998         if (rc == CONFACK) {
999             rc = CONFNAK;
1000             ucp = inp;                  /* reset pointer */
1001             wo->req_addr = 0;           /* don't ask again */
1002         }
1003         PUTCHAR(CI_ADDR, ucp);
1004         PUTCHAR(CILEN_ADDR, ucp);
1005         tl = ntohl(wo->hisaddr);
1006         PUTLONG(tl, ucp);
1007     }
1008
1009     *len = ucp - inp;                   /* Compute output length */
1010     IPCPDEBUG((LOG_INFO, "ipcp: returning Configure-%s", CODENAME(rc)));
1011     return (rc);                        /* Return final code */
1012 }
1013
1014
1015 /*
1016  * ipcp_up - IPCP has come UP.
1017  *
1018  * Configure the IP network interface appropriately and bring it up.
1019  */
1020 static void
1021 ipcp_up(f)
1022     fsm *f;
1023 {
1024     u_int32_t mask;
1025     ipcp_options *ho = &ipcp_hisoptions[f->unit];
1026     ipcp_options *go = &ipcp_gotoptions[f->unit];
1027
1028     IPCPDEBUG((LOG_INFO, "ipcp: up"));
1029     go->default_route = 0;
1030     go->proxy_arp = 0;
1031
1032     /*
1033      * We must have a non-zero IP address for both ends of the link.
1034      */
1035     if (!ho->neg_addr)
1036         ho->hisaddr = ipcp_wantoptions[f->unit].hisaddr;
1037
1038     if (ho->hisaddr == 0) {
1039         syslog(LOG_ERR, "Could not determine remote IP address");
1040         ipcp_close(f->unit, "Could not determine remote IP address");
1041         return;
1042     }
1043     if (go->ouraddr == 0) {
1044         syslog(LOG_ERR, "Could not determine local IP address");
1045         ipcp_close(f->unit, "Could not determine local IP address");
1046         return;
1047     }
1048
1049     /*
1050      * Check that the peer is allowed to use the IP address it wants.
1051      */
1052     if (!auth_ip_addr(f->unit, ho->hisaddr)) {
1053         syslog(LOG_ERR, "Peer is not authorized to use remote address %s",
1054                ip_ntoa(ho->hisaddr));
1055         ipcp_close(f->unit, "Unauthorized remote IP address");
1056         return;
1057     }
1058
1059     syslog(LOG_NOTICE, "local  IP address %s", ip_ntoa(go->ouraddr));
1060     syslog(LOG_NOTICE, "remote IP address %s", ip_ntoa(ho->hisaddr));
1061
1062     /*
1063      * Set IP addresses and (if specified) netmask.
1064      */
1065     mask = GetMask(go->ouraddr);
1066     if (!sifaddr(f->unit, go->ouraddr, ho->hisaddr, mask)) {
1067         IPCPDEBUG((LOG_WARNING, "sifaddr failed"));
1068         ipcp_close(f->unit, "Interface configuration failed");
1069         return;
1070     }
1071
1072     /* set tcp compression */
1073     sifvjcomp(f->unit, ho->neg_vj, ho->cflag, ho->maxslotindex);
1074
1075     /* bring the interface up for IP */
1076     if (!sifup(f->unit)) {
1077         IPCPDEBUG((LOG_WARNING, "sifup failed"));
1078         ipcp_close(f->unit, "Interface configuration failed");
1079         return;
1080     }
1081
1082     /* assign a default route through the interface if required */
1083     if (ipcp_wantoptions[f->unit].default_route) 
1084         if (sifdefaultroute(f->unit, ho->hisaddr))
1085             go->default_route = 1;
1086
1087     /* Make a proxy ARP entry if requested. */
1088     if (ipcp_wantoptions[f->unit].proxy_arp)
1089         if (sifproxyarp(f->unit, ho->hisaddr))
1090             go->proxy_arp = 1;
1091
1092     /*
1093      * Execute the ip-up script, like this:
1094      *  /etc/ppp/ip-up interface tty speed local-IP remote-IP
1095      */
1096     ipcp_script(f, _PATH_IPUP);
1097
1098 }
1099
1100
1101 /*
1102  * ipcp_down - IPCP has gone DOWN.
1103  *
1104  * Take the IP network interface down, clear its addresses
1105  * and delete routes through it.
1106  */
1107 static void
1108 ipcp_down(f)
1109     fsm *f;
1110 {
1111     u_int32_t ouraddr, hisaddr;
1112
1113     IPCPDEBUG((LOG_INFO, "ipcp: down"));
1114
1115     ouraddr = ipcp_gotoptions[f->unit].ouraddr;
1116     hisaddr = ipcp_hisoptions[f->unit].hisaddr;
1117     if (ipcp_gotoptions[f->unit].proxy_arp)
1118         cifproxyarp(f->unit, hisaddr);
1119     if (ipcp_gotoptions[f->unit].default_route) 
1120         cifdefaultroute(f->unit, hisaddr);
1121     sifdown(f->unit);
1122     cifaddr(f->unit, ouraddr, hisaddr);
1123
1124     /* Execute the ip-down script */
1125     ipcp_script(f, _PATH_IPDOWN);
1126 }
1127
1128
1129 /*
1130  * ipcp_script - Execute a script with arguments
1131  * interface-name tty-name speed local-IP remote-IP.
1132  */
1133 static void
1134 ipcp_script(f, script)
1135     fsm *f;
1136     char *script;
1137 {
1138     char strspeed[32], strlocal[32], strremote[32];
1139     char *argv[8];
1140
1141     sprintf(strspeed, "%d", baud_rate);
1142     strcpy(strlocal, ip_ntoa(ipcp_gotoptions[f->unit].ouraddr));
1143     strcpy(strremote, ip_ntoa(ipcp_hisoptions[f->unit].hisaddr));
1144
1145     argv[0] = script;
1146     argv[1] = ifname;
1147     argv[2] = devnam;
1148     argv[3] = strspeed;
1149     argv[4] = strlocal;
1150     argv[5] = strremote;
1151     argv[6] = ipparam;
1152     argv[7] = NULL;
1153     run_program(script, argv, 0);
1154 }
1155
1156 /*
1157  * ipcp_printpkt - print the contents of an IPCP packet.
1158  */
1159 char *ipcp_codenames[] = {
1160     "ConfReq", "ConfAck", "ConfNak", "ConfRej",
1161     "TermReq", "TermAck", "CodeRej"
1162 };
1163
1164 int
1165 ipcp_printpkt(p, plen, printer, arg)
1166     u_char *p;
1167     int plen;
1168     void (*printer)();
1169     void *arg;
1170 {
1171     int code, id, len, olen;
1172     u_char *pstart, *optend;
1173     u_short cishort;
1174     u_int32_t cilong;
1175
1176     if (plen < HEADERLEN)
1177         return 0;
1178     pstart = p;
1179     GETCHAR(code, p);
1180     GETCHAR(id, p);
1181     GETSHORT(len, p);
1182     if (len < HEADERLEN || len > plen)
1183         return 0;
1184
1185     if (code >= 1 && code <= sizeof(ipcp_codenames) / sizeof(char *))
1186         printer(arg, " %s", ipcp_codenames[code-1]);
1187     else
1188         printer(arg, " code=0x%x", code);
1189     printer(arg, " id=0x%x", id);
1190     len -= HEADERLEN;
1191     switch (code) {
1192     case CONFREQ:
1193     case CONFACK:
1194     case CONFNAK:
1195     case CONFREJ:
1196         /* print option list */
1197         while (len >= 2) {
1198             GETCHAR(code, p);
1199             GETCHAR(olen, p);
1200             p -= 2;
1201             if (olen < 2 || olen > len) {
1202                 break;
1203             }
1204             printer(arg, " <");
1205             len -= olen;
1206             optend = p + olen;
1207             switch (code) {
1208             case CI_ADDRS:
1209                 if (olen == CILEN_ADDRS) {
1210                     p += 2;
1211                     GETLONG(cilong, p);
1212                     printer(arg, "addrs %s", ip_ntoa(htonl(cilong)));
1213                     GETLONG(cilong, p);
1214                     printer(arg, " %s", ip_ntoa(htonl(cilong)));
1215                 }
1216                 break;
1217             case CI_COMPRESSTYPE:
1218                 if (olen >= CILEN_COMPRESS) {
1219                     p += 2;
1220                     GETSHORT(cishort, p);
1221                     printer(arg, "compress ");
1222                     switch (cishort) {
1223                     case IPCP_VJ_COMP:
1224                         printer(arg, "VJ");
1225                         break;
1226                     case IPCP_VJ_COMP_OLD:
1227                         printer(arg, "old-VJ");
1228                         break;
1229                     default:
1230                         printer(arg, "0x%x", cishort);
1231                     }
1232                 }
1233                 break;
1234             case CI_ADDR:
1235                 if (olen == CILEN_ADDR) {
1236                     p += 2;
1237                     GETLONG(cilong, p);
1238                     printer(arg, "addr %s", ip_ntoa(htonl(cilong)));
1239                 }
1240                 break;
1241             }
1242             while (p < optend) {
1243                 GETCHAR(code, p);
1244                 printer(arg, " %.2x", code);
1245             }
1246             printer(arg, ">");
1247         }
1248         break;
1249     }
1250
1251     /* print the rest of the bytes in the packet */
1252     for (; len > 0; --len) {
1253         GETCHAR(code, p);
1254         printer(arg, " %.2x", code);
1255     }
1256
1257     return p - pstart;
1258 }