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