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