2 * ipv6cp.c - PPP IPV6 Control Protocol.
7 * ipcp.c - PPP IP Control Protocol.
9 * Copyright (c) 1989 Carnegie Mellon University.
10 * All rights reserved.
12 * Redistribution and use in source and binary forms are permitted
13 * provided that the above copyright notice and this paragraph are
14 * duplicated in all such forms and that any documentation,
15 * advertising materials, and other materials related to such
16 * distribution and use acknowledge that the software was developed
17 * by Carnegie Mellon University. The name of the
18 * University may not be used to endorse or promote products derived
19 * from this software without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
22 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
24 * $Id: ipv6cp.c,v 1.3 1999/08/24 05:31:09 paulus Exp $
27 * Original version by Inria (www.inria.fr)
28 * Modified to match RFC2472 by Tommi Komulainen <Tommi.Komulainen@iki.fi>
31 #define RCSID "$Id: ipv6cp.c,v 1.3 1999/08/24 05:31:09 paulus Exp $"
36 * Better defines for selecting the ordering of
37 * interface up / set address. (currently checks for __linux__,
38 * since SVR4 && (SNI || __USLC__) didn't work properly)
45 #include <sys/param.h>
46 #include <sys/types.h>
47 #include <sys/socket.h>
48 #include <netinet/in.h>
49 #include <arpa/inet.h>
56 #include "pathnames.h"
58 static const char rcsid[] = RCSID;
61 ipv6cp_options ipv6cp_wantoptions[NUM_PPP]; /* Options that we want to request */
62 ipv6cp_options ipv6cp_gotoptions[NUM_PPP]; /* Options that peer ack'd */
63 ipv6cp_options ipv6cp_allowoptions[NUM_PPP]; /* Options we allow peer to request */
64 ipv6cp_options ipv6cp_hisoptions[NUM_PPP]; /* Options that we ack'd */
65 int no_ifaceid_neg = 0;
68 static int ipv6cp_is_up;
71 * Callbacks for fsm code. (CI = Configuration Information)
73 static void ipv6cp_resetci __P((fsm *)); /* Reset our CI */
74 static int ipv6cp_cilen __P((fsm *)); /* Return length of our CI */
75 static void ipv6cp_addci __P((fsm *, u_char *, int *)); /* Add our CI */
76 static int ipv6cp_ackci __P((fsm *, u_char *, int)); /* Peer ack'd our CI */
77 static int ipv6cp_nakci __P((fsm *, u_char *, int)); /* Peer nak'd our CI */
78 static int ipv6cp_rejci __P((fsm *, u_char *, int)); /* Peer rej'd our CI */
79 static int ipv6cp_reqci __P((fsm *, u_char *, int *, int)); /* Rcv CI */
80 static void ipv6cp_up __P((fsm *)); /* We're UP */
81 static void ipv6cp_down __P((fsm *)); /* We're DOWN */
82 static void ipv6cp_finished __P((fsm *)); /* Don't need lower layer */
84 fsm ipv6cp_fsm[NUM_PPP]; /* IPV6CP fsm structure */
86 static fsm_callbacks ipv6cp_callbacks = { /* IPV6CP callback routines */
87 ipv6cp_resetci, /* Reset our Configuration Information */
88 ipv6cp_cilen, /* Length of our Configuration Information */
89 ipv6cp_addci, /* Add our Configuration Information */
90 ipv6cp_ackci, /* ACK our Configuration Information */
91 ipv6cp_nakci, /* NAK our Configuration Information */
92 ipv6cp_rejci, /* Reject our Configuration Information */
93 ipv6cp_reqci, /* Request peer's Configuration Information */
94 ipv6cp_up, /* Called when fsm reaches OPENED state */
95 ipv6cp_down, /* Called when fsm leaves OPENED state */
96 NULL, /* Called when we want the lower layer up */
97 ipv6cp_finished, /* Called when we want the lower layer down */
98 NULL, /* Called when Protocol-Reject received */
99 NULL, /* Retransmission is necessary */
100 NULL, /* Called to handle protocol-specific codes */
101 "IPV6CP" /* String name of protocol */
105 * Command-line options.
107 static int setifaceid __P((char *arg));
109 static option_t ipv6cp_option_list[] = {
110 { "ipv6", o_special, setifaceid,
111 "Set interface identifiers for IPV6" },
112 { "noipv6", o_bool, &ipv6cp_protent.enabled_flag,
113 "Disable IPv6 and IPv6CP" },
114 { "-ipv6", o_bool, &ipv6cp_protent.enabled_flag,
115 "Disable IPv6 and IPv6CP" },
117 { "ipv6cp-accept-local", o_bool, &ipv6cp_allowoptions[0].accept_local,
118 "Accept peer's interface identifier for us", 1 },
119 { "ipv6cp-use-ipaddr", o_bool, &ipv6cp_allowoptions[0].use_ip,
120 "Use (default) IPv4 address as interface identifier", 0 },
122 { "ipv6cp-restart", o_int, &ipv6cp_fsm[0].timeouttime,
123 "Set timeout for IPv6CP" },
124 { "ipv6cp-max-terminate", o_int, &ipv6cp_fsm[0].maxtermtransmits,
125 "Set max #xmits for term-reqs" },
126 { "ipv6cp-max-configure", o_int, &ipv6cp_fsm[0].maxconfreqtransmits,
127 "Set max #xmits for conf-reqs" },
128 { "ipv6cp-max-failure", o_int, &ipv6cp_fsm[0].maxnakloops,
129 "Set max #conf-naks for IPv6CP" },
136 * Protocol entry points from main code.
138 static void ipv6cp_init __P((int));
139 static void ipv6cp_open __P((int));
140 static void ipv6cp_close __P((int, char *));
141 static void ipv6cp_lowerup __P((int));
142 static void ipv6cp_lowerdown __P((int));
143 static void ipv6cp_input __P((int, u_char *, int));
144 static void ipv6cp_protrej __P((int));
145 static int ipv6cp_printpkt __P((u_char *, int,
146 void (*) __P((void *, char *, ...)), void *));
147 static void ipv6_check_options __P((void));
148 static int ipv6_demand_conf __P((int));
149 static int ipv6_active_pkt __P((u_char *, int));
151 struct protent ipv6cp_protent = {
171 static void ipv6cp_clear_addrs __P((int));
172 static void ipv6cp_script __P((char *));
173 static void ipv6cp_script_done __P((void *));
176 * Lengths of configuration options.
179 #define CILEN_COMPRESS 4 /* length for RFC2023 compress opt. */
180 #define CILEN_IFACEID 10 /* RFC2472, interface identifier */
182 #define CODENAME(x) ((x) == CONFACK ? "ACK" : \
183 (x) == CONFNAK ? "NAK" : "REJ")
186 * This state variable is used to ensure that we don't
187 * run an ipcp-up/down script while one is already running.
189 static enum script_state {
192 } ipv6cp_script_state;
193 static pid_t ipv6cp_script_pid;
196 * setifaceid - set the interface identifiers manually
203 ipv6cp_options *wo = &ipv6cp_wantoptions[0];
204 struct in6_addr addr;
206 #define VALIDID(a) ( (((a).s6_addr32[0] == 0) && ((a).s6_addr32[1] == 0)) && \
207 (((a).s6_addr32[2] != 0) || ((a).s6_addr32[3] != 0)) )
209 if ((comma = strchr(arg, ',')) == NULL)
210 comma = arg + strlen(arg);
213 * If comma first character, then no local identifier
218 if (inet_pton(AF_INET6, arg, &addr) == 0 || !VALIDID(addr)) {
219 option_error("Illegal interface identifier: %s", arg);
223 eui64_copy(addr.s6_addr32[2], wo->ourid);
229 * If comma last character, the no remote identifier
231 if (*comma != 0 && *++comma != '\0') {
232 if (inet_pton(AF_INET6, comma, &addr) == 0 || !VALIDID(addr)) {
233 option_error("Illegal interface identifier: %s", comma);
236 eui64_copy(addr.s6_addr32[2], wo->hisid);
244 * Make a string representation of a network address.
252 sprintf(b, "fe80::%s", eui64_ntoa(ifaceid));
258 * ipv6cp_init - Initialize IPV6CP.
264 fsm *f = &ipv6cp_fsm[unit];
265 ipv6cp_options *wo = &ipv6cp_wantoptions[unit];
266 ipv6cp_options *ao = &ipv6cp_allowoptions[unit];
269 f->protocol = PPP_IPV6CP;
270 f->callbacks = &ipv6cp_callbacks;
271 fsm_init(&ipv6cp_fsm[unit]);
273 memset(wo, 0, sizeof(*wo));
274 memset(ao, 0, sizeof(*ao));
276 wo->accept_local = 1;
283 wo->vj_protocol = IPV6CP_COMP;
290 * ipv6cp_open - IPV6CP is allowed to come up.
296 fsm_open(&ipv6cp_fsm[unit]);
301 * ipv6cp_close - Take IPV6CP down.
304 ipv6cp_close(unit, reason)
308 fsm_close(&ipv6cp_fsm[unit], reason);
313 * ipv6cp_lowerup - The lower layer is up.
319 fsm_lowerup(&ipv6cp_fsm[unit]);
324 * ipv6cp_lowerdown - The lower layer is down.
327 ipv6cp_lowerdown(unit)
330 fsm_lowerdown(&ipv6cp_fsm[unit]);
335 * ipv6cp_input - Input IPV6CP packet.
338 ipv6cp_input(unit, p, len)
343 fsm_input(&ipv6cp_fsm[unit], p, len);
348 * ipv6cp_protrej - A Protocol-Reject was received for IPV6CP.
350 * Pretend the lower layer went down, so we shut up.
356 fsm_lowerdown(&ipv6cp_fsm[unit]);
361 * ipv6cp_resetci - Reset our CI.
367 ipv6cp_options *wo = &ipv6cp_wantoptions[f->unit];
368 ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
370 wo->req_ifaceid = wo->neg_ifaceid && ipv6cp_allowoptions[f->unit].neg_ifaceid;
372 if (!wo->opt_local) {
373 eui64_magic_nz(wo->ourid);
377 eui64_zero(go->hisid); /* last proposed interface identifier */
382 * ipv6cp_cilen - Return length of our CI.
388 ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
390 #define LENCIVJ(neg) (neg ? CILEN_COMPRESS : 0)
391 #define LENCIIFACEID(neg) (neg ? CILEN_IFACEID : 0)
393 return (LENCIIFACEID(go->neg_ifaceid) +
394 LENCIVJ(go->neg_vj));
399 * ipv6cp_addci - Add our desired CIs to a packet.
402 ipv6cp_addci(f, ucp, lenp)
407 ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
410 #define ADDCIVJ(opt, neg, val) \
412 int vjlen = CILEN_COMPRESS; \
413 if (len >= vjlen) { \
415 PUTCHAR(vjlen, ucp); \
416 PUTSHORT(val, ucp); \
422 #define ADDCIIFACEID(opt, neg, val1) \
424 int idlen = CILEN_IFACEID; \
425 if (len >= idlen) { \
427 PUTCHAR(idlen, ucp); \
428 eui64_put(val1, ucp); \
434 ADDCIIFACEID(CI_IFACEID, go->neg_ifaceid, go->ourid);
436 ADDCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol);
443 * ipv6cp_ackci - Ack our CIs.
450 ipv6cp_ackci(f, p, len)
455 ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
456 u_short cilen, citype, cishort;
460 * CIs must be in exactly the same order that we sent...
461 * Check packet length and CI length at each step.
462 * If we find any deviations, then this packet is bad.
465 #define ACKCIVJ(opt, neg, val) \
467 int vjlen = CILEN_COMPRESS; \
468 if ((len -= vjlen) < 0) \
470 GETCHAR(citype, p); \
472 if (cilen != vjlen || \
475 GETSHORT(cishort, p); \
476 if (cishort != val) \
480 #define ACKCIIFACEID(opt, neg, val1) \
482 int idlen = CILEN_IFACEID; \
483 if ((len -= idlen) < 0) \
485 GETCHAR(citype, p); \
487 if (cilen != idlen || \
490 eui64_get(ifaceid, p); \
491 if (! eui64_equals(val1, ifaceid)) \
495 ACKCIIFACEID(CI_IFACEID, go->neg_ifaceid, go->ourid);
497 ACKCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol);
500 * If there are any remaining CIs, then this packet is bad.
507 IPV6CPDEBUG(("ipv6cp_ackci: received bad Ack!"));
512 * ipv6cp_nakci - Peer has sent a NAK for some of our CIs.
513 * This should not modify any state if the Nak is bad
514 * or if IPV6CP is in the OPENED state.
521 ipv6cp_nakci(f, p, len)
526 ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
527 u_char citype, cilen, *next;
530 ipv6cp_options no; /* options we've seen Naks for */
531 ipv6cp_options try; /* options to request next time */
533 BZERO(&no, sizeof(no));
537 * Any Nak'd CIs must be in exactly the same order that we sent.
538 * Check packet length and CI length at each step.
539 * If we find any deviations, then this packet is bad.
541 #define NAKCIIFACEID(opt, neg, code) \
543 len >= (cilen = CILEN_IFACEID) && \
548 eui64_get(ifaceid, p); \
553 #define NAKCIVJ(opt, neg, code) \
555 ((cilen = p[1]) == CILEN_COMPRESS) && \
560 GETSHORT(cishort, p); \
566 * Accept the peer's idea of {our,his} interface identifier, if different
567 * from our idea, only if the accept_{local,remote} flag is set.
569 NAKCIIFACEID(CI_IFACEID, neg_ifaceid,
570 if (go->accept_local) {
571 while (eui64_iszero(ifaceid) ||
572 eui64_equals(ifaceid, go->hisid)) /* bad luck */
573 eui64_magic(ifaceid);
575 IPV6CPDEBUG(("local LL address %s", llv6_ntoa(ifaceid)));
580 NAKCIVJ(CI_COMPRESSTYPE, neg_vj,
582 if (cishort == IPV6CP_COMP) {
583 try.vj_protocol = cishort;
590 NAKCIVJ(CI_COMPRESSTYPE, neg_vj,
598 * There may be remaining CIs, if the peer is requesting negotiation
599 * on an option that we didn't include in our request packet.
600 * If they want to negotiate about interface identifier, we comply.
601 * If they want us to ask for compression, we refuse.
603 while (len > CILEN_VOID) {
606 if( (len -= cilen) < 0 )
608 next = p + cilen - 2;
611 case CI_COMPRESSTYPE:
612 if (go->neg_vj || no.neg_vj ||
613 (cilen != CILEN_COMPRESS))
618 if (go->neg_ifaceid || no.neg_ifaceid || cilen != CILEN_IFACEID)
621 eui64_get(ifaceid, p);
622 if (go->accept_local) {
623 while (eui64_iszero(ifaceid) ||
624 eui64_equals(ifaceid, go->hisid)) /* bad luck */
625 eui64_magic(ifaceid);
634 /* If there is still anything left, this packet is bad. */
639 * OK, the Nak is good. Now we can update state.
641 if (f->state != OPENED)
647 IPV6CPDEBUG(("ipv6cp_nakci: received bad Nak!"));
653 * ipv6cp_rejci - Reject some of our CIs.
656 ipv6cp_rejci(f, p, len)
661 ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
665 ipv6cp_options try; /* options to request next time */
669 * Any Rejected CIs must be in exactly the same order that we sent.
670 * Check packet length and CI length at each step.
671 * If we find any deviations, then this packet is bad.
673 #define REJCIIFACEID(opt, neg, val1) \
675 len >= (cilen = CILEN_IFACEID) && \
680 eui64_get(ifaceid, p); \
681 /* Check rejected value. */ \
682 if (! eui64_equals(ifaceid, val1)) \
687 #define REJCIVJ(opt, neg, val) \
689 p[1] == CILEN_COMPRESS && \
694 GETSHORT(cishort, p); \
695 /* Check rejected value. */ \
696 if (cishort != val) \
701 REJCIIFACEID(CI_IFACEID, neg_ifaceid, go->ourid);
703 REJCIVJ(CI_COMPRESSTYPE, neg_vj, go->vj_protocol);
706 * If there are any remaining CIs, then this packet is bad.
711 * Now we can update state.
713 if (f->state != OPENED)
718 IPV6CPDEBUG(("ipv6cp_rejci: received bad Reject!"));
724 * ipv6cp_reqci - Check the peer's requested CIs and send appropriate response.
726 * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified
727 * appropriately. If reject_if_disagree is non-zero, doesn't return
728 * CONFNAK; returns CONFREJ if it can't return CONFACK.
731 ipv6cp_reqci(f, inp, len, reject_if_disagree)
733 u_char *inp; /* Requested CIs */
734 int *len; /* Length of requested CIs */
735 int reject_if_disagree;
737 ipv6cp_options *wo = &ipv6cp_wantoptions[f->unit];
738 ipv6cp_options *ho = &ipv6cp_hisoptions[f->unit];
739 ipv6cp_options *ao = &ipv6cp_allowoptions[f->unit];
740 ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
741 u_char *cip, *next; /* Pointer to current and next CIs */
742 u_short cilen, citype; /* Parsed len, type */
743 u_short cishort; /* Parsed short value */
744 eui64_t ifaceid; /* Parsed interface identifier */
745 int rc = CONFACK; /* Final packet return code */
746 int orc; /* Individual option return code */
747 u_char *p; /* Pointer to next char to parse */
748 u_char *ucp = inp; /* Pointer to current output char */
749 int l = *len; /* Length left */
752 * Reset all his options.
754 BZERO(ho, sizeof(*ho));
757 * Process all his options.
761 orc = CONFACK; /* Assume success */
762 cip = p = next; /* Remember begining of CI */
763 if (l < 2 || /* Not enough data for CI header or */
764 p[1] < 2 || /* CI length too small or */
765 p[1] > l) { /* CI length too big? */
766 IPV6CPDEBUG(("ipv6cp_reqci: bad CI length!"));
767 orc = CONFREJ; /* Reject bad CI */
768 cilen = l; /* Reject till end of packet */
769 l = 0; /* Don't loop again */
772 GETCHAR(citype, p); /* Parse CI type */
773 GETCHAR(cilen, p); /* Parse CI length */
774 l -= cilen; /* Adjust remaining length */
775 next += cilen; /* Step to next CI */
777 switch (citype) { /* Check CI type */
779 IPV6CPDEBUG(("ipv6cp: received interface identifier "));
781 if (!ao->neg_ifaceid ||
782 cilen != CILEN_IFACEID) { /* Check CI length */
783 orc = CONFREJ; /* Reject CI */
788 * If he has no interface identifier, or if we both have same
789 * identifier then NAK it with new idea.
790 * In particular, if we don't know his identifier, but he does,
793 eui64_get(ifaceid, p);
794 IPV6CPDEBUG(("(%s)", llv6_ntoa(ifaceid)));
795 if (eui64_iszero(ifaceid) && eui64_iszero(go->ourid)) {
796 orc = CONFREJ; /* Reject CI */
799 if (!eui64_iszero(wo->hisid) &&
800 !eui64_equals(ifaceid, wo->hisid) &&
801 eui64_iszero(go->hisid)) {
806 DECPTR(sizeof(ifaceid), p);
807 eui64_put(ifaceid, p);
809 if (eui64_iszero(ifaceid) || eui64_equals(ifaceid, go->ourid)) {
811 if (eui64_iszero(go->hisid)) /* first time, try option */
813 while (eui64_iszero(ifaceid) ||
814 eui64_equals(ifaceid, go->ourid)) /* bad luck */
815 eui64_magic(ifaceid);
817 DECPTR(sizeof(ifaceid), p);
818 eui64_put(ifaceid, p);
825 case CI_COMPRESSTYPE:
826 IPV6CPDEBUG(("ipv6cp: received COMPRESSTYPE "));
828 (cilen != CILEN_COMPRESS)) {
832 GETSHORT(cishort, p);
833 IPV6CPDEBUG(("(%d)", cishort));
836 if (!(cishort == IPV6CP_COMP)) {
846 ho->vj_protocol = cishort;
855 IPV6CPDEBUG((" (%s)\n", CODENAME(orc)));
857 if (orc == CONFACK && /* Good CI */
858 rc != CONFACK) /* but prior CI wasnt? */
859 continue; /* Don't send this one */
861 if (orc == CONFNAK) { /* Nak this CI? */
862 if (reject_if_disagree) /* Getting fed up with sending NAKs? */
863 orc = CONFREJ; /* Get tough if so */
865 if (rc == CONFREJ) /* Rejecting prior CI? */
866 continue; /* Don't send this one */
867 if (rc == CONFACK) { /* Ack'd all prior CIs? */
868 rc = CONFNAK; /* Not anymore... */
869 ucp = inp; /* Backup */
874 if (orc == CONFREJ && /* Reject this CI */
875 rc != CONFREJ) { /* but no prior ones? */
877 ucp = inp; /* Backup */
880 /* Need to move CI? */
882 BCOPY(cip, ucp, cilen); /* Move it */
884 /* Update output pointer */
889 * If we aren't rejecting this packet, and we want to negotiate
890 * their identifier and they didn't send their identifier, then we
891 * send a NAK with a CI_IFACEID option appended. We assume the
892 * input buffer is long enough that we can append the extra
895 if (rc != CONFREJ && !ho->neg_ifaceid &&
896 wo->req_ifaceid && !reject_if_disagree) {
899 ucp = inp; /* reset pointer */
900 wo->req_ifaceid = 0; /* don't ask again */
902 PUTCHAR(CI_IFACEID, ucp);
903 PUTCHAR(CILEN_IFACEID, ucp);
904 eui64_put(wo->hisid, ucp);
907 *len = ucp - inp; /* Compute output length */
908 IPV6CPDEBUG(("ipv6cp: returning Configure-%s", CODENAME(rc)));
909 return (rc); /* Return final code */
914 * ipv6_check_options - check that any IP-related options are OK,
915 * and assign appropriate defaults.
920 ipv6cp_options *wo = &ipv6cp_wantoptions[0];
922 if (!wo->opt_local) { /* init interface identifier */
923 if (wo->use_ip && eui64_iszero(wo->ourid)) {
924 eui64_setlo32(wo->ourid, ntohl(ipcp_wantoptions[0].ouraddr));
925 if (!eui64_iszero(wo->ourid))
929 while (eui64_iszero(wo->ourid))
930 eui64_magic(wo->ourid);
933 if (!wo->opt_remote) {
934 if (wo->use_ip && eui64_iszero(wo->hisid)) {
935 eui64_setlo32(wo->hisid, ntohl(ipcp_wantoptions[0].hisaddr));
936 if (!eui64_iszero(wo->hisid))
941 if (demand && (eui64_iszero(wo->ourid) || eui64_iszero(wo->hisid))) {
942 option_error("local/remote LL address required for demand-dialling\n");
949 * ipv6_demand_conf - configure the interface as though
950 * IPV6CP were up, for use with dial-on-demand.
956 ipv6cp_options *wo = &ipv6cp_wantoptions[u];
958 #if defined(__linux__) || (defined(SVR4) && (defined(SNI) || defined(__USLC__)))
962 if (!sif6addr(u, wo->ourid, wo->hisid))
964 #if !defined(__linux__) && !(defined(SVR4) && (defined(SNI) || defined(__USLC__)))
968 if (!sifnpmode(u, PPP_IPV6, NPMODE_QUEUE))
971 notice("ipv6_demand_conf");
972 notice("local LL address %s", llv6_ntoa(wo->ourid));
973 notice("remote LL address %s", llv6_ntoa(wo->hisid));
980 * ipv6cp_up - IPV6CP has come UP.
982 * Configure the IPv6 network interface appropriately and bring it up.
988 ipv6cp_options *ho = &ipv6cp_hisoptions[f->unit];
989 ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
990 ipv6cp_options *wo = &ipv6cp_wantoptions[f->unit];
992 IPV6CPDEBUG(("ipv6cp: up"));
995 * We must have a non-zero LL address for both ends of the link.
997 if (!ho->neg_ifaceid)
998 ho->hisid = wo->hisid;
1000 if(!no_ifaceid_neg) {
1001 if (eui64_iszero(ho->hisid)) {
1002 error("Could not determine remote LL address");
1003 ipv6cp_close(f->unit, "Could not determine remote LL address");
1006 if (eui64_iszero(go->ourid)) {
1007 error("Could not determine local LL address");
1008 ipv6cp_close(f->unit, "Could not determine local LL address");
1011 if (eui64_equals(go->ourid, ho->hisid)) {
1012 error("local and remote LL addresses are equal");
1013 ipv6cp_close(f->unit, "local and remote LL addresses are equal");
1017 script_setenv("LLLOCAL", llv6_ntoa(go->ourid));
1018 script_setenv("LLREMOTE", llv6_ntoa(ho->hisid));
1021 /* set tcp compression */
1022 sif6comp(f->unit, ho->neg_vj);
1026 * If we are doing dial-on-demand, the interface is already
1027 * configured, so we put out any saved-up packets, then set the
1028 * interface to pass IPv6 packets.
1031 if (! eui64_equals(go->ourid, wo->ourid) ||
1032 ! eui64_equals(ho->hisid, wo->hisid)) {
1033 if (! eui64_equals(go->ourid, wo->ourid))
1034 warn("Local LL address changed to %s",
1035 llv6_ntoa(go->ourid));
1036 if (! eui64_equals(ho->hisid, wo->hisid))
1037 warn("Remote LL address changed to %s",
1038 llv6_ntoa(ho->hisid));
1039 ipv6cp_clear_addrs(f->unit);
1041 /* Set the interface to the new addresses */
1042 if (!sif6addr(f->unit, go->ourid, ho->hisid)) {
1044 warn("sif6addr failed");
1045 ipv6cp_close(f->unit, "Interface configuration failed");
1050 demand_rexmit(PPP_IPV6);
1051 sifnpmode(f->unit, PPP_IPV6, NPMODE_PASS);
1057 #if !defined(__linux__) && !(defined(SVR4) && (defined(SNI) || defined(__USLC__)))
1058 if (!sif6addr(f->unit, go->ourid, ho->hisid)) {
1060 warn("sif6addr failed");
1061 ipv6cp_close(f->unit, "Interface configuration failed");
1066 /* bring the interface up for IPv6 */
1067 if (!sifup(f->unit)) {
1069 warn("sif6up failed");
1070 ipv6cp_close(f->unit, "Interface configuration failed");
1074 #if defined(__linux__) || (defined(SVR4) && (defined(SNI) || defined(__USLC__)))
1075 if (!sif6addr(f->unit, go->ourid, ho->hisid)) {
1077 warn("sif6addr failed");
1078 ipv6cp_close(f->unit, "Interface configuration failed");
1082 sifnpmode(f->unit, PPP_IPV6, NPMODE_PASS);
1084 notice("local LL address %s", llv6_ntoa(go->ourid));
1085 notice("remote LL address %s", llv6_ntoa(ho->hisid));
1088 np_up(f->unit, PPP_IPV6);
1092 * Execute the ipv6-up script, like this:
1093 * /etc/ppp/ipv6-up interface tty speed local-LL remote-LL
1095 if (ipv6cp_script_state == s_down && ipv6cp_script_pid == 0) {
1096 ipv6cp_script_state = s_up;
1097 ipv6cp_script(_PATH_IPV6UP);
1103 * ipv6cp_down - IPV6CP has gone DOWN.
1105 * Take the IPv6 network interface down, clear its addresses
1106 * and delete routes through it.
1112 IPV6CPDEBUG(("ipv6cp: down"));
1113 update_link_stats(f->unit);
1116 np_down(f->unit, PPP_IPV6);
1119 sif6comp(f->unit, 0);
1123 * If we are doing dial-on-demand, set the interface
1124 * to queue up outgoing packets (for now).
1127 sifnpmode(f->unit, PPP_IPV6, NPMODE_QUEUE);
1129 #if !defined(__linux__) && !(defined(SVR4) && (defined(SNI) || defined(__USLC)))
1130 sifnpmode(f->unit, PPP_IPV6, NPMODE_DROP);
1133 ipv6cp_clear_addrs(f->unit);
1134 #if defined(__linux__) || (defined(SVR4) && (defined(SNI) || defined(__USLC)))
1139 /* Execute the ipv6-down script */
1140 if (ipv6cp_script_state == s_up && ipv6cp_script_pid == 0) {
1141 ipv6cp_script_state = s_down;
1142 ipv6cp_script(_PATH_IPV6DOWN);
1148 * ipv6cp_clear_addrs() - clear the interface addresses, routes,
1149 * proxy arp entries, etc.
1152 ipv6cp_clear_addrs(unit)
1155 eui64_t ourid, hisid;
1157 ourid = ipv6cp_gotoptions[unit].ourid;
1158 hisid = ipv6cp_hisoptions[unit].hisid;
1159 cif6addr(unit, ourid, hisid);
1164 * ipv6cp_finished - possibly shut down the lower layers.
1170 np_finished(f->unit, PPP_IPV6);
1175 * ipv6cp_script_done - called when the ipv6-up or ipv6-down script
1179 ipv6cp_script_done(arg)
1182 ipv6cp_script_pid = 0;
1183 switch (ipv6cp_script_state) {
1185 if (ipv6cp_fsm[0].state != OPENED) {
1186 ipv6cp_script_state = s_down;
1187 ipv6cp_script(_PATH_IPV6DOWN);
1191 if (ipv6cp_fsm[0].state == OPENED) {
1192 ipv6cp_script_state = s_up;
1193 ipv6cp_script(_PATH_IPV6UP);
1201 * ipv6cp_script - Execute a script with arguments
1202 * interface-name tty-name speed local-LL remote-LL.
1205 ipv6cp_script(script)
1208 char strspeed[32], strlocal[32], strremote[32];
1211 sprintf(strspeed, "%d", baud_rate);
1212 strcpy(strlocal, llv6_ntoa(ipv6cp_gotoptions[0].ourid));
1213 strcpy(strremote, llv6_ntoa(ipv6cp_hisoptions[0].hisid));
1220 argv[5] = strremote;
1224 ipv6cp_script_pid = run_program(script, argv, 0, ipv6cp_script_done, NULL);
1228 * ipv6cp_printpkt - print the contents of an IPV6CP packet.
1230 static char *ipv6cp_codenames[] = {
1231 "ConfReq", "ConfAck", "ConfNak", "ConfRej",
1232 "TermReq", "TermAck", "CodeRej"
1236 ipv6cp_printpkt(p, plen, printer, arg)
1239 void (*printer) __P((void *, char *, ...));
1242 int code, id, len, olen;
1243 u_char *pstart, *optend;
1247 if (plen < HEADERLEN)
1253 if (len < HEADERLEN || len > plen)
1256 if (code >= 1 && code <= sizeof(ipv6cp_codenames) / sizeof(char *))
1257 printer(arg, " %s", ipv6cp_codenames[code-1]);
1259 printer(arg, " code=0x%x", code);
1260 printer(arg, " id=0x%x", id);
1267 /* print option list */
1272 if (olen < 2 || olen > len) {
1279 case CI_COMPRESSTYPE:
1280 if (olen >= CILEN_COMPRESS) {
1282 GETSHORT(cishort, p);
1283 printer(arg, "compress ");
1284 printer(arg, "0x%x", cishort);
1288 if (olen == CILEN_IFACEID) {
1290 eui64_get(ifaceid, p);
1291 printer(arg, "addr %s", llv6_ntoa(ifaceid));
1295 while (p < optend) {
1297 printer(arg, " %.2x", code);
1305 if (len > 0 && *p >= ' ' && *p < 0x7f) {
1307 print_string(p, len, printer, arg);
1314 /* print the rest of the bytes in the packet */
1315 for (; len > 0; --len) {
1317 printer(arg, " %.2x", code);
1324 * ipv6_active_pkt - see if this IP packet is worth bringing the link up for.
1325 * We don't bring the link up for IP fragments or for TCP FIN packets
1328 #define IP6_HDRLEN 40 /* bytes */
1329 #define IP6_NHDR_FRAG 44 /* fragment IPv6 header */
1330 #define IPPROTO_TCP 6
1331 #define TCP_HDRLEN 20
1335 * We use these macros because the IP header may be at an odd address,
1336 * and some compilers might use word loads to get th_off or ip_hl.
1339 #define get_ip6nh(x) (((unsigned char *)(x))[6])
1340 #define get_tcpoff(x) (((unsigned char *)(x))[12] >> 4)
1341 #define get_tcpflags(x) (((unsigned char *)(x))[13])
1344 ipv6_active_pkt(pkt, len)
1352 if (len < IP6_HDRLEN)
1354 if (get_ip6nh(pkt) == IP6_NHDR_FRAG)
1356 if (get_ip6nh(pkt) != IPPROTO_TCP)
1358 if (len < IP6_HDRLEN + TCP_HDRLEN)
1360 tcp = pkt + IP6_HDRLEN;
1361 if ((get_tcpflags(tcp) & TH_FIN) != 0 && len == IP6_HDRLEN + get_tcpoff(tcp) * 4)