2 ipv6cp.c - PPP IPV6 Control Protocol.
3 Copyright (C) 1999 Tommi Komulainen <Tommi.Komulainen@iki.fi>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 /* Original version, based on RFC2023 :
22 Copyright (c) 1995, 1996, 1997 Francis.Dupont@inria.fr, INRIA Rocquencourt,
23 Alain.Durand@imag.fr, IMAG,
24 Jean-Luc.Richier@imag.fr, IMAG-LSR.
26 Copyright (c) 1998, 1999 Francis.Dupont@inria.fr, GIE DYADE,
27 Alain.Durand@imag.fr, IMAG,
28 Jean-Luc.Richier@imag.fr, IMAG-LSR.
30 Ce travail a été fait au sein du GIE DYADE (Groupement d'Intérêt
31 Économique ayant pour membres BULL S.A. et l'INRIA).
33 Ce logiciel informatique est disponible aux conditions
34 usuelles dans la recherche, c'est-à-dire qu'il peut
35 être utilisé, copié, modifié, distribué à l'unique
36 condition que ce texte soit conservé afin que
37 l'origine de ce logiciel soit reconnue.
39 Le nom de l'Institut National de Recherche en Informatique
40 et en Automatique (INRIA), de l'IMAG, ou d'une personne morale
41 ou physique ayant participé à l'élaboration de ce logiciel ne peut
42 être utilisé sans son accord préalable explicite.
44 Ce logiciel est fourni tel quel sans aucune garantie,
45 support ou responsabilité d'aucune sorte.
46 Ce logiciel est dérivé de sources d'origine
47 "University of California at Berkeley" et
48 "Digital Equipment Corporation" couvertes par des copyrights.
50 L'Institut d'Informatique et de Mathématiques Appliquées de Grenoble (IMAG)
51 est une fédération d'unités mixtes de recherche du CNRS, de l'Institut National
52 Polytechnique de Grenoble et de l'Université Joseph Fourier regroupant
53 sept laboratoires dont le laboratoire Logiciels, Systèmes, Réseaux (LSR).
55 This work has been done in the context of GIE DYADE (joint R & D venture
56 between BULL S.A. and INRIA).
58 This software is available with usual "research" terms
59 with the aim of retain credits of the software.
60 Permission to use, copy, modify and distribute this software for any
61 purpose and without fee is hereby granted, provided that the above
62 copyright notice and this permission notice appear in all copies,
63 and the name of INRIA, IMAG, or any contributor not be used in advertising
64 or publicity pertaining to this material without the prior explicit
65 permission. The software is provided "as is" without any
66 warranties, support or liabilities of any kind.
67 This software is derived from source code from
68 "University of California at Berkeley" and
69 "Digital Equipment Corporation" protected by copyrights.
71 Grenoble's Institute of Computer Science and Applied Mathematics (IMAG)
72 is a federation of seven research units funded by the CNRS, National
73 Polytechnic Institute of Grenoble and University Joseph Fourier.
74 The research unit in Software, Systems, Networks (LSR) is member of IMAG.
81 * ipcp.c - PPP IP Control Protocol.
83 * Copyright (c) 1989 Carnegie Mellon University.
84 * All rights reserved.
86 * Redistribution and use in source and binary forms are permitted
87 * provided that the above copyright notice and this paragraph are
88 * duplicated in all such forms and that any documentation,
89 * advertising materials, and other materials related to such
90 * distribution and use acknowledge that the software was developed
91 * by Carnegie Mellon University. The name of the
92 * University may not be used to endorse or promote products derived
93 * from this software without specific prior written permission.
94 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
95 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
96 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
98 * $Id: ipv6cp.c,v 1.6 1999/09/30 19:57:45 masputra Exp $
101 #define RCSID "$Id: ipv6cp.c,v 1.6 1999/09/30 19:57:45 masputra Exp $"
106 * Proxy Neighbour Discovery.
108 * Better defines for selecting the ordering of
109 * interface up / set address. (currently checks for __linux__,
110 * since SVR4 && (SNI || __USLC__) didn't work properly)
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>
128 #include "pathnames.h"
130 static const char rcsid[] = RCSID;
133 ipv6cp_options ipv6cp_wantoptions[NUM_PPP]; /* Options that we want to request */
134 ipv6cp_options ipv6cp_gotoptions[NUM_PPP]; /* Options that peer ack'd */
135 ipv6cp_options ipv6cp_allowoptions[NUM_PPP]; /* Options we allow peer to request */
136 ipv6cp_options ipv6cp_hisoptions[NUM_PPP]; /* Options that we ack'd */
137 int no_ifaceid_neg = 0;
140 static int ipv6cp_is_up;
143 * Callbacks for fsm code. (CI = Configuration Information)
145 static void ipv6cp_resetci __P((fsm *)); /* Reset our CI */
146 static int ipv6cp_cilen __P((fsm *)); /* Return length of our CI */
147 static void ipv6cp_addci __P((fsm *, u_char *, int *)); /* Add our CI */
148 static int ipv6cp_ackci __P((fsm *, u_char *, int)); /* Peer ack'd our CI */
149 static int ipv6cp_nakci __P((fsm *, u_char *, int)); /* Peer nak'd our CI */
150 static int ipv6cp_rejci __P((fsm *, u_char *, int)); /* Peer rej'd our CI */
151 static int ipv6cp_reqci __P((fsm *, u_char *, int *, int)); /* Rcv CI */
152 static void ipv6cp_up __P((fsm *)); /* We're UP */
153 static void ipv6cp_down __P((fsm *)); /* We're DOWN */
154 static void ipv6cp_finished __P((fsm *)); /* Don't need lower layer */
156 fsm ipv6cp_fsm[NUM_PPP]; /* IPV6CP fsm structure */
158 static fsm_callbacks ipv6cp_callbacks = { /* IPV6CP callback routines */
159 ipv6cp_resetci, /* Reset our Configuration Information */
160 ipv6cp_cilen, /* Length of our Configuration Information */
161 ipv6cp_addci, /* Add our Configuration Information */
162 ipv6cp_ackci, /* ACK our Configuration Information */
163 ipv6cp_nakci, /* NAK our Configuration Information */
164 ipv6cp_rejci, /* Reject our Configuration Information */
165 ipv6cp_reqci, /* Request peer's Configuration Information */
166 ipv6cp_up, /* Called when fsm reaches OPENED state */
167 ipv6cp_down, /* Called when fsm leaves OPENED state */
168 NULL, /* Called when we want the lower layer up */
169 ipv6cp_finished, /* Called when we want the lower layer down */
170 NULL, /* Called when Protocol-Reject received */
171 NULL, /* Retransmission is necessary */
172 NULL, /* Called to handle protocol-specific codes */
173 "IPV6CP" /* String name of protocol */
177 * Command-line options.
179 static int setifaceid __P((char **arg));
181 static option_t ipv6cp_option_list[] = {
182 { "ipv6", o_special, setifaceid,
183 "Set interface identifiers for IPV6" },
184 { "noipv6", o_bool, &ipv6cp_protent.enabled_flag,
185 "Disable IPv6 and IPv6CP" },
186 { "-ipv6", o_bool, &ipv6cp_protent.enabled_flag,
187 "Disable IPv6 and IPv6CP" },
188 { "+ipv6", o_bool, &ipv6cp_protent.enabled_flag,
189 "Enable IPv6 and IPv6CP", 1 },
191 { "ipv6cp-accept-local", o_bool, &ipv6cp_allowoptions[0].accept_local,
192 "Accept peer's interface identifier for us", 1 },
193 { "ipv6cp-use-ipaddr", o_bool, &ipv6cp_allowoptions[0].use_ip,
194 "Use (default) IPv4 address as interface identifier", 0 },
196 { "ipv6cp-use-persistent", o_bool, &ipv6cp_wantoptions[0].use_persistent,
197 "Use uniquely-available persistent value for link local address", 1 },
198 #endif /* defined(SOL2) */
199 { "ipv6cp-restart", o_int, &ipv6cp_fsm[0].timeouttime,
200 "Set timeout for IPv6CP" },
201 { "ipv6cp-max-terminate", o_int, &ipv6cp_fsm[0].maxtermtransmits,
202 "Set max #xmits for term-reqs" },
203 { "ipv6cp-max-configure", o_int, &ipv6cp_fsm[0].maxconfreqtransmits,
204 "Set max #xmits for conf-reqs" },
205 { "ipv6cp-max-failure", o_int, &ipv6cp_fsm[0].maxnakloops,
206 "Set max #conf-naks for IPv6CP" },
213 * Protocol entry points from main code.
215 static void ipv6cp_init __P((int));
216 static void ipv6cp_open __P((int));
217 static void ipv6cp_close __P((int, char *));
218 static void ipv6cp_lowerup __P((int));
219 static void ipv6cp_lowerdown __P((int));
220 static void ipv6cp_input __P((int, u_char *, int));
221 static void ipv6cp_protrej __P((int));
222 static int ipv6cp_printpkt __P((u_char *, int,
223 void (*) __P((void *, char *, ...)), void *));
224 static void ipv6_check_options __P((void));
225 static int ipv6_demand_conf __P((int));
226 static int ipv6_active_pkt __P((u_char *, int));
228 struct protent ipv6cp_protent = {
248 static void ipv6cp_clear_addrs __P((int, eui64_t, eui64_t));
249 static void ipv6cp_script __P((char *));
250 static void ipv6cp_script_done __P((void *));
253 * Lengths of configuration options.
256 #define CILEN_COMPRESS 4 /* length for RFC2023 compress opt. */
257 #define CILEN_IFACEID 10 /* RFC2472, interface identifier */
259 #define CODENAME(x) ((x) == CONFACK ? "ACK" : \
260 (x) == CONFNAK ? "NAK" : "REJ")
263 * This state variable is used to ensure that we don't
264 * run an ipcp-up/down script while one is already running.
266 static enum script_state {
269 } ipv6cp_script_state;
270 static pid_t ipv6cp_script_pid;
273 * setifaceid - set the interface identifiers manually
280 ipv6cp_options *wo = &ipv6cp_wantoptions[0];
281 struct in6_addr addr;
283 #define VALIDID(a) ( (((a).s6_addr32[0] == 0) && ((a).s6_addr32[1] == 0)) && \
284 (((a).s6_addr32[2] != 0) || ((a).s6_addr32[3] != 0)) )
287 if ((comma = strchr(arg, ',')) == NULL)
288 comma = arg + strlen(arg);
291 * If comma first character, then no local identifier
296 if (inet_pton(AF_INET6, arg, &addr) == 0 || !VALIDID(addr)) {
297 option_error("Illegal interface identifier (local): %s", arg);
301 eui64_copy(addr.s6_addr32[2], wo->ourid);
307 * If comma last character, the no remote identifier
309 if (*comma != 0 && *++comma != '\0') {
310 if (inet_pton(AF_INET6, comma, &addr) == 0 || !VALIDID(addr)) {
311 option_error("Illegal interface identifier (remote): %s", comma);
314 eui64_copy(addr.s6_addr32[2], wo->hisid);
318 ipv6cp_protent.enabled_flag = 1;
323 * Make a string representation of a network address.
331 sprintf(b, "fe80::%s", eui64_ntoa(ifaceid));
337 * ipv6cp_init - Initialize IPV6CP.
343 fsm *f = &ipv6cp_fsm[unit];
344 ipv6cp_options *wo = &ipv6cp_wantoptions[unit];
345 ipv6cp_options *ao = &ipv6cp_allowoptions[unit];
348 f->protocol = PPP_IPV6CP;
349 f->callbacks = &ipv6cp_callbacks;
350 fsm_init(&ipv6cp_fsm[unit]);
352 memset(wo, 0, sizeof(*wo));
353 memset(ao, 0, sizeof(*ao));
355 wo->accept_local = 1;
362 wo->vj_protocol = IPV6CP_COMP;
369 * ipv6cp_open - IPV6CP is allowed to come up.
375 fsm_open(&ipv6cp_fsm[unit]);
380 * ipv6cp_close - Take IPV6CP down.
383 ipv6cp_close(unit, reason)
387 fsm_close(&ipv6cp_fsm[unit], reason);
392 * ipv6cp_lowerup - The lower layer is up.
398 fsm_lowerup(&ipv6cp_fsm[unit]);
403 * ipv6cp_lowerdown - The lower layer is down.
406 ipv6cp_lowerdown(unit)
409 fsm_lowerdown(&ipv6cp_fsm[unit]);
414 * ipv6cp_input - Input IPV6CP packet.
417 ipv6cp_input(unit, p, len)
422 fsm_input(&ipv6cp_fsm[unit], p, len);
427 * ipv6cp_protrej - A Protocol-Reject was received for IPV6CP.
429 * Pretend the lower layer went down, so we shut up.
435 fsm_lowerdown(&ipv6cp_fsm[unit]);
440 * ipv6cp_resetci - Reset our CI.
446 ipv6cp_options *wo = &ipv6cp_wantoptions[f->unit];
447 ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
449 wo->req_ifaceid = wo->neg_ifaceid && ipv6cp_allowoptions[f->unit].neg_ifaceid;
451 if (!wo->opt_local) {
452 eui64_magic_nz(wo->ourid);
456 eui64_zero(go->hisid); /* last proposed interface identifier */
461 * ipv6cp_cilen - Return length of our CI.
467 ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
469 #define LENCIVJ(neg) (neg ? CILEN_COMPRESS : 0)
470 #define LENCIIFACEID(neg) (neg ? CILEN_IFACEID : 0)
472 return (LENCIIFACEID(go->neg_ifaceid) +
473 LENCIVJ(go->neg_vj));
478 * ipv6cp_addci - Add our desired CIs to a packet.
481 ipv6cp_addci(f, ucp, lenp)
486 ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
489 #define ADDCIVJ(opt, neg, val) \
491 int vjlen = CILEN_COMPRESS; \
492 if (len >= vjlen) { \
494 PUTCHAR(vjlen, ucp); \
495 PUTSHORT(val, ucp); \
501 #define ADDCIIFACEID(opt, neg, val1) \
503 int idlen = CILEN_IFACEID; \
504 if (len >= idlen) { \
506 PUTCHAR(idlen, ucp); \
507 eui64_put(val1, ucp); \
513 ADDCIIFACEID(CI_IFACEID, go->neg_ifaceid, go->ourid);
515 ADDCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol);
522 * ipv6cp_ackci - Ack our CIs.
529 ipv6cp_ackci(f, p, len)
534 ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
535 u_short cilen, citype, cishort;
539 * CIs must be in exactly the same order that we sent...
540 * Check packet length and CI length at each step.
541 * If we find any deviations, then this packet is bad.
544 #define ACKCIVJ(opt, neg, val) \
546 int vjlen = CILEN_COMPRESS; \
547 if ((len -= vjlen) < 0) \
549 GETCHAR(citype, p); \
551 if (cilen != vjlen || \
554 GETSHORT(cishort, p); \
555 if (cishort != val) \
559 #define ACKCIIFACEID(opt, neg, val1) \
561 int idlen = CILEN_IFACEID; \
562 if ((len -= idlen) < 0) \
564 GETCHAR(citype, p); \
566 if (cilen != idlen || \
569 eui64_get(ifaceid, p); \
570 if (! eui64_equals(val1, ifaceid)) \
574 ACKCIIFACEID(CI_IFACEID, go->neg_ifaceid, go->ourid);
576 ACKCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol);
579 * If there are any remaining CIs, then this packet is bad.
586 IPV6CPDEBUG(("ipv6cp_ackci: received bad Ack!"));
591 * ipv6cp_nakci - Peer has sent a NAK for some of our CIs.
592 * This should not modify any state if the Nak is bad
593 * or if IPV6CP is in the OPENED state.
600 ipv6cp_nakci(f, p, len)
605 ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
606 u_char citype, cilen, *next;
609 ipv6cp_options no; /* options we've seen Naks for */
610 ipv6cp_options try; /* options to request next time */
612 BZERO(&no, sizeof(no));
616 * Any Nak'd CIs must be in exactly the same order that we sent.
617 * Check packet length and CI length at each step.
618 * If we find any deviations, then this packet is bad.
620 #define NAKCIIFACEID(opt, neg, code) \
622 len >= (cilen = CILEN_IFACEID) && \
627 eui64_get(ifaceid, p); \
632 #define NAKCIVJ(opt, neg, code) \
634 ((cilen = p[1]) == CILEN_COMPRESS) && \
639 GETSHORT(cishort, p); \
645 * Accept the peer's idea of {our,his} interface identifier, if different
646 * from our idea, only if the accept_{local,remote} flag is set.
648 NAKCIIFACEID(CI_IFACEID, neg_ifaceid,
649 if (go->accept_local) {
650 while (eui64_iszero(ifaceid) ||
651 eui64_equals(ifaceid, go->hisid)) /* bad luck */
652 eui64_magic(ifaceid);
654 IPV6CPDEBUG(("local LL address %s", llv6_ntoa(ifaceid)));
659 NAKCIVJ(CI_COMPRESSTYPE, neg_vj,
661 if (cishort == IPV6CP_COMP) {
662 try.vj_protocol = cishort;
669 NAKCIVJ(CI_COMPRESSTYPE, neg_vj,
677 * There may be remaining CIs, if the peer is requesting negotiation
678 * on an option that we didn't include in our request packet.
679 * If they want to negotiate about interface identifier, we comply.
680 * If they want us to ask for compression, we refuse.
682 while (len > CILEN_VOID) {
685 if( (len -= cilen) < 0 )
687 next = p + cilen - 2;
690 case CI_COMPRESSTYPE:
691 if (go->neg_vj || no.neg_vj ||
692 (cilen != CILEN_COMPRESS))
697 if (go->neg_ifaceid || no.neg_ifaceid || cilen != CILEN_IFACEID)
700 eui64_get(ifaceid, p);
701 if (go->accept_local) {
702 while (eui64_iszero(ifaceid) ||
703 eui64_equals(ifaceid, go->hisid)) /* bad luck */
704 eui64_magic(ifaceid);
713 /* If there is still anything left, this packet is bad. */
718 * OK, the Nak is good. Now we can update state.
720 if (f->state != OPENED)
726 IPV6CPDEBUG(("ipv6cp_nakci: received bad Nak!"));
732 * ipv6cp_rejci - Reject some of our CIs.
735 ipv6cp_rejci(f, p, len)
740 ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
744 ipv6cp_options try; /* options to request next time */
748 * Any Rejected CIs must be in exactly the same order that we sent.
749 * Check packet length and CI length at each step.
750 * If we find any deviations, then this packet is bad.
752 #define REJCIIFACEID(opt, neg, val1) \
754 len >= (cilen = CILEN_IFACEID) && \
759 eui64_get(ifaceid, p); \
760 /* Check rejected value. */ \
761 if (! eui64_equals(ifaceid, val1)) \
766 #define REJCIVJ(opt, neg, val) \
768 p[1] == CILEN_COMPRESS && \
773 GETSHORT(cishort, p); \
774 /* Check rejected value. */ \
775 if (cishort != val) \
780 REJCIIFACEID(CI_IFACEID, neg_ifaceid, go->ourid);
782 REJCIVJ(CI_COMPRESSTYPE, neg_vj, go->vj_protocol);
785 * If there are any remaining CIs, then this packet is bad.
790 * Now we can update state.
792 if (f->state != OPENED)
797 IPV6CPDEBUG(("ipv6cp_rejci: received bad Reject!"));
803 * ipv6cp_reqci - Check the peer's requested CIs and send appropriate response.
805 * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified
806 * appropriately. If reject_if_disagree is non-zero, doesn't return
807 * CONFNAK; returns CONFREJ if it can't return CONFACK.
810 ipv6cp_reqci(f, inp, len, reject_if_disagree)
812 u_char *inp; /* Requested CIs */
813 int *len; /* Length of requested CIs */
814 int reject_if_disagree;
816 ipv6cp_options *wo = &ipv6cp_wantoptions[f->unit];
817 ipv6cp_options *ho = &ipv6cp_hisoptions[f->unit];
818 ipv6cp_options *ao = &ipv6cp_allowoptions[f->unit];
819 ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
820 u_char *cip, *next; /* Pointer to current and next CIs */
821 u_short cilen, citype; /* Parsed len, type */
822 u_short cishort; /* Parsed short value */
823 eui64_t ifaceid; /* Parsed interface identifier */
824 int rc = CONFACK; /* Final packet return code */
825 int orc; /* Individual option return code */
826 u_char *p; /* Pointer to next char to parse */
827 u_char *ucp = inp; /* Pointer to current output char */
828 int l = *len; /* Length left */
831 * Reset all his options.
833 BZERO(ho, sizeof(*ho));
836 * Process all his options.
840 orc = CONFACK; /* Assume success */
841 cip = p = next; /* Remember begining of CI */
842 if (l < 2 || /* Not enough data for CI header or */
843 p[1] < 2 || /* CI length too small or */
844 p[1] > l) { /* CI length too big? */
845 IPV6CPDEBUG(("ipv6cp_reqci: bad CI length!"));
846 orc = CONFREJ; /* Reject bad CI */
847 cilen = l; /* Reject till end of packet */
848 l = 0; /* Don't loop again */
851 GETCHAR(citype, p); /* Parse CI type */
852 GETCHAR(cilen, p); /* Parse CI length */
853 l -= cilen; /* Adjust remaining length */
854 next += cilen; /* Step to next CI */
856 switch (citype) { /* Check CI type */
858 IPV6CPDEBUG(("ipv6cp: received interface identifier "));
860 if (!ao->neg_ifaceid ||
861 cilen != CILEN_IFACEID) { /* Check CI length */
862 orc = CONFREJ; /* Reject CI */
867 * If he has no interface identifier, or if we both have same
868 * identifier then NAK it with new idea.
869 * In particular, if we don't know his identifier, but he does,
872 eui64_get(ifaceid, p);
873 IPV6CPDEBUG(("(%s)", llv6_ntoa(ifaceid)));
874 if (eui64_iszero(ifaceid) && eui64_iszero(go->ourid)) {
875 orc = CONFREJ; /* Reject CI */
878 if (!eui64_iszero(wo->hisid) &&
879 !eui64_equals(ifaceid, wo->hisid) &&
880 eui64_iszero(go->hisid)) {
885 DECPTR(sizeof(ifaceid), p);
886 eui64_put(ifaceid, p);
888 if (eui64_iszero(ifaceid) || eui64_equals(ifaceid, go->ourid)) {
890 if (eui64_iszero(go->hisid)) /* first time, try option */
892 while (eui64_iszero(ifaceid) ||
893 eui64_equals(ifaceid, go->ourid)) /* bad luck */
894 eui64_magic(ifaceid);
896 DECPTR(sizeof(ifaceid), p);
897 eui64_put(ifaceid, p);
904 case CI_COMPRESSTYPE:
905 IPV6CPDEBUG(("ipv6cp: received COMPRESSTYPE "));
907 (cilen != CILEN_COMPRESS)) {
911 GETSHORT(cishort, p);
912 IPV6CPDEBUG(("(%d)", cishort));
915 if (!(cishort == IPV6CP_COMP)) {
925 ho->vj_protocol = cishort;
934 IPV6CPDEBUG((" (%s)\n", CODENAME(orc)));
936 if (orc == CONFACK && /* Good CI */
937 rc != CONFACK) /* but prior CI wasnt? */
938 continue; /* Don't send this one */
940 if (orc == CONFNAK) { /* Nak this CI? */
941 if (reject_if_disagree) /* Getting fed up with sending NAKs? */
942 orc = CONFREJ; /* Get tough if so */
944 if (rc == CONFREJ) /* Rejecting prior CI? */
945 continue; /* Don't send this one */
946 if (rc == CONFACK) { /* Ack'd all prior CIs? */
947 rc = CONFNAK; /* Not anymore... */
948 ucp = inp; /* Backup */
953 if (orc == CONFREJ && /* Reject this CI */
954 rc != CONFREJ) { /* but no prior ones? */
956 ucp = inp; /* Backup */
959 /* Need to move CI? */
961 BCOPY(cip, ucp, cilen); /* Move it */
963 /* Update output pointer */
968 * If we aren't rejecting this packet, and we want to negotiate
969 * their identifier and they didn't send their identifier, then we
970 * send a NAK with a CI_IFACEID option appended. We assume the
971 * input buffer is long enough that we can append the extra
974 if (rc != CONFREJ && !ho->neg_ifaceid &&
975 wo->req_ifaceid && !reject_if_disagree) {
978 ucp = inp; /* reset pointer */
979 wo->req_ifaceid = 0; /* don't ask again */
981 PUTCHAR(CI_IFACEID, ucp);
982 PUTCHAR(CILEN_IFACEID, ucp);
983 eui64_put(wo->hisid, ucp);
986 *len = ucp - inp; /* Compute output length */
987 IPV6CPDEBUG(("ipv6cp: returning Configure-%s", CODENAME(rc)));
988 return (rc); /* Return final code */
993 * ipv6_check_options - check that any IP-related options are OK,
994 * and assign appropriate defaults.
999 ipv6cp_options *wo = &ipv6cp_wantoptions[0];
1003 * Persistent link-local id is only used when user has not explicitly
1004 * configure/hard-code the id
1006 if ((wo->use_persistent) && (!wo->opt_local) && (!wo->opt_remote)) {
1009 * On systems where there are no Ethernet interfaces used, there
1010 * may be other ways to obtain a persistent id. Right now, it
1011 * will fall back to using magic [see eui64_magic] below when
1012 * an EUI-48 from MAC address can't be obtained. Other possibilities
1013 * include obtaining EEPROM serial numbers, or some other unique
1014 * yet persistent number. On Sparc platforms, this is possible,
1015 * but too bad there's no standards yet for x86 machines.
1017 if (ether_to_eui64(&wo->ourid)) {
1023 if (!wo->opt_local) { /* init interface identifier */
1024 if (wo->use_ip && eui64_iszero(wo->ourid)) {
1025 eui64_setlo32(wo->ourid, ntohl(ipcp_wantoptions[0].ouraddr));
1026 if (!eui64_iszero(wo->ourid))
1030 while (eui64_iszero(wo->ourid))
1031 eui64_magic(wo->ourid);
1034 if (!wo->opt_remote) {
1035 if (wo->use_ip && eui64_iszero(wo->hisid)) {
1036 eui64_setlo32(wo->hisid, ntohl(ipcp_wantoptions[0].hisaddr));
1037 if (!eui64_iszero(wo->hisid))
1042 if (demand && (eui64_iszero(wo->ourid) || eui64_iszero(wo->hisid))) {
1043 option_error("local/remote LL address required for demand-dialling\n");
1050 * ipv6_demand_conf - configure the interface as though
1051 * IPV6CP were up, for use with dial-on-demand.
1057 ipv6cp_options *wo = &ipv6cp_wantoptions[u];
1059 #if defined(__linux__) || defined(SOL2) || (defined(SVR4) && (defined(SNI) || defined(__USLC__)))
1066 #endif /* defined(SOL2) */
1068 if (!sif6addr(u, wo->ourid, wo->hisid))
1070 #if !defined(__linux__) && !(defined(SVR4) && (defined(SNI) || defined(__USLC__)))
1074 if (!sifnpmode(u, PPP_IPV6, NPMODE_QUEUE))
1077 notice("ipv6_demand_conf");
1078 notice("local LL address %s", llv6_ntoa(wo->ourid));
1079 notice("remote LL address %s", llv6_ntoa(wo->hisid));
1086 * ipv6cp_up - IPV6CP has come UP.
1088 * Configure the IPv6 network interface appropriately and bring it up.
1094 ipv6cp_options *ho = &ipv6cp_hisoptions[f->unit];
1095 ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
1096 ipv6cp_options *wo = &ipv6cp_wantoptions[f->unit];
1098 IPV6CPDEBUG(("ipv6cp: up"));
1101 * We must have a non-zero LL address for both ends of the link.
1103 if (!ho->neg_ifaceid)
1104 ho->hisid = wo->hisid;
1106 if(!no_ifaceid_neg) {
1107 if (eui64_iszero(ho->hisid)) {
1108 error("Could not determine remote LL address");
1109 ipv6cp_close(f->unit, "Could not determine remote LL address");
1112 if (eui64_iszero(go->ourid)) {
1113 error("Could not determine local LL address");
1114 ipv6cp_close(f->unit, "Could not determine local LL address");
1117 if (eui64_equals(go->ourid, ho->hisid)) {
1118 error("local and remote LL addresses are equal");
1119 ipv6cp_close(f->unit, "local and remote LL addresses are equal");
1123 script_setenv("LLLOCAL", llv6_ntoa(go->ourid));
1124 script_setenv("LLREMOTE", llv6_ntoa(ho->hisid));
1127 /* set tcp compression */
1128 sif6comp(f->unit, ho->neg_vj);
1132 * If we are doing dial-on-demand, the interface is already
1133 * configured, so we put out any saved-up packets, then set the
1134 * interface to pass IPv6 packets.
1137 if (! eui64_equals(go->ourid, wo->ourid) ||
1138 ! eui64_equals(ho->hisid, wo->hisid)) {
1139 if (! eui64_equals(go->ourid, wo->ourid))
1140 warn("Local LL address changed to %s",
1141 llv6_ntoa(go->ourid));
1142 if (! eui64_equals(ho->hisid, wo->hisid))
1143 warn("Remote LL address changed to %s",
1144 llv6_ntoa(ho->hisid));
1145 ipv6cp_clear_addrs(f->unit, go->ourid, ho->hisid);
1147 /* Set the interface to the new addresses */
1148 if (!sif6addr(f->unit, go->ourid, ho->hisid)) {
1150 warn("sif6addr failed");
1151 ipv6cp_close(f->unit, "Interface configuration failed");
1156 demand_rexmit(PPP_IPV6);
1157 sifnpmode(f->unit, PPP_IPV6, NPMODE_PASS);
1163 #if !defined(__linux__) && !defined(SOL2) && !(defined(SVR4) && (defined(SNI) || defined(__USLC__)))
1164 if (!sif6addr(f->unit, go->ourid, ho->hisid)) {
1166 warn("sif6addr failed");
1167 ipv6cp_close(f->unit, "Interface configuration failed");
1172 /* bring the interface up for IPv6 */
1174 if (!sif6up(f->unit)) {
1176 warn("sifup failed (IPV6)");
1177 ipv6cp_close(f->unit, "Interface configuration failed");
1181 if (!sifup(f->unit)) {
1183 warn("sifup failed (IPV6)");
1184 ipv6cp_close(f->unit, "Interface configuration failed");
1187 #endif /* defined(SOL2) */
1189 #if defined(__linux__) || defined(SOL2) || (defined(SVR4) && (defined(SNI) || defined(__USLC__)))
1190 if (!sif6addr(f->unit, go->ourid, ho->hisid)) {
1192 warn("sif6addr failed");
1193 ipv6cp_close(f->unit, "Interface configuration failed");
1197 sifnpmode(f->unit, PPP_IPV6, NPMODE_PASS);
1199 notice("local LL address %s", llv6_ntoa(go->ourid));
1200 notice("remote LL address %s", llv6_ntoa(ho->hisid));
1203 np_up(f->unit, PPP_IPV6);
1207 * In Solaris, neighbor discovery and router advertisement are done
1208 * automatically by in.ndpd daemon when the interface comes up or down
1209 * and /etc/inet/ndpd.conf is configured properly
1213 * Execute the ipv6-up script, like this:
1214 * /etc/ppp/ipv6-up interface tty speed local-LL remote-LL
1216 if (ipv6cp_script_state == s_down && ipv6cp_script_pid == 0) {
1217 ipv6cp_script_state = s_up;
1218 ipv6cp_script(_PATH_IPV6UP);
1220 #endif /* !defined(SOL2) */
1225 * ipv6cp_down - IPV6CP has gone DOWN.
1227 * Take the IPv6 network interface down, clear its addresses
1228 * and delete routes through it.
1234 IPV6CPDEBUG(("ipv6cp: down"));
1235 update_link_stats(f->unit);
1238 np_down(f->unit, PPP_IPV6);
1241 sif6comp(f->unit, 0);
1245 * If we are doing dial-on-demand, set the interface
1246 * to queue up outgoing packets (for now).
1249 sifnpmode(f->unit, PPP_IPV6, NPMODE_QUEUE);
1251 sifnpmode(f->unit, PPP_IPV6, NPMODE_DROP);
1252 #if !defined(__linux__) && !(defined(SVR4) && (defined(SNI) || defined(__USLC)))
1257 #endif /* defined(SOL2) */
1259 ipv6cp_clear_addrs(f->unit,
1260 ipv6cp_gotoptions[f->unit].ourid,
1261 ipv6cp_hisoptions[f->unit].hisid);
1262 #if defined(__linux__) || (defined(SVR4) && (defined(SNI) || defined(__USLC)))
1268 * In Solaris, neighbor discovery and router advertisement are done
1269 * automatically by in.ndpd daemon when the interface comes up or down
1270 * and /etc/inet/ndpd.conf is configured properly
1273 /* Execute the ipv6-down script */
1274 if (ipv6cp_script_state == s_up && ipv6cp_script_pid == 0) {
1275 ipv6cp_script_state = s_down;
1276 ipv6cp_script(_PATH_IPV6DOWN);
1278 #endif /* !defined(SOL2) */
1283 * ipv6cp_clear_addrs() - clear the interface addresses, routes,
1284 * proxy neighbour discovery entries, etc.
1287 ipv6cp_clear_addrs(unit, ourid, hisid)
1292 cif6addr(unit, ourid, hisid);
1297 * ipv6cp_finished - possibly shut down the lower layers.
1303 np_finished(f->unit, PPP_IPV6);
1308 * ipv6cp_script_done - called when the ipv6-up or ipv6-down script
1312 ipv6cp_script_done(arg)
1315 ipv6cp_script_pid = 0;
1316 switch (ipv6cp_script_state) {
1318 if (ipv6cp_fsm[0].state != OPENED) {
1319 ipv6cp_script_state = s_down;
1320 ipv6cp_script(_PATH_IPV6DOWN);
1324 if (ipv6cp_fsm[0].state == OPENED) {
1325 ipv6cp_script_state = s_up;
1326 ipv6cp_script(_PATH_IPV6UP);
1334 * ipv6cp_script - Execute a script with arguments
1335 * interface-name tty-name speed local-LL remote-LL.
1338 ipv6cp_script(script)
1341 char strspeed[32], strlocal[32], strremote[32];
1344 sprintf(strspeed, "%d", baud_rate);
1345 strcpy(strlocal, llv6_ntoa(ipv6cp_gotoptions[0].ourid));
1346 strcpy(strremote, llv6_ntoa(ipv6cp_hisoptions[0].hisid));
1353 argv[5] = strremote;
1357 ipv6cp_script_pid = run_program(script, argv, 0, ipv6cp_script_done, NULL);
1361 * ipv6cp_printpkt - print the contents of an IPV6CP packet.
1363 static char *ipv6cp_codenames[] = {
1364 "ConfReq", "ConfAck", "ConfNak", "ConfRej",
1365 "TermReq", "TermAck", "CodeRej"
1369 ipv6cp_printpkt(p, plen, printer, arg)
1372 void (*printer) __P((void *, char *, ...));
1375 int code, id, len, olen;
1376 u_char *pstart, *optend;
1380 if (plen < HEADERLEN)
1386 if (len < HEADERLEN || len > plen)
1389 if (code >= 1 && code <= sizeof(ipv6cp_codenames) / sizeof(char *))
1390 printer(arg, " %s", ipv6cp_codenames[code-1]);
1392 printer(arg, " code=0x%x", code);
1393 printer(arg, " id=0x%x", id);
1400 /* print option list */
1405 if (olen < 2 || olen > len) {
1412 case CI_COMPRESSTYPE:
1413 if (olen >= CILEN_COMPRESS) {
1415 GETSHORT(cishort, p);
1416 printer(arg, "compress ");
1417 printer(arg, "0x%x", cishort);
1421 if (olen == CILEN_IFACEID) {
1423 eui64_get(ifaceid, p);
1424 printer(arg, "addr %s", llv6_ntoa(ifaceid));
1428 while (p < optend) {
1430 printer(arg, " %.2x", code);
1438 if (len > 0 && *p >= ' ' && *p < 0x7f) {
1440 print_string(p, len, printer, arg);
1447 /* print the rest of the bytes in the packet */
1448 for (; len > 0; --len) {
1450 printer(arg, " %.2x", code);
1457 * ipv6_active_pkt - see if this IP packet is worth bringing the link up for.
1458 * We don't bring the link up for IP fragments or for TCP FIN packets
1461 #define IP6_HDRLEN 40 /* bytes */
1462 #define IP6_NHDR_FRAG 44 /* fragment IPv6 header */
1463 #define IPPROTO_TCP 6
1464 #define TCP_HDRLEN 20
1468 * We use these macros because the IP header may be at an odd address,
1469 * and some compilers might use word loads to get th_off or ip_hl.
1472 #define get_ip6nh(x) (((unsigned char *)(x))[6])
1473 #define get_tcpoff(x) (((unsigned char *)(x))[12] >> 4)
1474 #define get_tcpflags(x) (((unsigned char *)(x))[13])
1477 ipv6_active_pkt(pkt, len)
1485 if (len < IP6_HDRLEN)
1487 if (get_ip6nh(pkt) == IP6_NHDR_FRAG)
1489 if (get_ip6nh(pkt) != IPPROTO_TCP)
1491 if (len < IP6_HDRLEN + TCP_HDRLEN)
1493 tcp = pkt + IP6_HDRLEN;
1494 if ((get_tcpflags(tcp) & TH_FIN) != 0 && len == IP6_HDRLEN + get_tcpoff(tcp) * 4)