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