]> git.ozlabs.org Git - ppp.git/blob - pppd/ipv6cp.c
38cb22bbb5f60bf7585d5cd1c3dcfaebfc79578a
[ppp.git] / pppd / ipv6cp.c
1 /*
2  * ipv6cp.c - PPP IPV6 Control Protocol.
3  *
4  * Derived from :
5  *
6  *
7  * ipcp.c - PPP IP Control Protocol.
8  *
9  * Copyright (c) 1989 Carnegie Mellon University.
10  * All rights reserved.
11  *
12  * Redistribution and use in source and binary forms are permitted
13  * provided that the above copyright notice and this paragraph are
14  * duplicated in all such forms and that any documentation,
15  * advertising materials, and other materials related to such
16  * distribution and use acknowledge that the software was developed
17  * by Carnegie Mellon University.  The name of the
18  * University may not be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
21  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
22  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
23  *
24  * $Id: ipv6cp.c,v 1.3 1999/08/24 05:31:09 paulus Exp $ 
25  *
26  *
27  * Original version by Inria (www.inria.fr)
28  * Modified to match RFC2472 by Tommi Komulainen <Tommi.Komulainen@iki.fi>
29  */
30
31 #define RCSID   "$Id: ipv6cp.c,v 1.3 1999/08/24 05:31:09 paulus Exp $"
32
33 /*
34  * TODO: 
35  *
36  * Better defines for selecting the ordering of
37  *   interface up / set address. (currently checks for __linux__,
38  *   since SVR4 && (SNI || __USLC__) didn't work properly)
39  */
40
41 #include <stdio.h>
42 #include <string.h>
43 #include <unistd.h>
44 #include <netdb.h>
45 #include <sys/param.h>
46 #include <sys/types.h>
47 #include <sys/socket.h>
48 #include <netinet/in.h>
49 #include <arpa/inet.h>
50
51 #include "pppd.h"
52 #include "fsm.h"
53 #include "ipcp.h"
54 #include "ipv6cp.h"
55 #include "magic.h"
56 #include "pathnames.h"
57
58 static const char rcsid[] = RCSID;
59
60 /* global vars */
61 ipv6cp_options ipv6cp_wantoptions[NUM_PPP];     /* Options that we want to request */
62 ipv6cp_options ipv6cp_gotoptions[NUM_PPP];      /* Options that peer ack'd */
63 ipv6cp_options ipv6cp_allowoptions[NUM_PPP];    /* Options we allow peer to request */
64 ipv6cp_options ipv6cp_hisoptions[NUM_PPP];      /* Options that we ack'd */
65 int no_ifaceid_neg = 0;
66
67 /* local vars */
68 static int ipv6cp_is_up;
69
70 /*
71  * Callbacks for fsm code.  (CI = Configuration Information)
72  */
73 static void ipv6cp_resetci __P((fsm *));        /* Reset our CI */
74 static int  ipv6cp_cilen __P((fsm *));          /* Return length of our CI */
75 static void ipv6cp_addci __P((fsm *, u_char *, int *)); /* Add our CI */
76 static int  ipv6cp_ackci __P((fsm *, u_char *, int));   /* Peer ack'd our CI */
77 static int  ipv6cp_nakci __P((fsm *, u_char *, int));   /* Peer nak'd our CI */
78 static int  ipv6cp_rejci __P((fsm *, u_char *, int));   /* Peer rej'd our CI */
79 static int  ipv6cp_reqci __P((fsm *, u_char *, int *, int)); /* Rcv CI */
80 static void ipv6cp_up __P((fsm *));             /* We're UP */
81 static void ipv6cp_down __P((fsm *));           /* We're DOWN */
82 static void ipv6cp_finished __P((fsm *));       /* Don't need lower layer */
83
84 fsm ipv6cp_fsm[NUM_PPP];                /* IPV6CP fsm structure */
85
86 static fsm_callbacks ipv6cp_callbacks = { /* IPV6CP callback routines */
87     ipv6cp_resetci,             /* Reset our Configuration Information */
88     ipv6cp_cilen,               /* Length of our Configuration Information */
89     ipv6cp_addci,               /* Add our Configuration Information */
90     ipv6cp_ackci,               /* ACK our Configuration Information */
91     ipv6cp_nakci,               /* NAK our Configuration Information */
92     ipv6cp_rejci,               /* Reject our Configuration Information */
93     ipv6cp_reqci,               /* Request peer's Configuration Information */
94     ipv6cp_up,                  /* Called when fsm reaches OPENED state */
95     ipv6cp_down,                /* Called when fsm leaves OPENED state */
96     NULL,                       /* Called when we want the lower layer up */
97     ipv6cp_finished,            /* Called when we want the lower layer down */
98     NULL,                       /* Called when Protocol-Reject received */
99     NULL,                       /* Retransmission is necessary */
100     NULL,                       /* Called to handle protocol-specific codes */
101     "IPV6CP"                    /* String name of protocol */
102 };
103
104 /*
105  * Command-line options.
106  */
107 static int setifaceid __P((char *arg));
108
109 static option_t ipv6cp_option_list[] = {
110     { "ipv6", o_special, setifaceid,
111       "Set interface identifiers for IPV6" },
112     { "noipv6", o_bool, &ipv6cp_protent.enabled_flag,
113       "Disable IPv6 and IPv6CP" },
114     { "-ipv6", o_bool, &ipv6cp_protent.enabled_flag,
115       "Disable IPv6 and IPv6CP" },
116
117     { "ipv6cp-accept-local", o_bool, &ipv6cp_allowoptions[0].accept_local,
118       "Accept peer's interface identifier for us", 1 },
119     { "ipv6cp-use-ipaddr", o_bool, &ipv6cp_allowoptions[0].use_ip,
120       "Use (default) IPv4 address as interface identifier", 0 },
121
122     { "ipv6cp-restart", o_int, &ipv6cp_fsm[0].timeouttime,
123       "Set timeout for IPv6CP" },
124     { "ipv6cp-max-terminate", o_int, &ipv6cp_fsm[0].maxtermtransmits,
125       "Set max #xmits for term-reqs" },
126     { "ipv6cp-max-configure", o_int, &ipv6cp_fsm[0].maxconfreqtransmits,
127       "Set max #xmits for conf-reqs" },
128     { "ipv6cp-max-failure", o_int, &ipv6cp_fsm[0].maxnakloops,
129       "Set max #conf-naks for IPv6CP" },
130
131    { NULL }
132 };
133
134
135 /*
136  * Protocol entry points from main code.
137  */
138 static void ipv6cp_init __P((int));
139 static void ipv6cp_open __P((int));
140 static void ipv6cp_close __P((int, char *));
141 static void ipv6cp_lowerup __P((int));
142 static void ipv6cp_lowerdown __P((int));
143 static void ipv6cp_input __P((int, u_char *, int));
144 static void ipv6cp_protrej __P((int));
145 static int  ipv6cp_printpkt __P((u_char *, int,
146                                void (*) __P((void *, char *, ...)), void *));
147 static void ipv6_check_options __P((void));
148 static int  ipv6_demand_conf __P((int));
149 static int  ipv6_active_pkt __P((u_char *, int));
150
151 struct protent ipv6cp_protent = {
152     PPP_IPV6CP,
153     ipv6cp_init,
154     ipv6cp_input,
155     ipv6cp_protrej,
156     ipv6cp_lowerup,
157     ipv6cp_lowerdown,
158     ipv6cp_open,
159     ipv6cp_close,
160     ipv6cp_printpkt,
161     NULL,
162     0,
163     "IPV6CP",
164     "IPV6",
165     ipv6cp_option_list,
166     ipv6_check_options,
167     ipv6_demand_conf,
168     ipv6_active_pkt
169 };
170
171 static void ipv6cp_clear_addrs __P((int));
172 static void ipv6cp_script __P((char *));
173 static void ipv6cp_script_done __P((void *));
174
175 /*
176  * Lengths of configuration options.
177  */
178 #define CILEN_VOID      2
179 #define CILEN_COMPRESS  4       /* length for RFC2023 compress opt. */
180 #define CILEN_IFACEID   10      /* RFC2472, interface identifier    */
181
182 #define CODENAME(x)     ((x) == CONFACK ? "ACK" : \
183                          (x) == CONFNAK ? "NAK" : "REJ")
184
185 /*
186  * This state variable is used to ensure that we don't
187  * run an ipcp-up/down script while one is already running.
188  */
189 static enum script_state {
190     s_down,
191     s_up,
192 } ipv6cp_script_state;
193 static pid_t ipv6cp_script_pid;
194
195 /*
196  * setifaceid - set the interface identifiers manually
197  */
198 static int
199 setifaceid(arg)
200     char *arg;
201 {
202     char *comma;
203     ipv6cp_options *wo = &ipv6cp_wantoptions[0];
204     struct in6_addr addr;
205     
206 #define VALIDID(a) ( (((a).s6_addr32[0] == 0) && ((a).s6_addr32[1] == 0)) && \
207                         (((a).s6_addr32[2] != 0) || ((a).s6_addr32[3] != 0)) )
208     
209     if ((comma = strchr(arg, ',')) == NULL)
210         comma = arg + strlen(arg);
211     
212     /* 
213      * If comma first character, then no local identifier
214      */
215     if (comma != arg) {
216         *comma = '\0';
217
218         if (inet_pton(AF_INET6, arg, &addr) == 0 || !VALIDID(addr)) {
219             option_error("Illegal interface identifier: %s", arg);
220             return 0;
221         }
222         
223         eui64_copy(addr.s6_addr32[2], wo->ourid);
224         wo->opt_local = 1;
225         *comma = ',';
226     }
227     
228     /*
229      * If comma last character, the no remote identifier
230      */
231     if (*comma != 0 && *++comma != '\0') {
232         if (inet_pton(AF_INET6, comma, &addr) == 0 || !VALIDID(addr)) {
233             option_error("Illegal interface identifier: %s", comma);
234             return 0;
235         }
236         eui64_copy(addr.s6_addr32[2], wo->hisid);
237         wo->opt_remote = 1;
238     }
239
240     return 1;
241 }
242
243 /*
244  * Make a string representation of a network address.
245  */
246 char *
247 llv6_ntoa(ifaceid)
248     eui64_t ifaceid;
249 {
250     static char b[64];
251
252     sprintf(b, "fe80::%s", eui64_ntoa(ifaceid));
253     return b;
254 }
255
256
257 /*
258  * ipv6cp_init - Initialize IPV6CP.
259  */
260 static void
261 ipv6cp_init(unit)
262     int unit;
263 {
264     fsm *f = &ipv6cp_fsm[unit];
265     ipv6cp_options *wo = &ipv6cp_wantoptions[unit];
266     ipv6cp_options *ao = &ipv6cp_allowoptions[unit];
267
268     f->unit = unit;
269     f->protocol = PPP_IPV6CP;
270     f->callbacks = &ipv6cp_callbacks;
271     fsm_init(&ipv6cp_fsm[unit]);
272
273     memset(wo, 0, sizeof(*wo));
274     memset(ao, 0, sizeof(*ao));
275
276     wo->accept_local = 1;
277     wo->neg_ifaceid = 1;
278     ao->neg_ifaceid = 1;
279
280 #ifdef IPV6CP_COMP
281     wo->neg_vj = 1;
282     ao->neg_vj = 1;
283     wo->vj_protocol = IPV6CP_COMP;
284 #endif
285
286 }
287
288
289 /*
290  * ipv6cp_open - IPV6CP is allowed to come up.
291  */
292 static void
293 ipv6cp_open(unit)
294     int unit;
295 {
296     fsm_open(&ipv6cp_fsm[unit]);
297 }
298
299
300 /*
301  * ipv6cp_close - Take IPV6CP down.
302  */
303 static void
304 ipv6cp_close(unit, reason)
305     int unit;
306     char *reason;
307 {
308     fsm_close(&ipv6cp_fsm[unit], reason);
309 }
310
311
312 /*
313  * ipv6cp_lowerup - The lower layer is up.
314  */
315 static void
316 ipv6cp_lowerup(unit)
317     int unit;
318 {
319     fsm_lowerup(&ipv6cp_fsm[unit]);
320 }
321
322
323 /*
324  * ipv6cp_lowerdown - The lower layer is down.
325  */
326 static void
327 ipv6cp_lowerdown(unit)
328     int unit;
329 {
330     fsm_lowerdown(&ipv6cp_fsm[unit]);
331 }
332
333
334 /*
335  * ipv6cp_input - Input IPV6CP packet.
336  */
337 static void
338 ipv6cp_input(unit, p, len)
339     int unit;
340     u_char *p;
341     int len;
342 {
343     fsm_input(&ipv6cp_fsm[unit], p, len);
344 }
345
346
347 /*
348  * ipv6cp_protrej - A Protocol-Reject was received for IPV6CP.
349  *
350  * Pretend the lower layer went down, so we shut up.
351  */
352 static void
353 ipv6cp_protrej(unit)
354     int unit;
355 {
356     fsm_lowerdown(&ipv6cp_fsm[unit]);
357 }
358
359
360 /*
361  * ipv6cp_resetci - Reset our CI.
362  */
363 static void
364 ipv6cp_resetci(f)
365     fsm *f;
366 {
367     ipv6cp_options *wo = &ipv6cp_wantoptions[f->unit];
368     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
369
370     wo->req_ifaceid = wo->neg_ifaceid && ipv6cp_allowoptions[f->unit].neg_ifaceid;
371     
372     if (!wo->opt_local) {
373         eui64_magic_nz(wo->ourid);
374     }
375     
376     *go = *wo;
377     eui64_zero(go->hisid);      /* last proposed interface identifier */
378 }
379
380
381 /*
382  * ipv6cp_cilen - Return length of our CI.
383  */
384 static int
385 ipv6cp_cilen(f)
386     fsm *f;
387 {
388     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
389
390 #define LENCIVJ(neg)            (neg ? CILEN_COMPRESS : 0)
391 #define LENCIIFACEID(neg)       (neg ? CILEN_IFACEID : 0)
392
393     return (LENCIIFACEID(go->neg_ifaceid) +
394             LENCIVJ(go->neg_vj));
395 }
396
397
398 /*
399  * ipv6cp_addci - Add our desired CIs to a packet.
400  */
401 static void
402 ipv6cp_addci(f, ucp, lenp)
403     fsm *f;
404     u_char *ucp;
405     int *lenp;
406 {
407     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
408     int len = *lenp;
409
410 #define ADDCIVJ(opt, neg, val) \
411     if (neg) { \
412         int vjlen = CILEN_COMPRESS; \
413         if (len >= vjlen) { \
414             PUTCHAR(opt, ucp); \
415             PUTCHAR(vjlen, ucp); \
416             PUTSHORT(val, ucp); \
417             len -= vjlen; \
418         } else \
419             neg = 0; \
420     }
421
422 #define ADDCIIFACEID(opt, neg, val1) \
423     if (neg) { \
424         int idlen = CILEN_IFACEID; \
425         if (len >= idlen) { \
426             PUTCHAR(opt, ucp); \
427             PUTCHAR(idlen, ucp); \
428             eui64_put(val1, ucp); \
429             len -= idlen; \
430         } else \
431             neg = 0; \
432     }
433
434     ADDCIIFACEID(CI_IFACEID, go->neg_ifaceid, go->ourid);
435
436     ADDCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol);
437
438     *lenp -= len;
439 }
440
441
442 /*
443  * ipv6cp_ackci - Ack our CIs.
444  *
445  * Returns:
446  *      0 - Ack was bad.
447  *      1 - Ack was good.
448  */
449 static int
450 ipv6cp_ackci(f, p, len)
451     fsm *f;
452     u_char *p;
453     int len;
454 {
455     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
456     u_short cilen, citype, cishort;
457     eui64_t ifaceid;
458
459     /*
460      * CIs must be in exactly the same order that we sent...
461      * Check packet length and CI length at each step.
462      * If we find any deviations, then this packet is bad.
463      */
464
465 #define ACKCIVJ(opt, neg, val) \
466     if (neg) { \
467         int vjlen = CILEN_COMPRESS; \
468         if ((len -= vjlen) < 0) \
469             goto bad; \
470         GETCHAR(citype, p); \
471         GETCHAR(cilen, p); \
472         if (cilen != vjlen || \
473             citype != opt)  \
474             goto bad; \
475         GETSHORT(cishort, p); \
476         if (cishort != val) \
477             goto bad; \
478     }
479
480 #define ACKCIIFACEID(opt, neg, val1) \
481     if (neg) { \
482         int idlen = CILEN_IFACEID; \
483         if ((len -= idlen) < 0) \
484             goto bad; \
485         GETCHAR(citype, p); \
486         GETCHAR(cilen, p); \
487         if (cilen != idlen || \
488             citype != opt) \
489             goto bad; \
490         eui64_get(ifaceid, p); \
491         if (! eui64_equals(val1, ifaceid)) \
492             goto bad; \
493     }
494
495     ACKCIIFACEID(CI_IFACEID, go->neg_ifaceid, go->ourid);
496
497     ACKCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol);
498
499     /*
500      * If there are any remaining CIs, then this packet is bad.
501      */
502     if (len != 0)
503         goto bad;
504     return (1);
505
506 bad:
507     IPV6CPDEBUG(("ipv6cp_ackci: received bad Ack!"));
508     return (0);
509 }
510
511 /*
512  * ipv6cp_nakci - Peer has sent a NAK for some of our CIs.
513  * This should not modify any state if the Nak is bad
514  * or if IPV6CP is in the OPENED state.
515  *
516  * Returns:
517  *      0 - Nak was bad.
518  *      1 - Nak was good.
519  */
520 static int
521 ipv6cp_nakci(f, p, len)
522     fsm *f;
523     u_char *p;
524     int len;
525 {
526     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
527     u_char citype, cilen, *next;
528     u_short cishort;
529     eui64_t ifaceid;
530     ipv6cp_options no;          /* options we've seen Naks for */
531     ipv6cp_options try;         /* options to request next time */
532
533     BZERO(&no, sizeof(no));
534     try = *go;
535
536     /*
537      * Any Nak'd CIs must be in exactly the same order that we sent.
538      * Check packet length and CI length at each step.
539      * If we find any deviations, then this packet is bad.
540      */
541 #define NAKCIIFACEID(opt, neg, code) \
542     if (go->neg && \
543         len >= (cilen = CILEN_IFACEID) && \
544         p[1] == cilen && \
545         p[0] == opt) { \
546         len -= cilen; \
547         INCPTR(2, p); \
548         eui64_get(ifaceid, p); \
549         no.neg = 1; \
550         code \
551     }
552
553 #define NAKCIVJ(opt, neg, code) \
554     if (go->neg && \
555         ((cilen = p[1]) == CILEN_COMPRESS) && \
556         len >= cilen && \
557         p[0] == opt) { \
558         len -= cilen; \
559         INCPTR(2, p); \
560         GETSHORT(cishort, p); \
561         no.neg = 1; \
562         code \
563     }
564
565     /*
566      * Accept the peer's idea of {our,his} interface identifier, if different
567      * from our idea, only if the accept_{local,remote} flag is set.
568      */
569     NAKCIIFACEID(CI_IFACEID, neg_ifaceid,
570               if (go->accept_local) {
571                   while (eui64_iszero(ifaceid) || 
572                          eui64_equals(ifaceid, go->hisid)) /* bad luck */
573                       eui64_magic(ifaceid);
574                   try.ourid = ifaceid;
575                   IPV6CPDEBUG(("local LL address %s", llv6_ntoa(ifaceid)));
576               }
577               );
578
579 #ifdef IPV6CP_COMP
580     NAKCIVJ(CI_COMPRESSTYPE, neg_vj,
581             {
582                 if (cishort == IPV6CP_COMP) {
583                     try.vj_protocol = cishort;
584                 } else {
585                     try.neg_vj = 0;
586                 }
587             }
588             );
589 #else
590     NAKCIVJ(CI_COMPRESSTYPE, neg_vj,
591             {
592                 try.neg_vj = 0;
593             }
594             );
595 #endif
596
597     /*
598      * There may be remaining CIs, if the peer is requesting negotiation
599      * on an option that we didn't include in our request packet.
600      * If they want to negotiate about interface identifier, we comply.
601      * If they want us to ask for compression, we refuse.
602      */
603     while (len > CILEN_VOID) {
604         GETCHAR(citype, p);
605         GETCHAR(cilen, p);
606         if( (len -= cilen) < 0 )
607             goto bad;
608         next = p + cilen - 2;
609
610         switch (citype) {
611         case CI_COMPRESSTYPE:
612             if (go->neg_vj || no.neg_vj ||
613                 (cilen != CILEN_COMPRESS))
614                 goto bad;
615             no.neg_vj = 1;
616             break;
617         case CI_IFACEID:
618             if (go->neg_ifaceid || no.neg_ifaceid || cilen != CILEN_IFACEID)
619                 goto bad;
620             try.neg_ifaceid = 1;
621             eui64_get(ifaceid, p);
622             if (go->accept_local) {
623                 while (eui64_iszero(ifaceid) || 
624                        eui64_equals(ifaceid, go->hisid)) /* bad luck */
625                     eui64_magic(ifaceid);
626                 try.ourid = ifaceid;
627             }
628             no.neg_ifaceid = 1;
629             break;
630         }
631         p = next;
632     }
633
634     /* If there is still anything left, this packet is bad. */
635     if (len != 0)
636         goto bad;
637
638     /*
639      * OK, the Nak is good.  Now we can update state.
640      */
641     if (f->state != OPENED)
642         *go = try;
643
644     return 1;
645
646 bad:
647     IPV6CPDEBUG(("ipv6cp_nakci: received bad Nak!"));
648     return 0;
649 }
650
651
652 /*
653  * ipv6cp_rejci - Reject some of our CIs.
654  */
655 static int
656 ipv6cp_rejci(f, p, len)
657     fsm *f;
658     u_char *p;
659     int len;
660 {
661     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
662     u_char cilen;
663     u_short cishort;
664     eui64_t ifaceid;
665     ipv6cp_options try;         /* options to request next time */
666
667     try = *go;
668     /*
669      * Any Rejected CIs must be in exactly the same order that we sent.
670      * Check packet length and CI length at each step.
671      * If we find any deviations, then this packet is bad.
672      */
673 #define REJCIIFACEID(opt, neg, val1) \
674     if (go->neg && \
675         len >= (cilen = CILEN_IFACEID) && \
676         p[1] == cilen && \
677         p[0] == opt) { \
678         len -= cilen; \
679         INCPTR(2, p); \
680         eui64_get(ifaceid, p); \
681         /* Check rejected value. */ \
682         if (! eui64_equals(ifaceid, val1)) \
683             goto bad; \
684         try.neg = 0; \
685     }
686
687 #define REJCIVJ(opt, neg, val) \
688     if (go->neg && \
689         p[1] == CILEN_COMPRESS && \
690         len >= p[1] && \
691         p[0] == opt) { \
692         len -= p[1]; \
693         INCPTR(2, p); \
694         GETSHORT(cishort, p); \
695         /* Check rejected value. */  \
696         if (cishort != val) \
697             goto bad; \
698         try.neg = 0; \
699      }
700
701     REJCIIFACEID(CI_IFACEID, neg_ifaceid, go->ourid);
702
703     REJCIVJ(CI_COMPRESSTYPE, neg_vj, go->vj_protocol);
704
705     /*
706      * If there are any remaining CIs, then this packet is bad.
707      */
708     if (len != 0)
709         goto bad;
710     /*
711      * Now we can update state.
712      */
713     if (f->state != OPENED)
714         *go = try;
715     return 1;
716
717 bad:
718     IPV6CPDEBUG(("ipv6cp_rejci: received bad Reject!"));
719     return 0;
720 }
721
722
723 /*
724  * ipv6cp_reqci - Check the peer's requested CIs and send appropriate response.
725  *
726  * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified
727  * appropriately.  If reject_if_disagree is non-zero, doesn't return
728  * CONFNAK; returns CONFREJ if it can't return CONFACK.
729  */
730 static int
731 ipv6cp_reqci(f, inp, len, reject_if_disagree)
732     fsm *f;
733     u_char *inp;                /* Requested CIs */
734     int *len;                   /* Length of requested CIs */
735     int reject_if_disagree;
736 {
737     ipv6cp_options *wo = &ipv6cp_wantoptions[f->unit];
738     ipv6cp_options *ho = &ipv6cp_hisoptions[f->unit];
739     ipv6cp_options *ao = &ipv6cp_allowoptions[f->unit];
740     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
741     u_char *cip, *next;         /* Pointer to current and next CIs */
742     u_short cilen, citype;      /* Parsed len, type */
743     u_short cishort;            /* Parsed short value */
744     eui64_t ifaceid;            /* Parsed interface identifier */
745     int rc = CONFACK;           /* Final packet return code */
746     int orc;                    /* Individual option return code */
747     u_char *p;                  /* Pointer to next char to parse */
748     u_char *ucp = inp;          /* Pointer to current output char */
749     int l = *len;               /* Length left */
750
751     /*
752      * Reset all his options.
753      */
754     BZERO(ho, sizeof(*ho));
755     
756     /*
757      * Process all his options.
758      */
759     next = inp;
760     while (l) {
761         orc = CONFACK;                  /* Assume success */
762         cip = p = next;                 /* Remember begining of CI */
763         if (l < 2 ||                    /* Not enough data for CI header or */
764             p[1] < 2 ||                 /*  CI length too small or */
765             p[1] > l) {                 /*  CI length too big? */
766             IPV6CPDEBUG(("ipv6cp_reqci: bad CI length!"));
767             orc = CONFREJ;              /* Reject bad CI */
768             cilen = l;                  /* Reject till end of packet */
769             l = 0;                      /* Don't loop again */
770             goto endswitch;
771         }
772         GETCHAR(citype, p);             /* Parse CI type */
773         GETCHAR(cilen, p);              /* Parse CI length */
774         l -= cilen;                     /* Adjust remaining length */
775         next += cilen;                  /* Step to next CI */
776
777         switch (citype) {               /* Check CI type */
778         case CI_IFACEID:
779             IPV6CPDEBUG(("ipv6cp: received interface identifier "));
780
781             if (!ao->neg_ifaceid ||
782                 cilen != CILEN_IFACEID) {       /* Check CI length */
783                 orc = CONFREJ;          /* Reject CI */
784                 break;
785             }
786
787             /*
788              * If he has no interface identifier, or if we both have same 
789              * identifier then NAK it with new idea.
790              * In particular, if we don't know his identifier, but he does,
791              * then accept it.
792              */
793             eui64_get(ifaceid, p);
794             IPV6CPDEBUG(("(%s)", llv6_ntoa(ifaceid)));
795             if (eui64_iszero(ifaceid) && eui64_iszero(go->ourid)) {
796                 orc = CONFREJ;          /* Reject CI */
797                 break;
798             }
799             if (!eui64_iszero(wo->hisid) && 
800                 !eui64_equals(ifaceid, wo->hisid) && 
801                 eui64_iszero(go->hisid)) {
802                     
803                 orc = CONFNAK;
804                 ifaceid = wo->hisid;
805                 go->hisid = ifaceid;
806                 DECPTR(sizeof(ifaceid), p);
807                 eui64_put(ifaceid, p);
808             } else
809             if (eui64_iszero(ifaceid) || eui64_equals(ifaceid, go->ourid)) {
810                 orc = CONFNAK;
811                 if (eui64_iszero(go->hisid))    /* first time, try option */
812                     ifaceid = wo->hisid;
813                 while (eui64_iszero(ifaceid) || 
814                        eui64_equals(ifaceid, go->ourid)) /* bad luck */
815                     eui64_magic(ifaceid);
816                 go->hisid = ifaceid;
817                 DECPTR(sizeof(ifaceid), p);
818                 eui64_put(ifaceid, p);
819             }
820
821             ho->neg_ifaceid = 1;
822             ho->hisid = ifaceid;
823             break;
824
825         case CI_COMPRESSTYPE:
826             IPV6CPDEBUG(("ipv6cp: received COMPRESSTYPE "));
827             if (!ao->neg_vj ||
828                 (cilen != CILEN_COMPRESS)) {
829                 orc = CONFREJ;
830                 break;
831             }
832             GETSHORT(cishort, p);
833             IPV6CPDEBUG(("(%d)", cishort));
834
835 #ifdef IPV6CP_COMP
836             if (!(cishort == IPV6CP_COMP)) {
837                 orc = CONFREJ;
838                 break;
839             }
840 #else
841             orc = CONFREJ;
842             break;
843 #endif
844
845             ho->neg_vj = 1;
846             ho->vj_protocol = cishort;
847             break;
848
849         default:
850             orc = CONFREJ;
851             break;
852         }
853
854 endswitch:
855         IPV6CPDEBUG((" (%s)\n", CODENAME(orc)));
856
857         if (orc == CONFACK &&           /* Good CI */
858             rc != CONFACK)              /*  but prior CI wasnt? */
859             continue;                   /* Don't send this one */
860
861         if (orc == CONFNAK) {           /* Nak this CI? */
862             if (reject_if_disagree)     /* Getting fed up with sending NAKs? */
863                 orc = CONFREJ;          /* Get tough if so */
864             else {
865                 if (rc == CONFREJ)      /* Rejecting prior CI? */
866                     continue;           /* Don't send this one */
867                 if (rc == CONFACK) {    /* Ack'd all prior CIs? */
868                     rc = CONFNAK;       /* Not anymore... */
869                     ucp = inp;          /* Backup */
870                 }
871             }
872         }
873
874         if (orc == CONFREJ &&           /* Reject this CI */
875             rc != CONFREJ) {            /*  but no prior ones? */
876             rc = CONFREJ;
877             ucp = inp;                  /* Backup */
878         }
879
880         /* Need to move CI? */
881         if (ucp != cip)
882             BCOPY(cip, ucp, cilen);     /* Move it */
883
884         /* Update output pointer */
885         INCPTR(cilen, ucp);
886     }
887
888     /*
889      * If we aren't rejecting this packet, and we want to negotiate
890      * their identifier and they didn't send their identifier, then we
891      * send a NAK with a CI_IFACEID option appended.  We assume the
892      * input buffer is long enough that we can append the extra
893      * option safely.
894      */
895     if (rc != CONFREJ && !ho->neg_ifaceid &&
896         wo->req_ifaceid && !reject_if_disagree) {
897         if (rc == CONFACK) {
898             rc = CONFNAK;
899             ucp = inp;                          /* reset pointer */
900             wo->req_ifaceid = 0;                /* don't ask again */
901         }
902         PUTCHAR(CI_IFACEID, ucp);
903         PUTCHAR(CILEN_IFACEID, ucp);
904         eui64_put(wo->hisid, ucp);
905     }
906
907     *len = ucp - inp;                   /* Compute output length */
908     IPV6CPDEBUG(("ipv6cp: returning Configure-%s", CODENAME(rc)));
909     return (rc);                        /* Return final code */
910 }
911
912
913 /*
914  * ipv6_check_options - check that any IP-related options are OK,
915  * and assign appropriate defaults.
916  */
917 static void
918 ipv6_check_options()
919 {
920     ipv6cp_options *wo = &ipv6cp_wantoptions[0];
921
922     if (!wo->opt_local) {       /* init interface identifier */
923         if (wo->use_ip && eui64_iszero(wo->ourid)) {
924             eui64_setlo32(wo->ourid, ntohl(ipcp_wantoptions[0].ouraddr));
925             if (!eui64_iszero(wo->ourid))
926                 wo->opt_local = 1;
927         }
928         
929         while (eui64_iszero(wo->ourid))
930             eui64_magic(wo->ourid);
931     }
932
933     if (!wo->opt_remote) {
934         if (wo->use_ip && eui64_iszero(wo->hisid)) {
935             eui64_setlo32(wo->hisid, ntohl(ipcp_wantoptions[0].hisaddr));
936             if (!eui64_iszero(wo->hisid))
937                 wo->opt_remote = 1;
938         }
939     }
940
941     if (demand && (eui64_iszero(wo->ourid) || eui64_iszero(wo->hisid))) {
942         option_error("local/remote LL address required for demand-dialling\n");
943         exit(1);
944     }
945 }
946
947
948 /*
949  * ipv6_demand_conf - configure the interface as though
950  * IPV6CP were up, for use with dial-on-demand.
951  */
952 static int
953 ipv6_demand_conf(u)
954     int u;
955 {
956     ipv6cp_options *wo = &ipv6cp_wantoptions[u];
957
958 #if defined(__linux__) || (defined(SVR4) && (defined(SNI) || defined(__USLC__)))
959     if (!sifup(u))
960         return 0;
961 #endif    
962     if (!sif6addr(u, wo->ourid, wo->hisid))
963         return 0;
964 #if !defined(__linux__) && !(defined(SVR4) && (defined(SNI) || defined(__USLC__)))
965     if (!sifup(u))
966         return 0;
967 #endif
968     if (!sifnpmode(u, PPP_IPV6, NPMODE_QUEUE))
969         return 0;
970
971     notice("ipv6_demand_conf");
972     notice("local  LL address %s", llv6_ntoa(wo->ourid));
973     notice("remote LL address %s", llv6_ntoa(wo->hisid));
974
975     return 1;
976 }
977
978
979 /*
980  * ipv6cp_up - IPV6CP has come UP.
981  *
982  * Configure the IPv6 network interface appropriately and bring it up.
983  */
984 static void
985 ipv6cp_up(f)
986     fsm *f;
987 {
988     ipv6cp_options *ho = &ipv6cp_hisoptions[f->unit];
989     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
990     ipv6cp_options *wo = &ipv6cp_wantoptions[f->unit];
991
992     IPV6CPDEBUG(("ipv6cp: up"));
993
994     /*
995      * We must have a non-zero LL address for both ends of the link.
996      */
997     if (!ho->neg_ifaceid)
998         ho->hisid = wo->hisid;
999
1000     if(!no_ifaceid_neg) {
1001         if (eui64_iszero(ho->hisid)) {
1002             error("Could not determine remote LL address");
1003             ipv6cp_close(f->unit, "Could not determine remote LL address");
1004             return;
1005         }
1006         if (eui64_iszero(go->ourid)) {
1007             error("Could not determine local LL address");
1008             ipv6cp_close(f->unit, "Could not determine local LL address");
1009             return;
1010         }
1011         if (eui64_equals(go->ourid, ho->hisid)) {
1012             error("local and remote LL addresses are equal");
1013             ipv6cp_close(f->unit, "local and remote LL addresses are equal");
1014             return;
1015         }
1016     }
1017     script_setenv("LLLOCAL", llv6_ntoa(go->ourid));
1018     script_setenv("LLREMOTE", llv6_ntoa(ho->hisid));
1019
1020 #ifdef IPV6CP_COMP
1021     /* set tcp compression */
1022     sif6comp(f->unit, ho->neg_vj);
1023 #endif
1024
1025     /*
1026      * If we are doing dial-on-demand, the interface is already
1027      * configured, so we put out any saved-up packets, then set the
1028      * interface to pass IPv6 packets.
1029      */
1030     if (demand) {
1031         if (! eui64_equals(go->ourid, wo->ourid) || 
1032             ! eui64_equals(ho->hisid, wo->hisid)) {
1033             if (! eui64_equals(go->ourid, wo->ourid))
1034                 warn("Local LL address changed to %s", 
1035                      llv6_ntoa(go->ourid));
1036             if (! eui64_equals(ho->hisid, wo->hisid))
1037                 warn("Remote LL address changed to %s", 
1038                      llv6_ntoa(ho->hisid));
1039             ipv6cp_clear_addrs(f->unit);
1040
1041             /* Set the interface to the new addresses */
1042             if (!sif6addr(f->unit, go->ourid, ho->hisid)) {
1043                 if (debug)
1044                     warn("sif6addr failed");
1045                 ipv6cp_close(f->unit, "Interface configuration failed");
1046                 return;
1047             }
1048
1049         }
1050         demand_rexmit(PPP_IPV6);
1051         sifnpmode(f->unit, PPP_IPV6, NPMODE_PASS);
1052
1053     } else {
1054         /*
1055          * Set LL addresses
1056          */
1057 #if !defined(__linux__) && !(defined(SVR4) && (defined(SNI) || defined(__USLC__)))
1058         if (!sif6addr(f->unit, go->ourid, ho->hisid)) {
1059             if (debug)
1060                 warn("sif6addr failed");
1061             ipv6cp_close(f->unit, "Interface configuration failed");
1062             return;
1063         }
1064 #endif
1065
1066         /* bring the interface up for IPv6 */
1067         if (!sifup(f->unit)) {
1068             if (debug)
1069                 warn("sif6up failed");
1070             ipv6cp_close(f->unit, "Interface configuration failed");
1071             return;
1072         }
1073
1074 #if defined(__linux__) || (defined(SVR4) && (defined(SNI) || defined(__USLC__)))
1075         if (!sif6addr(f->unit, go->ourid, ho->hisid)) {
1076             if (debug)
1077                 warn("sif6addr failed");
1078             ipv6cp_close(f->unit, "Interface configuration failed");
1079             return;
1080         }
1081 #endif
1082         sifnpmode(f->unit, PPP_IPV6, NPMODE_PASS);
1083
1084         notice("local  LL address %s", llv6_ntoa(go->ourid));
1085         notice("remote LL address %s", llv6_ntoa(ho->hisid));
1086     }
1087
1088     np_up(f->unit, PPP_IPV6);
1089     ipv6cp_is_up = 1;
1090
1091     /*
1092      * Execute the ipv6-up script, like this:
1093      *  /etc/ppp/ipv6-up interface tty speed local-LL remote-LL
1094      */
1095     if (ipv6cp_script_state == s_down && ipv6cp_script_pid == 0) {
1096         ipv6cp_script_state = s_up;
1097         ipv6cp_script(_PATH_IPV6UP);
1098     }
1099 }
1100
1101
1102 /*
1103  * ipv6cp_down - IPV6CP has gone DOWN.
1104  *
1105  * Take the IPv6 network interface down, clear its addresses
1106  * and delete routes through it.
1107  */
1108 static void
1109 ipv6cp_down(f)
1110     fsm *f;
1111 {
1112     IPV6CPDEBUG(("ipv6cp: down"));
1113     update_link_stats(f->unit);
1114     if (ipv6cp_is_up) {
1115         ipv6cp_is_up = 0;
1116         np_down(f->unit, PPP_IPV6);
1117     }
1118 #ifdef IPV6CP_COMP
1119     sif6comp(f->unit, 0);
1120 #endif
1121
1122     /*
1123      * If we are doing dial-on-demand, set the interface
1124      * to queue up outgoing packets (for now).
1125      */
1126     if (demand) {
1127         sifnpmode(f->unit, PPP_IPV6, NPMODE_QUEUE);
1128     } else {
1129 #if !defined(__linux__) && !(defined(SVR4) && (defined(SNI) || defined(__USLC)))
1130         sifnpmode(f->unit, PPP_IPV6, NPMODE_DROP);
1131         sifdown(f->unit);
1132 #endif
1133         ipv6cp_clear_addrs(f->unit);
1134 #if defined(__linux__) || (defined(SVR4) && (defined(SNI) || defined(__USLC)))
1135         sifdown(f->unit);
1136 #endif
1137     }
1138
1139     /* Execute the ipv6-down script */
1140     if (ipv6cp_script_state == s_up && ipv6cp_script_pid == 0) {
1141         ipv6cp_script_state = s_down;
1142         ipv6cp_script(_PATH_IPV6DOWN);
1143     }
1144 }
1145
1146
1147 /*
1148  * ipv6cp_clear_addrs() - clear the interface addresses, routes,
1149  * proxy arp entries, etc.
1150  */
1151 static void
1152 ipv6cp_clear_addrs(unit)
1153     int unit;
1154 {
1155     eui64_t ourid, hisid;
1156
1157     ourid = ipv6cp_gotoptions[unit].ourid;
1158     hisid = ipv6cp_hisoptions[unit].hisid;
1159     cif6addr(unit, ourid, hisid);
1160 }
1161
1162
1163 /*
1164  * ipv6cp_finished - possibly shut down the lower layers.
1165  */
1166 static void
1167 ipv6cp_finished(f)
1168     fsm *f;
1169 {
1170     np_finished(f->unit, PPP_IPV6);
1171 }
1172
1173
1174 /*
1175  * ipv6cp_script_done - called when the ipv6-up or ipv6-down script
1176  * has finished.
1177  */
1178 static void
1179 ipv6cp_script_done(arg)
1180     void *arg;
1181 {
1182     ipv6cp_script_pid = 0;
1183     switch (ipv6cp_script_state) {
1184     case s_up:
1185         if (ipv6cp_fsm[0].state != OPENED) {
1186             ipv6cp_script_state = s_down;
1187             ipv6cp_script(_PATH_IPV6DOWN);
1188         }
1189         break;
1190     case s_down:
1191         if (ipv6cp_fsm[0].state == OPENED) {
1192             ipv6cp_script_state = s_up;
1193             ipv6cp_script(_PATH_IPV6UP);
1194         }
1195         break;
1196     }
1197 }
1198
1199
1200 /*
1201  * ipv6cp_script - Execute a script with arguments
1202  * interface-name tty-name speed local-LL remote-LL.
1203  */
1204 static void
1205 ipv6cp_script(script)
1206     char *script;
1207 {
1208     char strspeed[32], strlocal[32], strremote[32];
1209     char *argv[8];
1210
1211     sprintf(strspeed, "%d", baud_rate);
1212     strcpy(strlocal, llv6_ntoa(ipv6cp_gotoptions[0].ourid));
1213     strcpy(strremote, llv6_ntoa(ipv6cp_hisoptions[0].hisid));
1214
1215     argv[0] = script;
1216     argv[1] = ifname;
1217     argv[2] = devnam;
1218     argv[3] = strspeed;
1219     argv[4] = strlocal;
1220     argv[5] = strremote;
1221     argv[6] = ipparam;
1222     argv[7] = NULL;
1223
1224     ipv6cp_script_pid = run_program(script, argv, 0, ipv6cp_script_done, NULL);
1225 }
1226
1227 /*
1228  * ipv6cp_printpkt - print the contents of an IPV6CP packet.
1229  */
1230 static char *ipv6cp_codenames[] = {
1231     "ConfReq", "ConfAck", "ConfNak", "ConfRej",
1232     "TermReq", "TermAck", "CodeRej"
1233 };
1234
1235 static int
1236 ipv6cp_printpkt(p, plen, printer, arg)
1237     u_char *p;
1238     int plen;
1239     void (*printer) __P((void *, char *, ...));
1240     void *arg;
1241 {
1242     int code, id, len, olen;
1243     u_char *pstart, *optend;
1244     u_short cishort;
1245     eui64_t ifaceid;
1246
1247     if (plen < HEADERLEN)
1248         return 0;
1249     pstart = p;
1250     GETCHAR(code, p);
1251     GETCHAR(id, p);
1252     GETSHORT(len, p);
1253     if (len < HEADERLEN || len > plen)
1254         return 0;
1255
1256     if (code >= 1 && code <= sizeof(ipv6cp_codenames) / sizeof(char *))
1257         printer(arg, " %s", ipv6cp_codenames[code-1]);
1258     else
1259         printer(arg, " code=0x%x", code);
1260     printer(arg, " id=0x%x", id);
1261     len -= HEADERLEN;
1262     switch (code) {
1263     case CONFREQ:
1264     case CONFACK:
1265     case CONFNAK:
1266     case CONFREJ:
1267         /* print option list */
1268         while (len >= 2) {
1269             GETCHAR(code, p);
1270             GETCHAR(olen, p);
1271             p -= 2;
1272             if (olen < 2 || olen > len) {
1273                 break;
1274             }
1275             printer(arg, " <");
1276             len -= olen;
1277             optend = p + olen;
1278             switch (code) {
1279             case CI_COMPRESSTYPE:
1280                 if (olen >= CILEN_COMPRESS) {
1281                     p += 2;
1282                     GETSHORT(cishort, p);
1283                     printer(arg, "compress ");
1284                     printer(arg, "0x%x", cishort);
1285                 }
1286                 break;
1287             case CI_IFACEID:
1288                 if (olen == CILEN_IFACEID) {
1289                     p += 2;
1290                     eui64_get(ifaceid, p);
1291                     printer(arg, "addr %s", llv6_ntoa(ifaceid));
1292                 }
1293                 break;
1294             }
1295             while (p < optend) {
1296                 GETCHAR(code, p);
1297                 printer(arg, " %.2x", code);
1298             }
1299             printer(arg, ">");
1300         }
1301         break;
1302
1303     case TERMACK:
1304     case TERMREQ:
1305         if (len > 0 && *p >= ' ' && *p < 0x7f) {
1306             printer(arg, " ");
1307             print_string(p, len, printer, arg);
1308             p += len;
1309             len = 0;
1310         }
1311         break;
1312     }
1313
1314     /* print the rest of the bytes in the packet */
1315     for (; len > 0; --len) {
1316         GETCHAR(code, p);
1317         printer(arg, " %.2x", code);
1318     }
1319
1320     return p - pstart;
1321 }
1322
1323 /*
1324  * ipv6_active_pkt - see if this IP packet is worth bringing the link up for.
1325  * We don't bring the link up for IP fragments or for TCP FIN packets
1326  * with no data.
1327  */
1328 #define IP6_HDRLEN      40      /* bytes */
1329 #define IP6_NHDR_FRAG   44      /* fragment IPv6 header */
1330 #define IPPROTO_TCP     6
1331 #define TCP_HDRLEN      20
1332 #define TH_FIN          0x01
1333
1334 /*
1335  * We use these macros because the IP header may be at an odd address,
1336  * and some compilers might use word loads to get th_off or ip_hl.
1337  */
1338
1339 #define get_ip6nh(x)    (((unsigned char *)(x))[6])
1340 #define get_tcpoff(x)   (((unsigned char *)(x))[12] >> 4)
1341 #define get_tcpflags(x) (((unsigned char *)(x))[13])
1342
1343 static int
1344 ipv6_active_pkt(pkt, len)
1345     u_char *pkt;
1346     int len;
1347 {
1348     u_char *tcp;
1349
1350     len -= PPP_HDRLEN;
1351     pkt += PPP_HDRLEN;
1352     if (len < IP6_HDRLEN)
1353         return 0;
1354     if (get_ip6nh(pkt) == IP6_NHDR_FRAG)
1355         return 0;
1356     if (get_ip6nh(pkt) != IPPROTO_TCP)
1357         return 1;
1358     if (len < IP6_HDRLEN + TCP_HDRLEN)
1359         return 0;
1360     tcp = pkt + IP6_HDRLEN;
1361     if ((get_tcpflags(tcp) & TH_FIN) != 0 && len == IP6_HDRLEN + get_tcpoff(tcp) * 4)
1362         return 0;
1363     return 1;
1364 }