ipv6cp.c revision 140905
183104Sphantom/*- 287659Sphantom * Copyright (c) 2001 Brian Somers <brian@Awfulhak.org> 383104Sphantom * All rights reserved. 483104Sphantom * 5227753Stheraven * Redistribution and use in source and binary forms, with or without 6227753Stheraven * modification, are permitted provided that the following conditions 7227753Stheraven * are met: 8227753Stheraven * 1. Redistributions of source code must retain the above copyright 9227753Stheraven * notice, this list of conditions and the following disclaimer. 1083104Sphantom * 2. Redistributions in binary form must reproduce the above copyright 1183104Sphantom * notice, this list of conditions and the following disclaimer in the 1283104Sphantom * documentation and/or other materials provided with the distribution. 1383104Sphantom * 1483104Sphantom * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1583104Sphantom * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1683104Sphantom * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1783104Sphantom * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1883104Sphantom * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1983104Sphantom * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2083104Sphantom * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2183104Sphantom * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2283104Sphantom * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2383104Sphantom * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2483104Sphantom * SUCH DAMAGE. 2583104Sphantom * 2683104Sphantom * $FreeBSD: head/usr.sbin/ppp/ipv6cp.c 140905 2005-01-27 14:09:33Z brian $ 2783104Sphantom */ 2883104Sphantom 2983104Sphantom#include <sys/param.h> 3083104Sphantom#include <netinet/in_systm.h> 3183104Sphantom#include <netinet/in.h> 3283104Sphantom#include <netinet/ip.h> 3392986Sobrien#include <sys/socket.h> 3492986Sobrien#include <net/route.h> 3583104Sphantom#include <net/if.h> 3683104Sphantom#include <net/if_types.h> 3783104Sphantom#include <net/if_dl.h> 3883104Sphantom#include <sys/un.h> 3983104Sphantom 4083104Sphantom#include <stdarg.h> 41150065Sstefanf#include <stdio.h> 4283104Sphantom#include <stdlib.h> 4383104Sphantom#include <string.h> 4483104Sphantom#include <termios.h> 4583104Sphantom#include <ifaddrs.h> 46227753Stheraven 4783104Sphantom#include "layer.h" 4883104Sphantom#include "defs.h" 4983104Sphantom#include "mbuf.h" 5083104Sphantom#include "timer.h" 5183104Sphantom#include "fsm.h" 5283104Sphantom#include "iplist.h" 53298830Spfg#include "throughput.h" 5483104Sphantom#include "slcompress.h" 5583104Sphantom#include "lqr.h" 5683104Sphantom#include "hdlc.h" 5783104Sphantom#include "lcp.h" 5883104Sphantom#include "ncpaddr.h" 5983559Smike#include "ip.h" 6083104Sphantom#include "ipcp.h" 6183104Sphantom#include "ipv6cp.h" 6283104Sphantom#include "filter.h" 6383559Smike#include "descriptor.h" 6483104Sphantom#include "ccp.h" 6583559Smike#include "link.h" 6683104Sphantom#include "mp.h" 6783104Sphantom#ifndef NORADIUS 6883104Sphantom#include "radius.h" 6983559Smike#endif 7083104Sphantom#include "ncp.h" 7183559Smike#include "bundle.h" 7283104Sphantom#include "route.h" 7383104Sphantom#include "iface.h" 74178457Sru#include "log.h" 75178457Sru#include "proto.h" 7683104Sphantom#include "command.h" 7783104Sphantom#include "prompt.h" 78178312Sru#include "async.h" 79178312Sru#include "physical.h" 8083104Sphantom#include "probe.h" 8183104Sphantom#include "systems.h" 8283559Smike 8383104Sphantom 8483559Smike#ifndef NOINET6 8583559Smike#define IN6ADDR_LINKLOCAL_MCAST_INIT \ 8683559Smike {{{ 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 8783559Smike 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}} 8883559Smikestatic const struct in6_addr in6addr_linklocal_mcast = 8983559Smike IN6ADDR_LINKLOCAL_MCAST_INIT; 9083559Smike 9183559Smikestatic int ipv6cp_LayerUp(struct fsm *); 9283559Smikestatic void ipv6cp_LayerDown(struct fsm *); 9383559Smikestatic void ipv6cp_LayerStart(struct fsm *); 9483559Smikestatic void ipv6cp_LayerFinish(struct fsm *); 9583559Smikestatic void ipv6cp_InitRestartCounter(struct fsm *, int); 9683559Smikestatic void ipv6cp_SendConfigReq(struct fsm *); 9783104Sphantomstatic void ipv6cp_SentTerminateReq(struct fsm *); 9883104Sphantomstatic void ipv6cp_SendTerminateAck(struct fsm *, u_char); 9983104Sphantomstatic void ipv6cp_DecodeConfig(struct fsm *, u_char *, u_char *, int, 10083104Sphantom struct fsm_decode *); 101227753Stheraven 102227753Stheravenstatic struct fsm_callbacks ipv6cp_Callbacks = { 103227753Stheraven ipv6cp_LayerUp, 10483104Sphantom ipv6cp_LayerDown, 10583104Sphantom ipv6cp_LayerStart, 10683104Sphantom ipv6cp_LayerFinish, 10783104Sphantom ipv6cp_InitRestartCounter, 10883104Sphantom ipv6cp_SendConfigReq, 10983104Sphantom ipv6cp_SentTerminateReq, 11083104Sphantom ipv6cp_SendTerminateAck, 11183104Sphantom ipv6cp_DecodeConfig, 11283104Sphantom fsm_NullRecvResetReq, 11383104Sphantom fsm_NullRecvResetAck 11483104Sphantom}; 11583104Sphantom 11683104Sphantomstatic void 11783104SphantomSetInterfaceID(u_char *ifid, int userandom) 11883104Sphantom{ 11983104Sphantom struct ifaddrs *ifa, *ifap = NULL; 12083104Sphantom struct sockaddr_dl *sdl; 12183104Sphantom const u_long i32_max = 0xffffffff; 12283104Sphantom u_long r1, r2; 12383104Sphantom 12483104Sphantom /* configure an interface ID based on Section 4.1 of RFC 2472 */ 12583104Sphantom memset(ifid, 0, IPV6CP_IFIDLEN); 126104946Stjr 127227753Stheraven /* 12883104Sphantom * 1) If an IEEE global identifier (EUI-48 or EUI-64) is 12983104Sphantom * available anywhere on the node, it should be used to construct 130227753Stheraven * the tentative Interface-Identifier due to its uniqueness 13183104Sphantom * properties. 13283104Sphantom */ 13383104Sphantom if (userandom) 13483104Sphantom goto randomid; 13583104Sphantom if (getifaddrs(&ifap) < 0) 13683104Sphantom goto randomid; 13783104Sphantom 13883104Sphantom for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 13983559Smike char *cp; 14083104Sphantom 14183104Sphantom if (ifa->ifa_addr->sa_family != AF_LINK) 14283104Sphantom continue; 14383104Sphantom 14483104Sphantom sdl = (struct sockaddr_dl *)ifa->ifa_addr; 14583104Sphantom if (sdl->sdl_alen < 6) 14683104Sphantom continue; 14783104Sphantom /* we're only interested in IEEE hardware addresses */ 14883104Sphantom switch(sdl->sdl_type) { 14983104Sphantom case IFT_ETHER: 15083104Sphantom case IFT_FDDI: 15183104Sphantom /* XXX need more cases? */ 15283104Sphantom break; 15383104Sphantom default: 15483104Sphantom continue; 15583104Sphantom } 15683104Sphantom 15783104Sphantom cp = (char *)(sdl->sdl_data + sdl->sdl_nlen); 15883104Sphantom ifid[0] = cp[0]; 15983104Sphantom ifid[0] ^= 0x02; /* reverse the u/l bit*/ 16083104Sphantom ifid[1] = cp[1]; 16183104Sphantom ifid[2] = cp[2]; 16283104Sphantom ifid[3] = 0xff; 16383104Sphantom ifid[4] = 0xfe; 16483104Sphantom ifid[5] = cp[3]; 16583104Sphantom ifid[6] = cp[4]; 16683104Sphantom ifid[7] = cp[5]; 16783104Sphantom 16883104Sphantom freeifaddrs(ifap); 16983104Sphantom return; 17083104Sphantom } 17183104Sphantom 17283104Sphantom freeifaddrs(ifap); 17383104Sphantom 17483104Sphantom /* 17583104Sphantom * 2) If an IEEE global identifier is not available a different source 17683104Sphantom * of uniqueness should be used. 17783104Sphantom * XXX: we skip this case. 17883104Sphantom */ 17983104Sphantom 18083104Sphantom /* 18183104Sphantom * 3) If a good source of uniqueness cannot be found, it is 18283104Sphantom * recommended that a random number be generated. In this case the 18383104Sphantom * "u" bit of the interface identifier MUST be set to zero (0). 18483104Sphantom */ 18583104Sphantom randomid: 18683104Sphantom randinit(); 18783104Sphantom r1 = (((u_long)random()) % i32_max) + 1; 18883104Sphantom r2 = (((u_long)random()) % i32_max) + 1; 18983104Sphantom memcpy(ifid, &r1, sizeof(r1)); 19083104Sphantom memcpy(ifid + 4, &r2, sizeof(r2)); 19183104Sphantom ifid[0] &= 0xfd; 19283104Sphantom return; 19383104Sphantom} 19483104Sphantom 19583104Sphantomstatic int 19683104Sphantomipcp_SetIPv6address(struct ipv6cp *ipv6cp, u_char *myifid, u_char *hisifid) 19783104Sphantom{ 19883104Sphantom struct bundle *bundle = ipv6cp->fsm.bundle; 199178312Sru struct in6_addr myaddr, hisaddr; 20083104Sphantom struct ncprange myrange, range; 20183104Sphantom struct ncpaddr addr; 202104942Stjr struct sockaddr_storage ssdst, ssgw, ssmask; 203104942Stjr struct sockaddr *sadst, *sagw, *samask; 204104942Stjr 205104942Stjr sadst = (struct sockaddr *)&ssdst; 206104942Stjr sagw = (struct sockaddr *)&ssgw; 207104942Stjr samask = (struct sockaddr *)&ssmask; 208178312Sru 209178312Sru memset(&myaddr, '\0', sizeof myaddr); 210104942Stjr memset(&hisaddr, '\0', sizeof hisaddr); 211104942Stjr 212104942Stjr myaddr.s6_addr[0] = 0xfe; 213104942Stjr myaddr.s6_addr[1] = 0x80; 214104942Stjr memcpy(&myaddr.s6_addr[8], myifid, IPV6CP_IFIDLEN); 215104942Stjr#if 0 216104942Stjr myaddr.s6_addr[8] |= 0x02; /* set 'universal' bit */ 217178312Sru#endif 218178312Sru 219178312Sru hisaddr.s6_addr[0] = 0xfe; 220104942Stjr hisaddr.s6_addr[1] = 0x80; 221104942Stjr memcpy(&hisaddr.s6_addr[8], hisifid, IPV6CP_IFIDLEN); 22283104Sphantom#if 0 22383104Sphantom hisaddr.s6_addr[8] |= 0x02; /* set 'universal' bit */ 22483104Sphantom#endif 22583104Sphantom 22683104Sphantom ncpaddr_setip6(&ipv6cp->myaddr, &myaddr); 22783104Sphantom ncpaddr_setip6(&ipv6cp->hisaddr, &hisaddr); 22883104Sphantom ncprange_set(&myrange, &ipv6cp->myaddr, 64); 22983104Sphantom 23083104Sphantom if (!iface_Add(bundle->iface, &bundle->ncp, &myrange, &ipv6cp->hisaddr, 23183104Sphantom IFACE_ADD_FIRST|IFACE_FORCE_ADD|IFACE_SYSTEM)) 23283104Sphantom return 0; 23383104Sphantom 23483104Sphantom if (!Enabled(bundle, OPT_IFACEALIAS)) 235178313Sru iface_Clear(bundle->iface, &bundle->ncp, AF_INET6, 236178313Sru IFACE_CLEAR_ALIASES|IFACE_SYSTEM); 23783104Sphantom 23883104Sphantom ncpaddr_setip6(&addr, &in6addr_linklocal_mcast); 23983104Sphantom ncprange_set(&range, &addr, 32); 24083104Sphantom rt_Set(bundle, RTM_ADD, &range, &ipv6cp->myaddr, 1, 0); 24183559Smike 24283104Sphantom if (bundle->ncp.cfg.sendpipe > 0 || bundle->ncp.cfg.recvpipe > 0) { 24383104Sphantom ncprange_getsa(&myrange, &ssgw, &ssmask); 24483104Sphantom if (ncpaddr_isset(&ipv6cp->hisaddr)) 24583104Sphantom ncpaddr_getsa(&ipv6cp->hisaddr, &ssdst); 24683104Sphantom else 24783104Sphantom sadst = NULL; 24883104Sphantom rt_Update(bundle, sadst, sagw, samask); 24983104Sphantom } 25083104Sphantom 25183104Sphantom if (Enabled(bundle, OPT_SROUTES)) 25283104Sphantom route_Change(bundle, bundle->ncp.route, &ipv6cp->myaddr, &ipv6cp->hisaddr); 25383104Sphantom 25483104Sphantom#ifndef NORADIUS 25583104Sphantom if (bundle->radius.valid) 25683104Sphantom route_Change(bundle, bundle->radius.ipv6routes, &ipv6cp->myaddr, 25783104Sphantom &ipv6cp->hisaddr); 25883104Sphantom#endif 25983104Sphantom 26083104Sphantom return 1; /* Ok */ 26183104Sphantom} 26283104Sphantom 26383104Sphantomvoid 26483104Sphantomipv6cp_Init(struct ipv6cp *ipv6cp, struct bundle *bundle, struct link *l, 265178313Sru const struct fsm_parent *parent) 266178313Sru{ 26783104Sphantom static const char * const timer_names[] = 26883104Sphantom {"IPV6CP restart", "IPV6CP openmode", "IPV6CP stopped"}; 26983104Sphantom int n; 27083104Sphantom 27183104Sphantom fsm_Init(&ipv6cp->fsm, "IPV6CP", PROTO_IPV6CP, 1, IPV6CP_MAXCODE, LogIPV6CP, 27283104Sphantom bundle, l, parent, &ipv6cp_Callbacks, timer_names); 27383104Sphantom 27483104Sphantom ipv6cp->cfg.fsm.timeout = DEF_FSMRETRY; 27583104Sphantom ipv6cp->cfg.fsm.maxreq = DEF_FSMTRIES; 27683104Sphantom ipv6cp->cfg.fsm.maxtrm = DEF_FSMTRIES; 27783104Sphantom 27883104Sphantom SetInterfaceID(ipv6cp->my_ifid, 0); 27983104Sphantom do { 28083104Sphantom SetInterfaceID(ipv6cp->his_ifid, 1); 28183104Sphantom } while (memcmp(ipv6cp->his_ifid, ipv6cp->my_ifid, IPV6CP_IFIDLEN) == 0); 28283104Sphantom 28383104Sphantom if (probe.ipv6_available) { 28483104Sphantom n = 100; 28583104Sphantom while (n && 28683104Sphantom !ipcp_SetIPv6address(ipv6cp, ipv6cp->my_ifid, ipv6cp->his_ifid)) { 28783104Sphantom do { 28883104Sphantom n--; 28983104Sphantom SetInterfaceID(ipv6cp->my_ifid, 1); 29083104Sphantom } while (n 29183104Sphantom && memcmp(ipv6cp->his_ifid, ipv6cp->my_ifid, IPV6CP_IFIDLEN) == 0); 29283104Sphantom } 29383104Sphantom } 29483104Sphantom 29583104Sphantom throughput_init(&ipv6cp->throughput, SAMPLE_PERIOD); 29683104Sphantom memset(ipv6cp->Queue, '\0', sizeof ipv6cp->Queue); 29783104Sphantom ipv6cp_Setup(ipv6cp); 29883104Sphantom} 29983104Sphantom 30083104Sphantomvoid 30183104Sphantomipv6cp_Destroy(struct ipv6cp *ipv6cp) 30283104Sphantom{ 30383104Sphantom throughput_destroy(&ipv6cp->throughput); 30483104Sphantom} 30583104Sphantom 30683104Sphantomvoid 30783104Sphantomipv6cp_Setup(struct ipv6cp *ipv6cp) 30883104Sphantom{ 30983104Sphantom ncpaddr_init(&ipv6cp->myaddr); 31083104Sphantom ncpaddr_init(&ipv6cp->hisaddr); 31183104Sphantom 31283104Sphantom ipv6cp->his_reject = 0; 313104943Stjr ipv6cp->my_reject = 0; 314104943Stjr} 31583104Sphantom 31683104Sphantomvoid 31783104Sphantomipv6cp_SetLink(struct ipv6cp *ipv6cp, struct link *l) 31883104Sphantom{ 31983104Sphantom ipv6cp->fsm.link = l; 32083104Sphantom} 32183104Sphantom 32283104Sphantomint 32383104Sphantomipv6cp_Show(struct cmdargs const *arg) 32483104Sphantom{ 32583104Sphantom struct ipv6cp *ipv6cp = &arg->bundle->ncp.ipv6cp; 32683104Sphantom 32783104Sphantom prompt_Printf(arg->prompt, "%s [%s]\n", ipv6cp->fsm.name, 32883104Sphantom State2Nam(ipv6cp->fsm.state)); 32983559Smike if (ipv6cp->fsm.state == ST_OPENED) { 33083104Sphantom prompt_Printf(arg->prompt, " His side: %s\n", 33183104Sphantom ncpaddr_ntoa(&ipv6cp->hisaddr)); 33283559Smike prompt_Printf(arg->prompt, " My side: %s\n", 33383559Smike ncpaddr_ntoa(&ipv6cp->myaddr)); 33483104Sphantom prompt_Printf(arg->prompt, " Queued packets: %lu\n", 33583559Smike (unsigned long)ipv6cp_QueueLen(ipv6cp)); 33683559Smike } 33783104Sphantom 33883104Sphantom prompt_Printf(arg->prompt, "\nDefaults:\n"); 33983104Sphantom prompt_Printf(arg->prompt, " FSM retry = %us, max %u Config" 34083104Sphantom " REQ%s, %u Term REQ%s\n\n", ipv6cp->cfg.fsm.timeout, 34183104Sphantom ipv6cp->cfg.fsm.maxreq, ipv6cp->cfg.fsm.maxreq == 1 ? "" : "s", 34283104Sphantom ipv6cp->cfg.fsm.maxtrm, ipv6cp->cfg.fsm.maxtrm == 1 ? "" : "s"); 34383104Sphantom 34483104Sphantom throughput_disp(&ipv6cp->throughput, arg->prompt); 34583104Sphantom 34683104Sphantom return 0; 34783104Sphantom} 34883104Sphantom 34983559Smikestruct mbuf * 350104963Stjripv6cp_Input(struct bundle *bundle, struct link *l, struct mbuf *bp) 35183559Smike{ 35283559Smike /* Got PROTO_IPV6CP from link */ 35383559Smike m_settype(bp, MB_IPV6CPIN); 35483559Smike if (bundle_Phase(bundle) == PHASE_NETWORK) 35583104Sphantom fsm_Input(&bundle->ncp.ipv6cp.fsm, bp); 35683104Sphantom else { 35783104Sphantom if (bundle_Phase(bundle) < PHASE_NETWORK) 35883104Sphantom log_Printf(LogIPV6CP, "%s: Error: Unexpected IPV6CP in phase %s" 35983104Sphantom " (ignored)\n", l->name, bundle_PhaseName(bundle)); 36083104Sphantom m_freem(bp); 36183104Sphantom } 36283104Sphantom return NULL; 36383104Sphantom} 36483104Sphantom 36583104Sphantomvoid 36683104Sphantomipv6cp_AddInOctets(struct ipv6cp *ipv6cp, int n) 36783104Sphantom{ 36883104Sphantom throughput_addin(&ipv6cp->throughput, n); 36983104Sphantom} 37083104Sphantom 37183104Sphantomvoid 37283104Sphantomipv6cp_AddOutOctets(struct ipv6cp *ipv6cp, int n) 37383104Sphantom{ 37483104Sphantom throughput_addout(&ipv6cp->throughput, n); 375104963Stjr} 37683104Sphantom 37783104Sphantomvoid 37883104Sphantomipv6cp_IfaceAddrAdded(struct ipv6cp *ipv6cp __unused, 37983559Smike const struct iface_addr *addr __unused) 38083559Smike{ 38183104Sphantom} 38283104Sphantom 38383104Sphantomvoid 38483104Sphantomipv6cp_IfaceAddrDeleted(struct ipv6cp *ipv6cp __unused, 38583104Sphantom const struct iface_addr *addr __unused) 38683104Sphantom{ 38783104Sphantom} 388104963Stjr 389104963Stjrint 39083104Sphantomipv6cp_InterfaceUp(struct ipv6cp *ipv6cp) 39183104Sphantom{ 39283104Sphantom if (!ipcp_SetIPv6address(ipv6cp, ipv6cp->my_ifid, ipv6cp->his_ifid)) { 39383104Sphantom log_Printf(LogERROR, "ipv6cp_InterfaceUp: unable to set ipv6 address\n"); 39483104Sphantom return 0; 39583104Sphantom } 39683104Sphantom 39783104Sphantom if (!iface_SetFlags(ipv6cp->fsm.bundle->iface->name, IFF_UP)) { 39883104Sphantom log_Printf(LogERROR, "ipv6cp_InterfaceUp: Can't set the IFF_UP" 39983104Sphantom " flag on %s\n", ipv6cp->fsm.bundle->iface->name); 400104946Stjr return 0; 40183104Sphantom } 40283104Sphantom 40383104Sphantom return 1; 40483104Sphantom} 405104946Stjr 40683104Sphantomsize_t 40783104Sphantomipv6cp_QueueLen(struct ipv6cp *ipv6cp) 408227753Stheraven{ 409227753Stheraven struct mqueue *q; 410227753Stheraven size_t result; 411227753Stheraven 412227753Stheraven result = 0; 413227753Stheraven for (q = ipv6cp->Queue; q < ipv6cp->Queue + IPV6CP_QUEUES(ipv6cp); q++) 414227753Stheraven result += q->len; 415227753Stheraven 416227753Stheraven return result; 417227753Stheraven} 418227753Stheraven 41983104Sphantomint 420227753Stheravenipv6cp_PushPacket(struct ipv6cp *ipv6cp, struct link *l) 421227753Stheraven{ 422227753Stheraven struct bundle *bundle = ipv6cp->fsm.bundle; 423227753Stheraven struct mqueue *queue; 424227753Stheraven struct mbuf *bp; 425227753Stheraven int m_len; 426227753Stheraven u_int32_t secs = 0; 427227753Stheraven unsigned alivesecs = 0; 428227753Stheraven 429227753Stheraven if (ipv6cp->fsm.state != ST_OPENED) 430227753Stheraven return 0; 431227753Stheraven 432227753Stheraven /* 43383104Sphantom * If ccp is not open but is required, do nothing. 43483104Sphantom */ 43583104Sphantom if (l->ccp.fsm.state != ST_OPENED && ccp_Required(&l->ccp)) { 43683104Sphantom log_Printf(LogPHASE, "%s: Not transmitting... waiting for CCP\n", l->name); 43783104Sphantom return 0; 43883104Sphantom } 439104944Stjr 440104944Stjr queue = ipv6cp->Queue + IPV6CP_QUEUES(ipv6cp) - 1; 441104944Stjr do { 442104944Stjr if (queue->top) { 443203734Scracauer bp = m_dequeue(queue); 444104944Stjr bp = mbuf_Read(bp, &secs, sizeof secs); 445104944Stjr bp = m_pullup(bp); 446104944Stjr m_len = m_length(bp); 447104944Stjr if (!FilterCheck(MBUF_CTOP(bp), AF_INET6, &bundle->filter.alive, 448104944Stjr &alivesecs)) { 449104944Stjr if (secs == 0) 450104944Stjr secs = alivesecs; 45183104Sphantom bundle_StartIdleTimer(bundle, secs); 45283104Sphantom } 45383559Smike link_PushPacket(l, bp, bundle, 0, PROTO_IPV6); 454203734Scracauer ipv6cp_AddOutOctets(ipv6cp, m_len); 45583559Smike return 1; 45683104Sphantom } 45783104Sphantom } while (queue-- != ipv6cp->Queue); 45883104Sphantom 45983559Smike return 0; 46083104Sphantom} 46183104Sphantom 46283104Sphantomstatic int 46383104Sphantomipv6cp_LayerUp(struct fsm *fp) 46483104Sphantom{ 46583104Sphantom /* We're now up */ 46683104Sphantom struct ipv6cp *ipv6cp = fsm2ipv6cp(fp); 46783104Sphantom char tbuff[40]; 46883104Sphantom 46983104Sphantom log_Printf(LogIPV6CP, "%s: LayerUp.\n", fp->link->name); 47083104Sphantom if (!ipv6cp_InterfaceUp(ipv6cp)) 47183104Sphantom return 0; 47283104Sphantom 47383104Sphantom snprintf(tbuff, sizeof tbuff, "%s", ncpaddr_ntoa(&ipv6cp->myaddr)); 47483104Sphantom log_Printf(LogIPV6CP, "myaddr %s hisaddr = %s\n", 47583104Sphantom tbuff, ncpaddr_ntoa(&ipv6cp->hisaddr)); 47683104Sphantom 47783104Sphantom#ifndef NORADIUS 47883104Sphantom radius_Account_Set_Ipv6(&fp->bundle->radacct6, ipv6cp->his_ifid); 47983104Sphantom radius_Account(&fp->bundle->radius, &fp->bundle->radacct6, 48083104Sphantom fp->bundle->links, RAD_START, &ipv6cp->throughput); 48183104Sphantom 48283104Sphantom /* 48383104Sphantom * XXX: Avoid duplicate evaluation of filterid between IPCP and 48483104Sphantom * IPV6CP. When IPCP is enabled and rejected, filterid is not 48583104Sphantom * evaluated. 48683104Sphantom */ 48783104Sphantom if (!Enabled(fp->bundle, OPT_IPCP)) { 48883104Sphantom if (fp->bundle->radius.cfg.file && fp->bundle->radius.filterid) 48983104Sphantom system_Select(fp->bundle, fp->bundle->radius.filterid, LINKUPFILE, 49083104Sphantom NULL, NULL); 49183104Sphantom } 49283104Sphantom#endif 49383559Smike 49483104Sphantom /* 49583559Smike * XXX this stuff should really live in the FSM. Our config should 49683104Sphantom * associate executable sections in files with events. 49783104Sphantom */ 49883104Sphantom if (system_Select(fp->bundle, tbuff, LINKUPFILE, NULL, NULL) < 0) { 49983104Sphantom /* 50083104Sphantom * XXX: Avoid duplicate evaluation of label between IPCP and 50183104Sphantom * IPV6CP. When IPCP is enabled and rejected, label is not 50283104Sphantom * evaluated. 50383104Sphantom */ 50483559Smike if (bundle_GetLabel(fp->bundle) && !Enabled(fp->bundle, OPT_IPCP)) { 50583104Sphantom if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle), 50683104Sphantom LINKUPFILE, NULL, NULL) < 0) 50783104Sphantom system_Select(fp->bundle, "MYADDR6", LINKUPFILE, NULL, NULL); 50883104Sphantom } else 50983104Sphantom system_Select(fp->bundle, "MYADDR6", LINKUPFILE, NULL, NULL); 51083104Sphantom } 51183104Sphantom 51283104Sphantom fp->more.reqs = fp->more.naks = fp->more.rejs = ipv6cp->cfg.fsm.maxreq * 3; 51383104Sphantom log_DisplayPrompts(); 51483104Sphantom 51583104Sphantom return 1; 51683104Sphantom} 51783104Sphantom 51883559Smikestatic void 51983104Sphantomipv6cp_LayerDown(struct fsm *fp) 52083104Sphantom{ 52183104Sphantom /* About to come down */ 52283104Sphantom struct ipv6cp *ipv6cp = fsm2ipv6cp(fp); 52383104Sphantom static int recursing; 52483104Sphantom char addr[40]; 52583104Sphantom 52683104Sphantom if (!recursing++) { 52783104Sphantom snprintf(addr, sizeof addr, "%s", ncpaddr_ntoa(&ipv6cp->myaddr)); 52883104Sphantom log_Printf(LogIPV6CP, "%s: LayerDown: %s\n", fp->link->name, addr); 52983104Sphantom 53083104Sphantom#ifndef NORADIUS 53183104Sphantom radius_Flush(&fp->bundle->radius); 53283104Sphantom radius_Account(&fp->bundle->radius, &fp->bundle->radacct6, 53383104Sphantom fp->bundle->links, RAD_STOP, &ipv6cp->throughput); 53483104Sphantom 53583104Sphantom /* 53683104Sphantom * XXX: Avoid duplicate evaluation of filterid between IPCP and 53783104Sphantom * IPV6CP. When IPCP is enabled and rejected, filterid is not 53883104Sphantom * evaluated. 53983104Sphantom */ 54083104Sphantom if (!Enabled(fp->bundle, OPT_IPCP)) { 54183104Sphantom if (fp->bundle->radius.cfg.file && fp->bundle->radius.filterid) 54283104Sphantom system_Select(fp->bundle, fp->bundle->radius.filterid, LINKDOWNFILE, 54383104Sphantom NULL, NULL); 544112427Sache } 54583104Sphantom#endif 54683104Sphantom 54783559Smike /* 54883104Sphantom * XXX this stuff should really live in the FSM. Our config should 54983104Sphantom * associate executable sections in files with events. 55083104Sphantom */ 55183104Sphantom if (system_Select(fp->bundle, addr, LINKDOWNFILE, NULL, NULL) < 0) { 55283104Sphantom /* 55383104Sphantom * XXX: Avoid duplicate evaluation of label between IPCP and 55483104Sphantom * IPV6CP. When IPCP is enabled and rejected, label is not 55583104Sphantom * evaluated. 55683104Sphantom */ 55783104Sphantom if (bundle_GetLabel(fp->bundle) && !Enabled(fp->bundle, OPT_IPCP)) { 55883104Sphantom if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle), 55983104Sphantom LINKDOWNFILE, NULL, NULL) < 0) 56083104Sphantom system_Select(fp->bundle, "MYADDR6", LINKDOWNFILE, NULL, NULL); 56183104Sphantom } else 56283104Sphantom system_Select(fp->bundle, "MYADDR6", LINKDOWNFILE, NULL, NULL); 56383104Sphantom } 56483104Sphantom 56583104Sphantom ipv6cp_Setup(ipv6cp); 56683104Sphantom } 56783104Sphantom recursing--; 56883104Sphantom} 569268569Spfg 570268569Spfgstatic void 57183104Sphantomipv6cp_LayerStart(struct fsm *fp) 57283559Smike{ 57383104Sphantom /* We're about to start up ! */ 57483104Sphantom struct ipv6cp *ipv6cp = fsm2ipv6cp(fp); 575268569Spfg 576178175Sdelphij log_Printf(LogIPV6CP, "%s: LayerStart.\n", fp->link->name); 57783104Sphantom throughput_start(&ipv6cp->throughput, "IPV6CP throughput", 57883104Sphantom Enabled(fp->bundle, OPT_THROUGHPUT)); 57983559Smike fp->more.reqs = fp->more.naks = fp->more.rejs = ipv6cp->cfg.fsm.maxreq * 3; 58083104Sphantom ipv6cp->peer_tokenreq = 0; 58183104Sphantom} 58283104Sphantom 583298830Spfgstatic void 58483104Sphantomipv6cp_LayerFinish(struct fsm *fp) 58583104Sphantom{ 58683104Sphantom /* We're now down */ 58783104Sphantom struct ipv6cp *ipv6cp = fsm2ipv6cp(fp); 58883104Sphantom 58983104Sphantom log_Printf(LogIPV6CP, "%s: LayerFinish.\n", fp->link->name); 59083104Sphantom throughput_stop(&ipv6cp->throughput); 59183104Sphantom throughput_log(&ipv6cp->throughput, LogIPV6CP, NULL); 59283559Smike} 59383559Smike 59483104Sphantomstatic void 59583104Sphantomipv6cp_InitRestartCounter(struct fsm *fp, int what) 59683104Sphantom{ 59783104Sphantom /* Set fsm timer load */ 59883104Sphantom struct ipv6cp *ipv6cp = fsm2ipv6cp(fp); 59983559Smike 60083559Smike fp->FsmTimer.load = ipv6cp->cfg.fsm.timeout * SECTICKS; 60183559Smike switch (what) { 60283104Sphantom case FSM_REQ_TIMER: 60383104Sphantom fp->restart = ipv6cp->cfg.fsm.maxreq; 60483104Sphantom break; 60583104Sphantom case FSM_TRM_TIMER: 60683104Sphantom fp->restart = ipv6cp->cfg.fsm.maxtrm; 60783104Sphantom break; 60883104Sphantom default: 60983104Sphantom fp->restart = 1; 61083104Sphantom break; 61183104Sphantom } 61283104Sphantom} 61383104Sphantom 61483104Sphantomstatic void 61583104Sphantomipv6cp_SendConfigReq(struct fsm *fp) 61683104Sphantom{ 61783104Sphantom /* Send config REQ please */ 61883104Sphantom struct physical *p = link2physical(fp->link); 61983104Sphantom struct ipv6cp *ipv6cp = fsm2ipv6cp(fp); 62083104Sphantom u_char buff[IPV6CP_IFIDLEN+2]; 62183104Sphantom struct fsm_opt *o; 62283104Sphantom 62383104Sphantom o = (struct fsm_opt *)buff; 62483104Sphantom 62583104Sphantom if ((p && !physical_IsSync(p)) || !REJECTED(ipv6cp, TY_TOKEN)) { 62683104Sphantom memcpy(o->data, ipv6cp->my_ifid, IPV6CP_IFIDLEN); 62783104Sphantom INC_FSM_OPT(TY_TOKEN, IPV6CP_IFIDLEN + 2, o); 62883104Sphantom } 62983104Sphantom 63083104Sphantom fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, (u_char *)o - buff, 63183104Sphantom MB_IPV6CPOUT); 63283104Sphantom} 63383104Sphantom 63483104Sphantomstatic void 63583104Sphantomipv6cp_SentTerminateReq(struct fsm *fp __unused) 63683104Sphantom{ 637104963Stjr /* Term REQ just sent by FSM */ 63883104Sphantom} 63983104Sphantom 64083559Smikestatic void 64183104Sphantomipv6cp_SendTerminateAck(struct fsm *fp, u_char id) 642{ 643 /* Send Term ACK please */ 644 fsm_Output(fp, CODE_TERMACK, id, NULL, 0, MB_IPV6CPOUT); 645} 646 647static const char * 648protoname(unsigned proto) 649{ 650 static const char *cftypes[] = { "IFACEID", "COMPPROTO" }; 651 652 if (proto > 0 && proto <= sizeof cftypes / sizeof *cftypes) 653 return cftypes[proto - 1]; 654 655 return NumStr(proto, NULL, 0); 656} 657 658static void 659ipv6cp_ValidateInterfaceID(struct ipv6cp *ipv6cp, u_char *ifid, 660 struct fsm_decode *dec) 661{ 662 struct fsm_opt opt; 663 u_char zero[IPV6CP_IFIDLEN]; 664 665 memset(zero, 0, IPV6CP_IFIDLEN); 666 667 if (memcmp(ifid, zero, IPV6CP_IFIDLEN) != 0 668 && memcmp(ifid, ipv6cp->my_ifid, IPV6CP_IFIDLEN) != 0) 669 memcpy(ipv6cp->his_ifid, ifid, IPV6CP_IFIDLEN); 670 671 opt.hdr.id = TY_TOKEN; 672 opt.hdr.len = IPV6CP_IFIDLEN + 2; 673 memcpy(opt.data, &ipv6cp->his_ifid, IPV6CP_IFIDLEN); 674 if (memcmp(ifid, ipv6cp->his_ifid, IPV6CP_IFIDLEN) == 0) 675 fsm_ack(dec, &opt); 676 else 677 fsm_nak(dec, &opt); 678} 679 680static void 681ipv6cp_DecodeConfig(struct fsm *fp, u_char *cp, u_char *end, int mode_type, 682 struct fsm_decode *dec) 683{ 684 /* Deal with incoming PROTO_IPV6CP */ 685 struct ipv6cp *ipv6cp = fsm2ipv6cp(fp); 686 int n; 687 char tbuff[100]; 688 u_char ifid[IPV6CP_IFIDLEN], zero[IPV6CP_IFIDLEN]; 689 struct fsm_opt *opt; 690 691 memset(zero, 0, IPV6CP_IFIDLEN); 692 693 while (end - cp >= (int)sizeof(opt->hdr)) { 694 if ((opt = fsm_readopt(&cp)) == NULL) 695 break; 696 697 snprintf(tbuff, sizeof tbuff, " %s[%d]", protoname(opt->hdr.id), 698 opt->hdr.len); 699 700 switch (opt->hdr.id) { 701 case TY_TOKEN: 702 memcpy(ifid, opt->data, IPV6CP_IFIDLEN); 703 log_Printf(LogIPV6CP, "%s 0x%02x%02x%02x%02x%02x%02x%02x%02x\n", tbuff, 704 ifid[0], ifid[1], ifid[2], ifid[3], ifid[4], ifid[5], ifid[6], ifid[7]); 705 706 switch (mode_type) { 707 case MODE_REQ: 708 ipv6cp->peer_tokenreq = 1; 709 ipv6cp_ValidateInterfaceID(ipv6cp, ifid, dec); 710 break; 711 712 case MODE_NAK: 713 if (memcmp(ifid, zero, IPV6CP_IFIDLEN) == 0) { 714 log_Printf(log_IsKept(LogIPV6CP) ? LogIPV6CP : LogPHASE, 715 "0x0000000000000000: Unacceptable IntefaceID!\n"); 716 fsm_Close(&ipv6cp->fsm); 717 } else if (memcmp(ifid, ipv6cp->his_ifid, IPV6CP_IFIDLEN) == 0) { 718 log_Printf(log_IsKept(LogIPV6CP) ? LogIPV6CP : LogPHASE, 719 "0x%02x%02x%02x%02x%02x%02x%02x%02x: " 720 "Unacceptable IntefaceID!\n", 721 ifid[0], ifid[1], ifid[2], ifid[3], 722 ifid[4], ifid[5], ifid[6], ifid[7]); 723 } else if (memcmp(ifid, ipv6cp->my_ifid, IPV6CP_IFIDLEN) != 0) { 724 n = 100; 725 while (n && !ipcp_SetIPv6address(ipv6cp, ifid, ipv6cp->his_ifid)) { 726 do { 727 n--; 728 SetInterfaceID(ifid, 1); 729 } while (n && memcmp(ifid, ipv6cp->his_ifid, IPV6CP_IFIDLEN) == 0); 730 } 731 732 if (n == 0) { 733 log_Printf(log_IsKept(LogIPV6CP) ? LogIPV6CP : LogPHASE, 734 "0x0000000000000000: Unacceptable IntefaceID!\n"); 735 fsm_Close(&ipv6cp->fsm); 736 } else { 737 log_Printf(LogIPV6CP, "%s changing IntefaceID: " 738 "0x%02x%02x%02x%02x%02x%02x%02x%02x " 739 "--> 0x%02x%02x%02x%02x%02x%02x%02x%02x\n", tbuff, 740 ipv6cp->my_ifid[0], ipv6cp->my_ifid[1], 741 ipv6cp->my_ifid[2], ipv6cp->my_ifid[3], 742 ipv6cp->my_ifid[4], ipv6cp->my_ifid[5], 743 ipv6cp->my_ifid[6], ipv6cp->my_ifid[7], 744 ifid[0], ifid[1], ifid[2], ifid[3], 745 ifid[4], ifid[5], ifid[6], ifid[7]); 746 memcpy(ipv6cp->my_ifid, ifid, IPV6CP_IFIDLEN); 747 bundle_AdjustFilters(fp->bundle, &ipv6cp->myaddr, NULL); 748 } 749 } 750 break; 751 752 case MODE_REJ: 753 ipv6cp->his_reject |= (1 << opt->hdr.id); 754 break; 755 } 756 break; 757 758 default: 759 if (mode_type != MODE_NOP) { 760 ipv6cp->my_reject |= (1 << opt->hdr.id); 761 fsm_rej(dec, opt); 762 } 763 break; 764 } 765 } 766 767 if (mode_type != MODE_NOP) { 768 if (mode_type == MODE_REQ && !ipv6cp->peer_tokenreq) { 769 if (dec->rejend == dec->rej && dec->nakend == dec->nak) { 770 /* 771 * Pretend the peer has requested a TOKEN. 772 * We do this to ensure that we only send one NAK if the only 773 * reason for the NAK is because the peer isn't sending a 774 * TY_TOKEN REQ. This stops us from repeatedly trying to tell 775 * the peer that we have to have an IP address on their end. 776 */ 777 ipv6cp->peer_tokenreq = 1; 778 } 779 memset(ifid, 0, IPV6CP_IFIDLEN); 780 ipv6cp_ValidateInterfaceID(ipv6cp, ifid, dec); 781 } 782 fsm_opt_normalise(dec); 783 } 784} 785#endif 786