]> git.ozlabs.org Git - ppp.git/blob - pppd/ipv6cp.c
The use of <net/ppp_defs.h> isn't guranteed to exist on Linux (e.g. uclibc, buildroot...
[ppp.git] / pppd / ipv6cp.c
1 /*
2  * ipv6cp.c - PPP IPV6 Control Protocol.
3  *
4  * Copyright (c) 1999 Tommi Komulainen.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  *
18  * 3. The name(s) of the authors of this software must not be used to
19  *    endorse or promote products derived from this software without
20  *    prior written permission.
21  *
22  * 4. Redistributions of any form whatsoever must retain the following
23  *    acknowledgment:
24  *    "This product includes software developed by Tommi Komulainen
25  *     <Tommi.Komulainen@iki.fi>".
26  *
27  * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
28  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
29  * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
30  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
31  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
32  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
33  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
34  *
35  */
36
37 /*  Original version, based on RFC2023 :
38
39     Copyright (c) 1995, 1996, 1997 Francis.Dupont@inria.fr, INRIA Rocquencourt,
40     Alain.Durand@imag.fr, IMAG,
41     Jean-Luc.Richier@imag.fr, IMAG-LSR.
42
43     Copyright (c) 1998, 1999 Francis.Dupont@inria.fr, GIE DYADE,
44     Alain.Durand@imag.fr, IMAG,
45     Jean-Luc.Richier@imag.fr, IMAG-LSR.
46
47     Ce travail a été fait au sein du GIE DYADE (Groupement d'Intérêt
48     Économique ayant pour membres BULL S.A. et l'INRIA).
49
50     Ce logiciel informatique est disponible aux conditions
51     usuelles dans la recherche, c'est-à-dire qu'il peut
52     être utilisé, copié, modifié, distribué à l'unique
53     condition que ce texte soit conservé afin que
54     l'origine de ce logiciel soit reconnue.
55
56     Le nom de l'Institut National de Recherche en Informatique
57     et en Automatique (INRIA), de l'IMAG, ou d'une personne morale
58     ou physique ayant participé à l'élaboration de ce logiciel ne peut
59     être utilisé sans son accord préalable explicite.
60
61     Ce logiciel est fourni tel quel sans aucune garantie,
62     support ou responsabilité d'aucune sorte.
63     Ce logiciel est dérivé de sources d'origine
64     "University of California at Berkeley" et
65     "Digital Equipment Corporation" couvertes par des copyrights.
66
67     L'Institut d'Informatique et de Mathématiques Appliquées de Grenoble (IMAG)
68     est une fédération d'unités mixtes de recherche du CNRS, de l'Institut National
69     Polytechnique de Grenoble et de l'Université Joseph Fourier regroupant
70     sept laboratoires dont le laboratoire Logiciels, Systèmes, Réseaux (LSR).
71
72     This work has been done in the context of GIE DYADE (joint R & D venture
73     between BULL S.A. and INRIA).
74
75     This software is available with usual "research" terms
76     with the aim of retain credits of the software. 
77     Permission to use, copy, modify and distribute this software for any
78     purpose and without fee is hereby granted, provided that the above
79     copyright notice and this permission notice appear in all copies,
80     and the name of INRIA, IMAG, or any contributor not be used in advertising
81     or publicity pertaining to this material without the prior explicit
82     permission. The software is provided "as is" without any
83     warranties, support or liabilities of any kind.
84     This software is derived from source code from
85     "University of California at Berkeley" and
86     "Digital Equipment Corporation" protected by copyrights.
87
88     Grenoble's Institute of Computer Science and Applied Mathematics (IMAG)
89     is a federation of seven research units funded by the CNRS, National
90     Polytechnic Institute of Grenoble and University Joseph Fourier.
91     The research unit in Software, Systems, Networks (LSR) is member of IMAG.
92 */
93
94 /*
95  * Derived from :
96  *
97  *
98  * ipcp.c - PPP IP Control Protocol.
99  *
100  * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved.
101  *
102  * Redistribution and use in source and binary forms, with or without
103  * modification, are permitted provided that the following conditions
104  * are met:
105  *
106  * 1. Redistributions of source code must retain the above copyright
107  *    notice, this list of conditions and the following disclaimer.
108  *
109  * 2. Redistributions in binary form must reproduce the above copyright
110  *    notice, this list of conditions and the following disclaimer in
111  *    the documentation and/or other materials provided with the
112  *    distribution.
113  *
114  * 3. The name "Carnegie Mellon University" must not be used to
115  *    endorse or promote products derived from this software without
116  *    prior written permission. For permission or any legal
117  *    details, please contact
118  *      Office of Technology Transfer
119  *      Carnegie Mellon University
120  *      5000 Forbes Avenue
121  *      Pittsburgh, PA  15213-3890
122  *      (412) 268-4387, fax: (412) 268-7395
123  *      tech-transfer@andrew.cmu.edu
124  *
125  * 4. Redistributions of any form whatsoever must retain the following
126  *    acknowledgment:
127  *    "This product includes software developed by Computing Services
128  *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
129  *
130  * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
131  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
132  * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
133  * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
134  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
135  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
136  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
137  */
138
139 /*
140  * TODO: 
141  *
142  * Proxy Neighbour Discovery.
143  *
144  * Better defines for selecting the ordering of
145  *   interface up / set address. (currently checks for __linux__,
146  *   since SVR4 && (SNI || __USLC__) didn't work properly)
147  */
148
149 #ifdef HAVE_CONFIG_H
150 #include "config.h"
151 #endif
152
153 #include <stdio.h>
154 #include <stdlib.h>
155 #include <string.h>
156 #include <errno.h>
157 #include <unistd.h>
158 #include <netdb.h>
159 #include <sys/param.h>
160 #include <sys/types.h>
161 #include <sys/socket.h>
162 #include <netinet/in.h>
163 #include <arpa/inet.h>
164
165 #include "pppd.h"
166 #include "fsm.h"
167 #include "eui64.h"
168 #include "ipcp.h"
169 #include "ipv6cp.h"
170 #include "magic.h"
171 #include "pathnames.h"
172
173
174 /* global vars */
175 ipv6cp_options ipv6cp_wantoptions[NUM_PPP];     /* Options that we want to request */
176 ipv6cp_options ipv6cp_gotoptions[NUM_PPP];      /* Options that peer ack'd */
177 ipv6cp_options ipv6cp_allowoptions[NUM_PPP];    /* Options we allow peer to request */
178 ipv6cp_options ipv6cp_hisoptions[NUM_PPP];      /* Options that we ack'd */
179 int no_ifaceid_neg = 0;
180
181 /* local vars */
182 static int default_route_set[NUM_PPP];          /* Have set up a default route */
183 static int ipv6cp_is_up;
184 static bool ipv6cp_noremote;
185
186 /* Hook for a plugin to know when IPv6 protocol has come up */
187 void (*ipv6_up_hook)(void) = NULL;
188
189 /* Hook for a plugin to know when IPv6 protocol has come down */
190 void (*ipv6_down_hook)(void) = NULL;
191
192 /* Notifiers for when IPCPv6 goes up and down */
193 struct notifier *ipv6_up_notifier = NULL;
194 struct notifier *ipv6_down_notifier = NULL;
195
196 /*
197  * Callbacks for fsm code.  (CI = Configuration Information)
198  */
199 static void ipv6cp_resetci (fsm *);     /* Reset our CI */
200 static int  ipv6cp_cilen (fsm *);               /* Return length of our CI */
201 static void ipv6cp_addci (fsm *, u_char *, int *); /* Add our CI */
202 static int  ipv6cp_ackci (fsm *, u_char *, int);        /* Peer ack'd our CI */
203 static int  ipv6cp_nakci (fsm *, u_char *, int, int);/* Peer nak'd our CI */
204 static int  ipv6cp_rejci (fsm *, u_char *, int);        /* Peer rej'd our CI */
205 static int  ipv6cp_reqci (fsm *, u_char *, int *, int); /* Rcv CI */
206 static void ipv6cp_up (fsm *);          /* We're UP */
207 static void ipv6cp_down (fsm *);                /* We're DOWN */
208 static void ipv6cp_finished (fsm *);    /* Don't need lower layer */
209
210 fsm ipv6cp_fsm[NUM_PPP];                /* IPV6CP fsm structure */
211
212 static fsm_callbacks ipv6cp_callbacks = { /* IPV6CP callback routines */
213     ipv6cp_resetci,             /* Reset our Configuration Information */
214     ipv6cp_cilen,               /* Length of our Configuration Information */
215     ipv6cp_addci,               /* Add our Configuration Information */
216     ipv6cp_ackci,               /* ACK our Configuration Information */
217     ipv6cp_nakci,               /* NAK our Configuration Information */
218     ipv6cp_rejci,               /* Reject our Configuration Information */
219     ipv6cp_reqci,               /* Request peer's Configuration Information */
220     ipv6cp_up,                  /* Called when fsm reaches OPENED state */
221     ipv6cp_down,                /* Called when fsm leaves OPENED state */
222     NULL,                       /* Called when we want the lower layer up */
223     ipv6cp_finished,            /* Called when we want the lower layer down */
224     NULL,                       /* Called when Protocol-Reject received */
225     NULL,                       /* Retransmission is necessary */
226     NULL,                       /* Called to handle protocol-specific codes */
227     "IPV6CP"                    /* String name of protocol */
228 };
229
230 /*
231  * Command-line options.
232  */
233 static int setifaceid (char **arg);
234 static void printifaceid (option_t *,
235                           void (*)(void *, char *, ...), void *);
236
237 static option_t ipv6cp_option_list[] = {
238     { "ipv6", o_special, (void *)setifaceid,
239       "Set interface identifiers for IPV6",
240       OPT_A2PRINTER, (void *)printifaceid },
241
242     { "+ipv6", o_bool, &ipv6cp_protent.enabled_flag,
243       "Enable IPv6 and IPv6CP", OPT_PRIO | 1 },
244     { "noipv6", o_bool, &ipv6cp_protent.enabled_flag,
245       "Disable IPv6 and IPv6CP", OPT_PRIOSUB },
246     { "-ipv6", o_bool, &ipv6cp_protent.enabled_flag,
247       "Disable IPv6 and IPv6CP", OPT_PRIOSUB | OPT_ALIAS },
248
249     { "ipv6cp-accept-local", o_bool, &ipv6cp_wantoptions[0].accept_local,
250       "Accept peer's interface identifier for us", 1 },
251     { "ipv6cp-accept-remote", o_bool, &ipv6cp_wantoptions[0].accept_remote,
252       "Accept peer's interface identifier for itself", 1 },
253
254     { "defaultroute6", o_bool, &ipv6cp_wantoptions[0].default_route,
255       "Add default IPv6 route", OPT_ENABLE|1, &ipv6cp_allowoptions[0].default_route },
256     { "nodefaultroute6", o_bool, &ipv6cp_allowoptions[0].default_route,
257       "disable defaultroute6 option", OPT_A2CLR,
258       &ipv6cp_wantoptions[0].default_route },
259     { "-defaultroute6", o_bool, &ipv6cp_allowoptions[0].default_route,
260       "disable defaultroute6 option", OPT_ALIAS | OPT_A2CLR,
261       &ipv6cp_wantoptions[0].default_route },
262
263     { "ipv6cp-use-ipaddr", o_bool, &ipv6cp_allowoptions[0].use_ip,
264       "Use (default) IPv4 addresses for both local and remote interface identifiers", 1 },
265     { "ipv6cp-use-persistent", o_bool, &ipv6cp_wantoptions[0].use_persistent,
266       "Use uniquely-available persistent value for local interface identifier", 1 },
267     { "ipv6cp-use-remotenumber", o_bool, &ipv6cp_wantoptions[0].use_remotenumber,
268       "Use remotenumber value for remote interface identifier", 1 },
269
270 #ifdef __linux__
271     { "ipv6cp-noremote", o_bool, &ipv6cp_noremote,
272       "Allow peer to have no interface identifier", 1 },
273 #endif
274     { "ipv6cp-nosend", o_bool, &ipv6cp_wantoptions[0].neg_ifaceid,
275       "Don't send local interface identifier to peer", OPT_A2CLR },
276
277     { "ipv6cp-restart", o_int, &ipv6cp_fsm[0].timeouttime,
278       "Set timeout for IPv6CP", OPT_PRIO },
279     { "ipv6cp-max-terminate", o_int, &ipv6cp_fsm[0].maxtermtransmits,
280       "Set max #xmits for term-reqs", OPT_PRIO },
281     { "ipv6cp-max-configure", o_int, &ipv6cp_fsm[0].maxconfreqtransmits,
282       "Set max #xmits for conf-reqs", OPT_PRIO },
283     { "ipv6cp-max-failure", o_int, &ipv6cp_fsm[0].maxnakloops,
284       "Set max #conf-naks for IPv6CP", OPT_PRIO },
285
286    { NULL }
287 };
288
289
290 /*
291  * Protocol entry points from main code.
292  */
293 static void ipv6cp_init (int);
294 static void ipv6cp_open (int);
295 static void ipv6cp_close (int, char *);
296 static void ipv6cp_lowerup (int);
297 static void ipv6cp_lowerdown (int);
298 static void ipv6cp_input (int, u_char *, int);
299 static void ipv6cp_protrej (int);
300 static int  ipv6cp_printpkt (u_char *, int,
301                              void (*) (void *, char *, ...), void *);
302 static void ipv6_check_options (void);
303 static int  ipv6_demand_conf (int);
304 static int  ipv6_active_pkt (u_char *, int);
305
306 struct protent ipv6cp_protent = {
307     PPP_IPV6CP,
308     ipv6cp_init,
309     ipv6cp_input,
310     ipv6cp_protrej,
311     ipv6cp_lowerup,
312     ipv6cp_lowerdown,
313     ipv6cp_open,
314     ipv6cp_close,
315     ipv6cp_printpkt,
316     NULL,
317     1,
318     "IPV6CP",
319     "IPV6",
320     ipv6cp_option_list,
321     ipv6_check_options,
322     ipv6_demand_conf,
323     ipv6_active_pkt
324 };
325
326 static void ipv6cp_clear_addrs (int, eui64_t, eui64_t);
327 static void ipv6cp_script (char *);
328 static void ipv6cp_script_done (void *);
329
330 /*
331  * Lengths of configuration options.
332  */
333 #define CILEN_VOID      2
334 #define CILEN_COMPRESS  4       /* length for RFC2023 compress opt. */
335 #define CILEN_IFACEID   10      /* RFC2472, interface identifier    */
336
337 #define CODENAME(x)     ((x) == CONFACK ? "ACK" : \
338                          (x) == CONFNAK ? "NAK" : "REJ")
339
340 /*
341  * This state variable is used to ensure that we don't
342  * run an ipcp-up/down script while one is already running.
343  */
344 static enum script_state {
345     s_down,
346     s_up,
347 } ipv6cp_script_state;
348 static pid_t ipv6cp_script_pid;
349
350 /*
351  * setifaceid - set the interface identifiers manually
352  */
353 static int
354 setifaceid(char **argv)
355 {
356     char *comma, *arg, c;
357     ipv6cp_options *wo = &ipv6cp_wantoptions[0];
358     struct in6_addr addr;
359     static int prio_local, prio_remote;
360
361 #define VALIDID(a) ( (((a).s6_addr32[0] == 0) && ((a).s6_addr32[1] == 0)) && \
362                         (((a).s6_addr32[2] != 0) || ((a).s6_addr32[3] != 0)) )
363     
364     arg = *argv;
365     if ((comma = strchr(arg, ',')) == NULL)
366         comma = arg + strlen(arg);
367     
368     /* 
369      * If comma first character, then no local identifier
370      */
371     if (comma != arg) {
372         c = *comma;
373         *comma = '\0';
374
375         if (inet_pton(AF_INET6, arg, &addr) == 0 || !VALIDID(addr)) {
376             option_error("Illegal interface identifier (local): %s", arg);
377             return 0;
378         }
379
380         if (option_priority >= prio_local) {
381             eui64_copy(addr.s6_addr32[2], wo->ourid);
382             wo->opt_local = 1;
383             prio_local = option_priority;
384         }
385         *comma = c;
386     }
387     
388     /*
389      * If comma last character, the no remote identifier
390      */
391     if (*comma != 0 && *++comma != '\0') {
392         if (inet_pton(AF_INET6, comma, &addr) == 0 || !VALIDID(addr)) {
393             option_error("Illegal interface identifier (remote): %s", comma);
394             return 0;
395         }
396         if (option_priority >= prio_remote) {
397             eui64_copy(addr.s6_addr32[2], wo->hisid);
398             wo->opt_remote = 1;
399             prio_remote = option_priority;
400         }
401     }
402
403     if (override_value("+ipv6", option_priority, option_source))
404         ipv6cp_protent.enabled_flag = 1;
405     return 1;
406 }
407
408 char *llv6_ntoa(eui64_t ifaceid);
409
410 static void
411 printifaceid(option_t *opt, void (*printer) (void *, char *, ...), void *arg)
412 {
413         ipv6cp_options *wo = &ipv6cp_wantoptions[0];
414
415         if (wo->opt_local)
416                 printer(arg, "%s", llv6_ntoa(wo->ourid));
417         printer(arg, ",");
418         if (wo->opt_remote)
419                 printer(arg, "%s", llv6_ntoa(wo->hisid));
420 }
421
422 /*
423  * Make a string representation of a network address.
424  */
425 char *
426 llv6_ntoa(eui64_t ifaceid)
427 {
428     static char b[64];
429
430     sprintf(b, "fe80::%s", eui64_ntoa(ifaceid));
431     return b;
432 }
433
434
435 /*
436  * ipv6cp_init - Initialize IPV6CP.
437  */
438 static void
439 ipv6cp_init(int unit)
440 {
441     fsm *f = &ipv6cp_fsm[unit];
442     ipv6cp_options *wo = &ipv6cp_wantoptions[unit];
443     ipv6cp_options *ao = &ipv6cp_allowoptions[unit];
444
445     f->unit = unit;
446     f->protocol = PPP_IPV6CP;
447     f->callbacks = &ipv6cp_callbacks;
448     fsm_init(&ipv6cp_fsm[unit]);
449
450     memset(wo, 0, sizeof(*wo));
451     memset(ao, 0, sizeof(*ao));
452
453     wo->accept_local = 0;
454     wo->accept_remote = 0;
455     wo->neg_ifaceid = 1;
456     ao->neg_ifaceid = 1;
457
458 #ifdef IPV6CP_COMP
459     wo->neg_vj = 1;
460     ao->neg_vj = 1;
461     wo->vj_protocol = IPV6CP_COMP;
462 #endif
463
464     /*
465      * XXX This controls whether the user may use the defaultroute option.
466      */
467     ao->default_route = 1;
468 }
469
470
471 /*
472  * ipv6cp_open - IPV6CP is allowed to come up.
473  */
474 static void
475 ipv6cp_open(int unit)
476 {
477     fsm_open(&ipv6cp_fsm[unit]);
478 }
479
480
481 /*
482  * ipv6cp_close - Take IPV6CP down.
483  */
484 static void
485 ipv6cp_close(int unit, char *reason)
486 {
487     fsm_close(&ipv6cp_fsm[unit], reason);
488 }
489
490
491 /*
492  * ipv6cp_lowerup - The lower layer is up.
493  */
494 static void
495 ipv6cp_lowerup(int unit)
496 {
497     fsm_lowerup(&ipv6cp_fsm[unit]);
498 }
499
500
501 /*
502  * ipv6cp_lowerdown - The lower layer is down.
503  */
504 static void
505 ipv6cp_lowerdown(int unit)
506 {
507     fsm_lowerdown(&ipv6cp_fsm[unit]);
508 }
509
510
511 /*
512  * ipv6cp_input - Input IPV6CP packet.
513  */
514 static void
515 ipv6cp_input(int unit, u_char *p, int len)
516 {
517     fsm_input(&ipv6cp_fsm[unit], p, len);
518 }
519
520
521 /*
522  * ipv6cp_protrej - A Protocol-Reject was received for IPV6CP.
523  *
524  * Pretend the lower layer went down, so we shut up.
525  */
526 static void
527 ipv6cp_protrej(int unit)
528 {
529     fsm_lowerdown(&ipv6cp_fsm[unit]);
530 }
531
532
533 /*
534  * ipv6cp_resetci - Reset our CI.
535  */
536 static void
537 ipv6cp_resetci(fsm *f)
538 {
539     ipv6cp_options *wo = &ipv6cp_wantoptions[f->unit];
540     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
541
542     wo->req_ifaceid = wo->neg_ifaceid && ipv6cp_allowoptions[f->unit].neg_ifaceid;
543     
544     if (!wo->opt_local) {
545         wo->accept_local = 1;
546         if (!demand)
547             eui64_magic_nz(wo->ourid);
548     }
549     if (!wo->opt_remote)
550         wo->accept_remote = 1;
551     
552     *go = *wo;
553     eui64_zero(go->hisid);      /* last proposed interface identifier */
554 }
555
556
557 /*
558  * ipv6cp_cilen - Return length of our CI.
559  */
560 static int
561 ipv6cp_cilen(fsm *f)
562 {
563     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
564
565 #define LENCIVJ(neg)            (neg ? CILEN_COMPRESS : 0)
566 #define LENCIIFACEID(neg)       (neg ? CILEN_IFACEID : 0)
567
568     return (LENCIIFACEID(go->neg_ifaceid) +
569             LENCIVJ(go->neg_vj));
570 }
571
572
573 /*
574  * ipv6cp_addci - Add our desired CIs to a packet.
575  */
576 static void
577 ipv6cp_addci(fsm *f, u_char *ucp, int *lenp)
578 {
579     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
580     int len = *lenp;
581
582 #define ADDCIVJ(opt, neg, val) \
583     if (neg) { \
584         int vjlen = CILEN_COMPRESS; \
585         if (len >= vjlen) { \
586             PUTCHAR(opt, ucp); \
587             PUTCHAR(vjlen, ucp); \
588             PUTSHORT(val, ucp); \
589             len -= vjlen; \
590         } else \
591             neg = 0; \
592     }
593
594 #define ADDCIIFACEID(opt, neg, val1) \
595     if (neg) { \
596         int idlen = CILEN_IFACEID; \
597         if (len >= idlen) { \
598             PUTCHAR(opt, ucp); \
599             PUTCHAR(idlen, ucp); \
600             eui64_put(val1, ucp); \
601             len -= idlen; \
602         } else \
603             neg = 0; \
604     }
605
606     ADDCIIFACEID(CI_IFACEID, go->neg_ifaceid, go->ourid);
607
608     ADDCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol);
609
610     *lenp -= len;
611 }
612
613
614 /*
615  * ipv6cp_ackci - Ack our CIs.
616  *
617  * Returns:
618  *      0 - Ack was bad.
619  *      1 - Ack was good.
620  */
621 static int
622 ipv6cp_ackci(fsm *f, u_char *p, int len)
623 {
624     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
625     u_short cilen, citype, cishort;
626     eui64_t ifaceid;
627
628     /*
629      * CIs must be in exactly the same order that we sent...
630      * Check packet length and CI length at each step.
631      * If we find any deviations, then this packet is bad.
632      */
633
634 #define ACKCIVJ(opt, neg, val) \
635     if (neg) { \
636         int vjlen = CILEN_COMPRESS; \
637         if ((len -= vjlen) < 0) \
638             goto bad; \
639         GETCHAR(citype, p); \
640         GETCHAR(cilen, p); \
641         if (cilen != vjlen || \
642             citype != opt)  \
643             goto bad; \
644         GETSHORT(cishort, p); \
645         if (cishort != val) \
646             goto bad; \
647     }
648
649 #define ACKCIIFACEID(opt, neg, val1) \
650     if (neg) { \
651         int idlen = CILEN_IFACEID; \
652         if ((len -= idlen) < 0) \
653             goto bad; \
654         GETCHAR(citype, p); \
655         GETCHAR(cilen, p); \
656         if (cilen != idlen || \
657             citype != opt) \
658             goto bad; \
659         eui64_get(ifaceid, p); \
660         if (! eui64_equals(val1, ifaceid)) \
661             goto bad; \
662     }
663
664     ACKCIIFACEID(CI_IFACEID, go->neg_ifaceid, go->ourid);
665
666     ACKCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol);
667
668     /*
669      * If there are any remaining CIs, then this packet is bad.
670      */
671     if (len != 0)
672         goto bad;
673     return (1);
674
675 bad:
676     IPV6CPDEBUG(("ipv6cp_ackci: received bad Ack!"));
677     return (0);
678 }
679
680 /*
681  * ipv6cp_nakci - Peer has sent a NAK for some of our CIs.
682  * This should not modify any state if the Nak is bad
683  * or if IPV6CP is in the OPENED state.
684  *
685  * Returns:
686  *      0 - Nak was bad.
687  *      1 - Nak was good.
688  */
689 static int
690 ipv6cp_nakci(fsm *f, u_char *p, int len, int treat_as_reject)
691 {
692     ipv6cp_options *wo = &ipv6cp_wantoptions[f->unit];
693     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
694     u_char citype, cilen, *next;
695     u_short cishort;
696     eui64_t ifaceid;
697     ipv6cp_options no;          /* options we've seen Naks for */
698     ipv6cp_options try;         /* options to request next time */
699
700     BZERO(&no, sizeof(no));
701     try = *go;
702
703     /*
704      * Any Nak'd CIs must be in exactly the same order that we sent.
705      * Check packet length and CI length at each step.
706      * If we find any deviations, then this packet is bad.
707      */
708 #define NAKCIIFACEID(opt, neg, code) \
709     if (go->neg && \
710         len >= (cilen = CILEN_IFACEID) && \
711         p[1] == cilen && \
712         p[0] == opt) { \
713         len -= cilen; \
714         INCPTR(2, p); \
715         eui64_get(ifaceid, p); \
716         no.neg = 1; \
717         code \
718     }
719
720 #define NAKCIVJ(opt, neg, code) \
721     if (go->neg && \
722         ((cilen = p[1]) == CILEN_COMPRESS) && \
723         len >= cilen && \
724         p[0] == opt) { \
725         len -= cilen; \
726         INCPTR(2, p); \
727         GETSHORT(cishort, p); \
728         no.neg = 1; \
729         code \
730     }
731
732     /*
733      * Accept the peer's idea of {our,his} interface identifier, if different
734      * from our idea, only if the accept_{local,remote} flag is set.
735      */
736     NAKCIIFACEID(CI_IFACEID, neg_ifaceid,
737                  if (treat_as_reject) {
738                      try.neg_ifaceid = 0;
739                  } else if (go->accept_local && !eui64_iszero(ifaceid) && !eui64_equals(ifaceid, go->hisid)) {
740                      try.ourid = ifaceid;
741                  } else if (eui64_iszero(ifaceid) && !go->opt_local && wo->neg_ifaceid) {
742                      while (eui64_iszero(ifaceid) || 
743                             eui64_equals(ifaceid, go->hisid)) /* bad luck */
744                          eui64_magic(ifaceid);
745                      try.ourid = ifaceid;
746                      IPV6CPDEBUG(("local LL address %s", llv6_ntoa(ifaceid)));
747                  }
748                  );
749
750 #ifdef IPV6CP_COMP
751     NAKCIVJ(CI_COMPRESSTYPE, neg_vj,
752             {
753                 if (cishort == IPV6CP_COMP && !treat_as_reject) {
754                     try.vj_protocol = cishort;
755                 } else {
756                     try.neg_vj = 0;
757                 }
758             }
759             );
760 #else
761     NAKCIVJ(CI_COMPRESSTYPE, neg_vj,
762             {
763                 try.neg_vj = 0;
764             }
765             );
766 #endif
767
768     /*
769      * There may be remaining CIs, if the peer is requesting negotiation
770      * on an option that we didn't include in our request packet.
771      * If they want to negotiate about interface identifier, we comply.
772      * If they want us to ask for compression, we refuse.
773      */
774     while (len >= CILEN_VOID) {
775         GETCHAR(citype, p);
776         GETCHAR(cilen, p);
777         if ( cilen < CILEN_VOID || (len -= cilen) < 0 )
778             goto bad;
779         next = p + cilen - 2;
780
781         switch (citype) {
782         case CI_COMPRESSTYPE:
783             if (go->neg_vj || no.neg_vj ||
784                 (cilen != CILEN_COMPRESS))
785                 goto bad;
786             no.neg_vj = 1;
787             break;
788         case CI_IFACEID:
789             if (go->neg_ifaceid || no.neg_ifaceid || cilen != CILEN_IFACEID)
790                 goto bad;
791             try.neg_ifaceid = 1;
792             eui64_get(ifaceid, p);
793             if (go->accept_local && !eui64_iszero(ifaceid) && !eui64_equals(ifaceid, go->hisid)) {
794                 try.ourid = ifaceid;
795             } else if (eui64_iszero(ifaceid) && !go->opt_local && wo->neg_ifaceid) {
796                 while (eui64_iszero(ifaceid) || 
797                        eui64_equals(ifaceid, go->hisid)) /* bad luck */
798                     eui64_magic(ifaceid);
799                 try.ourid = ifaceid;
800             } else {
801                 try.neg_ifaceid = 0;
802             }
803             no.neg_ifaceid = 1;
804             break;
805         }
806         p = next;
807     }
808
809     /* If there is still anything left, this packet is bad. */
810     if (len != 0)
811         goto bad;
812
813     /*
814      * OK, the Nak is good.  Now we can update state.
815      */
816     if (f->state != OPENED)
817         *go = try;
818
819     return 1;
820
821 bad:
822     IPV6CPDEBUG(("ipv6cp_nakci: received bad Nak!"));
823     return 0;
824 }
825
826
827 /*
828  * ipv6cp_rejci - Reject some of our CIs.
829  */
830 static int
831 ipv6cp_rejci(fsm *f, u_char *p, int len)
832 {
833     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
834     u_char cilen;
835     u_short cishort;
836     eui64_t ifaceid;
837     ipv6cp_options try;         /* options to request next time */
838
839     try = *go;
840     /*
841      * Any Rejected CIs must be in exactly the same order that we sent.
842      * Check packet length and CI length at each step.
843      * If we find any deviations, then this packet is bad.
844      */
845 #define REJCIIFACEID(opt, neg, val1) \
846     if (go->neg && \
847         len >= (cilen = CILEN_IFACEID) && \
848         p[1] == cilen && \
849         p[0] == opt) { \
850         len -= cilen; \
851         INCPTR(2, p); \
852         eui64_get(ifaceid, p); \
853         /* Check rejected value. */ \
854         if (! eui64_equals(ifaceid, val1)) \
855             goto bad; \
856         try.neg = 0; \
857     }
858
859 #define REJCIVJ(opt, neg, val) \
860     if (go->neg && \
861         p[1] == CILEN_COMPRESS && \
862         len >= p[1] && \
863         p[0] == opt) { \
864         len -= p[1]; \
865         INCPTR(2, p); \
866         GETSHORT(cishort, p); \
867         /* Check rejected value. */  \
868         if (cishort != val) \
869             goto bad; \
870         try.neg = 0; \
871      }
872
873     REJCIIFACEID(CI_IFACEID, neg_ifaceid, go->ourid);
874
875     REJCIVJ(CI_COMPRESSTYPE, neg_vj, go->vj_protocol);
876
877     /*
878      * If there are any remaining CIs, then this packet is bad.
879      */
880     if (len != 0)
881         goto bad;
882     /*
883      * Now we can update state.
884      */
885     if (f->state != OPENED)
886         *go = try;
887     return 1;
888
889 bad:
890     IPV6CPDEBUG(("ipv6cp_rejci: received bad Reject!"));
891     return 0;
892 }
893
894
895 /*
896  * ipv6cp_reqci - Check the peer's requested CIs and send appropriate response.
897  *
898  * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified
899  * appropriately.  If reject_if_disagree is non-zero, doesn't return
900  * CONFNAK; returns CONFREJ if it can't return CONFACK.
901  */
902 static int
903 ipv6cp_reqci(fsm *f, u_char *inp, int *len, int reject_if_disagree)
904 {
905     ipv6cp_options *wo = &ipv6cp_wantoptions[f->unit];
906     ipv6cp_options *ho = &ipv6cp_hisoptions[f->unit];
907     ipv6cp_options *ao = &ipv6cp_allowoptions[f->unit];
908     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
909     u_char *cip, *next;         /* Pointer to current and next CIs */
910     u_short cilen, citype;      /* Parsed len, type */
911     u_short cishort;            /* Parsed short value */
912     eui64_t ifaceid;            /* Parsed interface identifier */
913     int rc = CONFACK;           /* Final packet return code */
914     int orc;                    /* Individual option return code */
915     u_char *p;                  /* Pointer to next char to parse */
916     u_char *ucp = inp;          /* Pointer to current output char */
917     int l = *len;               /* Length left */
918
919     /*
920      * Reset all his options.
921      */
922     BZERO(ho, sizeof(*ho));
923     
924     /*
925      * Process all his options.
926      */
927     next = inp;
928     while (l) {
929         orc = CONFACK;                  /* Assume success */
930         cip = p = next;                 /* Remember begining of CI */
931         if (l < 2 ||                    /* Not enough data for CI header or */
932             p[1] < 2 ||                 /*  CI length too small or */
933             p[1] > l) {                 /*  CI length too big? */
934             IPV6CPDEBUG(("ipv6cp_reqci: bad CI length!"));
935             orc = CONFREJ;              /* Reject bad CI */
936             cilen = l;                  /* Reject till end of packet */
937             l = 0;                      /* Don't loop again */
938             goto endswitch;
939         }
940         GETCHAR(citype, p);             /* Parse CI type */
941         GETCHAR(cilen, p);              /* Parse CI length */
942         l -= cilen;                     /* Adjust remaining length */
943         next += cilen;                  /* Step to next CI */
944
945         switch (citype) {               /* Check CI type */
946         case CI_IFACEID:
947             IPV6CPDEBUG(("ipv6cp: received interface identifier "));
948
949             if (!ao->neg_ifaceid ||
950                 cilen != CILEN_IFACEID) {       /* Check CI length */
951                 orc = CONFREJ;          /* Reject CI */
952                 break;
953             }
954
955             /*
956              * If he has no interface identifier, or if we both have same 
957              * identifier then NAK it with new idea.
958              * In particular, if we don't know his identifier, but he does,
959              * then accept it.
960              */
961             eui64_get(ifaceid, p);
962             IPV6CPDEBUG(("(%s)", llv6_ntoa(ifaceid)));
963             if (eui64_iszero(ifaceid) && eui64_iszero(go->ourid)) {
964                 orc = CONFREJ;          /* Reject CI */
965                 break;
966             }
967             if (!eui64_iszero(wo->hisid) && !wo->accept_remote &&
968                 !eui64_equals(ifaceid, wo->hisid)) {
969                     
970                 orc = CONFNAK;
971                 ifaceid = wo->hisid;
972                 go->hisid = ifaceid;
973                 DECPTR(sizeof(ifaceid), p);
974                 eui64_put(ifaceid, p);
975             } else
976             if (eui64_iszero(ifaceid) || eui64_equals(ifaceid, go->ourid)) {
977                 orc = CONFNAK;
978                 if (eui64_iszero(go->hisid))    /* first time, try option */
979                     ifaceid = wo->hisid;
980                 if (eui64_equals(ifaceid, go->ourid)) /* bad luck */
981                     eui64_zero(ifaceid);
982                 if (eui64_iszero(ifaceid)) {
983                     if (wo->opt_remote)
984                         ifaceid = wo->hisid;
985                     else {
986                         while (eui64_iszero(ifaceid) ||
987                                eui64_equals(ifaceid, go->ourid)) /* bad luck */
988                             eui64_magic(ifaceid);
989                     }
990                 }
991                 go->hisid = ifaceid;
992                 DECPTR(sizeof(ifaceid), p);
993                 eui64_put(ifaceid, p);
994             }
995
996             ho->neg_ifaceid = 1;
997             ho->hisid = ifaceid;
998             break;
999
1000         case CI_COMPRESSTYPE:
1001             IPV6CPDEBUG(("ipv6cp: received COMPRESSTYPE "));
1002             if (!ao->neg_vj ||
1003                 (cilen != CILEN_COMPRESS)) {
1004                 orc = CONFREJ;
1005                 break;
1006             }
1007             GETSHORT(cishort, p);
1008             IPV6CPDEBUG(("(%d)", cishort));
1009
1010 #ifdef IPV6CP_COMP
1011             if (!(cishort == IPV6CP_COMP)) {
1012                 orc = CONFREJ;
1013                 break;
1014             }
1015
1016             ho->neg_vj = 1;
1017             ho->vj_protocol = cishort;
1018             break;
1019 #else
1020             orc = CONFREJ;
1021             break;
1022 #endif
1023
1024         default:
1025             orc = CONFREJ;
1026             break;
1027         }
1028
1029 endswitch:
1030         IPV6CPDEBUG((" (%s)\n", CODENAME(orc)));
1031
1032         if (orc == CONFACK &&           /* Good CI */
1033             rc != CONFACK)              /*  but prior CI wasnt? */
1034             continue;                   /* Don't send this one */
1035
1036         if (orc == CONFNAK) {           /* Nak this CI? */
1037             if (reject_if_disagree)     /* Getting fed up with sending NAKs? */
1038                 orc = CONFREJ;          /* Get tough if so */
1039             else {
1040                 if (rc == CONFREJ)      /* Rejecting prior CI? */
1041                     continue;           /* Don't send this one */
1042                 if (rc == CONFACK) {    /* Ack'd all prior CIs? */
1043                     rc = CONFNAK;       /* Not anymore... */
1044                     ucp = inp;          /* Backup */
1045                 }
1046             }
1047         }
1048
1049         if (orc == CONFREJ &&           /* Reject this CI */
1050             rc != CONFREJ) {            /*  but no prior ones? */
1051             rc = CONFREJ;
1052             ucp = inp;                  /* Backup */
1053         }
1054
1055         /* Need to move CI? */
1056         if (ucp != cip)
1057             BCOPY(cip, ucp, cilen);     /* Move it */
1058
1059         /* Update output pointer */
1060         INCPTR(cilen, ucp);
1061     }
1062
1063     /*
1064      * If we aren't rejecting this packet, and we want to negotiate
1065      * their identifier and they didn't send their identifier, then we
1066      * send a NAK with a CI_IFACEID option appended.  We assume the
1067      * input buffer is long enough that we can append the extra
1068      * option safely.
1069      */
1070     if (rc != CONFREJ && !ho->neg_ifaceid &&
1071         wo->req_ifaceid && !reject_if_disagree) {
1072         if (rc == CONFACK) {
1073             rc = CONFNAK;
1074             ucp = inp;                          /* reset pointer */
1075             wo->req_ifaceid = 0;                /* don't ask again */
1076         }
1077         PUTCHAR(CI_IFACEID, ucp);
1078         PUTCHAR(CILEN_IFACEID, ucp);
1079         eui64_put(wo->hisid, ucp);
1080     }
1081
1082     *len = ucp - inp;                   /* Compute output length */
1083     IPV6CPDEBUG(("ipv6cp: returning Configure-%s", CODENAME(rc)));
1084     return (rc);                        /* Return final code */
1085 }
1086
1087
1088 /*
1089  * eui48_to_eui64 - Convert the EUI-48 into EUI-64, per RFC 2472 [sec 4.1]
1090  */
1091 static void
1092 eui48_to_eui64(eui64_t *p_eui64, const u_char addr[6])
1093 {
1094     p_eui64->e8[0] = addr[0] | 0x02;
1095     p_eui64->e8[1] = addr[1];
1096     p_eui64->e8[2] = addr[2];
1097     p_eui64->e8[3] = 0xFF;
1098     p_eui64->e8[4] = 0xFE;
1099     p_eui64->e8[5] = addr[3];
1100     p_eui64->e8[6] = addr[4];
1101     p_eui64->e8[7] = addr[5];
1102 }
1103
1104
1105 /*
1106  * ether_to_eui64 - Convert 48-bit Ethernet address into 64-bit EUI
1107  *
1108  * walks the list of valid ethernet interfaces, starting with devnam
1109  * (for PPPoE it is ethernet interface), and convert the first
1110  * found 48-bit MAC address into EUI 64. caller also assumes that
1111  * the system has a properly configured Ethernet interface for this
1112  * function to return non-zero.
1113  */
1114 static int
1115 ether_to_eui64(eui64_t *p_eui64)
1116 {
1117     u_char addr[6];
1118
1119     if (get_if_hwaddr(addr, devnam) < 0 && get_first_ether_hwaddr(addr) < 0) {
1120         error("ipv6cp: no persistent id can be found");
1121         return 0;
1122     }
1123
1124     eui48_to_eui64(p_eui64, addr);
1125     return 1;
1126 }
1127
1128
1129 /*
1130  * ipv6_check_options - check that any IP-related options are OK,
1131  * and assign appropriate defaults.
1132  */
1133 static void
1134 ipv6_check_options(void)
1135 {
1136     ipv6cp_options *wo = &ipv6cp_wantoptions[0];
1137
1138     if (!ipv6cp_protent.enabled_flag)
1139         return;
1140
1141     /*
1142      * Persistent link-local id is only used when user has not explicitly
1143      * configure/hard-code the id
1144      */
1145     if ((wo->use_persistent) && (!wo->opt_local)) {
1146
1147         /* 
1148          * On systems where there are no Ethernet interfaces used, there
1149          * may be other ways to obtain a persistent id. Right now, it
1150          * will fall back to using magic [see eui64_magic] below when
1151          * an EUI-48 from MAC address can't be obtained. Other possibilities
1152          * include obtaining EEPROM serial numbers, or some other unique
1153          * yet persistent number. On Sparc platforms, this is possible,
1154          * but too bad there's no standards yet for x86 machines.
1155          */
1156         if (ether_to_eui64(&wo->ourid)) {
1157             wo->opt_local = 1;
1158         }
1159     }
1160
1161     if (!wo->opt_remote && wo->use_remotenumber && *remote_number) {
1162         /* remote number can be either MAC address, IPv4 address, IPv6 address or telephone number */
1163         struct in_addr addr;
1164         struct in6_addr addr6;
1165         unsigned long long tel;
1166         unsigned char mac[6];
1167         const char *str;
1168         char *endptr;
1169         if (sscanf(remote_number, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
1170                    &mac[0], &mac[1], &mac[2],
1171                    &mac[3], &mac[4], &mac[5]) == 6) {
1172             eui48_to_eui64(&wo->hisid, mac);
1173         } else if (inet_pton(AF_INET, remote_number, &addr) == 1) {
1174             eui64_setlo32(wo->hisid, ntohl(addr.s_addr));
1175         } else if (inet_pton(AF_INET6, remote_number, &addr6) == 1) {
1176             /* use low 64 bits of IPv6 address for interface identifier */
1177             wo->hisid.e8[0] = addr6.s6_addr[8];
1178             wo->hisid.e8[1] = addr6.s6_addr[9];
1179             wo->hisid.e8[2] = addr6.s6_addr[10];
1180             wo->hisid.e8[3] = addr6.s6_addr[11];
1181             wo->hisid.e8[4] = addr6.s6_addr[12];
1182             wo->hisid.e8[5] = addr6.s6_addr[13];
1183             wo->hisid.e8[6] = addr6.s6_addr[14];
1184             wo->hisid.e8[7] = addr6.s6_addr[15];
1185         } else {
1186             str = remote_number;
1187             /* telephone number may start with leading '+' sign, so skip it */
1188             if (str[0] == '+')
1189                 str++;
1190             errno = 0;
1191             tel = strtoull(str, &endptr, 10);
1192             if (!errno && *str && !*endptr && tel) {
1193                 wo->hisid.e32[0] = htonl(tel >> 32);
1194                 wo->hisid.e32[1] = htonl(tel & 0xFFFFFFFF);
1195             }
1196         }
1197         if (!eui64_iszero(wo->hisid))
1198             wo->opt_remote = 1;
1199     }
1200
1201     if (!wo->opt_local) {       /* init interface identifier */
1202         if (wo->use_ip && eui64_iszero(wo->ourid)) {
1203             eui64_setlo32(wo->ourid, ntohl(ipcp_wantoptions[0].ouraddr));
1204             if (!eui64_iszero(wo->ourid))
1205                 wo->opt_local = 1;
1206         }
1207         
1208         while (eui64_iszero(wo->ourid))
1209             eui64_magic(wo->ourid);
1210     }
1211
1212     if (!wo->opt_remote) {
1213         if (wo->use_ip && eui64_iszero(wo->hisid)) {
1214             eui64_setlo32(wo->hisid, ntohl(ipcp_wantoptions[0].hisaddr));
1215             if (!eui64_iszero(wo->hisid))
1216                 wo->opt_remote = 1;
1217         }
1218     }
1219 }
1220
1221
1222 /*
1223  * ipv6_demand_conf - configure the interface as though
1224  * IPV6CP were up, for use with dial-on-demand.
1225  */
1226 static int
1227 ipv6_demand_conf(int u)
1228 {
1229     ipv6cp_options *wo = &ipv6cp_wantoptions[u];
1230
1231     if (eui64_iszero(wo->hisid) && !ipv6cp_noremote) {
1232         /* make up an arbitrary identifier for the peer */
1233         eui64_magic_nz(wo->hisid);
1234     }
1235     if (eui64_iszero(wo->ourid)) {
1236         /* make up an arbitrary identifier for us */
1237         eui64_magic_nz(wo->ourid);
1238     }
1239
1240     if (!sif6up(u))
1241         return 0;
1242     if (!sif6addr(u, wo->ourid, wo->hisid))
1243         return 0;
1244 #if !defined(__linux__) && !(defined(SVR4) && (defined(SNI) || defined(__USLC__)))
1245     if (!sifup(u))
1246         return 0;
1247 #endif
1248     if (!sifnpmode(u, PPP_IPV6, NPMODE_QUEUE))
1249         return 0;
1250     if (wo->default_route)
1251         if (sif6defaultroute(u, wo->ourid, wo->hisid))
1252             default_route_set[u] = 1;
1253
1254     notice("local  LL address %s", llv6_ntoa(wo->ourid));
1255     if (!eui64_iszero(wo->hisid))
1256        notice("remote LL address %s", llv6_ntoa(wo->hisid));
1257
1258     return 1;
1259 }
1260
1261
1262 /*
1263  * ipv6cp_up - IPV6CP has come UP.
1264  *
1265  * Configure the IPv6 network interface appropriately and bring it up.
1266  */
1267 static void
1268 ipv6cp_up(fsm *f)
1269 {
1270     ipv6cp_options *ho = &ipv6cp_hisoptions[f->unit];
1271     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
1272     ipv6cp_options *wo = &ipv6cp_wantoptions[f->unit];
1273
1274     IPV6CPDEBUG(("ipv6cp: up"));
1275
1276     /*
1277      * We must have a non-zero LL address for both ends of the link.
1278      */
1279
1280     if (!eui64_iszero(wo->hisid) && !wo->accept_remote && (!ho->neg_ifaceid || !eui64_equals(ho->hisid, wo->hisid))) {
1281         error("Peer refused to agree to his interface identifier");
1282         ipv6cp_close(f->unit, "Refused his interface identifier");
1283         return;
1284     }
1285     if (!ho->neg_ifaceid)
1286         ho->hisid = wo->hisid;
1287
1288     if(!no_ifaceid_neg) {
1289         if (eui64_iszero(ho->hisid) && !ipv6cp_noremote) {
1290             error("Could not determine remote LL address");
1291             ipv6cp_close(f->unit, "Could not determine remote LL address");
1292             return;
1293         }
1294         if (eui64_iszero(go->ourid)) {
1295             error("Could not determine local LL address");
1296             ipv6cp_close(f->unit, "Could not determine local LL address");
1297             return;
1298         }
1299         if (eui64_equals(go->ourid, ho->hisid)) {
1300             error("local and remote LL addresses are equal");
1301             ipv6cp_close(f->unit, "local and remote LL addresses are equal");
1302             return;
1303         }
1304     }
1305     script_setenv("LLLOCAL", llv6_ntoa(go->ourid), 0);
1306     if (!eui64_iszero(ho->hisid))
1307         script_setenv("LLREMOTE", llv6_ntoa(ho->hisid), 0);
1308
1309 #ifdef IPV6CP_COMP
1310     /* set tcp compression */
1311     sif6comp(f->unit, ho->neg_vj);
1312 #endif
1313
1314     /*
1315      * If we are doing dial-on-demand, the interface is already
1316      * configured, so we put out any saved-up packets, then set the
1317      * interface to pass IPv6 packets.
1318      */
1319     if (demand) {
1320         if (! eui64_equals(go->ourid, wo->ourid) || 
1321             ! eui64_equals(ho->hisid, wo->hisid)) {
1322             if (! eui64_equals(go->ourid, wo->ourid))
1323                 warn("Local LL address changed to %s", 
1324                      llv6_ntoa(go->ourid));
1325             if (! eui64_equals(ho->hisid, wo->hisid))
1326                 warn("Remote LL address changed to %s", 
1327                      llv6_ntoa(ho->hisid));
1328             ipv6cp_clear_addrs(f->unit, wo->ourid, wo->hisid);
1329
1330             /* Set the interface to the new addresses */
1331             if (!sif6addr(f->unit, go->ourid, ho->hisid)) {
1332                 if (debug)
1333                     warn("sif6addr failed");
1334                 ipv6cp_close(f->unit, "Interface configuration failed");
1335                 return;
1336             }
1337
1338             /* assign a default route through the interface if required */
1339             if (ipv6cp_wantoptions[f->unit].default_route)
1340                 if (sif6defaultroute(f->unit, go->ourid, ho->hisid))
1341                     default_route_set[f->unit] = 1;
1342         }
1343         demand_rexmit(PPP_IPV6);
1344         sifnpmode(f->unit, PPP_IPV6, NPMODE_PASS);
1345
1346     } else {
1347         /* bring the interface up for IPv6 */
1348         if (!sif6up(f->unit)) {
1349             if (debug)
1350                 warn("sif6up failed (IPV6)");
1351             ipv6cp_close(f->unit, "Interface configuration failed");
1352             return;
1353         }
1354
1355         if (!sif6addr(f->unit, go->ourid, ho->hisid)) {
1356             if (debug)
1357                 warn("sif6addr failed");
1358             ipv6cp_close(f->unit, "Interface configuration failed");
1359             return;
1360         }
1361         sifnpmode(f->unit, PPP_IPV6, NPMODE_PASS);
1362
1363         /* assign a default route through the interface if required */
1364         if (ipv6cp_wantoptions[f->unit].default_route)
1365             if (sif6defaultroute(f->unit, go->ourid, ho->hisid))
1366                 default_route_set[f->unit] = 1;
1367
1368         notice("local  LL address %s", llv6_ntoa(go->ourid));
1369         if (!eui64_iszero(ho->hisid))
1370             notice("remote LL address %s", llv6_ntoa(ho->hisid));
1371     }
1372
1373     np_up(f->unit, PPP_IPV6);
1374     ipv6cp_is_up = 1;
1375
1376     notify(ipv6_up_notifier, 0);
1377     if (ipv6_up_hook)
1378        ipv6_up_hook();
1379
1380     /*
1381      * Execute the ipv6-up script, like this:
1382      *  /etc/ppp/ipv6-up interface tty speed local-LL remote-LL
1383      */
1384     if (ipv6cp_script_state == s_down && ipv6cp_script_pid == 0) {
1385         ipv6cp_script_state = s_up;
1386         ipv6cp_script(path_ipv6up);
1387     }
1388 }
1389
1390
1391 /*
1392  * ipv6cp_down - IPV6CP has gone DOWN.
1393  *
1394  * Take the IPv6 network interface down, clear its addresses
1395  * and delete routes through it.
1396  */
1397 static void
1398 ipv6cp_down(fsm *f)
1399 {
1400     IPV6CPDEBUG(("ipv6cp: down"));
1401     update_link_stats(f->unit);
1402     notify(ipv6_down_notifier, 0);
1403     if (ipv6_down_hook)
1404        ipv6_down_hook();
1405     if (ipv6cp_is_up) {
1406         ipv6cp_is_up = 0;
1407         np_down(f->unit, PPP_IPV6);
1408     }
1409 #ifdef IPV6CP_COMP
1410     sif6comp(f->unit, 0);
1411 #endif
1412
1413     /*
1414      * If we are doing dial-on-demand, set the interface
1415      * to queue up outgoing packets (for now).
1416      */
1417     if (demand) {
1418         sifnpmode(f->unit, PPP_IPV6, NPMODE_QUEUE);
1419     } else {
1420         sifnpmode(f->unit, PPP_IPV6, NPMODE_DROP);
1421 #if !defined(__linux__) && !(defined(SVR4) && (defined(SNI) || defined(__USLC)))
1422         sif6down(f->unit);
1423 #endif
1424         ipv6cp_clear_addrs(f->unit, 
1425                            ipv6cp_gotoptions[f->unit].ourid,
1426                            ipv6cp_hisoptions[f->unit].hisid);
1427 #if defined(__linux__)
1428         sif6down(f->unit);
1429 #elif defined(SVR4) && (defined(SNI) || defined(__USLC))
1430         sifdown(f->unit);
1431 #endif
1432     }
1433
1434     /* Execute the ipv6-down script */
1435     if (ipv6cp_script_state == s_up && ipv6cp_script_pid == 0) {
1436         ipv6cp_script_state = s_down;
1437         ipv6cp_script(path_ipv6down);
1438     }
1439 }
1440
1441
1442 /*
1443  * ipv6cp_clear_addrs() - clear the interface addresses, routes,
1444  * proxy neighbour discovery entries, etc.
1445  */
1446 static void
1447 ipv6cp_clear_addrs(int unit, eui64_t ourid, eui64_t hisid)
1448 {
1449     cif6addr(unit, ourid, hisid);
1450 }
1451
1452
1453 /*
1454  * ipv6cp_finished - possibly shut down the lower layers.
1455  */
1456 static void
1457 ipv6cp_finished(fsm *f)
1458 {
1459     np_finished(f->unit, PPP_IPV6);
1460 }
1461
1462
1463 /*
1464  * ipv6cp_script_done - called when the ipv6-up or ipv6-down script
1465  * has finished.
1466  */
1467 static void
1468 ipv6cp_script_done(void *arg)
1469 {
1470     ipv6cp_script_pid = 0;
1471     switch (ipv6cp_script_state) {
1472     case s_up:
1473         if (ipv6cp_fsm[0].state != OPENED) {
1474             ipv6cp_script_state = s_down;
1475             ipv6cp_script(path_ipv6down);
1476         }
1477         break;
1478     case s_down:
1479         if (ipv6cp_fsm[0].state == OPENED) {
1480             ipv6cp_script_state = s_up;
1481             ipv6cp_script(path_ipv6up);
1482         }
1483         break;
1484     }
1485 }
1486
1487
1488 /*
1489  * ipv6cp_script - Execute a script with arguments
1490  * interface-name tty-name speed local-LL remote-LL.
1491  */
1492 static void
1493 ipv6cp_script(char *script)
1494 {
1495     char strspeed[32], strlocal[32], strremote[32];
1496     char *argv[8];
1497
1498     sprintf(strspeed, "%d", baud_rate);
1499     strcpy(strlocal, llv6_ntoa(ipv6cp_gotoptions[0].ourid));
1500     strcpy(strremote, llv6_ntoa(ipv6cp_hisoptions[0].hisid));
1501
1502     argv[0] = script;
1503     argv[1] = ifname;
1504     argv[2] = devnam;
1505     argv[3] = strspeed;
1506     argv[4] = strlocal;
1507     argv[5] = strremote;
1508     argv[6] = ipparam;
1509     argv[7] = NULL;
1510
1511     ipv6cp_script_pid = run_program(script, argv, 0, ipv6cp_script_done,
1512                                     NULL, 0);
1513 }
1514
1515 /*
1516  * ipv6cp_printpkt - print the contents of an IPV6CP packet.
1517  */
1518 static char *ipv6cp_codenames[] = {
1519     "ConfReq", "ConfAck", "ConfNak", "ConfRej",
1520     "TermReq", "TermAck", "CodeRej"
1521 };
1522
1523 static int
1524 ipv6cp_printpkt(u_char *p, int plen,
1525                 void (*printer) (void *, char *, ...), void *arg)
1526 {
1527     int code, id, len, olen;
1528     u_char *pstart, *optend;
1529     u_short cishort;
1530     eui64_t ifaceid;
1531
1532     if (plen < HEADERLEN)
1533         return 0;
1534     pstart = p;
1535     GETCHAR(code, p);
1536     GETCHAR(id, p);
1537     GETSHORT(len, p);
1538     if (len < HEADERLEN || len > plen)
1539         return 0;
1540
1541     if (code >= 1 && code <= sizeof(ipv6cp_codenames) / sizeof(char *))
1542         printer(arg, " %s", ipv6cp_codenames[code-1]);
1543     else
1544         printer(arg, " code=0x%x", code);
1545     printer(arg, " id=0x%x", id);
1546     len -= HEADERLEN;
1547     switch (code) {
1548     case CONFREQ:
1549     case CONFACK:
1550     case CONFNAK:
1551     case CONFREJ:
1552         /* print option list */
1553         while (len >= 2) {
1554             GETCHAR(code, p);
1555             GETCHAR(olen, p);
1556             p -= 2;
1557             if (olen < 2 || olen > len) {
1558                 break;
1559             }
1560             printer(arg, " <");
1561             len -= olen;
1562             optend = p + olen;
1563             switch (code) {
1564             case CI_COMPRESSTYPE:
1565                 if (olen >= CILEN_COMPRESS) {
1566                     p += 2;
1567                     GETSHORT(cishort, p);
1568                     printer(arg, "compress ");
1569                     printer(arg, "0x%x", cishort);
1570                 }
1571                 break;
1572             case CI_IFACEID:
1573                 if (olen == CILEN_IFACEID) {
1574                     p += 2;
1575                     eui64_get(ifaceid, p);
1576                     printer(arg, "addr %s", llv6_ntoa(ifaceid));
1577                 }
1578                 break;
1579             }
1580             while (p < optend) {
1581                 GETCHAR(code, p);
1582                 printer(arg, " %.2x", code);
1583             }
1584             printer(arg, ">");
1585         }
1586         break;
1587
1588     case TERMACK:
1589     case TERMREQ:
1590         if (len > 0 && *p >= ' ' && *p < 0x7f) {
1591             printer(arg, " ");
1592             print_string((char *)p, len, printer, arg);
1593             p += len;
1594             len = 0;
1595         }
1596         break;
1597     }
1598
1599     /* print the rest of the bytes in the packet */
1600     for (; len > 0; --len) {
1601         GETCHAR(code, p);
1602         printer(arg, " %.2x", code);
1603     }
1604
1605     return p - pstart;
1606 }
1607
1608 /*
1609  * ipv6_active_pkt - see if this IP packet is worth bringing the link up for.
1610  * We don't bring the link up for IP fragments or for TCP FIN packets
1611  * with no data.
1612  */
1613 #define IP6_HDRLEN      40      /* bytes */
1614 #define IP6_NHDR_FRAG   44      /* fragment IPv6 header */
1615 #define TCP_HDRLEN      20
1616 #define TH_FIN          0x01
1617
1618 /*
1619  * We use these macros because the IP header may be at an odd address,
1620  * and some compilers might use word loads to get th_off or ip_hl.
1621  */
1622
1623 #define get_ip6nh(x)    (((unsigned char *)(x))[6])
1624 #define get_tcpoff(x)   (((unsigned char *)(x))[12] >> 4)
1625 #define get_tcpflags(x) (((unsigned char *)(x))[13])
1626
1627 static int
1628 ipv6_active_pkt(u_char *pkt, int len)
1629 {
1630     u_char *tcp;
1631
1632     len -= PPP_HDRLEN;
1633     pkt += PPP_HDRLEN;
1634     if (len < IP6_HDRLEN)
1635         return 0;
1636     if (get_ip6nh(pkt) == IP6_NHDR_FRAG)
1637         return 0;
1638     if (get_ip6nh(pkt) != IPPROTO_TCP)
1639         return 1;
1640     if (len < IP6_HDRLEN + TCP_HDRLEN)
1641         return 0;
1642     tcp = pkt + IP6_HDRLEN;
1643     if ((get_tcpflags(tcp) & TH_FIN) != 0 && len == IP6_HDRLEN + get_tcpoff(tcp) * 4)
1644         return 0;
1645     return 1;
1646 }