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