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