]> git.ozlabs.org Git - ppp.git/blob - pppd/ipv6cp.c
Forgot to remote *.ln files (made by lint) when doing make clean.
[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.5 1999/09/11 12:04:22 paulus Exp $ 
99  */
100
101 #define RCSID   "$Id: ipv6cp.c,v 1.5 1999/09/11 12:04:22 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     ipv6cp_protent.enabled_flag = 1;
316     return 1;
317 }
318
319 /*
320  * Make a string representation of a network address.
321  */
322 char *
323 llv6_ntoa(ifaceid)
324     eui64_t ifaceid;
325 {
326     static char b[64];
327
328     sprintf(b, "fe80::%s", eui64_ntoa(ifaceid));
329     return b;
330 }
331
332
333 /*
334  * ipv6cp_init - Initialize IPV6CP.
335  */
336 static void
337 ipv6cp_init(unit)
338     int unit;
339 {
340     fsm *f = &ipv6cp_fsm[unit];
341     ipv6cp_options *wo = &ipv6cp_wantoptions[unit];
342     ipv6cp_options *ao = &ipv6cp_allowoptions[unit];
343
344     f->unit = unit;
345     f->protocol = PPP_IPV6CP;
346     f->callbacks = &ipv6cp_callbacks;
347     fsm_init(&ipv6cp_fsm[unit]);
348
349     memset(wo, 0, sizeof(*wo));
350     memset(ao, 0, sizeof(*ao));
351
352     wo->accept_local = 1;
353     wo->neg_ifaceid = 1;
354     ao->neg_ifaceid = 1;
355
356 #ifdef IPV6CP_COMP
357     wo->neg_vj = 1;
358     ao->neg_vj = 1;
359     wo->vj_protocol = IPV6CP_COMP;
360 #endif
361
362 }
363
364
365 /*
366  * ipv6cp_open - IPV6CP is allowed to come up.
367  */
368 static void
369 ipv6cp_open(unit)
370     int unit;
371 {
372     fsm_open(&ipv6cp_fsm[unit]);
373 }
374
375
376 /*
377  * ipv6cp_close - Take IPV6CP down.
378  */
379 static void
380 ipv6cp_close(unit, reason)
381     int unit;
382     char *reason;
383 {
384     fsm_close(&ipv6cp_fsm[unit], reason);
385 }
386
387
388 /*
389  * ipv6cp_lowerup - The lower layer is up.
390  */
391 static void
392 ipv6cp_lowerup(unit)
393     int unit;
394 {
395     fsm_lowerup(&ipv6cp_fsm[unit]);
396 }
397
398
399 /*
400  * ipv6cp_lowerdown - The lower layer is down.
401  */
402 static void
403 ipv6cp_lowerdown(unit)
404     int unit;
405 {
406     fsm_lowerdown(&ipv6cp_fsm[unit]);
407 }
408
409
410 /*
411  * ipv6cp_input - Input IPV6CP packet.
412  */
413 static void
414 ipv6cp_input(unit, p, len)
415     int unit;
416     u_char *p;
417     int len;
418 {
419     fsm_input(&ipv6cp_fsm[unit], p, len);
420 }
421
422
423 /*
424  * ipv6cp_protrej - A Protocol-Reject was received for IPV6CP.
425  *
426  * Pretend the lower layer went down, so we shut up.
427  */
428 static void
429 ipv6cp_protrej(unit)
430     int unit;
431 {
432     fsm_lowerdown(&ipv6cp_fsm[unit]);
433 }
434
435
436 /*
437  * ipv6cp_resetci - Reset our CI.
438  */
439 static void
440 ipv6cp_resetci(f)
441     fsm *f;
442 {
443     ipv6cp_options *wo = &ipv6cp_wantoptions[f->unit];
444     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
445
446     wo->req_ifaceid = wo->neg_ifaceid && ipv6cp_allowoptions[f->unit].neg_ifaceid;
447     
448     if (!wo->opt_local) {
449         eui64_magic_nz(wo->ourid);
450     }
451     
452     *go = *wo;
453     eui64_zero(go->hisid);      /* last proposed interface identifier */
454 }
455
456
457 /*
458  * ipv6cp_cilen - Return length of our CI.
459  */
460 static int
461 ipv6cp_cilen(f)
462     fsm *f;
463 {
464     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
465
466 #define LENCIVJ(neg)            (neg ? CILEN_COMPRESS : 0)
467 #define LENCIIFACEID(neg)       (neg ? CILEN_IFACEID : 0)
468
469     return (LENCIIFACEID(go->neg_ifaceid) +
470             LENCIVJ(go->neg_vj));
471 }
472
473
474 /*
475  * ipv6cp_addci - Add our desired CIs to a packet.
476  */
477 static void
478 ipv6cp_addci(f, ucp, lenp)
479     fsm *f;
480     u_char *ucp;
481     int *lenp;
482 {
483     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
484     int len = *lenp;
485
486 #define ADDCIVJ(opt, neg, val) \
487     if (neg) { \
488         int vjlen = CILEN_COMPRESS; \
489         if (len >= vjlen) { \
490             PUTCHAR(opt, ucp); \
491             PUTCHAR(vjlen, ucp); \
492             PUTSHORT(val, ucp); \
493             len -= vjlen; \
494         } else \
495             neg = 0; \
496     }
497
498 #define ADDCIIFACEID(opt, neg, val1) \
499     if (neg) { \
500         int idlen = CILEN_IFACEID; \
501         if (len >= idlen) { \
502             PUTCHAR(opt, ucp); \
503             PUTCHAR(idlen, ucp); \
504             eui64_put(val1, ucp); \
505             len -= idlen; \
506         } else \
507             neg = 0; \
508     }
509
510     ADDCIIFACEID(CI_IFACEID, go->neg_ifaceid, go->ourid);
511
512     ADDCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol);
513
514     *lenp -= len;
515 }
516
517
518 /*
519  * ipv6cp_ackci - Ack our CIs.
520  *
521  * Returns:
522  *      0 - Ack was bad.
523  *      1 - Ack was good.
524  */
525 static int
526 ipv6cp_ackci(f, p, len)
527     fsm *f;
528     u_char *p;
529     int len;
530 {
531     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
532     u_short cilen, citype, cishort;
533     eui64_t ifaceid;
534
535     /*
536      * CIs must be in exactly the same order that we sent...
537      * Check packet length and CI length at each step.
538      * If we find any deviations, then this packet is bad.
539      */
540
541 #define ACKCIVJ(opt, neg, val) \
542     if (neg) { \
543         int vjlen = CILEN_COMPRESS; \
544         if ((len -= vjlen) < 0) \
545             goto bad; \
546         GETCHAR(citype, p); \
547         GETCHAR(cilen, p); \
548         if (cilen != vjlen || \
549             citype != opt)  \
550             goto bad; \
551         GETSHORT(cishort, p); \
552         if (cishort != val) \
553             goto bad; \
554     }
555
556 #define ACKCIIFACEID(opt, neg, val1) \
557     if (neg) { \
558         int idlen = CILEN_IFACEID; \
559         if ((len -= idlen) < 0) \
560             goto bad; \
561         GETCHAR(citype, p); \
562         GETCHAR(cilen, p); \
563         if (cilen != idlen || \
564             citype != opt) \
565             goto bad; \
566         eui64_get(ifaceid, p); \
567         if (! eui64_equals(val1, ifaceid)) \
568             goto bad; \
569     }
570
571     ACKCIIFACEID(CI_IFACEID, go->neg_ifaceid, go->ourid);
572
573     ACKCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol);
574
575     /*
576      * If there are any remaining CIs, then this packet is bad.
577      */
578     if (len != 0)
579         goto bad;
580     return (1);
581
582 bad:
583     IPV6CPDEBUG(("ipv6cp_ackci: received bad Ack!"));
584     return (0);
585 }
586
587 /*
588  * ipv6cp_nakci - Peer has sent a NAK for some of our CIs.
589  * This should not modify any state if the Nak is bad
590  * or if IPV6CP is in the OPENED state.
591  *
592  * Returns:
593  *      0 - Nak was bad.
594  *      1 - Nak was good.
595  */
596 static int
597 ipv6cp_nakci(f, p, len)
598     fsm *f;
599     u_char *p;
600     int len;
601 {
602     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
603     u_char citype, cilen, *next;
604     u_short cishort;
605     eui64_t ifaceid;
606     ipv6cp_options no;          /* options we've seen Naks for */
607     ipv6cp_options try;         /* options to request next time */
608
609     BZERO(&no, sizeof(no));
610     try = *go;
611
612     /*
613      * Any Nak'd CIs must be in exactly the same order that we sent.
614      * Check packet length and CI length at each step.
615      * If we find any deviations, then this packet is bad.
616      */
617 #define NAKCIIFACEID(opt, neg, code) \
618     if (go->neg && \
619         len >= (cilen = CILEN_IFACEID) && \
620         p[1] == cilen && \
621         p[0] == opt) { \
622         len -= cilen; \
623         INCPTR(2, p); \
624         eui64_get(ifaceid, p); \
625         no.neg = 1; \
626         code \
627     }
628
629 #define NAKCIVJ(opt, neg, code) \
630     if (go->neg && \
631         ((cilen = p[1]) == CILEN_COMPRESS) && \
632         len >= cilen && \
633         p[0] == opt) { \
634         len -= cilen; \
635         INCPTR(2, p); \
636         GETSHORT(cishort, p); \
637         no.neg = 1; \
638         code \
639     }
640
641     /*
642      * Accept the peer's idea of {our,his} interface identifier, if different
643      * from our idea, only if the accept_{local,remote} flag is set.
644      */
645     NAKCIIFACEID(CI_IFACEID, neg_ifaceid,
646               if (go->accept_local) {
647                   while (eui64_iszero(ifaceid) || 
648                          eui64_equals(ifaceid, go->hisid)) /* bad luck */
649                       eui64_magic(ifaceid);
650                   try.ourid = ifaceid;
651                   IPV6CPDEBUG(("local LL address %s", llv6_ntoa(ifaceid)));
652               }
653               );
654
655 #ifdef IPV6CP_COMP
656     NAKCIVJ(CI_COMPRESSTYPE, neg_vj,
657             {
658                 if (cishort == IPV6CP_COMP) {
659                     try.vj_protocol = cishort;
660                 } else {
661                     try.neg_vj = 0;
662                 }
663             }
664             );
665 #else
666     NAKCIVJ(CI_COMPRESSTYPE, neg_vj,
667             {
668                 try.neg_vj = 0;
669             }
670             );
671 #endif
672
673     /*
674      * There may be remaining CIs, if the peer is requesting negotiation
675      * on an option that we didn't include in our request packet.
676      * If they want to negotiate about interface identifier, we comply.
677      * If they want us to ask for compression, we refuse.
678      */
679     while (len > CILEN_VOID) {
680         GETCHAR(citype, p);
681         GETCHAR(cilen, p);
682         if( (len -= cilen) < 0 )
683             goto bad;
684         next = p + cilen - 2;
685
686         switch (citype) {
687         case CI_COMPRESSTYPE:
688             if (go->neg_vj || no.neg_vj ||
689                 (cilen != CILEN_COMPRESS))
690                 goto bad;
691             no.neg_vj = 1;
692             break;
693         case CI_IFACEID:
694             if (go->neg_ifaceid || no.neg_ifaceid || cilen != CILEN_IFACEID)
695                 goto bad;
696             try.neg_ifaceid = 1;
697             eui64_get(ifaceid, p);
698             if (go->accept_local) {
699                 while (eui64_iszero(ifaceid) || 
700                        eui64_equals(ifaceid, go->hisid)) /* bad luck */
701                     eui64_magic(ifaceid);
702                 try.ourid = ifaceid;
703             }
704             no.neg_ifaceid = 1;
705             break;
706         }
707         p = next;
708     }
709
710     /* If there is still anything left, this packet is bad. */
711     if (len != 0)
712         goto bad;
713
714     /*
715      * OK, the Nak is good.  Now we can update state.
716      */
717     if (f->state != OPENED)
718         *go = try;
719
720     return 1;
721
722 bad:
723     IPV6CPDEBUG(("ipv6cp_nakci: received bad Nak!"));
724     return 0;
725 }
726
727
728 /*
729  * ipv6cp_rejci - Reject some of our CIs.
730  */
731 static int
732 ipv6cp_rejci(f, p, len)
733     fsm *f;
734     u_char *p;
735     int len;
736 {
737     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
738     u_char cilen;
739     u_short cishort;
740     eui64_t ifaceid;
741     ipv6cp_options try;         /* options to request next time */
742
743     try = *go;
744     /*
745      * Any Rejected CIs must be in exactly the same order that we sent.
746      * Check packet length and CI length at each step.
747      * If we find any deviations, then this packet is bad.
748      */
749 #define REJCIIFACEID(opt, neg, val1) \
750     if (go->neg && \
751         len >= (cilen = CILEN_IFACEID) && \
752         p[1] == cilen && \
753         p[0] == opt) { \
754         len -= cilen; \
755         INCPTR(2, p); \
756         eui64_get(ifaceid, p); \
757         /* Check rejected value. */ \
758         if (! eui64_equals(ifaceid, val1)) \
759             goto bad; \
760         try.neg = 0; \
761     }
762
763 #define REJCIVJ(opt, neg, val) \
764     if (go->neg && \
765         p[1] == CILEN_COMPRESS && \
766         len >= p[1] && \
767         p[0] == opt) { \
768         len -= p[1]; \
769         INCPTR(2, p); \
770         GETSHORT(cishort, p); \
771         /* Check rejected value. */  \
772         if (cishort != val) \
773             goto bad; \
774         try.neg = 0; \
775      }
776
777     REJCIIFACEID(CI_IFACEID, neg_ifaceid, go->ourid);
778
779     REJCIVJ(CI_COMPRESSTYPE, neg_vj, go->vj_protocol);
780
781     /*
782      * If there are any remaining CIs, then this packet is bad.
783      */
784     if (len != 0)
785         goto bad;
786     /*
787      * Now we can update state.
788      */
789     if (f->state != OPENED)
790         *go = try;
791     return 1;
792
793 bad:
794     IPV6CPDEBUG(("ipv6cp_rejci: received bad Reject!"));
795     return 0;
796 }
797
798
799 /*
800  * ipv6cp_reqci - Check the peer's requested CIs and send appropriate response.
801  *
802  * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified
803  * appropriately.  If reject_if_disagree is non-zero, doesn't return
804  * CONFNAK; returns CONFREJ if it can't return CONFACK.
805  */
806 static int
807 ipv6cp_reqci(f, inp, len, reject_if_disagree)
808     fsm *f;
809     u_char *inp;                /* Requested CIs */
810     int *len;                   /* Length of requested CIs */
811     int reject_if_disagree;
812 {
813     ipv6cp_options *wo = &ipv6cp_wantoptions[f->unit];
814     ipv6cp_options *ho = &ipv6cp_hisoptions[f->unit];
815     ipv6cp_options *ao = &ipv6cp_allowoptions[f->unit];
816     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
817     u_char *cip, *next;         /* Pointer to current and next CIs */
818     u_short cilen, citype;      /* Parsed len, type */
819     u_short cishort;            /* Parsed short value */
820     eui64_t ifaceid;            /* Parsed interface identifier */
821     int rc = CONFACK;           /* Final packet return code */
822     int orc;                    /* Individual option return code */
823     u_char *p;                  /* Pointer to next char to parse */
824     u_char *ucp = inp;          /* Pointer to current output char */
825     int l = *len;               /* Length left */
826
827     /*
828      * Reset all his options.
829      */
830     BZERO(ho, sizeof(*ho));
831     
832     /*
833      * Process all his options.
834      */
835     next = inp;
836     while (l) {
837         orc = CONFACK;                  /* Assume success */
838         cip = p = next;                 /* Remember begining of CI */
839         if (l < 2 ||                    /* Not enough data for CI header or */
840             p[1] < 2 ||                 /*  CI length too small or */
841             p[1] > l) {                 /*  CI length too big? */
842             IPV6CPDEBUG(("ipv6cp_reqci: bad CI length!"));
843             orc = CONFREJ;              /* Reject bad CI */
844             cilen = l;                  /* Reject till end of packet */
845             l = 0;                      /* Don't loop again */
846             goto endswitch;
847         }
848         GETCHAR(citype, p);             /* Parse CI type */
849         GETCHAR(cilen, p);              /* Parse CI length */
850         l -= cilen;                     /* Adjust remaining length */
851         next += cilen;                  /* Step to next CI */
852
853         switch (citype) {               /* Check CI type */
854         case CI_IFACEID:
855             IPV6CPDEBUG(("ipv6cp: received interface identifier "));
856
857             if (!ao->neg_ifaceid ||
858                 cilen != CILEN_IFACEID) {       /* Check CI length */
859                 orc = CONFREJ;          /* Reject CI */
860                 break;
861             }
862
863             /*
864              * If he has no interface identifier, or if we both have same 
865              * identifier then NAK it with new idea.
866              * In particular, if we don't know his identifier, but he does,
867              * then accept it.
868              */
869             eui64_get(ifaceid, p);
870             IPV6CPDEBUG(("(%s)", llv6_ntoa(ifaceid)));
871             if (eui64_iszero(ifaceid) && eui64_iszero(go->ourid)) {
872                 orc = CONFREJ;          /* Reject CI */
873                 break;
874             }
875             if (!eui64_iszero(wo->hisid) && 
876                 !eui64_equals(ifaceid, wo->hisid) && 
877                 eui64_iszero(go->hisid)) {
878                     
879                 orc = CONFNAK;
880                 ifaceid = wo->hisid;
881                 go->hisid = ifaceid;
882                 DECPTR(sizeof(ifaceid), p);
883                 eui64_put(ifaceid, p);
884             } else
885             if (eui64_iszero(ifaceid) || eui64_equals(ifaceid, go->ourid)) {
886                 orc = CONFNAK;
887                 if (eui64_iszero(go->hisid))    /* first time, try option */
888                     ifaceid = wo->hisid;
889                 while (eui64_iszero(ifaceid) || 
890                        eui64_equals(ifaceid, go->ourid)) /* bad luck */
891                     eui64_magic(ifaceid);
892                 go->hisid = ifaceid;
893                 DECPTR(sizeof(ifaceid), p);
894                 eui64_put(ifaceid, p);
895             }
896
897             ho->neg_ifaceid = 1;
898             ho->hisid = ifaceid;
899             break;
900
901         case CI_COMPRESSTYPE:
902             IPV6CPDEBUG(("ipv6cp: received COMPRESSTYPE "));
903             if (!ao->neg_vj ||
904                 (cilen != CILEN_COMPRESS)) {
905                 orc = CONFREJ;
906                 break;
907             }
908             GETSHORT(cishort, p);
909             IPV6CPDEBUG(("(%d)", cishort));
910
911 #ifdef IPV6CP_COMP
912             if (!(cishort == IPV6CP_COMP)) {
913                 orc = CONFREJ;
914                 break;
915             }
916 #else
917             orc = CONFREJ;
918             break;
919 #endif
920
921             ho->neg_vj = 1;
922             ho->vj_protocol = cishort;
923             break;
924
925         default:
926             orc = CONFREJ;
927             break;
928         }
929
930 endswitch:
931         IPV6CPDEBUG((" (%s)\n", CODENAME(orc)));
932
933         if (orc == CONFACK &&           /* Good CI */
934             rc != CONFACK)              /*  but prior CI wasnt? */
935             continue;                   /* Don't send this one */
936
937         if (orc == CONFNAK) {           /* Nak this CI? */
938             if (reject_if_disagree)     /* Getting fed up with sending NAKs? */
939                 orc = CONFREJ;          /* Get tough if so */
940             else {
941                 if (rc == CONFREJ)      /* Rejecting prior CI? */
942                     continue;           /* Don't send this one */
943                 if (rc == CONFACK) {    /* Ack'd all prior CIs? */
944                     rc = CONFNAK;       /* Not anymore... */
945                     ucp = inp;          /* Backup */
946                 }
947             }
948         }
949
950         if (orc == CONFREJ &&           /* Reject this CI */
951             rc != CONFREJ) {            /*  but no prior ones? */
952             rc = CONFREJ;
953             ucp = inp;                  /* Backup */
954         }
955
956         /* Need to move CI? */
957         if (ucp != cip)
958             BCOPY(cip, ucp, cilen);     /* Move it */
959
960         /* Update output pointer */
961         INCPTR(cilen, ucp);
962     }
963
964     /*
965      * If we aren't rejecting this packet, and we want to negotiate
966      * their identifier and they didn't send their identifier, then we
967      * send a NAK with a CI_IFACEID option appended.  We assume the
968      * input buffer is long enough that we can append the extra
969      * option safely.
970      */
971     if (rc != CONFREJ && !ho->neg_ifaceid &&
972         wo->req_ifaceid && !reject_if_disagree) {
973         if (rc == CONFACK) {
974             rc = CONFNAK;
975             ucp = inp;                          /* reset pointer */
976             wo->req_ifaceid = 0;                /* don't ask again */
977         }
978         PUTCHAR(CI_IFACEID, ucp);
979         PUTCHAR(CILEN_IFACEID, ucp);
980         eui64_put(wo->hisid, ucp);
981     }
982
983     *len = ucp - inp;                   /* Compute output length */
984     IPV6CPDEBUG(("ipv6cp: returning Configure-%s", CODENAME(rc)));
985     return (rc);                        /* Return final code */
986 }
987
988
989 /*
990  * ipv6_check_options - check that any IP-related options are OK,
991  * and assign appropriate defaults.
992  */
993 static void
994 ipv6_check_options()
995 {
996     ipv6cp_options *wo = &ipv6cp_wantoptions[0];
997
998     if (!wo->opt_local) {       /* init interface identifier */
999         if (wo->use_ip && eui64_iszero(wo->ourid)) {
1000             eui64_setlo32(wo->ourid, ntohl(ipcp_wantoptions[0].ouraddr));
1001             if (!eui64_iszero(wo->ourid))
1002                 wo->opt_local = 1;
1003         }
1004         
1005         while (eui64_iszero(wo->ourid))
1006             eui64_magic(wo->ourid);
1007     }
1008
1009     if (!wo->opt_remote) {
1010         if (wo->use_ip && eui64_iszero(wo->hisid)) {
1011             eui64_setlo32(wo->hisid, ntohl(ipcp_wantoptions[0].hisaddr));
1012             if (!eui64_iszero(wo->hisid))
1013                 wo->opt_remote = 1;
1014         }
1015     }
1016
1017     if (demand && (eui64_iszero(wo->ourid) || eui64_iszero(wo->hisid))) {
1018         option_error("local/remote LL address required for demand-dialling\n");
1019         exit(1);
1020     }
1021 }
1022
1023
1024 /*
1025  * ipv6_demand_conf - configure the interface as though
1026  * IPV6CP were up, for use with dial-on-demand.
1027  */
1028 static int
1029 ipv6_demand_conf(u)
1030     int u;
1031 {
1032     ipv6cp_options *wo = &ipv6cp_wantoptions[u];
1033
1034 #if defined(__linux__) || (defined(SVR4) && (defined(SNI) || defined(__USLC__)))
1035     if (!sifup(u))
1036         return 0;
1037 #endif    
1038     if (!sif6addr(u, wo->ourid, wo->hisid))
1039         return 0;
1040 #if !defined(__linux__) && !(defined(SVR4) && (defined(SNI) || defined(__USLC__)))
1041     if (!sifup(u))
1042         return 0;
1043 #endif
1044     if (!sifnpmode(u, PPP_IPV6, NPMODE_QUEUE))
1045         return 0;
1046
1047     notice("ipv6_demand_conf");
1048     notice("local  LL address %s", llv6_ntoa(wo->ourid));
1049     notice("remote LL address %s", llv6_ntoa(wo->hisid));
1050
1051     return 1;
1052 }
1053
1054
1055 /*
1056  * ipv6cp_up - IPV6CP has come UP.
1057  *
1058  * Configure the IPv6 network interface appropriately and bring it up.
1059  */
1060 static void
1061 ipv6cp_up(f)
1062     fsm *f;
1063 {
1064     ipv6cp_options *ho = &ipv6cp_hisoptions[f->unit];
1065     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
1066     ipv6cp_options *wo = &ipv6cp_wantoptions[f->unit];
1067
1068     IPV6CPDEBUG(("ipv6cp: up"));
1069
1070     /*
1071      * We must have a non-zero LL address for both ends of the link.
1072      */
1073     if (!ho->neg_ifaceid)
1074         ho->hisid = wo->hisid;
1075
1076     if(!no_ifaceid_neg) {
1077         if (eui64_iszero(ho->hisid)) {
1078             error("Could not determine remote LL address");
1079             ipv6cp_close(f->unit, "Could not determine remote LL address");
1080             return;
1081         }
1082         if (eui64_iszero(go->ourid)) {
1083             error("Could not determine local LL address");
1084             ipv6cp_close(f->unit, "Could not determine local LL address");
1085             return;
1086         }
1087         if (eui64_equals(go->ourid, ho->hisid)) {
1088             error("local and remote LL addresses are equal");
1089             ipv6cp_close(f->unit, "local and remote LL addresses are equal");
1090             return;
1091         }
1092     }
1093     script_setenv("LLLOCAL", llv6_ntoa(go->ourid));
1094     script_setenv("LLREMOTE", llv6_ntoa(ho->hisid));
1095
1096 #ifdef IPV6CP_COMP
1097     /* set tcp compression */
1098     sif6comp(f->unit, ho->neg_vj);
1099 #endif
1100
1101     /*
1102      * If we are doing dial-on-demand, the interface is already
1103      * configured, so we put out any saved-up packets, then set the
1104      * interface to pass IPv6 packets.
1105      */
1106     if (demand) {
1107         if (! eui64_equals(go->ourid, wo->ourid) || 
1108             ! eui64_equals(ho->hisid, wo->hisid)) {
1109             if (! eui64_equals(go->ourid, wo->ourid))
1110                 warn("Local LL address changed to %s", 
1111                      llv6_ntoa(go->ourid));
1112             if (! eui64_equals(ho->hisid, wo->hisid))
1113                 warn("Remote LL address changed to %s", 
1114                      llv6_ntoa(ho->hisid));
1115             ipv6cp_clear_addrs(f->unit, go->ourid, ho->hisid);
1116
1117             /* Set the interface to the new addresses */
1118             if (!sif6addr(f->unit, go->ourid, ho->hisid)) {
1119                 if (debug)
1120                     warn("sif6addr failed");
1121                 ipv6cp_close(f->unit, "Interface configuration failed");
1122                 return;
1123             }
1124
1125         }
1126         demand_rexmit(PPP_IPV6);
1127         sifnpmode(f->unit, PPP_IPV6, NPMODE_PASS);
1128
1129     } else {
1130         /*
1131          * Set LL addresses
1132          */
1133 #if !defined(__linux__) && !(defined(SVR4) && (defined(SNI) || defined(__USLC__)))
1134         if (!sif6addr(f->unit, go->ourid, ho->hisid)) {
1135             if (debug)
1136                 warn("sif6addr failed");
1137             ipv6cp_close(f->unit, "Interface configuration failed");
1138             return;
1139         }
1140 #endif
1141
1142         /* bring the interface up for IPv6 */
1143         if (!sifup(f->unit)) {
1144             if (debug)
1145                 warn("sifup failed (IPV6)");
1146             ipv6cp_close(f->unit, "Interface configuration failed");
1147             return;
1148         }
1149
1150 #if defined(__linux__) || (defined(SVR4) && (defined(SNI) || defined(__USLC__)))
1151         if (!sif6addr(f->unit, go->ourid, ho->hisid)) {
1152             if (debug)
1153                 warn("sif6addr failed");
1154             ipv6cp_close(f->unit, "Interface configuration failed");
1155             return;
1156         }
1157 #endif
1158         sifnpmode(f->unit, PPP_IPV6, NPMODE_PASS);
1159
1160         notice("local  LL address %s", llv6_ntoa(go->ourid));
1161         notice("remote LL address %s", llv6_ntoa(ho->hisid));
1162     }
1163
1164     np_up(f->unit, PPP_IPV6);
1165     ipv6cp_is_up = 1;
1166
1167     /*
1168      * Execute the ipv6-up script, like this:
1169      *  /etc/ppp/ipv6-up interface tty speed local-LL remote-LL
1170      */
1171     if (ipv6cp_script_state == s_down && ipv6cp_script_pid == 0) {
1172         ipv6cp_script_state = s_up;
1173         ipv6cp_script(_PATH_IPV6UP);
1174     }
1175 }
1176
1177
1178 /*
1179  * ipv6cp_down - IPV6CP has gone DOWN.
1180  *
1181  * Take the IPv6 network interface down, clear its addresses
1182  * and delete routes through it.
1183  */
1184 static void
1185 ipv6cp_down(f)
1186     fsm *f;
1187 {
1188     IPV6CPDEBUG(("ipv6cp: down"));
1189     update_link_stats(f->unit);
1190     if (ipv6cp_is_up) {
1191         ipv6cp_is_up = 0;
1192         np_down(f->unit, PPP_IPV6);
1193     }
1194 #ifdef IPV6CP_COMP
1195     sif6comp(f->unit, 0);
1196 #endif
1197
1198     /*
1199      * If we are doing dial-on-demand, set the interface
1200      * to queue up outgoing packets (for now).
1201      */
1202     if (demand) {
1203         sifnpmode(f->unit, PPP_IPV6, NPMODE_QUEUE);
1204     } else {
1205         sifnpmode(f->unit, PPP_IPV6, NPMODE_DROP);
1206 #if !defined(__linux__) && !(defined(SVR4) && (defined(SNI) || defined(__USLC)))
1207         sifdown(f->unit);
1208 #endif
1209         ipv6cp_clear_addrs(f->unit, 
1210                            ipv6cp_gotoptions[f->unit].ourid,
1211                            ipv6cp_hisoptions[f->unit].hisid);
1212 #if defined(__linux__) || (defined(SVR4) && (defined(SNI) || defined(__USLC)))
1213         sifdown(f->unit);
1214 #endif
1215     }
1216
1217     /* Execute the ipv6-down script */
1218     if (ipv6cp_script_state == s_up && ipv6cp_script_pid == 0) {
1219         ipv6cp_script_state = s_down;
1220         ipv6cp_script(_PATH_IPV6DOWN);
1221     }
1222 }
1223
1224
1225 /*
1226  * ipv6cp_clear_addrs() - clear the interface addresses, routes,
1227  * proxy neighbour discovery entries, etc.
1228  */
1229 static void
1230 ipv6cp_clear_addrs(unit, ourid, hisid)
1231     int unit;
1232     eui64_t ourid;
1233     eui64_t hisid;
1234 {
1235     cif6addr(unit, ourid, hisid);
1236 }
1237
1238
1239 /*
1240  * ipv6cp_finished - possibly shut down the lower layers.
1241  */
1242 static void
1243 ipv6cp_finished(f)
1244     fsm *f;
1245 {
1246     np_finished(f->unit, PPP_IPV6);
1247 }
1248
1249
1250 /*
1251  * ipv6cp_script_done - called when the ipv6-up or ipv6-down script
1252  * has finished.
1253  */
1254 static void
1255 ipv6cp_script_done(arg)
1256     void *arg;
1257 {
1258     ipv6cp_script_pid = 0;
1259     switch (ipv6cp_script_state) {
1260     case s_up:
1261         if (ipv6cp_fsm[0].state != OPENED) {
1262             ipv6cp_script_state = s_down;
1263             ipv6cp_script(_PATH_IPV6DOWN);
1264         }
1265         break;
1266     case s_down:
1267         if (ipv6cp_fsm[0].state == OPENED) {
1268             ipv6cp_script_state = s_up;
1269             ipv6cp_script(_PATH_IPV6UP);
1270         }
1271         break;
1272     }
1273 }
1274
1275
1276 /*
1277  * ipv6cp_script - Execute a script with arguments
1278  * interface-name tty-name speed local-LL remote-LL.
1279  */
1280 static void
1281 ipv6cp_script(script)
1282     char *script;
1283 {
1284     char strspeed[32], strlocal[32], strremote[32];
1285     char *argv[8];
1286
1287     sprintf(strspeed, "%d", baud_rate);
1288     strcpy(strlocal, llv6_ntoa(ipv6cp_gotoptions[0].ourid));
1289     strcpy(strremote, llv6_ntoa(ipv6cp_hisoptions[0].hisid));
1290
1291     argv[0] = script;
1292     argv[1] = ifname;
1293     argv[2] = devnam;
1294     argv[3] = strspeed;
1295     argv[4] = strlocal;
1296     argv[5] = strremote;
1297     argv[6] = ipparam;
1298     argv[7] = NULL;
1299
1300     ipv6cp_script_pid = run_program(script, argv, 0, ipv6cp_script_done, NULL);
1301 }
1302
1303 /*
1304  * ipv6cp_printpkt - print the contents of an IPV6CP packet.
1305  */
1306 static char *ipv6cp_codenames[] = {
1307     "ConfReq", "ConfAck", "ConfNak", "ConfRej",
1308     "TermReq", "TermAck", "CodeRej"
1309 };
1310
1311 static int
1312 ipv6cp_printpkt(p, plen, printer, arg)
1313     u_char *p;
1314     int plen;
1315     void (*printer) __P((void *, char *, ...));
1316     void *arg;
1317 {
1318     int code, id, len, olen;
1319     u_char *pstart, *optend;
1320     u_short cishort;
1321     eui64_t ifaceid;
1322
1323     if (plen < HEADERLEN)
1324         return 0;
1325     pstart = p;
1326     GETCHAR(code, p);
1327     GETCHAR(id, p);
1328     GETSHORT(len, p);
1329     if (len < HEADERLEN || len > plen)
1330         return 0;
1331
1332     if (code >= 1 && code <= sizeof(ipv6cp_codenames) / sizeof(char *))
1333         printer(arg, " %s", ipv6cp_codenames[code-1]);
1334     else
1335         printer(arg, " code=0x%x", code);
1336     printer(arg, " id=0x%x", id);
1337     len -= HEADERLEN;
1338     switch (code) {
1339     case CONFREQ:
1340     case CONFACK:
1341     case CONFNAK:
1342     case CONFREJ:
1343         /* print option list */
1344         while (len >= 2) {
1345             GETCHAR(code, p);
1346             GETCHAR(olen, p);
1347             p -= 2;
1348             if (olen < 2 || olen > len) {
1349                 break;
1350             }
1351             printer(arg, " <");
1352             len -= olen;
1353             optend = p + olen;
1354             switch (code) {
1355             case CI_COMPRESSTYPE:
1356                 if (olen >= CILEN_COMPRESS) {
1357                     p += 2;
1358                     GETSHORT(cishort, p);
1359                     printer(arg, "compress ");
1360                     printer(arg, "0x%x", cishort);
1361                 }
1362                 break;
1363             case CI_IFACEID:
1364                 if (olen == CILEN_IFACEID) {
1365                     p += 2;
1366                     eui64_get(ifaceid, p);
1367                     printer(arg, "addr %s", llv6_ntoa(ifaceid));
1368                 }
1369                 break;
1370             }
1371             while (p < optend) {
1372                 GETCHAR(code, p);
1373                 printer(arg, " %.2x", code);
1374             }
1375             printer(arg, ">");
1376         }
1377         break;
1378
1379     case TERMACK:
1380     case TERMREQ:
1381         if (len > 0 && *p >= ' ' && *p < 0x7f) {
1382             printer(arg, " ");
1383             print_string(p, len, printer, arg);
1384             p += len;
1385             len = 0;
1386         }
1387         break;
1388     }
1389
1390     /* print the rest of the bytes in the packet */
1391     for (; len > 0; --len) {
1392         GETCHAR(code, p);
1393         printer(arg, " %.2x", code);
1394     }
1395
1396     return p - pstart;
1397 }
1398
1399 /*
1400  * ipv6_active_pkt - see if this IP packet is worth bringing the link up for.
1401  * We don't bring the link up for IP fragments or for TCP FIN packets
1402  * with no data.
1403  */
1404 #define IP6_HDRLEN      40      /* bytes */
1405 #define IP6_NHDR_FRAG   44      /* fragment IPv6 header */
1406 #define IPPROTO_TCP     6
1407 #define TCP_HDRLEN      20
1408 #define TH_FIN          0x01
1409
1410 /*
1411  * We use these macros because the IP header may be at an odd address,
1412  * and some compilers might use word loads to get th_off or ip_hl.
1413  */
1414
1415 #define get_ip6nh(x)    (((unsigned char *)(x))[6])
1416 #define get_tcpoff(x)   (((unsigned char *)(x))[12] >> 4)
1417 #define get_tcpflags(x) (((unsigned char *)(x))[13])
1418
1419 static int
1420 ipv6_active_pkt(pkt, len)
1421     u_char *pkt;
1422     int len;
1423 {
1424     u_char *tcp;
1425
1426     len -= PPP_HDRLEN;
1427     pkt += PPP_HDRLEN;
1428     if (len < IP6_HDRLEN)
1429         return 0;
1430     if (get_ip6nh(pkt) == IP6_NHDR_FRAG)
1431         return 0;
1432     if (get_ip6nh(pkt) != IPPROTO_TCP)
1433         return 1;
1434     if (len < IP6_HDRLEN + TCP_HDRLEN)
1435         return 0;
1436     tcp = pkt + IP6_HDRLEN;
1437     if ((get_tcpflags(tcp) & TH_FIN) != 0 && len == IP6_HDRLEN + get_tcpoff(tcp) * 4)
1438         return 0;
1439     return 1;
1440 }