130949fd4SBrian Somers /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
31de7b4b8SPedro F. Giffuni *
430949fd4SBrian Somers * Copyright (c) 2001 Brian Somers <brian@Awfulhak.org>
530949fd4SBrian Somers * All rights reserved.
630949fd4SBrian Somers *
730949fd4SBrian Somers * Redistribution and use in source and binary forms, with or without
830949fd4SBrian Somers * modification, are permitted provided that the following conditions
930949fd4SBrian Somers * are met:
1030949fd4SBrian Somers * 1. Redistributions of source code must retain the above copyright
1130949fd4SBrian Somers * notice, this list of conditions and the following disclaimer.
1230949fd4SBrian Somers * 2. Redistributions in binary form must reproduce the above copyright
1330949fd4SBrian Somers * notice, this list of conditions and the following disclaimer in the
1430949fd4SBrian Somers * documentation and/or other materials provided with the distribution.
1530949fd4SBrian Somers *
1630949fd4SBrian Somers * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1730949fd4SBrian Somers * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1830949fd4SBrian Somers * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1930949fd4SBrian Somers * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2030949fd4SBrian Somers * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2130949fd4SBrian Somers * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2230949fd4SBrian Somers * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2330949fd4SBrian Somers * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2430949fd4SBrian Somers * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2530949fd4SBrian Somers * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2630949fd4SBrian Somers * SUCH DAMAGE.
2730949fd4SBrian Somers */
2830949fd4SBrian Somers
2930949fd4SBrian Somers #include <sys/param.h>
3030949fd4SBrian Somers #include <netinet/in_systm.h>
3130949fd4SBrian Somers #include <netinet/in.h>
3230949fd4SBrian Somers #include <netinet/ip.h>
3330949fd4SBrian Somers #include <sys/socket.h>
3430949fd4SBrian Somers #include <net/route.h>
3530949fd4SBrian Somers #include <net/if.h>
36a3c48b40SBrian Somers #include <net/if_types.h>
37a3c48b40SBrian Somers #include <net/if_dl.h>
3830949fd4SBrian Somers #include <sys/un.h>
3930949fd4SBrian Somers
406eafd353SBrian Somers #include <stdarg.h>
4130949fd4SBrian Somers #include <stdio.h>
4230949fd4SBrian Somers #include <stdlib.h>
4330949fd4SBrian Somers #include <string.h>
4430949fd4SBrian Somers #include <termios.h>
45a3c48b40SBrian Somers #include <ifaddrs.h>
4630949fd4SBrian Somers
4730949fd4SBrian Somers #include "layer.h"
4830949fd4SBrian Somers #include "defs.h"
4930949fd4SBrian Somers #include "mbuf.h"
5030949fd4SBrian Somers #include "timer.h"
5130949fd4SBrian Somers #include "fsm.h"
5230949fd4SBrian Somers #include "iplist.h"
5330949fd4SBrian Somers #include "throughput.h"
5430949fd4SBrian Somers #include "slcompress.h"
5530949fd4SBrian Somers #include "lqr.h"
5630949fd4SBrian Somers #include "hdlc.h"
5730949fd4SBrian Somers #include "lcp.h"
5830949fd4SBrian Somers #include "ncpaddr.h"
5930949fd4SBrian Somers #include "ip.h"
6030949fd4SBrian Somers #include "ipcp.h"
6130949fd4SBrian Somers #include "ipv6cp.h"
6230949fd4SBrian Somers #include "filter.h"
6330949fd4SBrian Somers #include "descriptor.h"
6430949fd4SBrian Somers #include "ccp.h"
6530949fd4SBrian Somers #include "link.h"
6630949fd4SBrian Somers #include "mp.h"
6730949fd4SBrian Somers #ifndef NORADIUS
6830949fd4SBrian Somers #include "radius.h"
6930949fd4SBrian Somers #endif
7030949fd4SBrian Somers #include "ncp.h"
7130949fd4SBrian Somers #include "bundle.h"
7230949fd4SBrian Somers #include "route.h"
7330949fd4SBrian Somers #include "iface.h"
7430949fd4SBrian Somers #include "log.h"
7530949fd4SBrian Somers #include "proto.h"
7630949fd4SBrian Somers #include "command.h"
7730949fd4SBrian Somers #include "prompt.h"
7830949fd4SBrian Somers #include "async.h"
7930949fd4SBrian Somers #include "physical.h"
80c5109a32SBrian Somers #include "probe.h"
815ba934c3SKris Kennaway #include "systems.h"
8230949fd4SBrian Somers
8330949fd4SBrian Somers
8430949fd4SBrian Somers #ifndef NOINET6
853efad8b4SHajimu UMEMOTO #define IN6ADDR_LINKLOCAL_MCAST_INIT \
863efad8b4SHajimu UMEMOTO {{{ 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
873efad8b4SHajimu UMEMOTO 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}}
883efad8b4SHajimu UMEMOTO static const struct in6_addr in6addr_linklocal_mcast =
893efad8b4SHajimu UMEMOTO IN6ADDR_LINKLOCAL_MCAST_INIT;
903efad8b4SHajimu UMEMOTO
9130949fd4SBrian Somers static int ipv6cp_LayerUp(struct fsm *);
9230949fd4SBrian Somers static void ipv6cp_LayerDown(struct fsm *);
9330949fd4SBrian Somers static void ipv6cp_LayerStart(struct fsm *);
9430949fd4SBrian Somers static void ipv6cp_LayerFinish(struct fsm *);
9530949fd4SBrian Somers static void ipv6cp_InitRestartCounter(struct fsm *, int);
9630949fd4SBrian Somers static void ipv6cp_SendConfigReq(struct fsm *);
9730949fd4SBrian Somers static void ipv6cp_SentTerminateReq(struct fsm *);
9830949fd4SBrian Somers static void ipv6cp_SendTerminateAck(struct fsm *, u_char);
99ff360cc9SBrian Somers static void ipv6cp_DecodeConfig(struct fsm *, u_char *, u_char *, int,
10030949fd4SBrian Somers struct fsm_decode *);
10130949fd4SBrian Somers
10230949fd4SBrian Somers static struct fsm_callbacks ipv6cp_Callbacks = {
10330949fd4SBrian Somers ipv6cp_LayerUp,
10430949fd4SBrian Somers ipv6cp_LayerDown,
10530949fd4SBrian Somers ipv6cp_LayerStart,
10630949fd4SBrian Somers ipv6cp_LayerFinish,
10730949fd4SBrian Somers ipv6cp_InitRestartCounter,
10830949fd4SBrian Somers ipv6cp_SendConfigReq,
10930949fd4SBrian Somers ipv6cp_SentTerminateReq,
11030949fd4SBrian Somers ipv6cp_SendTerminateAck,
11130949fd4SBrian Somers ipv6cp_DecodeConfig,
11230949fd4SBrian Somers fsm_NullRecvResetReq,
11330949fd4SBrian Somers fsm_NullRecvResetAck
11430949fd4SBrian Somers };
11530949fd4SBrian Somers
116a3c48b40SBrian Somers static void
SetInterfaceID(u_char * ifid,int userandom)117a3c48b40SBrian Somers SetInterfaceID(u_char *ifid, int userandom)
11830949fd4SBrian Somers {
119a3c48b40SBrian Somers struct ifaddrs *ifa, *ifap = NULL;
120a3c48b40SBrian Somers struct sockaddr_dl *sdl;
121a3c48b40SBrian Somers const u_long i32_max = 0xffffffff;
122a3c48b40SBrian Somers u_long r1, r2;
12330949fd4SBrian Somers
124a3c48b40SBrian Somers /* configure an interface ID based on Section 4.1 of RFC 2472 */
125a3c48b40SBrian Somers memset(ifid, 0, IPV6CP_IFIDLEN);
126a3c48b40SBrian Somers
127a3c48b40SBrian Somers /*
128a3c48b40SBrian Somers * 1) If an IEEE global identifier (EUI-48 or EUI-64) is
129a3c48b40SBrian Somers * available anywhere on the node, it should be used to construct
130a3c48b40SBrian Somers * the tentative Interface-Identifier due to its uniqueness
131a3c48b40SBrian Somers * properties.
132a3c48b40SBrian Somers */
133a3c48b40SBrian Somers if (userandom)
134a3c48b40SBrian Somers goto randomid;
135a3c48b40SBrian Somers if (getifaddrs(&ifap) < 0)
136a3c48b40SBrian Somers goto randomid;
137a3c48b40SBrian Somers
138a3c48b40SBrian Somers for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
139a3c48b40SBrian Somers char *cp;
140a3c48b40SBrian Somers
141a3c48b40SBrian Somers if (ifa->ifa_addr->sa_family != AF_LINK)
142a3c48b40SBrian Somers continue;
143a3c48b40SBrian Somers
144a3c48b40SBrian Somers sdl = (struct sockaddr_dl *)ifa->ifa_addr;
145a3c48b40SBrian Somers if (sdl->sdl_alen < 6)
146a3c48b40SBrian Somers continue;
147a3c48b40SBrian Somers /* we're only interested in IEEE hardware addresses */
148a3c48b40SBrian Somers switch(sdl->sdl_type) {
149a3c48b40SBrian Somers case IFT_ETHER:
150a3c48b40SBrian Somers case IFT_FDDI:
151d99d8e2eSJohn Baldwin case IFT_L2VLAN:
152a3c48b40SBrian Somers /* XXX need more cases? */
153a3c48b40SBrian Somers break;
154a3c48b40SBrian Somers default:
155a3c48b40SBrian Somers continue;
156a3c48b40SBrian Somers }
157a3c48b40SBrian Somers
158a3c48b40SBrian Somers cp = (char *)(sdl->sdl_data + sdl->sdl_nlen);
159a3c48b40SBrian Somers ifid[0] = cp[0];
160a3c48b40SBrian Somers ifid[0] ^= 0x02; /* reverse the u/l bit*/
161a3c48b40SBrian Somers ifid[1] = cp[1];
162a3c48b40SBrian Somers ifid[2] = cp[2];
163a3c48b40SBrian Somers ifid[3] = 0xff;
164a3c48b40SBrian Somers ifid[4] = 0xfe;
165a3c48b40SBrian Somers ifid[5] = cp[3];
166a3c48b40SBrian Somers ifid[6] = cp[4];
167a3c48b40SBrian Somers ifid[7] = cp[5];
168a3c48b40SBrian Somers
169a3c48b40SBrian Somers freeifaddrs(ifap);
170a3c48b40SBrian Somers return;
171a3c48b40SBrian Somers }
172a3c48b40SBrian Somers
173a3c48b40SBrian Somers freeifaddrs(ifap);
174a3c48b40SBrian Somers
175a3c48b40SBrian Somers /*
176a3c48b40SBrian Somers * 2) If an IEEE global identifier is not available a different source
177a3c48b40SBrian Somers * of uniqueness should be used.
178a3c48b40SBrian Somers * XXX: we skip this case.
179a3c48b40SBrian Somers */
180a3c48b40SBrian Somers
181a3c48b40SBrian Somers /*
182a3c48b40SBrian Somers * 3) If a good source of uniqueness cannot be found, it is
183a3c48b40SBrian Somers * recommended that a random number be generated. In this case the
184a3c48b40SBrian Somers * "u" bit of the interface identifier MUST be set to zero (0).
185a3c48b40SBrian Somers */
186a3c48b40SBrian Somers randomid:
187a3c48b40SBrian Somers randinit();
188a3c48b40SBrian Somers r1 = (((u_long)random()) % i32_max) + 1;
189a3c48b40SBrian Somers r2 = (((u_long)random()) % i32_max) + 1;
190a3c48b40SBrian Somers memcpy(ifid, &r1, sizeof(r1));
191a3c48b40SBrian Somers memcpy(ifid + 4, &r2, sizeof(r2));
192a3c48b40SBrian Somers ifid[0] &= 0xfd;
193a3c48b40SBrian Somers return;
19430949fd4SBrian Somers }
19530949fd4SBrian Somers
19630949fd4SBrian Somers static int
ipcp_SetIPv6address(struct ipv6cp * ipv6cp,u_char * myifid,u_char * hisifid)197a3c48b40SBrian Somers ipcp_SetIPv6address(struct ipv6cp *ipv6cp, u_char *myifid, u_char *hisifid)
19830949fd4SBrian Somers {
19930949fd4SBrian Somers struct bundle *bundle = ipv6cp->fsm.bundle;
20030949fd4SBrian Somers struct in6_addr myaddr, hisaddr;
2013efad8b4SHajimu UMEMOTO struct ncprange myrange, range;
2023efad8b4SHajimu UMEMOTO struct ncpaddr addr;
2035ae08329SBrian Somers struct sockaddr_storage ssdst, ssgw, ssmask;
2045ae08329SBrian Somers struct sockaddr *sadst, *sagw, *samask;
2055ae08329SBrian Somers
2065ae08329SBrian Somers sadst = (struct sockaddr *)&ssdst;
2075ae08329SBrian Somers sagw = (struct sockaddr *)&ssgw;
2085ae08329SBrian Somers samask = (struct sockaddr *)&ssmask;
20930949fd4SBrian Somers
21030949fd4SBrian Somers memset(&myaddr, '\0', sizeof myaddr);
21130949fd4SBrian Somers memset(&hisaddr, '\0', sizeof hisaddr);
21230949fd4SBrian Somers
21330949fd4SBrian Somers myaddr.s6_addr[0] = 0xfe;
21430949fd4SBrian Somers myaddr.s6_addr[1] = 0x80;
215a3c48b40SBrian Somers memcpy(&myaddr.s6_addr[8], myifid, IPV6CP_IFIDLEN);
216a3c48b40SBrian Somers #if 0
217a3c48b40SBrian Somers myaddr.s6_addr[8] |= 0x02; /* set 'universal' bit */
218a3c48b40SBrian Somers #endif
21930949fd4SBrian Somers
22030949fd4SBrian Somers hisaddr.s6_addr[0] = 0xfe;
22130949fd4SBrian Somers hisaddr.s6_addr[1] = 0x80;
222a3c48b40SBrian Somers memcpy(&hisaddr.s6_addr[8], hisifid, IPV6CP_IFIDLEN);
223a3c48b40SBrian Somers #if 0
224a3c48b40SBrian Somers hisaddr.s6_addr[8] |= 0x02; /* set 'universal' bit */
225a3c48b40SBrian Somers #endif
22630949fd4SBrian Somers
22730949fd4SBrian Somers ncpaddr_setip6(&ipv6cp->myaddr, &myaddr);
22830949fd4SBrian Somers ncpaddr_setip6(&ipv6cp->hisaddr, &hisaddr);
229977e6c08SHajimu UMEMOTO ncprange_set(&myrange, &ipv6cp->myaddr, 64);
23030949fd4SBrian Somers
23130949fd4SBrian Somers if (!iface_Add(bundle->iface, &bundle->ncp, &myrange, &ipv6cp->hisaddr,
23230949fd4SBrian Somers IFACE_ADD_FIRST|IFACE_FORCE_ADD|IFACE_SYSTEM))
23330949fd4SBrian Somers return 0;
23430949fd4SBrian Somers
23530949fd4SBrian Somers if (!Enabled(bundle, OPT_IFACEALIAS))
23630949fd4SBrian Somers iface_Clear(bundle->iface, &bundle->ncp, AF_INET6,
23730949fd4SBrian Somers IFACE_CLEAR_ALIASES|IFACE_SYSTEM);
23830949fd4SBrian Somers
2393efad8b4SHajimu UMEMOTO ncpaddr_setip6(&addr, &in6addr_linklocal_mcast);
2403efad8b4SHajimu UMEMOTO ncprange_set(&range, &addr, 32);
2413efad8b4SHajimu UMEMOTO rt_Set(bundle, RTM_ADD, &range, &ipv6cp->myaddr, 1, 0);
2423efad8b4SHajimu UMEMOTO
24330949fd4SBrian Somers if (bundle->ncp.cfg.sendpipe > 0 || bundle->ncp.cfg.recvpipe > 0) {
2445ae08329SBrian Somers ncprange_getsa(&myrange, &ssgw, &ssmask);
2455ae08329SBrian Somers if (ncpaddr_isset(&ipv6cp->hisaddr))
2465ae08329SBrian Somers ncpaddr_getsa(&ipv6cp->hisaddr, &ssdst);
2475ae08329SBrian Somers else
2485ae08329SBrian Somers sadst = NULL;
2490e81959dSBjoern A. Zeeb rt_Update(bundle, sadst, sagw, samask, NULL, NULL);
25030949fd4SBrian Somers }
25130949fd4SBrian Somers
25230949fd4SBrian Somers if (Enabled(bundle, OPT_SROUTES))
25330949fd4SBrian Somers route_Change(bundle, bundle->ncp.route, &ipv6cp->myaddr, &ipv6cp->hisaddr);
25430949fd4SBrian Somers
25530949fd4SBrian Somers #ifndef NORADIUS
25630949fd4SBrian Somers if (bundle->radius.valid)
2570fe74aa4SHajimu UMEMOTO route_Change(bundle, bundle->radius.ipv6routes, &ipv6cp->myaddr,
25830949fd4SBrian Somers &ipv6cp->hisaddr);
25930949fd4SBrian Somers #endif
26030949fd4SBrian Somers
26130949fd4SBrian Somers return 1; /* Ok */
26230949fd4SBrian Somers }
26330949fd4SBrian Somers
26430949fd4SBrian Somers void
ipv6cp_Init(struct ipv6cp * ipv6cp,struct bundle * bundle,struct link * l,const struct fsm_parent * parent)26530949fd4SBrian Somers ipv6cp_Init(struct ipv6cp *ipv6cp, struct bundle *bundle, struct link *l,
26630949fd4SBrian Somers const struct fsm_parent *parent)
26730949fd4SBrian Somers {
26830949fd4SBrian Somers static const char * const timer_names[] =
26930949fd4SBrian Somers {"IPV6CP restart", "IPV6CP openmode", "IPV6CP stopped"};
27030949fd4SBrian Somers int n;
27130949fd4SBrian Somers
27230949fd4SBrian Somers fsm_Init(&ipv6cp->fsm, "IPV6CP", PROTO_IPV6CP, 1, IPV6CP_MAXCODE, LogIPV6CP,
27330949fd4SBrian Somers bundle, l, parent, &ipv6cp_Callbacks, timer_names);
27430949fd4SBrian Somers
27530949fd4SBrian Somers ipv6cp->cfg.fsm.timeout = DEF_FSMRETRY;
27630949fd4SBrian Somers ipv6cp->cfg.fsm.maxreq = DEF_FSMTRIES;
27730949fd4SBrian Somers ipv6cp->cfg.fsm.maxtrm = DEF_FSMTRIES;
27830949fd4SBrian Somers
279a3c48b40SBrian Somers SetInterfaceID(ipv6cp->my_ifid, 0);
280a3c48b40SBrian Somers do {
281a3c48b40SBrian Somers SetInterfaceID(ipv6cp->his_ifid, 1);
282a3c48b40SBrian Somers } while (memcmp(ipv6cp->his_ifid, ipv6cp->my_ifid, IPV6CP_IFIDLEN) == 0);
28330949fd4SBrian Somers
2841136c6acSBrian Somers if (probe.ipv6_available) {
28530949fd4SBrian Somers n = 100;
28630949fd4SBrian Somers while (n &&
287a3c48b40SBrian Somers !ipcp_SetIPv6address(ipv6cp, ipv6cp->my_ifid, ipv6cp->his_ifid)) {
288a3c48b40SBrian Somers do {
2891136c6acSBrian Somers n--;
290a3c48b40SBrian Somers SetInterfaceID(ipv6cp->my_ifid, 1);
291a3c48b40SBrian Somers } while (n
292a3c48b40SBrian Somers && memcmp(ipv6cp->his_ifid, ipv6cp->my_ifid, IPV6CP_IFIDLEN) == 0);
2931136c6acSBrian Somers }
2941136c6acSBrian Somers }
29530949fd4SBrian Somers
29630949fd4SBrian Somers throughput_init(&ipv6cp->throughput, SAMPLE_PERIOD);
29730949fd4SBrian Somers memset(ipv6cp->Queue, '\0', sizeof ipv6cp->Queue);
29830949fd4SBrian Somers ipv6cp_Setup(ipv6cp);
29930949fd4SBrian Somers }
30030949fd4SBrian Somers
30130949fd4SBrian Somers void
ipv6cp_Destroy(struct ipv6cp * ipv6cp)30230949fd4SBrian Somers ipv6cp_Destroy(struct ipv6cp *ipv6cp)
30330949fd4SBrian Somers {
30430949fd4SBrian Somers throughput_destroy(&ipv6cp->throughput);
30530949fd4SBrian Somers }
30630949fd4SBrian Somers
30730949fd4SBrian Somers void
ipv6cp_Setup(struct ipv6cp * ipv6cp)30830949fd4SBrian Somers ipv6cp_Setup(struct ipv6cp *ipv6cp)
30930949fd4SBrian Somers {
31030949fd4SBrian Somers ncpaddr_init(&ipv6cp->myaddr);
31130949fd4SBrian Somers ncpaddr_init(&ipv6cp->hisaddr);
31230949fd4SBrian Somers
31330949fd4SBrian Somers ipv6cp->his_reject = 0;
31430949fd4SBrian Somers ipv6cp->my_reject = 0;
31530949fd4SBrian Somers }
31630949fd4SBrian Somers
31730949fd4SBrian Somers void
ipv6cp_SetLink(struct ipv6cp * ipv6cp,struct link * l)31830949fd4SBrian Somers ipv6cp_SetLink(struct ipv6cp *ipv6cp, struct link *l)
31930949fd4SBrian Somers {
32030949fd4SBrian Somers ipv6cp->fsm.link = l;
32130949fd4SBrian Somers }
32230949fd4SBrian Somers
32330949fd4SBrian Somers int
ipv6cp_Show(struct cmdargs const * arg)32430949fd4SBrian Somers ipv6cp_Show(struct cmdargs const *arg)
32530949fd4SBrian Somers {
32630949fd4SBrian Somers struct ipv6cp *ipv6cp = &arg->bundle->ncp.ipv6cp;
32730949fd4SBrian Somers
32830949fd4SBrian Somers prompt_Printf(arg->prompt, "%s [%s]\n", ipv6cp->fsm.name,
32930949fd4SBrian Somers State2Nam(ipv6cp->fsm.state));
33030949fd4SBrian Somers if (ipv6cp->fsm.state == ST_OPENED) {
33130949fd4SBrian Somers prompt_Printf(arg->prompt, " His side: %s\n",
33230949fd4SBrian Somers ncpaddr_ntoa(&ipv6cp->hisaddr));
33330949fd4SBrian Somers prompt_Printf(arg->prompt, " My side: %s\n",
33430949fd4SBrian Somers ncpaddr_ntoa(&ipv6cp->myaddr));
33530949fd4SBrian Somers prompt_Printf(arg->prompt, " Queued packets: %lu\n",
33630949fd4SBrian Somers (unsigned long)ipv6cp_QueueLen(ipv6cp));
33730949fd4SBrian Somers }
33830949fd4SBrian Somers
33930949fd4SBrian Somers prompt_Printf(arg->prompt, "\nDefaults:\n");
34030949fd4SBrian Somers prompt_Printf(arg->prompt, " FSM retry = %us, max %u Config"
34130949fd4SBrian Somers " REQ%s, %u Term REQ%s\n\n", ipv6cp->cfg.fsm.timeout,
34230949fd4SBrian Somers ipv6cp->cfg.fsm.maxreq, ipv6cp->cfg.fsm.maxreq == 1 ? "" : "s",
34330949fd4SBrian Somers ipv6cp->cfg.fsm.maxtrm, ipv6cp->cfg.fsm.maxtrm == 1 ? "" : "s");
34430949fd4SBrian Somers
34530949fd4SBrian Somers throughput_disp(&ipv6cp->throughput, arg->prompt);
34630949fd4SBrian Somers
34730949fd4SBrian Somers return 0;
34830949fd4SBrian Somers }
34930949fd4SBrian Somers
35030949fd4SBrian Somers struct mbuf *
ipv6cp_Input(struct bundle * bundle,struct link * l,struct mbuf * bp)35130949fd4SBrian Somers ipv6cp_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
35230949fd4SBrian Somers {
35330949fd4SBrian Somers /* Got PROTO_IPV6CP from link */
35430949fd4SBrian Somers m_settype(bp, MB_IPV6CPIN);
3551136c6acSBrian Somers if (bundle_Phase(bundle) == PHASE_NETWORK)
35630949fd4SBrian Somers fsm_Input(&bundle->ncp.ipv6cp.fsm, bp);
35730949fd4SBrian Somers else {
35830949fd4SBrian Somers if (bundle_Phase(bundle) < PHASE_NETWORK)
35930949fd4SBrian Somers log_Printf(LogIPV6CP, "%s: Error: Unexpected IPV6CP in phase %s"
36030949fd4SBrian Somers " (ignored)\n", l->name, bundle_PhaseName(bundle));
36130949fd4SBrian Somers m_freem(bp);
36230949fd4SBrian Somers }
36330949fd4SBrian Somers return NULL;
36430949fd4SBrian Somers }
36530949fd4SBrian Somers
36630949fd4SBrian Somers void
ipv6cp_AddInOctets(struct ipv6cp * ipv6cp,int n)36730949fd4SBrian Somers ipv6cp_AddInOctets(struct ipv6cp *ipv6cp, int n)
36830949fd4SBrian Somers {
36930949fd4SBrian Somers throughput_addin(&ipv6cp->throughput, n);
37030949fd4SBrian Somers }
37130949fd4SBrian Somers
37230949fd4SBrian Somers void
ipv6cp_AddOutOctets(struct ipv6cp * ipv6cp,int n)37330949fd4SBrian Somers ipv6cp_AddOutOctets(struct ipv6cp *ipv6cp, int n)
37430949fd4SBrian Somers {
37530949fd4SBrian Somers throughput_addout(&ipv6cp->throughput, n);
37630949fd4SBrian Somers }
37730949fd4SBrian Somers
37830949fd4SBrian Somers void
ipv6cp_IfaceAddrAdded(struct ipv6cp * ipv6cp __unused,const struct iface_addr * addr __unused)379057f1760SBrian Somers ipv6cp_IfaceAddrAdded(struct ipv6cp *ipv6cp __unused,
380057f1760SBrian Somers const struct iface_addr *addr __unused)
38130949fd4SBrian Somers {
38230949fd4SBrian Somers }
38330949fd4SBrian Somers
38430949fd4SBrian Somers void
ipv6cp_IfaceAddrDeleted(struct ipv6cp * ipv6cp __unused,const struct iface_addr * addr __unused)385057f1760SBrian Somers ipv6cp_IfaceAddrDeleted(struct ipv6cp *ipv6cp __unused,
386057f1760SBrian Somers const struct iface_addr *addr __unused)
38730949fd4SBrian Somers {
38830949fd4SBrian Somers }
38930949fd4SBrian Somers
39030949fd4SBrian Somers int
ipv6cp_InterfaceUp(struct ipv6cp * ipv6cp)39130949fd4SBrian Somers ipv6cp_InterfaceUp(struct ipv6cp *ipv6cp)
39230949fd4SBrian Somers {
393a3c48b40SBrian Somers if (!ipcp_SetIPv6address(ipv6cp, ipv6cp->my_ifid, ipv6cp->his_ifid)) {
39430949fd4SBrian Somers log_Printf(LogERROR, "ipv6cp_InterfaceUp: unable to set ipv6 address\n");
39530949fd4SBrian Somers return 0;
39630949fd4SBrian Somers }
39730949fd4SBrian Somers
39830949fd4SBrian Somers if (!iface_SetFlags(ipv6cp->fsm.bundle->iface->name, IFF_UP)) {
39930949fd4SBrian Somers log_Printf(LogERROR, "ipv6cp_InterfaceUp: Can't set the IFF_UP"
40030949fd4SBrian Somers " flag on %s\n", ipv6cp->fsm.bundle->iface->name);
40130949fd4SBrian Somers return 0;
40230949fd4SBrian Somers }
40330949fd4SBrian Somers
40430949fd4SBrian Somers return 1;
40530949fd4SBrian Somers }
40630949fd4SBrian Somers
40730949fd4SBrian Somers size_t
ipv6cp_QueueLen(struct ipv6cp * ipv6cp)40830949fd4SBrian Somers ipv6cp_QueueLen(struct ipv6cp *ipv6cp)
40930949fd4SBrian Somers {
41030949fd4SBrian Somers struct mqueue *q;
41130949fd4SBrian Somers size_t result;
41230949fd4SBrian Somers
41330949fd4SBrian Somers result = 0;
41430949fd4SBrian Somers for (q = ipv6cp->Queue; q < ipv6cp->Queue + IPV6CP_QUEUES(ipv6cp); q++)
41530949fd4SBrian Somers result += q->len;
41630949fd4SBrian Somers
41730949fd4SBrian Somers return result;
41830949fd4SBrian Somers }
41930949fd4SBrian Somers
42030949fd4SBrian Somers int
ipv6cp_PushPacket(struct ipv6cp * ipv6cp,struct link * l)42130949fd4SBrian Somers ipv6cp_PushPacket(struct ipv6cp *ipv6cp, struct link *l)
42230949fd4SBrian Somers {
42330949fd4SBrian Somers struct bundle *bundle = ipv6cp->fsm.bundle;
42430949fd4SBrian Somers struct mqueue *queue;
42530949fd4SBrian Somers struct mbuf *bp;
42630949fd4SBrian Somers int m_len;
42730949fd4SBrian Somers u_int32_t secs = 0;
42830949fd4SBrian Somers unsigned alivesecs = 0;
42930949fd4SBrian Somers
43030949fd4SBrian Somers if (ipv6cp->fsm.state != ST_OPENED)
43130949fd4SBrian Somers return 0;
43230949fd4SBrian Somers
43330949fd4SBrian Somers /*
43430949fd4SBrian Somers * If ccp is not open but is required, do nothing.
43530949fd4SBrian Somers */
43630949fd4SBrian Somers if (l->ccp.fsm.state != ST_OPENED && ccp_Required(&l->ccp)) {
43730949fd4SBrian Somers log_Printf(LogPHASE, "%s: Not transmitting... waiting for CCP\n", l->name);
43830949fd4SBrian Somers return 0;
43930949fd4SBrian Somers }
44030949fd4SBrian Somers
44130949fd4SBrian Somers queue = ipv6cp->Queue + IPV6CP_QUEUES(ipv6cp) - 1;
44230949fd4SBrian Somers do {
44330949fd4SBrian Somers if (queue->top) {
44430949fd4SBrian Somers bp = m_dequeue(queue);
44530949fd4SBrian Somers bp = mbuf_Read(bp, &secs, sizeof secs);
44630949fd4SBrian Somers bp = m_pullup(bp);
44730949fd4SBrian Somers m_len = m_length(bp);
44830949fd4SBrian Somers if (!FilterCheck(MBUF_CTOP(bp), AF_INET6, &bundle->filter.alive,
44930949fd4SBrian Somers &alivesecs)) {
45030949fd4SBrian Somers if (secs == 0)
45130949fd4SBrian Somers secs = alivesecs;
45230949fd4SBrian Somers bundle_StartIdleTimer(bundle, secs);
45330949fd4SBrian Somers }
45430949fd4SBrian Somers link_PushPacket(l, bp, bundle, 0, PROTO_IPV6);
45530949fd4SBrian Somers ipv6cp_AddOutOctets(ipv6cp, m_len);
45630949fd4SBrian Somers return 1;
45730949fd4SBrian Somers }
45830949fd4SBrian Somers } while (queue-- != ipv6cp->Queue);
45930949fd4SBrian Somers
46030949fd4SBrian Somers return 0;
46130949fd4SBrian Somers }
46230949fd4SBrian Somers
46330949fd4SBrian Somers static int
ipv6cp_LayerUp(struct fsm * fp)46430949fd4SBrian Somers ipv6cp_LayerUp(struct fsm *fp)
46530949fd4SBrian Somers {
46630949fd4SBrian Somers /* We're now up */
46730949fd4SBrian Somers struct ipv6cp *ipv6cp = fsm2ipv6cp(fp);
4686cd3353bSEugene Grosbein char tbuff[NCP_ASCIIBUFFERSIZE];
46930949fd4SBrian Somers
47030949fd4SBrian Somers log_Printf(LogIPV6CP, "%s: LayerUp.\n", fp->link->name);
47130949fd4SBrian Somers if (!ipv6cp_InterfaceUp(ipv6cp))
47230949fd4SBrian Somers return 0;
47330949fd4SBrian Somers
47430949fd4SBrian Somers snprintf(tbuff, sizeof tbuff, "%s", ncpaddr_ntoa(&ipv6cp->myaddr));
47530949fd4SBrian Somers log_Printf(LogIPV6CP, "myaddr %s hisaddr = %s\n",
47630949fd4SBrian Somers tbuff, ncpaddr_ntoa(&ipv6cp->hisaddr));
47730949fd4SBrian Somers
478cf7c10d0SHajimu UMEMOTO #ifndef NORADIUS
479cf7c10d0SHajimu UMEMOTO radius_Account_Set_Ipv6(&fp->bundle->radacct6, ipv6cp->his_ifid);
480cf7c10d0SHajimu UMEMOTO radius_Account(&fp->bundle->radius, &fp->bundle->radacct6,
481cf7c10d0SHajimu UMEMOTO fp->bundle->links, RAD_START, &ipv6cp->throughput);
482cf7c10d0SHajimu UMEMOTO
483cf7c10d0SHajimu UMEMOTO /*
484cf7c10d0SHajimu UMEMOTO * XXX: Avoid duplicate evaluation of filterid between IPCP and
485cf7c10d0SHajimu UMEMOTO * IPV6CP. When IPCP is enabled and rejected, filterid is not
486cf7c10d0SHajimu UMEMOTO * evaluated.
487cf7c10d0SHajimu UMEMOTO */
488cf7c10d0SHajimu UMEMOTO if (!Enabled(fp->bundle, OPT_IPCP)) {
4899304cfd0SDimitry Andric if (*fp->bundle->radius.cfg.file && fp->bundle->radius.filterid)
490cf7c10d0SHajimu UMEMOTO system_Select(fp->bundle, fp->bundle->radius.filterid, LINKUPFILE,
491cf7c10d0SHajimu UMEMOTO NULL, NULL);
492cf7c10d0SHajimu UMEMOTO }
493cf7c10d0SHajimu UMEMOTO #endif
49411f9e243SHajimu UMEMOTO
49511f9e243SHajimu UMEMOTO /*
49611f9e243SHajimu UMEMOTO * XXX this stuff should really live in the FSM. Our config should
49711f9e243SHajimu UMEMOTO * associate executable sections in files with events.
49811f9e243SHajimu UMEMOTO */
49911f9e243SHajimu UMEMOTO if (system_Select(fp->bundle, tbuff, LINKUPFILE, NULL, NULL) < 0) {
500cf7c10d0SHajimu UMEMOTO /*
501cf7c10d0SHajimu UMEMOTO * XXX: Avoid duplicate evaluation of label between IPCP and
502cf7c10d0SHajimu UMEMOTO * IPV6CP. When IPCP is enabled and rejected, label is not
503cf7c10d0SHajimu UMEMOTO * evaluated.
504cf7c10d0SHajimu UMEMOTO */
5051f8db65aSHajimu UMEMOTO if (bundle_GetLabel(fp->bundle) && !Enabled(fp->bundle, OPT_IPCP)) {
50611f9e243SHajimu UMEMOTO if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle),
50711f9e243SHajimu UMEMOTO LINKUPFILE, NULL, NULL) < 0)
50811f9e243SHajimu UMEMOTO system_Select(fp->bundle, "MYADDR6", LINKUPFILE, NULL, NULL);
50911f9e243SHajimu UMEMOTO } else
51011f9e243SHajimu UMEMOTO system_Select(fp->bundle, "MYADDR6", LINKUPFILE, NULL, NULL);
51111f9e243SHajimu UMEMOTO }
51230949fd4SBrian Somers
51330949fd4SBrian Somers fp->more.reqs = fp->more.naks = fp->more.rejs = ipv6cp->cfg.fsm.maxreq * 3;
51430949fd4SBrian Somers log_DisplayPrompts();
51530949fd4SBrian Somers
51630949fd4SBrian Somers return 1;
51730949fd4SBrian Somers }
51830949fd4SBrian Somers
51930949fd4SBrian Somers static void
ipv6cp_LayerDown(struct fsm * fp)52030949fd4SBrian Somers ipv6cp_LayerDown(struct fsm *fp)
52130949fd4SBrian Somers {
52230949fd4SBrian Somers /* About to come down */
52330949fd4SBrian Somers struct ipv6cp *ipv6cp = fsm2ipv6cp(fp);
52430949fd4SBrian Somers static int recursing;
5256cd3353bSEugene Grosbein char addr[NCP_ASCIIBUFFERSIZE];
52630949fd4SBrian Somers
52730949fd4SBrian Somers if (!recursing++) {
52830949fd4SBrian Somers snprintf(addr, sizeof addr, "%s", ncpaddr_ntoa(&ipv6cp->myaddr));
52930949fd4SBrian Somers log_Printf(LogIPV6CP, "%s: LayerDown: %s\n", fp->link->name, addr);
53030949fd4SBrian Somers
531cf7c10d0SHajimu UMEMOTO #ifndef NORADIUS
53288044778SBrian Somers radius_Flush(&fp->bundle->radius);
533cf7c10d0SHajimu UMEMOTO radius_Account(&fp->bundle->radius, &fp->bundle->radacct6,
534cf7c10d0SHajimu UMEMOTO fp->bundle->links, RAD_STOP, &ipv6cp->throughput);
535cf7c10d0SHajimu UMEMOTO
536cf7c10d0SHajimu UMEMOTO /*
537cf7c10d0SHajimu UMEMOTO * XXX: Avoid duplicate evaluation of filterid between IPCP and
538cf7c10d0SHajimu UMEMOTO * IPV6CP. When IPCP is enabled and rejected, filterid is not
539cf7c10d0SHajimu UMEMOTO * evaluated.
540cf7c10d0SHajimu UMEMOTO */
541cf7c10d0SHajimu UMEMOTO if (!Enabled(fp->bundle, OPT_IPCP)) {
5429304cfd0SDimitry Andric if (*fp->bundle->radius.cfg.file && fp->bundle->radius.filterid)
543cf7c10d0SHajimu UMEMOTO system_Select(fp->bundle, fp->bundle->radius.filterid, LINKDOWNFILE,
544cf7c10d0SHajimu UMEMOTO NULL, NULL);
545cf7c10d0SHajimu UMEMOTO }
546cf7c10d0SHajimu UMEMOTO #endif
54711f9e243SHajimu UMEMOTO
54811f9e243SHajimu UMEMOTO /*
54911f9e243SHajimu UMEMOTO * XXX this stuff should really live in the FSM. Our config should
55011f9e243SHajimu UMEMOTO * associate executable sections in files with events.
55111f9e243SHajimu UMEMOTO */
55211f9e243SHajimu UMEMOTO if (system_Select(fp->bundle, addr, LINKDOWNFILE, NULL, NULL) < 0) {
553cf7c10d0SHajimu UMEMOTO /*
554cf7c10d0SHajimu UMEMOTO * XXX: Avoid duplicate evaluation of label between IPCP and
555cf7c10d0SHajimu UMEMOTO * IPV6CP. When IPCP is enabled and rejected, label is not
556cf7c10d0SHajimu UMEMOTO * evaluated.
557cf7c10d0SHajimu UMEMOTO */
5581f8db65aSHajimu UMEMOTO if (bundle_GetLabel(fp->bundle) && !Enabled(fp->bundle, OPT_IPCP)) {
55911f9e243SHajimu UMEMOTO if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle),
56011f9e243SHajimu UMEMOTO LINKDOWNFILE, NULL, NULL) < 0)
56111f9e243SHajimu UMEMOTO system_Select(fp->bundle, "MYADDR6", LINKDOWNFILE, NULL, NULL);
56211f9e243SHajimu UMEMOTO } else
56311f9e243SHajimu UMEMOTO system_Select(fp->bundle, "MYADDR6", LINKDOWNFILE, NULL, NULL);
56411f9e243SHajimu UMEMOTO }
56530949fd4SBrian Somers
56630949fd4SBrian Somers ipv6cp_Setup(ipv6cp);
56730949fd4SBrian Somers }
56830949fd4SBrian Somers recursing--;
56930949fd4SBrian Somers }
57030949fd4SBrian Somers
57130949fd4SBrian Somers static void
ipv6cp_LayerStart(struct fsm * fp)57230949fd4SBrian Somers ipv6cp_LayerStart(struct fsm *fp)
57330949fd4SBrian Somers {
57430949fd4SBrian Somers /* We're about to start up ! */
57530949fd4SBrian Somers struct ipv6cp *ipv6cp = fsm2ipv6cp(fp);
57630949fd4SBrian Somers
57730949fd4SBrian Somers log_Printf(LogIPV6CP, "%s: LayerStart.\n", fp->link->name);
57830949fd4SBrian Somers throughput_start(&ipv6cp->throughput, "IPV6CP throughput",
57930949fd4SBrian Somers Enabled(fp->bundle, OPT_THROUGHPUT));
58030949fd4SBrian Somers fp->more.reqs = fp->more.naks = fp->more.rejs = ipv6cp->cfg.fsm.maxreq * 3;
58130949fd4SBrian Somers ipv6cp->peer_tokenreq = 0;
58230949fd4SBrian Somers }
58330949fd4SBrian Somers
58430949fd4SBrian Somers static void
ipv6cp_LayerFinish(struct fsm * fp)58530949fd4SBrian Somers ipv6cp_LayerFinish(struct fsm *fp)
58630949fd4SBrian Somers {
58730949fd4SBrian Somers /* We're now down */
58830949fd4SBrian Somers struct ipv6cp *ipv6cp = fsm2ipv6cp(fp);
58930949fd4SBrian Somers
59030949fd4SBrian Somers log_Printf(LogIPV6CP, "%s: LayerFinish.\n", fp->link->name);
59130949fd4SBrian Somers throughput_stop(&ipv6cp->throughput);
59230949fd4SBrian Somers throughput_log(&ipv6cp->throughput, LogIPV6CP, NULL);
59330949fd4SBrian Somers }
59430949fd4SBrian Somers
59530949fd4SBrian Somers static void
ipv6cp_InitRestartCounter(struct fsm * fp,int what)59630949fd4SBrian Somers ipv6cp_InitRestartCounter(struct fsm *fp, int what)
59730949fd4SBrian Somers {
59830949fd4SBrian Somers /* Set fsm timer load */
59930949fd4SBrian Somers struct ipv6cp *ipv6cp = fsm2ipv6cp(fp);
60030949fd4SBrian Somers
60130949fd4SBrian Somers fp->FsmTimer.load = ipv6cp->cfg.fsm.timeout * SECTICKS;
60230949fd4SBrian Somers switch (what) {
60330949fd4SBrian Somers case FSM_REQ_TIMER:
60430949fd4SBrian Somers fp->restart = ipv6cp->cfg.fsm.maxreq;
60530949fd4SBrian Somers break;
60630949fd4SBrian Somers case FSM_TRM_TIMER:
60730949fd4SBrian Somers fp->restart = ipv6cp->cfg.fsm.maxtrm;
60830949fd4SBrian Somers break;
60930949fd4SBrian Somers default:
61030949fd4SBrian Somers fp->restart = 1;
61130949fd4SBrian Somers break;
61230949fd4SBrian Somers }
61330949fd4SBrian Somers }
61430949fd4SBrian Somers
61530949fd4SBrian Somers static void
ipv6cp_SendConfigReq(struct fsm * fp)61630949fd4SBrian Somers ipv6cp_SendConfigReq(struct fsm *fp)
61730949fd4SBrian Somers {
61830949fd4SBrian Somers /* Send config REQ please */
61930949fd4SBrian Somers struct physical *p = link2physical(fp->link);
62030949fd4SBrian Somers struct ipv6cp *ipv6cp = fsm2ipv6cp(fp);
621a3c48b40SBrian Somers u_char buff[IPV6CP_IFIDLEN+2];
622ff360cc9SBrian Somers struct fsm_opt *o;
62330949fd4SBrian Somers
624ff360cc9SBrian Somers o = (struct fsm_opt *)buff;
62530949fd4SBrian Somers
62630949fd4SBrian Somers if ((p && !physical_IsSync(p)) || !REJECTED(ipv6cp, TY_TOKEN)) {
627a3c48b40SBrian Somers memcpy(o->data, ipv6cp->my_ifid, IPV6CP_IFIDLEN);
628a3c48b40SBrian Somers INC_FSM_OPT(TY_TOKEN, IPV6CP_IFIDLEN + 2, o);
62930949fd4SBrian Somers }
63030949fd4SBrian Somers
63130949fd4SBrian Somers fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, (u_char *)o - buff,
63230949fd4SBrian Somers MB_IPV6CPOUT);
63330949fd4SBrian Somers }
63430949fd4SBrian Somers
63530949fd4SBrian Somers static void
ipv6cp_SentTerminateReq(struct fsm * fp __unused)636057f1760SBrian Somers ipv6cp_SentTerminateReq(struct fsm *fp __unused)
63730949fd4SBrian Somers {
63830949fd4SBrian Somers /* Term REQ just sent by FSM */
63930949fd4SBrian Somers }
64030949fd4SBrian Somers
64130949fd4SBrian Somers static void
ipv6cp_SendTerminateAck(struct fsm * fp,u_char id)64230949fd4SBrian Somers ipv6cp_SendTerminateAck(struct fsm *fp, u_char id)
64330949fd4SBrian Somers {
64430949fd4SBrian Somers /* Send Term ACK please */
64530949fd4SBrian Somers fsm_Output(fp, CODE_TERMACK, id, NULL, 0, MB_IPV6CPOUT);
64630949fd4SBrian Somers }
64730949fd4SBrian Somers
64830949fd4SBrian Somers static const char *
protoname(unsigned proto)649057f1760SBrian Somers protoname(unsigned proto)
65030949fd4SBrian Somers {
651a3c48b40SBrian Somers static const char *cftypes[] = { "IFACEID", "COMPPROTO" };
65230949fd4SBrian Somers
65330949fd4SBrian Somers if (proto > 0 && proto <= sizeof cftypes / sizeof *cftypes)
65430949fd4SBrian Somers return cftypes[proto - 1];
65530949fd4SBrian Somers
65630949fd4SBrian Somers return NumStr(proto, NULL, 0);
65730949fd4SBrian Somers }
65830949fd4SBrian Somers
65930949fd4SBrian Somers static void
ipv6cp_ValidateInterfaceID(struct ipv6cp * ipv6cp,u_char * ifid,struct fsm_decode * dec)660a3c48b40SBrian Somers ipv6cp_ValidateInterfaceID(struct ipv6cp *ipv6cp, u_char *ifid,
66130949fd4SBrian Somers struct fsm_decode *dec)
66230949fd4SBrian Somers {
663ff360cc9SBrian Somers struct fsm_opt opt;
664a3c48b40SBrian Somers u_char zero[IPV6CP_IFIDLEN];
665ff360cc9SBrian Somers
666a3c48b40SBrian Somers memset(zero, 0, IPV6CP_IFIDLEN);
667a3c48b40SBrian Somers
668a3c48b40SBrian Somers if (memcmp(ifid, zero, IPV6CP_IFIDLEN) != 0
669a3c48b40SBrian Somers && memcmp(ifid, ipv6cp->my_ifid, IPV6CP_IFIDLEN) != 0)
670a3c48b40SBrian Somers memcpy(ipv6cp->his_ifid, ifid, IPV6CP_IFIDLEN);
67130949fd4SBrian Somers
672ff360cc9SBrian Somers opt.hdr.id = TY_TOKEN;
673a3c48b40SBrian Somers opt.hdr.len = IPV6CP_IFIDLEN + 2;
674a3c48b40SBrian Somers memcpy(opt.data, &ipv6cp->his_ifid, IPV6CP_IFIDLEN);
675a3c48b40SBrian Somers if (memcmp(ifid, ipv6cp->his_ifid, IPV6CP_IFIDLEN) == 0)
676ff360cc9SBrian Somers fsm_ack(dec, &opt);
677ff360cc9SBrian Somers else
678ff360cc9SBrian Somers fsm_nak(dec, &opt);
67930949fd4SBrian Somers }
68030949fd4SBrian Somers
68130949fd4SBrian Somers static void
ipv6cp_DecodeConfig(struct fsm * fp,u_char * cp,u_char * end,int mode_type,struct fsm_decode * dec)682ff360cc9SBrian Somers ipv6cp_DecodeConfig(struct fsm *fp, u_char *cp, u_char *end, int mode_type,
68330949fd4SBrian Somers struct fsm_decode *dec)
68430949fd4SBrian Somers {
68530949fd4SBrian Somers /* Deal with incoming PROTO_IPV6CP */
68630949fd4SBrian Somers struct ipv6cp *ipv6cp = fsm2ipv6cp(fp);
687ff360cc9SBrian Somers int n;
68830949fd4SBrian Somers char tbuff[100];
689a3c48b40SBrian Somers u_char ifid[IPV6CP_IFIDLEN], zero[IPV6CP_IFIDLEN];
690ff360cc9SBrian Somers struct fsm_opt *opt;
69130949fd4SBrian Somers
692a3c48b40SBrian Somers memset(zero, 0, IPV6CP_IFIDLEN);
693a3c48b40SBrian Somers
694057f1760SBrian Somers while (end - cp >= (int)sizeof(opt->hdr)) {
695ff360cc9SBrian Somers if ((opt = fsm_readopt(&cp)) == NULL)
69630949fd4SBrian Somers break;
69730949fd4SBrian Somers
698ff360cc9SBrian Somers snprintf(tbuff, sizeof tbuff, " %s[%d]", protoname(opt->hdr.id),
699ff360cc9SBrian Somers opt->hdr.len);
70030949fd4SBrian Somers
701ff360cc9SBrian Somers switch (opt->hdr.id) {
70230949fd4SBrian Somers case TY_TOKEN:
703a3c48b40SBrian Somers memcpy(ifid, opt->data, IPV6CP_IFIDLEN);
704a3c48b40SBrian Somers log_Printf(LogIPV6CP, "%s 0x%02x%02x%02x%02x%02x%02x%02x%02x\n", tbuff,
705a3c48b40SBrian Somers ifid[0], ifid[1], ifid[2], ifid[3], ifid[4], ifid[5], ifid[6], ifid[7]);
70630949fd4SBrian Somers
70730949fd4SBrian Somers switch (mode_type) {
70830949fd4SBrian Somers case MODE_REQ:
70930949fd4SBrian Somers ipv6cp->peer_tokenreq = 1;
710a3c48b40SBrian Somers ipv6cp_ValidateInterfaceID(ipv6cp, ifid, dec);
71130949fd4SBrian Somers break;
71230949fd4SBrian Somers
71330949fd4SBrian Somers case MODE_NAK:
714a3c48b40SBrian Somers if (memcmp(ifid, zero, IPV6CP_IFIDLEN) == 0) {
71530949fd4SBrian Somers log_Printf(log_IsKept(LogIPV6CP) ? LogIPV6CP : LogPHASE,
716a3c48b40SBrian Somers "0x0000000000000000: Unacceptable IntefaceID!\n");
71730949fd4SBrian Somers fsm_Close(&ipv6cp->fsm);
718a3c48b40SBrian Somers } else if (memcmp(ifid, ipv6cp->his_ifid, IPV6CP_IFIDLEN) == 0) {
71930949fd4SBrian Somers log_Printf(log_IsKept(LogIPV6CP) ? LogIPV6CP : LogPHASE,
720a3c48b40SBrian Somers "0x%02x%02x%02x%02x%02x%02x%02x%02x: "
721a3c48b40SBrian Somers "Unacceptable IntefaceID!\n",
722a3c48b40SBrian Somers ifid[0], ifid[1], ifid[2], ifid[3],
723a3c48b40SBrian Somers ifid[4], ifid[5], ifid[6], ifid[7]);
724a3c48b40SBrian Somers } else if (memcmp(ifid, ipv6cp->my_ifid, IPV6CP_IFIDLEN) != 0) {
72530949fd4SBrian Somers n = 100;
726a3c48b40SBrian Somers while (n && !ipcp_SetIPv6address(ipv6cp, ifid, ipv6cp->his_ifid)) {
727a3c48b40SBrian Somers do {
7281136c6acSBrian Somers n--;
729a3c48b40SBrian Somers SetInterfaceID(ifid, 1);
730a3c48b40SBrian Somers } while (n && memcmp(ifid, ipv6cp->his_ifid, IPV6CP_IFIDLEN) == 0);
7311136c6acSBrian Somers }
73230949fd4SBrian Somers
73330949fd4SBrian Somers if (n == 0) {
73430949fd4SBrian Somers log_Printf(log_IsKept(LogIPV6CP) ? LogIPV6CP : LogPHASE,
735a3c48b40SBrian Somers "0x0000000000000000: Unacceptable IntefaceID!\n");
73630949fd4SBrian Somers fsm_Close(&ipv6cp->fsm);
73730949fd4SBrian Somers } else {
738a3c48b40SBrian Somers log_Printf(LogIPV6CP, "%s changing IntefaceID: "
739a3c48b40SBrian Somers "0x%02x%02x%02x%02x%02x%02x%02x%02x "
740a3c48b40SBrian Somers "--> 0x%02x%02x%02x%02x%02x%02x%02x%02x\n", tbuff,
741a3c48b40SBrian Somers ipv6cp->my_ifid[0], ipv6cp->my_ifid[1],
742a3c48b40SBrian Somers ipv6cp->my_ifid[2], ipv6cp->my_ifid[3],
743a3c48b40SBrian Somers ipv6cp->my_ifid[4], ipv6cp->my_ifid[5],
744a3c48b40SBrian Somers ipv6cp->my_ifid[6], ipv6cp->my_ifid[7],
745a3c48b40SBrian Somers ifid[0], ifid[1], ifid[2], ifid[3],
746a3c48b40SBrian Somers ifid[4], ifid[5], ifid[6], ifid[7]);
747a3c48b40SBrian Somers memcpy(ipv6cp->my_ifid, ifid, IPV6CP_IFIDLEN);
74830949fd4SBrian Somers bundle_AdjustFilters(fp->bundle, &ipv6cp->myaddr, NULL);
74930949fd4SBrian Somers }
75030949fd4SBrian Somers }
75130949fd4SBrian Somers break;
75230949fd4SBrian Somers
75330949fd4SBrian Somers case MODE_REJ:
754ff360cc9SBrian Somers ipv6cp->his_reject |= (1 << opt->hdr.id);
75530949fd4SBrian Somers break;
75630949fd4SBrian Somers }
75730949fd4SBrian Somers break;
75830949fd4SBrian Somers
75930949fd4SBrian Somers default:
76030949fd4SBrian Somers if (mode_type != MODE_NOP) {
761ff360cc9SBrian Somers ipv6cp->my_reject |= (1 << opt->hdr.id);
762ff360cc9SBrian Somers fsm_rej(dec, opt);
76330949fd4SBrian Somers }
76430949fd4SBrian Somers break;
76530949fd4SBrian Somers }
76630949fd4SBrian Somers }
76730949fd4SBrian Somers
76830949fd4SBrian Somers if (mode_type != MODE_NOP) {
76930949fd4SBrian Somers if (mode_type == MODE_REQ && !ipv6cp->peer_tokenreq) {
77030949fd4SBrian Somers if (dec->rejend == dec->rej && dec->nakend == dec->nak) {
77130949fd4SBrian Somers /*
77230949fd4SBrian Somers * Pretend the peer has requested a TOKEN.
77330949fd4SBrian Somers * We do this to ensure that we only send one NAK if the only
77430949fd4SBrian Somers * reason for the NAK is because the peer isn't sending a
77530949fd4SBrian Somers * TY_TOKEN REQ. This stops us from repeatedly trying to tell
77630949fd4SBrian Somers * the peer that we have to have an IP address on their end.
77730949fd4SBrian Somers */
77830949fd4SBrian Somers ipv6cp->peer_tokenreq = 1;
77930949fd4SBrian Somers }
780a3c48b40SBrian Somers memset(ifid, 0, IPV6CP_IFIDLEN);
781a3c48b40SBrian Somers ipv6cp_ValidateInterfaceID(ipv6cp, ifid, dec);
78230949fd4SBrian Somers }
783ff360cc9SBrian Somers fsm_opt_normalise(dec);
78430949fd4SBrian Somers }
78530949fd4SBrian Somers }
78630949fd4SBrian Somers #endif
787