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