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.1 1999/08/13 01:58:43 paulus Exp $
27 * Original version by Inria (www.inria.fr)
28 * Modified to match RFC2472 by Tommi Komulainen <Tommi.Komulainen@iki.fi>
32 static char rcsid[]="$Id: ipv6cp.c,v 1.1 1999/08/13 01:58:43 paulus Exp $";
38 * Better defines for selecting the ordering of
39 * interface up / set address. (currently checks for __linux__,
40 * since SVR4 && (SNI || __USLC__) didn't work properly)
47 #include <sys/param.h>
48 #include <sys/types.h>
49 #include <sys/socket.h>
50 #include <netinet/in.h>
57 #include "pathnames.h"
60 ipv6cp_options ipv6cp_wantoptions[NUM_PPP]; /* Options that we want to request */
61 ipv6cp_options ipv6cp_gotoptions[NUM_PPP]; /* Options that peer ack'd */
62 ipv6cp_options ipv6cp_allowoptions[NUM_PPP]; /* Options we allow peer to request */
63 ipv6cp_options ipv6cp_hisoptions[NUM_PPP]; /* Options that we ack'd */
64 int no_ifaceid_neg = 0;
67 static int ipv6cp_is_up;
70 * Callbacks for fsm code. (CI = Configuration Information)
72 static void ipv6cp_resetci __P((fsm *)); /* Reset our CI */
73 static int ipv6cp_cilen __P((fsm *)); /* Return length of our CI */
74 static void ipv6cp_addci __P((fsm *, u_char *, int *)); /* Add our CI */
75 static int ipv6cp_ackci __P((fsm *, u_char *, int)); /* Peer ack'd our CI */
76 static int ipv6cp_nakci __P((fsm *, u_char *, int)); /* Peer nak'd our CI */
77 static int ipv6cp_rejci __P((fsm *, u_char *, int)); /* Peer rej'd our CI */
78 static int ipv6cp_reqci __P((fsm *, u_char *, int *, int)); /* Rcv CI */
79 static void ipv6cp_up __P((fsm *)); /* We're UP */
80 static void ipv6cp_down __P((fsm *)); /* We're DOWN */
81 static void ipv6cp_finished __P((fsm *)); /* Don't need lower layer */
83 fsm ipv6cp_fsm[NUM_PPP]; /* IPV6CP fsm structure */
85 static fsm_callbacks ipv6cp_callbacks = { /* IPV6CP callback routines */
86 ipv6cp_resetci, /* Reset our Configuration Information */
87 ipv6cp_cilen, /* Length of our Configuration Information */
88 ipv6cp_addci, /* Add our Configuration Information */
89 ipv6cp_ackci, /* ACK our Configuration Information */
90 ipv6cp_nakci, /* NAK our Configuration Information */
91 ipv6cp_rejci, /* Reject our Configuration Information */
92 ipv6cp_reqci, /* Request peer's Configuration Information */
93 ipv6cp_up, /* Called when fsm reaches OPENED state */
94 ipv6cp_down, /* Called when fsm leaves OPENED state */
95 NULL, /* Called when we want the lower layer up */
96 ipv6cp_finished, /* Called when we want the lower layer down */
97 NULL, /* Called when Protocol-Reject received */
98 NULL, /* Retransmission is necessary */
99 NULL, /* Called to handle protocol-specific codes */
100 "IPV6CP" /* String name of protocol */
104 * Command-line options.
106 static int setifaceid __P((char *arg));
108 static option_t ipv6cp_option_list[] = {
109 { "ipv6", o_special, setifaceid,
110 "Set interface identifiers for IPV6" },
111 { "noipv6", o_bool, &ipv6cp_protent.enabled_flag,
112 "Disable IPv6 and IPv6CP" },
113 { "-ipv6", o_bool, &ipv6cp_protent.enabled_flag,
114 "Disable IPv6 and IPv6CP" },
116 { "ipv6cp-accept-local", o_bool, &ipv6cp_allowoptions[0].accept_local,
117 "Accept peer's interface identifier for us", 1 },
118 { "ipv6cp-use-ipaddr", o_bool, &ipv6cp_allowoptions[0].use_ip,
119 "Use (default) IPv4 address as interface identifier", 0 },
121 { "ipv6cp-restart", o_int, &ipv6cp_fsm[0].timeouttime,
122 "Set timeout for IPv6CP" },
123 { "ipv6cp-max-terminate", o_int, &ipv6cp_fsm[0].maxtermtransmits,
124 "Set max #xmits for term-reqs" },
125 { "ipv6cp-max-configure", o_int, &ipv6cp_fsm[0].maxconfreqtransmits,
126 "Set max #xmits for conf-reqs" },
127 { "ipv6cp-max-failure", o_int, &ipv6cp_fsm[0].maxnakloops,
128 "Set max #conf-naks for IPv6CP" },
135 * Protocol entry points from main code.
137 static void ipv6cp_init __P((int));
138 static void ipv6cp_open __P((int));
139 static void ipv6cp_close __P((int, char *));
140 static void ipv6cp_lowerup __P((int));
141 static void ipv6cp_lowerdown __P((int));
142 static void ipv6cp_input __P((int, u_char *, int));
143 static void ipv6cp_protrej __P((int));
144 static int ipv6cp_printpkt __P((u_char *, int,
145 void (*) __P((void *, char *, ...)), void *));
146 static void ipv6_check_options __P((void));
147 static int ipv6_demand_conf __P((int));
148 static int ipv6_active_pkt __P((u_char *, int));
150 struct protent ipv6cp_protent = {
170 static void ipv6cp_clear_addrs __P((int));
171 static void ipv6cp_script __P((char *));
172 static void ipv6cp_script_done __P((void *));
175 * Lengths of configuration options.
178 #define CILEN_COMPRESS 4 /* length for RFC2023 compress opt. */
179 #define CILEN_IFACEID 10 /* RFC2472, interface identifier */
181 #define CODENAME(x) ((x) == CONFACK ? "ACK" : \
182 (x) == CONFNAK ? "NAK" : "REJ")
185 * This state variable is used to ensure that we don't
186 * run an ipcp-up/down script while one is already running.
188 static enum script_state {
191 } ipv6cp_script_state;
192 static pid_t ipv6cp_script_pid;
195 * setifaceid - set the interface identifiers manually
202 ipv6cp_options *wo = &ipv6cp_wantoptions[0];
203 struct in6_addr addr;
205 #define VALIDID(a) ( ((a).s6_addr64[0] == 0) && \
206 ((a).s6_addr64[1] != 0) )
208 if ((comma = strchr(arg, ',')) == NULL)
209 comma = arg + strlen(arg);
212 * If comma first character, then no local identifier
217 if (inet_pton(AF_INET6, arg, &addr) == 0 || !VALIDID(addr)) {
218 option_error("Illegal interface identifier: %s", arg);
222 eui64_copy(addr.s6_addr32[2], wo->ourid);
228 * If comma last character, the no remote identifier
230 if (*comma != 0 && *++comma != '\0') {
231 if (inet_pton(AF_INET6, comma, &addr) == 0 || !VALIDID(addr)) {
232 option_error("Illegal interface identifier: %s", comma);
235 eui64_copy(addr.s6_addr32[2], wo->hisid);
243 * Make a string representation of a network address.
251 sprintf(b, "fe80::%s", eui64_ntoa(ifaceid));
257 * ipv6cp_init - Initialize IPV6CP.
263 fsm *f = &ipv6cp_fsm[unit];
264 ipv6cp_options *wo = &ipv6cp_wantoptions[unit];
265 ipv6cp_options *ao = &ipv6cp_allowoptions[unit];
268 f->protocol = PPP_IPV6CP;
269 f->callbacks = &ipv6cp_callbacks;
270 fsm_init(&ipv6cp_fsm[unit]);
272 memset(wo, 0, sizeof(*wo));
273 memset(ao, 0, sizeof(*ao));
275 wo->accept_local = 1;
282 wo->vj_protocol = IPV6CP_COMP;
289 * ipv6cp_open - IPV6CP is allowed to come up.
295 fsm_open(&ipv6cp_fsm[unit]);
300 * ipv6cp_close - Take IPV6CP down.
303 ipv6cp_close(unit, reason)
307 fsm_close(&ipv6cp_fsm[unit], reason);
312 * ipv6cp_lowerup - The lower layer is up.
318 fsm_lowerup(&ipv6cp_fsm[unit]);
323 * ipv6cp_lowerdown - The lower layer is down.
326 ipv6cp_lowerdown(unit)
329 fsm_lowerdown(&ipv6cp_fsm[unit]);
334 * ipv6cp_input - Input IPV6CP packet.
337 ipv6cp_input(unit, p, len)
342 fsm_input(&ipv6cp_fsm[unit], p, len);
347 * ipv6cp_protrej - A Protocol-Reject was received for IPV6CP.
349 * Pretend the lower layer went down, so we shut up.
355 fsm_lowerdown(&ipv6cp_fsm[unit]);
360 * ipv6cp_resetci - Reset our CI.
366 ipv6cp_options *wo = &ipv6cp_wantoptions[f->unit];
367 ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
369 wo->req_ifaceid = wo->neg_ifaceid && ipv6cp_allowoptions[f->unit].neg_ifaceid;
371 if (!wo->opt_local) {
372 eui64_magic_nz(wo->ourid);
376 eui64_zero(go->hisid); /* last proposed interface identifier */
381 * ipv6cp_cilen - Return length of our CI.
387 ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
389 #define LENCIVJ(neg) (neg ? CILEN_COMPRESS : 0)
390 #define LENCIIFACEID(neg) (neg ? CILEN_IFACEID : 0)
392 return (LENCIIFACEID(go->neg_ifaceid) +
393 LENCIVJ(go->neg_vj));
398 * ipv6cp_addci - Add our desired CIs to a packet.
401 ipv6cp_addci(f, ucp, lenp)
406 ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
409 #define ADDCIVJ(opt, neg, val) \
411 int vjlen = CILEN_COMPRESS; \
412 if (len >= vjlen) { \
414 PUTCHAR(vjlen, ucp); \
415 PUTSHORT(val, ucp); \
421 #define ADDCIIFACEID(opt, neg, val1) \
423 int idlen = CILEN_IFACEID; \
424 if (len >= idlen) { \
426 PUTCHAR(idlen, ucp); \
427 eui64_put(val1, ucp); \
433 ADDCIIFACEID(CI_IFACEID, go->neg_ifaceid, go->ourid);
435 ADDCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol);
442 * ipv6cp_ackci - Ack our CIs.
449 ipv6cp_ackci(f, p, len)
454 ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
455 u_short cilen, citype, cishort;
459 * CIs must be in exactly the same order that we sent...
460 * Check packet length and CI length at each step.
461 * If we find any deviations, then this packet is bad.
464 #define ACKCIVJ(opt, neg, val) \
466 int vjlen = CILEN_COMPRESS; \
467 if ((len -= vjlen) < 0) \
469 GETCHAR(citype, p); \
471 if (cilen != vjlen || \
474 GETSHORT(cishort, p); \
475 if (cishort != val) \
479 #define ACKCIIFACEID(opt, neg, val1) \
481 int idlen = CILEN_IFACEID; \
482 if ((len -= idlen) < 0) \
484 GETCHAR(citype, p); \
486 if (cilen != idlen || \
489 eui64_get(ifaceid, p); \
490 if (! eui64_equals(val1, ifaceid)) \
494 ACKCIIFACEID(CI_IFACEID, go->neg_ifaceid, go->ourid);
496 ACKCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol);
499 * If there are any remaining CIs, then this packet is bad.
506 IPV6CPDEBUG(("ipv6cp_ackci: received bad Ack!"));
511 * ipv6cp_nakci - Peer has sent a NAK for some of our CIs.
512 * This should not modify any state if the Nak is bad
513 * or if IPV6CP is in the OPENED state.
520 ipv6cp_nakci(f, p, len)
525 ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
526 u_char citype, cilen, *next;
529 ipv6cp_options no; /* options we've seen Naks for */
530 ipv6cp_options try; /* options to request next time */
532 BZERO(&no, sizeof(no));
536 * Any Nak'd CIs must be in exactly the same order that we sent.
537 * Check packet length and CI length at each step.
538 * If we find any deviations, then this packet is bad.
540 #define NAKCIIFACEID(opt, neg, code) \
542 len >= (cilen = CILEN_IFACEID) && \
547 eui64_get(ifaceid, p); \
552 #define NAKCIVJ(opt, neg, code) \
554 ((cilen = p[1]) == CILEN_COMPRESS) && \
559 GETSHORT(cishort, p); \
565 * Accept the peer's idea of {our,his} interface identifier, if different
566 * from our idea, only if the accept_{local,remote} flag is set.
568 NAKCIIFACEID(CI_IFACEID, neg_ifaceid,
569 if (go->accept_local) {
570 while (eui64_iszero(ifaceid) ||
571 eui64_equals(ifaceid, go->hisid)) /* bad luck */
572 eui64_magic(ifaceid);
574 IPV6CPDEBUG(("local LL address %s", llv6_ntoa(ifaceid)));
579 NAKCIVJ(CI_COMPRESSTYPE, neg_vj,
581 if (cishort == IPV6CP_COMP) {
582 try.vj_protocol = cishort;
589 NAKCIVJ(CI_COMPRESSTYPE, neg_vj,
597 * There may be remaining CIs, if the peer is requesting negotiation
598 * on an option that we didn't include in our request packet.
599 * If they want to negotiate about interface identifier, we comply.
600 * If they want us to ask for compression, we refuse.
602 while (len > CILEN_VOID) {
605 if( (len -= cilen) < 0 )
607 next = p + cilen - 2;
610 case CI_COMPRESSTYPE:
611 if (go->neg_vj || no.neg_vj ||
612 (cilen != CILEN_COMPRESS))
617 if (go->neg_ifaceid || no.neg_ifaceid || cilen != CILEN_IFACEID)
620 eui64_get(ifaceid, p);
621 if (go->accept_local) {
622 while (eui64_iszero(ifaceid) ||
623 eui64_equals(ifaceid, go->hisid)) /* bad luck */
624 eui64_magic(ifaceid);
633 /* If there is still anything left, this packet is bad. */
638 * OK, the Nak is good. Now we can update state.
640 if (f->state != OPENED)
646 IPV6CPDEBUG(("ipv6cp_nakci: received bad Nak!"));
652 * ipv6cp_rejci - Reject some of our CIs.
655 ipv6cp_rejci(f, p, len)
660 ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
664 ipv6cp_options try; /* options to request next time */
668 * Any Rejected CIs must be in exactly the same order that we sent.
669 * Check packet length and CI length at each step.
670 * If we find any deviations, then this packet is bad.
672 #define REJCIIFACEID(opt, neg, val1) \
674 len >= (cilen = CILEN_IFACEID) && \
679 eui64_get(ifaceid, p); \
680 /* Check rejected value. */ \
681 if (! eui64_equals(ifaceid, val1)) \
686 #define REJCIVJ(opt, neg, val) \
688 p[1] == CILEN_COMPRESS && \
693 GETSHORT(cishort, p); \
694 /* Check rejected value. */ \
695 if (cishort != val) \
700 REJCIIFACEID(CI_IFACEID, neg_ifaceid, go->ourid);
702 REJCIVJ(CI_COMPRESSTYPE, neg_vj, go->vj_protocol);
705 * If there are any remaining CIs, then this packet is bad.
710 * Now we can update state.
712 if (f->state != OPENED)
717 IPV6CPDEBUG(("ipv6cp_rejci: received bad Reject!"));
723 * ipv6cp_reqci - Check the peer's requested CIs and send appropriate response.
725 * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified
726 * appropriately. If reject_if_disagree is non-zero, doesn't return
727 * CONFNAK; returns CONFREJ if it can't return CONFACK.
730 ipv6cp_reqci(f, inp, len, reject_if_disagree)
732 u_char *inp; /* Requested CIs */
733 int *len; /* Length of requested CIs */
734 int reject_if_disagree;
736 ipv6cp_options *wo = &ipv6cp_wantoptions[f->unit];
737 ipv6cp_options *ho = &ipv6cp_hisoptions[f->unit];
738 ipv6cp_options *ao = &ipv6cp_allowoptions[f->unit];
739 ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
740 u_char *cip, *next; /* Pointer to current and next CIs */
741 u_short cilen, citype; /* Parsed len, type */
742 u_short cishort; /* Parsed short value */
743 eui64_t ifaceid; /* Parsed interface identifier */
744 int rc = CONFACK; /* Final packet return code */
745 int orc; /* Individual option return code */
746 u_char *p; /* Pointer to next char to parse */
747 u_char *ucp = inp; /* Pointer to current output char */
748 int l = *len; /* Length left */
751 * Reset all his options.
753 BZERO(ho, sizeof(*ho));
756 * Process all his options.
760 orc = CONFACK; /* Assume success */
761 cip = p = next; /* Remember begining of CI */
762 if (l < 2 || /* Not enough data for CI header or */
763 p[1] < 2 || /* CI length too small or */
764 p[1] > l) { /* CI length too big? */
765 IPV6CPDEBUG(("ipv6cp_reqci: bad CI length!"));
766 orc = CONFREJ; /* Reject bad CI */
767 cilen = l; /* Reject till end of packet */
768 l = 0; /* Don't loop again */
771 GETCHAR(citype, p); /* Parse CI type */
772 GETCHAR(cilen, p); /* Parse CI length */
773 l -= cilen; /* Adjust remaining length */
774 next += cilen; /* Step to next CI */
776 switch (citype) { /* Check CI type */
778 IPV6CPDEBUG(("ipv6cp: received interface identifier "));
780 if (!ao->neg_ifaceid ||
781 cilen != CILEN_IFACEID) { /* Check CI length */
782 orc = CONFREJ; /* Reject CI */
787 * If he has no interface identifier, or if we both have same
788 * identifier then NAK it with new idea.
789 * In particular, if we don't know his identifier, but he does,
792 eui64_get(ifaceid, p);
793 IPV6CPDEBUG(("(%s)", llv6_ntoa(ifaceid)));
794 if (eui64_iszero(ifaceid) && eui64_iszero(go->ourid)) {
795 orc = CONFREJ; /* Reject CI */
798 if (!eui64_iszero(wo->hisid) &&
799 !eui64_equals(ifaceid, wo->hisid) &&
800 eui64_iszero(go->hisid)) {
805 DECPTR(sizeof(ifaceid), p);
806 eui64_put(ifaceid, p);
808 if (eui64_iszero(ifaceid) || eui64_equals(ifaceid, go->ourid)) {
810 if (eui64_iszero(go->hisid)) /* first time, try option */
812 while (eui64_iszero(ifaceid) ||
813 eui64_equals(ifaceid, go->ourid)) /* bad luck */
814 eui64_magic(ifaceid);
816 DECPTR(sizeof(ifaceid), p);
817 eui64_put(ifaceid, p);
824 case CI_COMPRESSTYPE:
825 IPV6CPDEBUG(("ipv6cp: received COMPRESSTYPE "));
827 (cilen != CILEN_COMPRESS)) {
831 GETSHORT(cishort, p);
832 IPV6CPDEBUG(("(%d)", cishort));
835 if (!(cishort == IPV6CP_COMP)) {
845 ho->vj_protocol = cishort;
854 IPV6CPDEBUG((" (%s)\n", CODENAME(orc)));
856 if (orc == CONFACK && /* Good CI */
857 rc != CONFACK) /* but prior CI wasnt? */
858 continue; /* Don't send this one */
860 if (orc == CONFNAK) { /* Nak this CI? */
861 if (reject_if_disagree) /* Getting fed up with sending NAKs? */
862 orc = CONFREJ; /* Get tough if so */
864 if (rc == CONFREJ) /* Rejecting prior CI? */
865 continue; /* Don't send this one */
866 if (rc == CONFACK) { /* Ack'd all prior CIs? */
867 rc = CONFNAK; /* Not anymore... */
868 ucp = inp; /* Backup */
873 if (orc == CONFREJ && /* Reject this CI */
874 rc != CONFREJ) { /* but no prior ones? */
876 ucp = inp; /* Backup */
879 /* Need to move CI? */
881 BCOPY(cip, ucp, cilen); /* Move it */
883 /* Update output pointer */
888 * If we aren't rejecting this packet, and we want to negotiate
889 * their identifier and they didn't send their identifier, then we
890 * send a NAK with a CI_IFACEID option appended. We assume the
891 * input buffer is long enough that we can append the extra
894 if (rc != CONFREJ && !ho->neg_ifaceid &&
895 wo->req_ifaceid && !reject_if_disagree) {
898 ucp = inp; /* reset pointer */
899 wo->req_ifaceid = 0; /* don't ask again */
901 PUTCHAR(CI_IFACEID, ucp);
902 PUTCHAR(CILEN_IFACEID, ucp);
903 eui64_put(wo->hisid, ucp);
906 *len = ucp - inp; /* Compute output length */
907 IPV6CPDEBUG(("ipv6cp: returning Configure-%s", CODENAME(rc)));
908 return (rc); /* Return final code */
913 * ipv6_check_options - check that any IP-related options are OK,
914 * and assign appropriate defaults.
919 ipv6cp_options *wo = &ipv6cp_wantoptions[0];
921 if (!wo->opt_local) { /* init interface identifier */
922 if (wo->use_ip && eui64_iszero(wo->ourid)) {
923 eui64_setlo32(wo->ourid, ntohl(ipcp_wantoptions[0].ouraddr));
924 if (!eui64_iszero(wo->ourid))
928 while (eui64_iszero(wo->ourid))
929 eui64_magic(wo->ourid);
932 if (!wo->opt_remote) {
933 if (wo->use_ip && eui64_iszero(wo->hisid)) {
934 eui64_setlo32(wo->hisid, ntohl(ipcp_wantoptions[0].hisaddr));
935 if (!eui64_iszero(wo->hisid))
940 if (demand && (eui64_iszero(wo->ourid) || eui64_iszero(wo->hisid))) {
941 option_error("local/remote LL address required for demand-dialling\n");
948 * ipv6_demand_conf - configure the interface as though
949 * IPV6CP were up, for use with dial-on-demand.
955 ipv6cp_options *wo = &ipv6cp_wantoptions[u];
957 #if defined(__linux__) || (defined(SVR4) && (defined(SNI) || defined(__USLC__)))
958 if (!sifup(u, PPP_IPV6))
961 if (!sif6addr(u, wo->ourid, wo->hisid))
963 #if !defined(__linux__) && !(defined(SVR4) && (defined(SNI) || defined(__USLC__)))
964 if (!sifup(u, PPP_IPV6))
967 if (!sifnpmode(u, PPP_IPV6, NPMODE_QUEUE))
970 notice("ipv6_demand_conf");
971 notice("local LL address %s", llv6_ntoa(wo->ourid));
972 notice("remote LL address %s", llv6_ntoa(wo->hisid));
979 * ipv6cp_up - IPV6CP has come UP.
981 * Configure the IPv6 network interface appropriately and bring it up.
987 ipv6cp_options *ho = &ipv6cp_hisoptions[f->unit];
988 ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
989 ipv6cp_options *wo = &ipv6cp_wantoptions[f->unit];
991 IPV6CPDEBUG(("ipv6cp: up"));
994 * We must have a non-zero LL address for both ends of the link.
996 if (!ho->neg_ifaceid)
997 ho->hisid = wo->hisid;
999 if(!no_ifaceid_neg) {
1000 if (eui64_iszero(ho->hisid)) {
1001 error("Could not determine remote LL address");
1002 ipv6cp_close(f->unit, "Could not determine remote LL address");
1005 if (eui64_iszero(go->ourid)) {
1006 error("Could not determine local LL address");
1007 ipv6cp_close(f->unit, "Could not determine local LL address");
1010 if (eui64_equals(go->ourid, ho->hisid)) {
1011 error("local and remote LL addresses are equal");
1012 ipv6cp_close(f->unit, "local and remote LL addresses are equal");
1016 script_setenv("LLLOCAL", llv6_ntoa(go->ourid));
1017 script_setenv("LLREMOTE", llv6_ntoa(ho->hisid));
1020 /* set tcp compression */
1021 sif6comp(f->unit, ho->neg_vj);
1025 * If we are doing dial-on-demand, the interface is already
1026 * configured, so we put out any saved-up packets, then set the
1027 * interface to pass IPv6 packets.
1030 if (! eui64_equals(go->ourid, wo->ourid) ||
1031 ! eui64_equals(ho->hisid, wo->hisid)) {
1032 if (! eui64_equals(go->ourid, wo->ourid))
1033 warn("Local LL address changed to %s",
1034 llv6_ntoa(go->ourid));
1035 if (! eui64_equals(ho->hisid, wo->hisid))
1036 warn("Remote LL address changed to %s",
1037 llv6_ntoa(ho->hisid));
1038 ipv6cp_clear_addrs(f->unit);
1040 /* Set the interface to the new addresses */
1041 if (!sif6addr(f->unit, go->ourid, ho->hisid)) {
1043 warn("sif6addr failed");
1044 ipv6cp_close(f->unit, "Interface configuration failed");
1049 demand_rexmit(PPP_IPV6);
1050 sifnpmode(f->unit, PPP_IPV6, NPMODE_PASS);
1056 #if !defined(__linux__) && !(defined(SVR4) && (defined(SNI) || defined(__USLC__)))
1057 if (!sif6addr(f->unit, go->ourid, ho->hisid)) {
1059 warn("sif6addr failed");
1060 ipv6cp_close(f->unit, "Interface configuration failed");
1065 /* bring the interface up for IPv6 */
1066 if (!sifup(f->unit, PPP_IPV6)) {
1068 warn("sif6up failed");
1069 ipv6cp_close(f->unit, "Interface configuration failed");
1073 #if defined(__linux__) || (defined(SVR4) && (defined(SNI) || defined(__USLC__)))
1074 if (!sif6addr(f->unit, go->ourid, ho->hisid)) {
1076 warn("sif6addr failed");
1077 ipv6cp_close(f->unit, "Interface configuration failed");
1081 sifnpmode(f->unit, PPP_IPV6, NPMODE_PASS);
1083 notice("local LL address %s", llv6_ntoa(go->ourid));
1084 notice("remote LL address %s", llv6_ntoa(ho->hisid));
1087 np_up(f->unit, PPP_IPV6);
1091 * Execute the ipv6-up script, like this:
1092 * /etc/ppp/ipv6-up interface tty speed local-LL remote-LL
1094 if (ipv6cp_script_state == s_down && ipv6cp_script_pid == 0) {
1095 ipv6cp_script_state = s_up;
1096 ipv6cp_script(_PATH_IPV6UP);
1102 * ipv6cp_down - IPV6CP has gone DOWN.
1104 * Take the IPv6 network interface down, clear its addresses
1105 * and delete routes through it.
1111 IPV6CPDEBUG(("ipv6cp: down"));
1112 update_link_stats(f->unit);
1115 np_down(f->unit, PPP_IPV6);
1118 sif6comp(f->unit, 0);
1122 * If we are doing dial-on-demand, set the interface
1123 * to queue up outgoing packets (for now).
1126 sifnpmode(f->unit, PPP_IPV6, NPMODE_QUEUE);
1128 #if !defined(__linux__) && !(defined(SVR4) && (defined(SNI) || defined(__USLC)))
1129 sifdown(f->unit, PPP_IPV6);
1131 ipv6cp_clear_addrs(f->unit);
1132 #if defined(__linux__) || (defined(SVR4) && (defined(SNI) || defined(__USLC)))
1133 sifdown(f->unit, PPP_IPV6);
1137 /* Execute the ipv6-down script */
1138 if (ipv6cp_script_state == s_up && ipv6cp_script_pid == 0) {
1139 ipv6cp_script_state = s_down;
1140 ipv6cp_script(_PATH_IPV6DOWN);
1146 * ipv6cp_clear_addrs() - clear the interface addresses, routes,
1147 * proxy arp entries, etc.
1150 ipv6cp_clear_addrs(unit)
1153 eui64_t ourid, hisid;
1155 ourid = ipv6cp_gotoptions[unit].ourid;
1156 hisid = ipv6cp_hisoptions[unit].hisid;
1157 cif6addr(unit, ourid, hisid);
1162 * ipv6cp_finished - possibly shut down the lower layers.
1168 np_finished(f->unit, PPP_IPV6);
1173 * ipv6cp_script_done - called when the ipv6-up or ipv6-down script
1177 ipv6cp_script_done(arg)
1180 ipv6cp_script_pid = 0;
1181 switch (ipv6cp_script_state) {
1183 if (ipv6cp_fsm[0].state != OPENED) {
1184 ipv6cp_script_state = s_down;
1185 ipv6cp_script(_PATH_IPV6DOWN);
1189 if (ipv6cp_fsm[0].state == OPENED) {
1190 ipv6cp_script_state = s_up;
1191 ipv6cp_script(_PATH_IPV6UP);
1199 * ipv6cp_script - Execute a script with arguments
1200 * interface-name tty-name speed local-LL remote-LL.
1203 ipv6cp_script(script)
1206 char strspeed[32], strlocal[32], strremote[32];
1209 sprintf(strspeed, "%d", baud_rate);
1210 strcpy(strlocal, llv6_ntoa(ipv6cp_gotoptions[0].ourid));
1211 strcpy(strremote, llv6_ntoa(ipv6cp_hisoptions[0].hisid));
1218 argv[5] = strremote;
1222 ipv6cp_script_pid = run_program(script, argv, 0, ipv6cp_script_done, NULL);
1226 * ipv6cp_printpkt - print the contents of an IPV6CP packet.
1228 static char *ipv6cp_codenames[] = {
1229 "ConfReq", "ConfAck", "ConfNak", "ConfRej",
1230 "TermReq", "TermAck", "CodeRej"
1234 ipv6cp_printpkt(p, plen, printer, arg)
1237 void (*printer) __P((void *, char *, ...));
1240 int code, id, len, olen;
1241 u_char *pstart, *optend;
1245 if (plen < HEADERLEN)
1251 if (len < HEADERLEN || len > plen)
1254 if (code >= 1 && code <= sizeof(ipv6cp_codenames) / sizeof(char *))
1255 printer(arg, " %s", ipv6cp_codenames[code-1]);
1257 printer(arg, " code=0x%x", code);
1258 printer(arg, " id=0x%x", id);
1265 /* print option list */
1270 if (olen < 2 || olen > len) {
1277 case CI_COMPRESSTYPE:
1278 if (olen >= CILEN_COMPRESS) {
1280 GETSHORT(cishort, p);
1281 printer(arg, "compress ");
1282 printer(arg, "0x%x", cishort);
1286 if (olen == CILEN_IFACEID) {
1288 eui64_get(ifaceid, p);
1289 printer(arg, "addr %s", llv6_ntoa(ifaceid));
1293 while (p < optend) {
1295 printer(arg, " %.2x", code);
1303 if (len > 0 && *p >= ' ' && *p < 0x7f) {
1305 print_string(p, len, printer, arg);
1312 /* print the rest of the bytes in the packet */
1313 for (; len > 0; --len) {
1315 printer(arg, " %.2x", code);
1322 * ipv6_active_pkt - see if this IP packet is worth bringing the link up for.
1323 * We don't bring the link up for IP fragments or for TCP FIN packets
1326 #define IP6_HDRLEN 40 /* bytes */
1327 #define IP6_NHDR_FRAG 44 /* fragment IPv6 header */
1328 #define IPPROTO_TCP 6
1329 #define TCP_HDRLEN 20
1333 * We use these macros because the IP header may be at an odd address,
1334 * and some compilers might use word loads to get th_off or ip_hl.
1337 #define get_ip6nh(x) (((unsigned char *)(x))[6])
1338 #define get_tcpoff(x) (((unsigned char *)(x))[12] >> 4)
1339 #define get_tcpflags(x) (((unsigned char *)(x))[13])
1342 ipv6_active_pkt(pkt, len)
1350 if (len < IP6_HDRLEN)
1352 if (get_ip6nh(pkt) == IP6_NHDR_FRAG)
1354 if (get_ip6nh(pkt) != IPPROTO_TCP)
1356 if (len < IP6_HDRLEN + TCP_HDRLEN)
1358 tcp = pkt + IP6_HDRLEN;
1359 if ((get_tcpflags(tcp) & TH_FIN) != 0 && len == IP6_HDRLEN + get_tcpoff(tcp) * 4)