181634Sbrian/*- 281634Sbrian * Copyright (c) 2001 Brian Somers <brian@Awfulhak.org> 381634Sbrian * All rights reserved. 481634Sbrian * 581634Sbrian * Redistribution and use in source and binary forms, with or without 681634Sbrian * modification, are permitted provided that the following conditions 781634Sbrian * are met: 881634Sbrian * 1. Redistributions of source code must retain the above copyright 981634Sbrian * notice, this list of conditions and the following disclaimer. 1081634Sbrian * 2. Redistributions in binary form must reproduce the above copyright 1181634Sbrian * notice, this list of conditions and the following disclaimer in the 1281634Sbrian * documentation and/or other materials provided with the distribution. 1381634Sbrian * 1481634Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1581634Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1681634Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1781634Sbrian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1881634Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1981634Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2081634Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2181634Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2281634Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2381634Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2481634Sbrian * SUCH DAMAGE. 2581634Sbrian * 2681634Sbrian * $FreeBSD$ 2781634Sbrian */ 2881634Sbrian 2981634Sbrian#include <sys/param.h> 3081634Sbrian#include <netinet/in_systm.h> 3181634Sbrian#include <netinet/in.h> 3281634Sbrian#include <netinet/ip.h> 3381634Sbrian#include <sys/socket.h> 3481634Sbrian#include <net/route.h> 3581634Sbrian#include <net/if.h> 36102558Sbrian#include <net/if_types.h> 37102558Sbrian#include <net/if_dl.h> 3881634Sbrian#include <sys/un.h> 3981634Sbrian 40102500Sbrian#include <stdarg.h> 4181634Sbrian#include <stdio.h> 4281634Sbrian#include <stdlib.h> 4381634Sbrian#include <string.h> 4481634Sbrian#include <termios.h> 45102558Sbrian#include <ifaddrs.h> 4681634Sbrian 4781634Sbrian#include "layer.h" 4881634Sbrian#include "defs.h" 4981634Sbrian#include "mbuf.h" 5081634Sbrian#include "timer.h" 5181634Sbrian#include "fsm.h" 5281634Sbrian#include "iplist.h" 5381634Sbrian#include "throughput.h" 5481634Sbrian#include "slcompress.h" 5581634Sbrian#include "lqr.h" 5681634Sbrian#include "hdlc.h" 5781634Sbrian#include "lcp.h" 5881634Sbrian#include "ncpaddr.h" 5981634Sbrian#include "ip.h" 6081634Sbrian#include "ipcp.h" 6181634Sbrian#include "ipv6cp.h" 6281634Sbrian#include "filter.h" 6381634Sbrian#include "descriptor.h" 6481634Sbrian#include "ccp.h" 6581634Sbrian#include "link.h" 6681634Sbrian#include "mp.h" 6781634Sbrian#ifndef NORADIUS 6881634Sbrian#include "radius.h" 6981634Sbrian#endif 7081634Sbrian#include "ncp.h" 7181634Sbrian#include "bundle.h" 7281634Sbrian#include "route.h" 7381634Sbrian#include "iface.h" 7481634Sbrian#include "log.h" 7581634Sbrian#include "proto.h" 7681634Sbrian#include "command.h" 7781634Sbrian#include "prompt.h" 7881634Sbrian#include "async.h" 7981634Sbrian#include "physical.h" 8081888Sbrian#include "probe.h" 81116251Skris#include "systems.h" 8281634Sbrian 8381634Sbrian 8481634Sbrian#ifndef NOINET6 85112618Sume#define IN6ADDR_LINKLOCAL_MCAST_INIT \ 86112618Sume {{{ 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 87112618Sume 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}} 88112618Sumestatic const struct in6_addr in6addr_linklocal_mcast = 89112618Sume IN6ADDR_LINKLOCAL_MCAST_INIT; 90112618Sume 9181634Sbrianstatic int ipv6cp_LayerUp(struct fsm *); 9281634Sbrianstatic void ipv6cp_LayerDown(struct fsm *); 9381634Sbrianstatic void ipv6cp_LayerStart(struct fsm *); 9481634Sbrianstatic void ipv6cp_LayerFinish(struct fsm *); 9581634Sbrianstatic void ipv6cp_InitRestartCounter(struct fsm *, int); 9681634Sbrianstatic void ipv6cp_SendConfigReq(struct fsm *); 9781634Sbrianstatic void ipv6cp_SentTerminateReq(struct fsm *); 9881634Sbrianstatic void ipv6cp_SendTerminateAck(struct fsm *, u_char); 9994894Sbrianstatic void ipv6cp_DecodeConfig(struct fsm *, u_char *, u_char *, int, 10081634Sbrian struct fsm_decode *); 10181634Sbrian 10281634Sbrianstatic struct fsm_callbacks ipv6cp_Callbacks = { 10381634Sbrian ipv6cp_LayerUp, 10481634Sbrian ipv6cp_LayerDown, 10581634Sbrian ipv6cp_LayerStart, 10681634Sbrian ipv6cp_LayerFinish, 10781634Sbrian ipv6cp_InitRestartCounter, 10881634Sbrian ipv6cp_SendConfigReq, 10981634Sbrian ipv6cp_SentTerminateReq, 11081634Sbrian ipv6cp_SendTerminateAck, 11181634Sbrian ipv6cp_DecodeConfig, 11281634Sbrian fsm_NullRecvResetReq, 11381634Sbrian fsm_NullRecvResetAck 11481634Sbrian}; 11581634Sbrian 116102558Sbrianstatic void 117102558SbrianSetInterfaceID(u_char *ifid, int userandom) 11881634Sbrian{ 119102558Sbrian struct ifaddrs *ifa, *ifap = NULL; 120102558Sbrian struct sockaddr_dl *sdl; 121102558Sbrian const u_long i32_max = 0xffffffff; 122102558Sbrian u_long r1, r2; 123102558Sbrian 124102558Sbrian /* configure an interface ID based on Section 4.1 of RFC 2472 */ 125102558Sbrian memset(ifid, 0, IPV6CP_IFIDLEN); 126102558Sbrian 127102558Sbrian /* 128102558Sbrian * 1) If an IEEE global identifier (EUI-48 or EUI-64) is 129102558Sbrian * available anywhere on the node, it should be used to construct 130102558Sbrian * the tentative Interface-Identifier due to its uniqueness 131102558Sbrian * properties. 132102558Sbrian */ 133102558Sbrian if (userandom) 134102558Sbrian goto randomid; 135102558Sbrian if (getifaddrs(&ifap) < 0) 136102558Sbrian goto randomid; 137102558Sbrian 138102558Sbrian for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 139102558Sbrian char *cp; 140102558Sbrian 141102558Sbrian if (ifa->ifa_addr->sa_family != AF_LINK) 142102558Sbrian continue; 143102558Sbrian 144102558Sbrian sdl = (struct sockaddr_dl *)ifa->ifa_addr; 145102558Sbrian if (sdl->sdl_alen < 6) 146102558Sbrian continue; 147102558Sbrian /* we're only interested in IEEE hardware addresses */ 148102558Sbrian switch(sdl->sdl_type) { 149102558Sbrian case IFT_ETHER: 150102558Sbrian case IFT_FDDI: 151210936Sjhb case IFT_L2VLAN: 152102558Sbrian /* XXX need more cases? */ 153102558Sbrian break; 154102558Sbrian default: 155102558Sbrian continue; 156102558Sbrian } 157102558Sbrian 158102558Sbrian cp = (char *)(sdl->sdl_data + sdl->sdl_nlen); 159102558Sbrian ifid[0] = cp[0]; 160102558Sbrian ifid[0] ^= 0x02; /* reverse the u/l bit*/ 161102558Sbrian ifid[1] = cp[1]; 162102558Sbrian ifid[2] = cp[2]; 163102558Sbrian ifid[3] = 0xff; 164102558Sbrian ifid[4] = 0xfe; 165102558Sbrian ifid[5] = cp[3]; 166102558Sbrian ifid[6] = cp[4]; 167102558Sbrian ifid[7] = cp[5]; 168102558Sbrian 169102558Sbrian freeifaddrs(ifap); 170102558Sbrian return; 171102558Sbrian } 172102558Sbrian 173102558Sbrian freeifaddrs(ifap); 174102558Sbrian 175102558Sbrian /* 176102558Sbrian * 2) If an IEEE global identifier is not available a different source 177102558Sbrian * of uniqueness should be used. 178102558Sbrian * XXX: we skip this case. 179102558Sbrian */ 180102558Sbrian 181102558Sbrian /* 182102558Sbrian * 3) If a good source of uniqueness cannot be found, it is 183102558Sbrian * recommended that a random number be generated. In this case the 184102558Sbrian * "u" bit of the interface identifier MUST be set to zero (0). 185102558Sbrian */ 186102558Sbrian randomid: 18781634Sbrian randinit(); 188102558Sbrian r1 = (((u_long)random()) % i32_max) + 1; 189102558Sbrian r2 = (((u_long)random()) % i32_max) + 1; 190102558Sbrian memcpy(ifid, &r1, sizeof(r1)); 191102558Sbrian memcpy(ifid + 4, &r2, sizeof(r2)); 192102558Sbrian ifid[0] &= 0xfd; 193102558Sbrian return; 19481634Sbrian} 19581634Sbrian 19681634Sbrianstatic int 197102558Sbrianipcp_SetIPv6address(struct ipv6cp *ipv6cp, u_char *myifid, u_char *hisifid) 19881634Sbrian{ 19981634Sbrian struct bundle *bundle = ipv6cp->fsm.bundle; 20081634Sbrian struct in6_addr myaddr, hisaddr; 201112618Sume struct ncprange myrange, range; 202112618Sume struct ncpaddr addr; 20381739Sbrian struct sockaddr_storage ssdst, ssgw, ssmask; 20481739Sbrian struct sockaddr *sadst, *sagw, *samask; 20581634Sbrian 20681739Sbrian sadst = (struct sockaddr *)&ssdst; 20781739Sbrian sagw = (struct sockaddr *)&ssgw; 20881739Sbrian samask = (struct sockaddr *)&ssmask; 20981739Sbrian 21081634Sbrian memset(&myaddr, '\0', sizeof myaddr); 21181634Sbrian memset(&hisaddr, '\0', sizeof hisaddr); 21281634Sbrian 21381634Sbrian myaddr.s6_addr[0] = 0xfe; 21481634Sbrian myaddr.s6_addr[1] = 0x80; 215102558Sbrian memcpy(&myaddr.s6_addr[8], myifid, IPV6CP_IFIDLEN); 216102558Sbrian#if 0 217102558Sbrian myaddr.s6_addr[8] |= 0x02; /* set 'universal' bit */ 218102558Sbrian#endif 21981634Sbrian 22081634Sbrian hisaddr.s6_addr[0] = 0xfe; 22181634Sbrian hisaddr.s6_addr[1] = 0x80; 222102558Sbrian memcpy(&hisaddr.s6_addr[8], hisifid, IPV6CP_IFIDLEN); 223102558Sbrian#if 0 224102558Sbrian hisaddr.s6_addr[8] |= 0x02; /* set 'universal' bit */ 225102558Sbrian#endif 22681634Sbrian 22781634Sbrian ncpaddr_setip6(&ipv6cp->myaddr, &myaddr); 22881634Sbrian ncpaddr_setip6(&ipv6cp->hisaddr, &hisaddr); 229113067Sume ncprange_set(&myrange, &ipv6cp->myaddr, 64); 23081634Sbrian 23181634Sbrian if (!iface_Add(bundle->iface, &bundle->ncp, &myrange, &ipv6cp->hisaddr, 23281634Sbrian IFACE_ADD_FIRST|IFACE_FORCE_ADD|IFACE_SYSTEM)) 23381634Sbrian return 0; 23481634Sbrian 23581634Sbrian if (!Enabled(bundle, OPT_IFACEALIAS)) 23681634Sbrian iface_Clear(bundle->iface, &bundle->ncp, AF_INET6, 23781634Sbrian IFACE_CLEAR_ALIASES|IFACE_SYSTEM); 23881634Sbrian 239112618Sume ncpaddr_setip6(&addr, &in6addr_linklocal_mcast); 240112618Sume ncprange_set(&range, &addr, 32); 241112618Sume rt_Set(bundle, RTM_ADD, &range, &ipv6cp->myaddr, 1, 0); 242112618Sume 24381634Sbrian if (bundle->ncp.cfg.sendpipe > 0 || bundle->ncp.cfg.recvpipe > 0) { 24481739Sbrian ncprange_getsa(&myrange, &ssgw, &ssmask); 24581739Sbrian if (ncpaddr_isset(&ipv6cp->hisaddr)) 24681739Sbrian ncpaddr_getsa(&ipv6cp->hisaddr, &ssdst); 24781739Sbrian else 24881739Sbrian sadst = NULL; 249191316Sbz rt_Update(bundle, sadst, sagw, samask, NULL, NULL); 25081634Sbrian } 25181634Sbrian 25281634Sbrian if (Enabled(bundle, OPT_SROUTES)) 25381634Sbrian route_Change(bundle, bundle->ncp.route, &ipv6cp->myaddr, &ipv6cp->hisaddr); 25481634Sbrian 25581634Sbrian#ifndef NORADIUS 25681634Sbrian if (bundle->radius.valid) 257116586Sume route_Change(bundle, bundle->radius.ipv6routes, &ipv6cp->myaddr, 25881634Sbrian &ipv6cp->hisaddr); 25981634Sbrian#endif 26081634Sbrian 26181634Sbrian return 1; /* Ok */ 26281634Sbrian} 26381634Sbrian 26481634Sbrianvoid 26581634Sbrianipv6cp_Init(struct ipv6cp *ipv6cp, struct bundle *bundle, struct link *l, 26681634Sbrian const struct fsm_parent *parent) 26781634Sbrian{ 26881634Sbrian static const char * const timer_names[] = 26981634Sbrian {"IPV6CP restart", "IPV6CP openmode", "IPV6CP stopped"}; 27081634Sbrian int n; 27181634Sbrian 27281634Sbrian fsm_Init(&ipv6cp->fsm, "IPV6CP", PROTO_IPV6CP, 1, IPV6CP_MAXCODE, LogIPV6CP, 27381634Sbrian bundle, l, parent, &ipv6cp_Callbacks, timer_names); 27481634Sbrian 27581634Sbrian ipv6cp->cfg.fsm.timeout = DEF_FSMRETRY; 27681634Sbrian ipv6cp->cfg.fsm.maxreq = DEF_FSMTRIES; 27781634Sbrian ipv6cp->cfg.fsm.maxtrm = DEF_FSMTRIES; 27881634Sbrian 279102558Sbrian SetInterfaceID(ipv6cp->my_ifid, 0); 280102558Sbrian do { 281102558Sbrian SetInterfaceID(ipv6cp->his_ifid, 1); 282102558Sbrian } while (memcmp(ipv6cp->his_ifid, ipv6cp->my_ifid, IPV6CP_IFIDLEN) == 0); 28381634Sbrian 28481897Sbrian if (probe.ipv6_available) { 28581897Sbrian n = 100; 28681897Sbrian while (n && 287102558Sbrian !ipcp_SetIPv6address(ipv6cp, ipv6cp->my_ifid, ipv6cp->his_ifid)) { 288102558Sbrian do { 289102558Sbrian n--; 290102558Sbrian SetInterfaceID(ipv6cp->my_ifid, 1); 291102558Sbrian } while (n 292102558Sbrian && memcmp(ipv6cp->his_ifid, ipv6cp->my_ifid, IPV6CP_IFIDLEN) == 0); 29381897Sbrian } 29481897Sbrian } 29581634Sbrian 29681634Sbrian throughput_init(&ipv6cp->throughput, SAMPLE_PERIOD); 29781634Sbrian memset(ipv6cp->Queue, '\0', sizeof ipv6cp->Queue); 29881634Sbrian ipv6cp_Setup(ipv6cp); 29981634Sbrian} 30081634Sbrian 30181634Sbrianvoid 30281634Sbrianipv6cp_Destroy(struct ipv6cp *ipv6cp) 30381634Sbrian{ 30481634Sbrian throughput_destroy(&ipv6cp->throughput); 30581634Sbrian} 30681634Sbrian 30781634Sbrianvoid 30881634Sbrianipv6cp_Setup(struct ipv6cp *ipv6cp) 30981634Sbrian{ 31081634Sbrian ncpaddr_init(&ipv6cp->myaddr); 31181634Sbrian ncpaddr_init(&ipv6cp->hisaddr); 31281634Sbrian 31381634Sbrian ipv6cp->his_reject = 0; 31481634Sbrian ipv6cp->my_reject = 0; 31581634Sbrian} 31681634Sbrian 31781634Sbrianvoid 31881634Sbrianipv6cp_SetLink(struct ipv6cp *ipv6cp, struct link *l) 31981634Sbrian{ 32081634Sbrian ipv6cp->fsm.link = l; 32181634Sbrian} 32281634Sbrian 32381634Sbrianint 32481634Sbrianipv6cp_Show(struct cmdargs const *arg) 32581634Sbrian{ 32681634Sbrian struct ipv6cp *ipv6cp = &arg->bundle->ncp.ipv6cp; 32781634Sbrian 32881634Sbrian prompt_Printf(arg->prompt, "%s [%s]\n", ipv6cp->fsm.name, 32981634Sbrian State2Nam(ipv6cp->fsm.state)); 33081634Sbrian if (ipv6cp->fsm.state == ST_OPENED) { 33181634Sbrian prompt_Printf(arg->prompt, " His side: %s\n", 33294894Sbrian ncpaddr_ntoa(&ipv6cp->hisaddr)); 33381634Sbrian prompt_Printf(arg->prompt, " My side: %s\n", 33494894Sbrian ncpaddr_ntoa(&ipv6cp->myaddr)); 33581634Sbrian prompt_Printf(arg->prompt, " Queued packets: %lu\n", 33681634Sbrian (unsigned long)ipv6cp_QueueLen(ipv6cp)); 33781634Sbrian } 33881634Sbrian 33981634Sbrian prompt_Printf(arg->prompt, "\nDefaults:\n"); 34081634Sbrian prompt_Printf(arg->prompt, " FSM retry = %us, max %u Config" 34181634Sbrian " REQ%s, %u Term REQ%s\n\n", ipv6cp->cfg.fsm.timeout, 34281634Sbrian ipv6cp->cfg.fsm.maxreq, ipv6cp->cfg.fsm.maxreq == 1 ? "" : "s", 34381634Sbrian ipv6cp->cfg.fsm.maxtrm, ipv6cp->cfg.fsm.maxtrm == 1 ? "" : "s"); 34481634Sbrian 34581634Sbrian throughput_disp(&ipv6cp->throughput, arg->prompt); 34681634Sbrian 34781634Sbrian return 0; 34881634Sbrian} 34981634Sbrian 35081634Sbrianstruct mbuf * 35181634Sbrianipv6cp_Input(struct bundle *bundle, struct link *l, struct mbuf *bp) 35281634Sbrian{ 35381634Sbrian /* Got PROTO_IPV6CP from link */ 35481634Sbrian m_settype(bp, MB_IPV6CPIN); 35581897Sbrian if (bundle_Phase(bundle) == PHASE_NETWORK) 35681634Sbrian fsm_Input(&bundle->ncp.ipv6cp.fsm, bp); 35781634Sbrian else { 35881634Sbrian if (bundle_Phase(bundle) < PHASE_NETWORK) 35981634Sbrian log_Printf(LogIPV6CP, "%s: Error: Unexpected IPV6CP in phase %s" 36081634Sbrian " (ignored)\n", l->name, bundle_PhaseName(bundle)); 36181634Sbrian m_freem(bp); 36281634Sbrian } 36381634Sbrian return NULL; 36481634Sbrian} 36581634Sbrian 36681634Sbrianvoid 36781634Sbrianipv6cp_AddInOctets(struct ipv6cp *ipv6cp, int n) 36881634Sbrian{ 36981634Sbrian throughput_addin(&ipv6cp->throughput, n); 37081634Sbrian} 37181634Sbrian 37281634Sbrianvoid 37381634Sbrianipv6cp_AddOutOctets(struct ipv6cp *ipv6cp, int n) 37481634Sbrian{ 37581634Sbrian throughput_addout(&ipv6cp->throughput, n); 37681634Sbrian} 37781634Sbrian 37881634Sbrianvoid 379134789Sbrianipv6cp_IfaceAddrAdded(struct ipv6cp *ipv6cp __unused, 380134789Sbrian const struct iface_addr *addr __unused) 38181634Sbrian{ 38281634Sbrian} 38381634Sbrian 38481634Sbrianvoid 385134789Sbrianipv6cp_IfaceAddrDeleted(struct ipv6cp *ipv6cp __unused, 386134789Sbrian const struct iface_addr *addr __unused) 38781634Sbrian{ 38881634Sbrian} 38981634Sbrian 39081634Sbrianint 39181634Sbrianipv6cp_InterfaceUp(struct ipv6cp *ipv6cp) 39281634Sbrian{ 393102558Sbrian if (!ipcp_SetIPv6address(ipv6cp, ipv6cp->my_ifid, ipv6cp->his_ifid)) { 39481634Sbrian log_Printf(LogERROR, "ipv6cp_InterfaceUp: unable to set ipv6 address\n"); 39581634Sbrian return 0; 39681634Sbrian } 39781634Sbrian 39881634Sbrian if (!iface_SetFlags(ipv6cp->fsm.bundle->iface->name, IFF_UP)) { 39981634Sbrian log_Printf(LogERROR, "ipv6cp_InterfaceUp: Can't set the IFF_UP" 40081634Sbrian " flag on %s\n", ipv6cp->fsm.bundle->iface->name); 40181634Sbrian return 0; 40281634Sbrian } 40381634Sbrian 40481634Sbrian return 1; 40581634Sbrian} 40681634Sbrian 40781634Sbriansize_t 40881634Sbrianipv6cp_QueueLen(struct ipv6cp *ipv6cp) 40981634Sbrian{ 41081634Sbrian struct mqueue *q; 41181634Sbrian size_t result; 41281634Sbrian 41381634Sbrian result = 0; 41481634Sbrian for (q = ipv6cp->Queue; q < ipv6cp->Queue + IPV6CP_QUEUES(ipv6cp); q++) 41581634Sbrian result += q->len; 41681634Sbrian 41781634Sbrian return result; 41881634Sbrian} 41981634Sbrian 42081634Sbrianint 42181634Sbrianipv6cp_PushPacket(struct ipv6cp *ipv6cp, struct link *l) 42281634Sbrian{ 42381634Sbrian struct bundle *bundle = ipv6cp->fsm.bundle; 42481634Sbrian struct mqueue *queue; 42581634Sbrian struct mbuf *bp; 42681634Sbrian int m_len; 42781634Sbrian u_int32_t secs = 0; 42881634Sbrian unsigned alivesecs = 0; 42981634Sbrian 43081634Sbrian if (ipv6cp->fsm.state != ST_OPENED) 43181634Sbrian return 0; 43281634Sbrian 43381634Sbrian /* 43481634Sbrian * If ccp is not open but is required, do nothing. 43581634Sbrian */ 43681634Sbrian if (l->ccp.fsm.state != ST_OPENED && ccp_Required(&l->ccp)) { 43781634Sbrian log_Printf(LogPHASE, "%s: Not transmitting... waiting for CCP\n", l->name); 43881634Sbrian return 0; 43981634Sbrian } 44081634Sbrian 44181634Sbrian queue = ipv6cp->Queue + IPV6CP_QUEUES(ipv6cp) - 1; 44281634Sbrian do { 44381634Sbrian if (queue->top) { 44481634Sbrian bp = m_dequeue(queue); 44581634Sbrian bp = mbuf_Read(bp, &secs, sizeof secs); 44681634Sbrian bp = m_pullup(bp); 44781634Sbrian m_len = m_length(bp); 44881634Sbrian if (!FilterCheck(MBUF_CTOP(bp), AF_INET6, &bundle->filter.alive, 44981634Sbrian &alivesecs)) { 45081634Sbrian if (secs == 0) 45181634Sbrian secs = alivesecs; 45281634Sbrian bundle_StartIdleTimer(bundle, secs); 45381634Sbrian } 45481634Sbrian link_PushPacket(l, bp, bundle, 0, PROTO_IPV6); 45581634Sbrian ipv6cp_AddOutOctets(ipv6cp, m_len); 45681634Sbrian return 1; 45781634Sbrian } 45881634Sbrian } while (queue-- != ipv6cp->Queue); 45981634Sbrian 46081634Sbrian return 0; 46181634Sbrian} 46281634Sbrian 46381634Sbrianstatic int 46481634Sbrianipv6cp_LayerUp(struct fsm *fp) 46581634Sbrian{ 46681634Sbrian /* We're now up */ 46781634Sbrian struct ipv6cp *ipv6cp = fsm2ipv6cp(fp); 46881634Sbrian char tbuff[40]; 46981634Sbrian 47081634Sbrian log_Printf(LogIPV6CP, "%s: LayerUp.\n", fp->link->name); 47181634Sbrian if (!ipv6cp_InterfaceUp(ipv6cp)) 47281634Sbrian return 0; 47381634Sbrian 47481634Sbrian snprintf(tbuff, sizeof tbuff, "%s", ncpaddr_ntoa(&ipv6cp->myaddr)); 47581634Sbrian log_Printf(LogIPV6CP, "myaddr %s hisaddr = %s\n", 47681634Sbrian tbuff, ncpaddr_ntoa(&ipv6cp->hisaddr)); 47781634Sbrian 478116588Sume#ifndef NORADIUS 479116588Sume radius_Account_Set_Ipv6(&fp->bundle->radacct6, ipv6cp->his_ifid); 480116588Sume radius_Account(&fp->bundle->radius, &fp->bundle->radacct6, 481116588Sume fp->bundle->links, RAD_START, &ipv6cp->throughput); 48281634Sbrian 483116443Sume /* 484116588Sume * XXX: Avoid duplicate evaluation of filterid between IPCP and 485116588Sume * IPV6CP. When IPCP is enabled and rejected, filterid is not 486116588Sume * evaluated. 487116588Sume */ 488116588Sume if (!Enabled(fp->bundle, OPT_IPCP)) { 489116588Sume if (fp->bundle->radius.cfg.file && fp->bundle->radius.filterid) 490116588Sume system_Select(fp->bundle, fp->bundle->radius.filterid, LINKUPFILE, 491116588Sume NULL, NULL); 492116588Sume } 493116588Sume#endif 494116588Sume 495116588Sume /* 496116443Sume * XXX this stuff should really live in the FSM. Our config should 497116443Sume * associate executable sections in files with events. 498116443Sume */ 499116443Sume if (system_Select(fp->bundle, tbuff, LINKUPFILE, NULL, NULL) < 0) { 500116588Sume /* 501116588Sume * XXX: Avoid duplicate evaluation of label between IPCP and 502116588Sume * IPV6CP. When IPCP is enabled and rejected, label is not 503116588Sume * evaluated. 504116588Sume */ 505116443Sume if (bundle_GetLabel(fp->bundle) && !Enabled(fp->bundle, OPT_IPCP)) { 506116443Sume if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle), 507116443Sume LINKUPFILE, NULL, NULL) < 0) 508112613Sume system_Select(fp->bundle, "MYADDR6", LINKUPFILE, NULL, NULL); 509116443Sume } else 510116443Sume system_Select(fp->bundle, "MYADDR6", LINKUPFILE, NULL, NULL); 511112613Sume } 512112613Sume 51381634Sbrian fp->more.reqs = fp->more.naks = fp->more.rejs = ipv6cp->cfg.fsm.maxreq * 3; 51481634Sbrian log_DisplayPrompts(); 51581634Sbrian 51681634Sbrian return 1; 51781634Sbrian} 51881634Sbrian 51981634Sbrianstatic void 52081634Sbrianipv6cp_LayerDown(struct fsm *fp) 52181634Sbrian{ 52281634Sbrian /* About to come down */ 52381634Sbrian struct ipv6cp *ipv6cp = fsm2ipv6cp(fp); 52481634Sbrian static int recursing; 52581634Sbrian char addr[40]; 52681634Sbrian 52781634Sbrian if (!recursing++) { 52881634Sbrian snprintf(addr, sizeof addr, "%s", ncpaddr_ntoa(&ipv6cp->myaddr)); 52981634Sbrian log_Printf(LogIPV6CP, "%s: LayerDown: %s\n", fp->link->name, addr); 53081634Sbrian 531116588Sume#ifndef NORADIUS 532140905Sbrian radius_Flush(&fp->bundle->radius); 533116588Sume radius_Account(&fp->bundle->radius, &fp->bundle->radacct6, 534116588Sume fp->bundle->links, RAD_STOP, &ipv6cp->throughput); 53581634Sbrian 536116443Sume /* 537116588Sume * XXX: Avoid duplicate evaluation of filterid between IPCP and 538116588Sume * IPV6CP. When IPCP is enabled and rejected, filterid is not 539116588Sume * evaluated. 540116588Sume */ 541116588Sume if (!Enabled(fp->bundle, OPT_IPCP)) { 542116588Sume if (fp->bundle->radius.cfg.file && fp->bundle->radius.filterid) 543116588Sume system_Select(fp->bundle, fp->bundle->radius.filterid, LINKDOWNFILE, 544116588Sume NULL, NULL); 545116588Sume } 546116588Sume#endif 547116588Sume 548116588Sume /* 549116443Sume * XXX this stuff should really live in the FSM. Our config should 550116443Sume * associate executable sections in files with events. 551116443Sume */ 552116443Sume if (system_Select(fp->bundle, addr, LINKDOWNFILE, NULL, NULL) < 0) { 553116588Sume /* 554116588Sume * XXX: Avoid duplicate evaluation of label between IPCP and 555116588Sume * IPV6CP. When IPCP is enabled and rejected, label is not 556116588Sume * evaluated. 557116588Sume */ 558116443Sume if (bundle_GetLabel(fp->bundle) && !Enabled(fp->bundle, OPT_IPCP)) { 559116443Sume if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle), 560116443Sume LINKDOWNFILE, NULL, NULL) < 0) 561112613Sume system_Select(fp->bundle, "MYADDR6", LINKDOWNFILE, NULL, NULL); 562116443Sume } else 563116443Sume system_Select(fp->bundle, "MYADDR6", LINKDOWNFILE, NULL, NULL); 564112613Sume } 565112613Sume 56681634Sbrian ipv6cp_Setup(ipv6cp); 56781634Sbrian } 56881634Sbrian recursing--; 56981634Sbrian} 57081634Sbrian 57181634Sbrianstatic void 57281634Sbrianipv6cp_LayerStart(struct fsm *fp) 57381634Sbrian{ 57481634Sbrian /* We're about to start up ! */ 57581634Sbrian struct ipv6cp *ipv6cp = fsm2ipv6cp(fp); 57681634Sbrian 57781634Sbrian log_Printf(LogIPV6CP, "%s: LayerStart.\n", fp->link->name); 57881634Sbrian throughput_start(&ipv6cp->throughput, "IPV6CP throughput", 57981634Sbrian Enabled(fp->bundle, OPT_THROUGHPUT)); 58081634Sbrian fp->more.reqs = fp->more.naks = fp->more.rejs = ipv6cp->cfg.fsm.maxreq * 3; 58181634Sbrian ipv6cp->peer_tokenreq = 0; 58281634Sbrian} 58381634Sbrian 58481634Sbrianstatic void 58581634Sbrianipv6cp_LayerFinish(struct fsm *fp) 58681634Sbrian{ 58781634Sbrian /* We're now down */ 58881634Sbrian struct ipv6cp *ipv6cp = fsm2ipv6cp(fp); 58981634Sbrian 59081634Sbrian log_Printf(LogIPV6CP, "%s: LayerFinish.\n", fp->link->name); 59181634Sbrian throughput_stop(&ipv6cp->throughput); 59281634Sbrian throughput_log(&ipv6cp->throughput, LogIPV6CP, NULL); 59381634Sbrian} 59481634Sbrian 59581634Sbrianstatic void 59681634Sbrianipv6cp_InitRestartCounter(struct fsm *fp, int what) 59781634Sbrian{ 59881634Sbrian /* Set fsm timer load */ 59981634Sbrian struct ipv6cp *ipv6cp = fsm2ipv6cp(fp); 60081634Sbrian 60181634Sbrian fp->FsmTimer.load = ipv6cp->cfg.fsm.timeout * SECTICKS; 60281634Sbrian switch (what) { 60381634Sbrian case FSM_REQ_TIMER: 60481634Sbrian fp->restart = ipv6cp->cfg.fsm.maxreq; 60581634Sbrian break; 60681634Sbrian case FSM_TRM_TIMER: 60781634Sbrian fp->restart = ipv6cp->cfg.fsm.maxtrm; 60881634Sbrian break; 60981634Sbrian default: 61081634Sbrian fp->restart = 1; 61181634Sbrian break; 61281634Sbrian } 61381634Sbrian} 61481634Sbrian 61581634Sbrianstatic void 61681634Sbrianipv6cp_SendConfigReq(struct fsm *fp) 61781634Sbrian{ 61881634Sbrian /* Send config REQ please */ 61981634Sbrian struct physical *p = link2physical(fp->link); 62081634Sbrian struct ipv6cp *ipv6cp = fsm2ipv6cp(fp); 621102558Sbrian u_char buff[IPV6CP_IFIDLEN+2]; 62294894Sbrian struct fsm_opt *o; 62381634Sbrian 62494894Sbrian o = (struct fsm_opt *)buff; 62581634Sbrian 62681634Sbrian if ((p && !physical_IsSync(p)) || !REJECTED(ipv6cp, TY_TOKEN)) { 627102558Sbrian memcpy(o->data, ipv6cp->my_ifid, IPV6CP_IFIDLEN); 628102558Sbrian INC_FSM_OPT(TY_TOKEN, IPV6CP_IFIDLEN + 2, o); 62981634Sbrian } 63081634Sbrian 63181634Sbrian fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, (u_char *)o - buff, 63281634Sbrian MB_IPV6CPOUT); 63381634Sbrian} 63481634Sbrian 63581634Sbrianstatic void 636134789Sbrianipv6cp_SentTerminateReq(struct fsm *fp __unused) 63781634Sbrian{ 63881634Sbrian /* Term REQ just sent by FSM */ 63981634Sbrian} 64081634Sbrian 64181634Sbrianstatic void 64281634Sbrianipv6cp_SendTerminateAck(struct fsm *fp, u_char id) 64381634Sbrian{ 64481634Sbrian /* Send Term ACK please */ 64581634Sbrian fsm_Output(fp, CODE_TERMACK, id, NULL, 0, MB_IPV6CPOUT); 64681634Sbrian} 64781634Sbrian 64881634Sbrianstatic const char * 649134789Sbrianprotoname(unsigned proto) 65081634Sbrian{ 651102558Sbrian static const char *cftypes[] = { "IFACEID", "COMPPROTO" }; 65281634Sbrian 65381634Sbrian if (proto > 0 && proto <= sizeof cftypes / sizeof *cftypes) 65481634Sbrian return cftypes[proto - 1]; 65581634Sbrian 65681634Sbrian return NumStr(proto, NULL, 0); 65781634Sbrian} 65881634Sbrian 65981634Sbrianstatic void 660102558Sbrianipv6cp_ValidateInterfaceID(struct ipv6cp *ipv6cp, u_char *ifid, 661102558Sbrian struct fsm_decode *dec) 66281634Sbrian{ 66394894Sbrian struct fsm_opt opt; 664102558Sbrian u_char zero[IPV6CP_IFIDLEN]; 66594894Sbrian 666102558Sbrian memset(zero, 0, IPV6CP_IFIDLEN); 66781634Sbrian 668102558Sbrian if (memcmp(ifid, zero, IPV6CP_IFIDLEN) != 0 669102558Sbrian && memcmp(ifid, ipv6cp->my_ifid, IPV6CP_IFIDLEN) != 0) 670102558Sbrian memcpy(ipv6cp->his_ifid, ifid, IPV6CP_IFIDLEN); 671102558Sbrian 67294894Sbrian opt.hdr.id = TY_TOKEN; 673102558Sbrian opt.hdr.len = IPV6CP_IFIDLEN + 2; 674102558Sbrian memcpy(opt.data, &ipv6cp->his_ifid, IPV6CP_IFIDLEN); 675102558Sbrian if (memcmp(ifid, ipv6cp->his_ifid, IPV6CP_IFIDLEN) == 0) 67694894Sbrian fsm_ack(dec, &opt); 67794894Sbrian else 67894894Sbrian fsm_nak(dec, &opt); 67981634Sbrian} 68081634Sbrian 68181634Sbrianstatic void 68294894Sbrianipv6cp_DecodeConfig(struct fsm *fp, u_char *cp, u_char *end, int mode_type, 68381634Sbrian struct fsm_decode *dec) 68481634Sbrian{ 68581634Sbrian /* Deal with incoming PROTO_IPV6CP */ 68681634Sbrian struct ipv6cp *ipv6cp = fsm2ipv6cp(fp); 68794894Sbrian int n; 68881634Sbrian char tbuff[100]; 689102558Sbrian u_char ifid[IPV6CP_IFIDLEN], zero[IPV6CP_IFIDLEN]; 69094894Sbrian struct fsm_opt *opt; 69181634Sbrian 692102558Sbrian memset(zero, 0, IPV6CP_IFIDLEN); 693102558Sbrian 694134789Sbrian while (end - cp >= (int)sizeof(opt->hdr)) { 69594894Sbrian if ((opt = fsm_readopt(&cp)) == NULL) 69681634Sbrian break; 69781634Sbrian 69894894Sbrian snprintf(tbuff, sizeof tbuff, " %s[%d]", protoname(opt->hdr.id), 69994894Sbrian opt->hdr.len); 70081634Sbrian 70194894Sbrian switch (opt->hdr.id) { 70281634Sbrian case TY_TOKEN: 703102558Sbrian memcpy(ifid, opt->data, IPV6CP_IFIDLEN); 704102558Sbrian log_Printf(LogIPV6CP, "%s 0x%02x%02x%02x%02x%02x%02x%02x%02x\n", tbuff, 705102558Sbrian ifid[0], ifid[1], ifid[2], ifid[3], ifid[4], ifid[5], ifid[6], ifid[7]); 70681634Sbrian 70781634Sbrian switch (mode_type) { 70881634Sbrian case MODE_REQ: 70981634Sbrian ipv6cp->peer_tokenreq = 1; 710102558Sbrian ipv6cp_ValidateInterfaceID(ipv6cp, ifid, dec); 71194894Sbrian break; 71281634Sbrian 71381634Sbrian case MODE_NAK: 714102558Sbrian if (memcmp(ifid, zero, IPV6CP_IFIDLEN) == 0) { 71594894Sbrian log_Printf(log_IsKept(LogIPV6CP) ? LogIPV6CP : LogPHASE, 716102558Sbrian "0x0000000000000000: Unacceptable IntefaceID!\n"); 71781634Sbrian fsm_Close(&ipv6cp->fsm); 718102558Sbrian } else if (memcmp(ifid, ipv6cp->his_ifid, IPV6CP_IFIDLEN) == 0) { 71994894Sbrian log_Printf(log_IsKept(LogIPV6CP) ? LogIPV6CP : LogPHASE, 720102558Sbrian "0x%02x%02x%02x%02x%02x%02x%02x%02x: " 721102558Sbrian "Unacceptable IntefaceID!\n", 722102558Sbrian ifid[0], ifid[1], ifid[2], ifid[3], 723102558Sbrian ifid[4], ifid[5], ifid[6], ifid[7]); 724102558Sbrian } else if (memcmp(ifid, ipv6cp->my_ifid, IPV6CP_IFIDLEN) != 0) { 72581634Sbrian n = 100; 726102558Sbrian while (n && !ipcp_SetIPv6address(ipv6cp, ifid, ipv6cp->his_ifid)) { 727102558Sbrian do { 728102558Sbrian n--; 729102558Sbrian SetInterfaceID(ifid, 1); 730102558Sbrian } while (n && memcmp(ifid, ipv6cp->his_ifid, IPV6CP_IFIDLEN) == 0); 731102558Sbrian } 73281634Sbrian 73381634Sbrian if (n == 0) { 73494894Sbrian log_Printf(log_IsKept(LogIPV6CP) ? LogIPV6CP : LogPHASE, 735102558Sbrian "0x0000000000000000: Unacceptable IntefaceID!\n"); 73681634Sbrian fsm_Close(&ipv6cp->fsm); 73781634Sbrian } else { 738102558Sbrian log_Printf(LogIPV6CP, "%s changing IntefaceID: " 739102558Sbrian "0x%02x%02x%02x%02x%02x%02x%02x%02x " 740102558Sbrian "--> 0x%02x%02x%02x%02x%02x%02x%02x%02x\n", tbuff, 741102558Sbrian ipv6cp->my_ifid[0], ipv6cp->my_ifid[1], 742102558Sbrian ipv6cp->my_ifid[2], ipv6cp->my_ifid[3], 743102558Sbrian ipv6cp->my_ifid[4], ipv6cp->my_ifid[5], 744102558Sbrian ipv6cp->my_ifid[6], ipv6cp->my_ifid[7], 745102558Sbrian ifid[0], ifid[1], ifid[2], ifid[3], 746102558Sbrian ifid[4], ifid[5], ifid[6], ifid[7]); 747102558Sbrian memcpy(ipv6cp->my_ifid, ifid, IPV6CP_IFIDLEN); 74881634Sbrian bundle_AdjustFilters(fp->bundle, &ipv6cp->myaddr, NULL); 74981634Sbrian } 75081634Sbrian } 75194894Sbrian break; 75281634Sbrian 75381634Sbrian case MODE_REJ: 75494894Sbrian ipv6cp->his_reject |= (1 << opt->hdr.id); 75594894Sbrian break; 75681634Sbrian } 75781634Sbrian break; 75881634Sbrian 75981634Sbrian default: 76081634Sbrian if (mode_type != MODE_NOP) { 76194894Sbrian ipv6cp->my_reject |= (1 << opt->hdr.id); 76294894Sbrian fsm_rej(dec, opt); 76381634Sbrian } 76481634Sbrian break; 76581634Sbrian } 76681634Sbrian } 76781634Sbrian 76881634Sbrian if (mode_type != MODE_NOP) { 76981634Sbrian if (mode_type == MODE_REQ && !ipv6cp->peer_tokenreq) { 77081634Sbrian if (dec->rejend == dec->rej && dec->nakend == dec->nak) { 77181634Sbrian /* 77281634Sbrian * Pretend the peer has requested a TOKEN. 77381634Sbrian * We do this to ensure that we only send one NAK if the only 77481634Sbrian * reason for the NAK is because the peer isn't sending a 77581634Sbrian * TY_TOKEN REQ. This stops us from repeatedly trying to tell 77681634Sbrian * the peer that we have to have an IP address on their end. 77781634Sbrian */ 77881634Sbrian ipv6cp->peer_tokenreq = 1; 77981634Sbrian } 780102558Sbrian memset(ifid, 0, IPV6CP_IFIDLEN); 781102558Sbrian ipv6cp_ValidateInterfaceID(ipv6cp, ifid, dec); 78281634Sbrian } 78394894Sbrian fsm_opt_normalise(dec); 78481634Sbrian } 78581634Sbrian} 78681634Sbrian#endif 787