Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / third_party / lwip / repo / lwip / src / netif / ppp / 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 */