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