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