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