ipv6cp.c revision 140905
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: head/usr.sbin/ppp/ipv6cp.c 140905 2005-01-27 14:09:33Z brian $ 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: 151102558Sbrian /* XXX need more cases? */ 152102558Sbrian break; 153102558Sbrian default: 154102558Sbrian continue; 155102558Sbrian } 156102558Sbrian 157102558Sbrian cp = (char *)(sdl->sdl_data + sdl->sdl_nlen); 158102558Sbrian ifid[0] = cp[0]; 159102558Sbrian ifid[0] ^= 0x02; /* reverse the u/l bit*/ 160102558Sbrian ifid[1] = cp[1]; 161102558Sbrian ifid[2] = cp[2]; 162102558Sbrian ifid[3] = 0xff; 163102558Sbrian ifid[4] = 0xfe; 164102558Sbrian ifid[5] = cp[3]; 165102558Sbrian ifid[6] = cp[4]; 166102558Sbrian ifid[7] = cp[5]; 167102558Sbrian 168102558Sbrian freeifaddrs(ifap); 169102558Sbrian return; 170102558Sbrian } 171102558Sbrian 172102558Sbrian freeifaddrs(ifap); 173102558Sbrian 174102558Sbrian /* 175102558Sbrian * 2) If an IEEE global identifier is not available a different source 176102558Sbrian * of uniqueness should be used. 177102558Sbrian * XXX: we skip this case. 178102558Sbrian */ 179102558Sbrian 180102558Sbrian /* 181102558Sbrian * 3) If a good source of uniqueness cannot be found, it is 182102558Sbrian * recommended that a random number be generated. In this case the 183102558Sbrian * "u" bit of the interface identifier MUST be set to zero (0). 184102558Sbrian */ 185102558Sbrian randomid: 18681634Sbrian randinit(); 187102558Sbrian r1 = (((u_long)random()) % i32_max) + 1; 188102558Sbrian r2 = (((u_long)random()) % i32_max) + 1; 189102558Sbrian memcpy(ifid, &r1, sizeof(r1)); 190102558Sbrian memcpy(ifid + 4, &r2, sizeof(r2)); 191102558Sbrian ifid[0] &= 0xfd; 192102558Sbrian return; 19381634Sbrian} 19481634Sbrian 19581634Sbrianstatic int 196102558Sbrianipcp_SetIPv6address(struct ipv6cp *ipv6cp, u_char *myifid, u_char *hisifid) 19781634Sbrian{ 19881634Sbrian struct bundle *bundle = ipv6cp->fsm.bundle; 19981634Sbrian struct in6_addr myaddr, hisaddr; 200112618Sume struct ncprange myrange, range; 201112618Sume struct ncpaddr addr; 20281739Sbrian struct sockaddr_storage ssdst, ssgw, ssmask; 20381739Sbrian struct sockaddr *sadst, *sagw, *samask; 20481634Sbrian 20581739Sbrian sadst = (struct sockaddr *)&ssdst; 20681739Sbrian sagw = (struct sockaddr *)&ssgw; 20781739Sbrian samask = (struct sockaddr *)&ssmask; 20881739Sbrian 20981634Sbrian memset(&myaddr, '\0', sizeof myaddr); 21081634Sbrian memset(&hisaddr, '\0', sizeof hisaddr); 21181634Sbrian 21281634Sbrian myaddr.s6_addr[0] = 0xfe; 21381634Sbrian myaddr.s6_addr[1] = 0x80; 214102558Sbrian memcpy(&myaddr.s6_addr[8], myifid, IPV6CP_IFIDLEN); 215102558Sbrian#if 0 216102558Sbrian myaddr.s6_addr[8] |= 0x02; /* set 'universal' bit */ 217102558Sbrian#endif 21881634Sbrian 21981634Sbrian hisaddr.s6_addr[0] = 0xfe; 22081634Sbrian hisaddr.s6_addr[1] = 0x80; 221102558Sbrian memcpy(&hisaddr.s6_addr[8], hisifid, IPV6CP_IFIDLEN); 222102558Sbrian#if 0 223102558Sbrian hisaddr.s6_addr[8] |= 0x02; /* set 'universal' bit */ 224102558Sbrian#endif 22581634Sbrian 22681634Sbrian ncpaddr_setip6(&ipv6cp->myaddr, &myaddr); 22781634Sbrian ncpaddr_setip6(&ipv6cp->hisaddr, &hisaddr); 228113067Sume ncprange_set(&myrange, &ipv6cp->myaddr, 64); 22981634Sbrian 23081634Sbrian if (!iface_Add(bundle->iface, &bundle->ncp, &myrange, &ipv6cp->hisaddr, 23181634Sbrian IFACE_ADD_FIRST|IFACE_FORCE_ADD|IFACE_SYSTEM)) 23281634Sbrian return 0; 23381634Sbrian 23481634Sbrian if (!Enabled(bundle, OPT_IFACEALIAS)) 23581634Sbrian iface_Clear(bundle->iface, &bundle->ncp, AF_INET6, 23681634Sbrian IFACE_CLEAR_ALIASES|IFACE_SYSTEM); 23781634Sbrian 238112618Sume ncpaddr_setip6(&addr, &in6addr_linklocal_mcast); 239112618Sume ncprange_set(&range, &addr, 32); 240112618Sume rt_Set(bundle, RTM_ADD, &range, &ipv6cp->myaddr, 1, 0); 241112618Sume 24281634Sbrian if (bundle->ncp.cfg.sendpipe > 0 || bundle->ncp.cfg.recvpipe > 0) { 24381739Sbrian ncprange_getsa(&myrange, &ssgw, &ssmask); 24481739Sbrian if (ncpaddr_isset(&ipv6cp->hisaddr)) 24581739Sbrian ncpaddr_getsa(&ipv6cp->hisaddr, &ssdst); 24681739Sbrian else 24781739Sbrian sadst = NULL; 24881739Sbrian rt_Update(bundle, sadst, sagw, samask); 24981634Sbrian } 25081634Sbrian 25181634Sbrian if (Enabled(bundle, OPT_SROUTES)) 25281634Sbrian route_Change(bundle, bundle->ncp.route, &ipv6cp->myaddr, &ipv6cp->hisaddr); 25381634Sbrian 25481634Sbrian#ifndef NORADIUS 25581634Sbrian if (bundle->radius.valid) 256116586Sume route_Change(bundle, bundle->radius.ipv6routes, &ipv6cp->myaddr, 25781634Sbrian &ipv6cp->hisaddr); 25881634Sbrian#endif 25981634Sbrian 26081634Sbrian return 1; /* Ok */ 26181634Sbrian} 26281634Sbrian 26381634Sbrianvoid 26481634Sbrianipv6cp_Init(struct ipv6cp *ipv6cp, struct bundle *bundle, struct link *l, 26581634Sbrian const struct fsm_parent *parent) 26681634Sbrian{ 26781634Sbrian static const char * const timer_names[] = 26881634Sbrian {"IPV6CP restart", "IPV6CP openmode", "IPV6CP stopped"}; 26981634Sbrian int n; 27081634Sbrian 27181634Sbrian fsm_Init(&ipv6cp->fsm, "IPV6CP", PROTO_IPV6CP, 1, IPV6CP_MAXCODE, LogIPV6CP, 27281634Sbrian bundle, l, parent, &ipv6cp_Callbacks, timer_names); 27381634Sbrian 27481634Sbrian ipv6cp->cfg.fsm.timeout = DEF_FSMRETRY; 27581634Sbrian ipv6cp->cfg.fsm.maxreq = DEF_FSMTRIES; 27681634Sbrian ipv6cp->cfg.fsm.maxtrm = DEF_FSMTRIES; 27781634Sbrian 278102558Sbrian SetInterfaceID(ipv6cp->my_ifid, 0); 279102558Sbrian do { 280102558Sbrian SetInterfaceID(ipv6cp->his_ifid, 1); 281102558Sbrian } while (memcmp(ipv6cp->his_ifid, ipv6cp->my_ifid, IPV6CP_IFIDLEN) == 0); 28281634Sbrian 28381897Sbrian if (probe.ipv6_available) { 28481897Sbrian n = 100; 28581897Sbrian while (n && 286102558Sbrian !ipcp_SetIPv6address(ipv6cp, ipv6cp->my_ifid, ipv6cp->his_ifid)) { 287102558Sbrian do { 288102558Sbrian n--; 289102558Sbrian SetInterfaceID(ipv6cp->my_ifid, 1); 290102558Sbrian } while (n 291102558Sbrian && memcmp(ipv6cp->his_ifid, ipv6cp->my_ifid, IPV6CP_IFIDLEN) == 0); 29281897Sbrian } 29381897Sbrian } 29481634Sbrian 29581634Sbrian throughput_init(&ipv6cp->throughput, SAMPLE_PERIOD); 29681634Sbrian memset(ipv6cp->Queue, '\0', sizeof ipv6cp->Queue); 29781634Sbrian ipv6cp_Setup(ipv6cp); 29881634Sbrian} 29981634Sbrian 30081634Sbrianvoid 30181634Sbrianipv6cp_Destroy(struct ipv6cp *ipv6cp) 30281634Sbrian{ 30381634Sbrian throughput_destroy(&ipv6cp->throughput); 30481634Sbrian} 30581634Sbrian 30681634Sbrianvoid 30781634Sbrianipv6cp_Setup(struct ipv6cp *ipv6cp) 30881634Sbrian{ 30981634Sbrian ncpaddr_init(&ipv6cp->myaddr); 31081634Sbrian ncpaddr_init(&ipv6cp->hisaddr); 31181634Sbrian 31281634Sbrian ipv6cp->his_reject = 0; 31381634Sbrian ipv6cp->my_reject = 0; 31481634Sbrian} 31581634Sbrian 31681634Sbrianvoid 31781634Sbrianipv6cp_SetLink(struct ipv6cp *ipv6cp, struct link *l) 31881634Sbrian{ 31981634Sbrian ipv6cp->fsm.link = l; 32081634Sbrian} 32181634Sbrian 32281634Sbrianint 32381634Sbrianipv6cp_Show(struct cmdargs const *arg) 32481634Sbrian{ 32581634Sbrian struct ipv6cp *ipv6cp = &arg->bundle->ncp.ipv6cp; 32681634Sbrian 32781634Sbrian prompt_Printf(arg->prompt, "%s [%s]\n", ipv6cp->fsm.name, 32881634Sbrian State2Nam(ipv6cp->fsm.state)); 32981634Sbrian if (ipv6cp->fsm.state == ST_OPENED) { 33081634Sbrian prompt_Printf(arg->prompt, " His side: %s\n", 33194894Sbrian ncpaddr_ntoa(&ipv6cp->hisaddr)); 33281634Sbrian prompt_Printf(arg->prompt, " My side: %s\n", 33394894Sbrian ncpaddr_ntoa(&ipv6cp->myaddr)); 33481634Sbrian prompt_Printf(arg->prompt, " Queued packets: %lu\n", 33581634Sbrian (unsigned long)ipv6cp_QueueLen(ipv6cp)); 33681634Sbrian } 33781634Sbrian 33881634Sbrian prompt_Printf(arg->prompt, "\nDefaults:\n"); 33981634Sbrian prompt_Printf(arg->prompt, " FSM retry = %us, max %u Config" 34081634Sbrian " REQ%s, %u Term REQ%s\n\n", ipv6cp->cfg.fsm.timeout, 34181634Sbrian ipv6cp->cfg.fsm.maxreq, ipv6cp->cfg.fsm.maxreq == 1 ? "" : "s", 34281634Sbrian ipv6cp->cfg.fsm.maxtrm, ipv6cp->cfg.fsm.maxtrm == 1 ? "" : "s"); 34381634Sbrian 34481634Sbrian throughput_disp(&ipv6cp->throughput, arg->prompt); 34581634Sbrian 34681634Sbrian return 0; 34781634Sbrian} 34881634Sbrian 34981634Sbrianstruct mbuf * 35081634Sbrianipv6cp_Input(struct bundle *bundle, struct link *l, struct mbuf *bp) 35181634Sbrian{ 35281634Sbrian /* Got PROTO_IPV6CP from link */ 35381634Sbrian m_settype(bp, MB_IPV6CPIN); 35481897Sbrian if (bundle_Phase(bundle) == PHASE_NETWORK) 35581634Sbrian fsm_Input(&bundle->ncp.ipv6cp.fsm, bp); 35681634Sbrian else { 35781634Sbrian if (bundle_Phase(bundle) < PHASE_NETWORK) 35881634Sbrian log_Printf(LogIPV6CP, "%s: Error: Unexpected IPV6CP in phase %s" 35981634Sbrian " (ignored)\n", l->name, bundle_PhaseName(bundle)); 36081634Sbrian m_freem(bp); 36181634Sbrian } 36281634Sbrian return NULL; 36381634Sbrian} 36481634Sbrian 36581634Sbrianvoid 36681634Sbrianipv6cp_AddInOctets(struct ipv6cp *ipv6cp, int n) 36781634Sbrian{ 36881634Sbrian throughput_addin(&ipv6cp->throughput, n); 36981634Sbrian} 37081634Sbrian 37181634Sbrianvoid 37281634Sbrianipv6cp_AddOutOctets(struct ipv6cp *ipv6cp, int n) 37381634Sbrian{ 37481634Sbrian throughput_addout(&ipv6cp->throughput, n); 37581634Sbrian} 37681634Sbrian 37781634Sbrianvoid 378134789Sbrianipv6cp_IfaceAddrAdded(struct ipv6cp *ipv6cp __unused, 379134789Sbrian const struct iface_addr *addr __unused) 38081634Sbrian{ 38181634Sbrian} 38281634Sbrian 38381634Sbrianvoid 384134789Sbrianipv6cp_IfaceAddrDeleted(struct ipv6cp *ipv6cp __unused, 385134789Sbrian const struct iface_addr *addr __unused) 38681634Sbrian{ 38781634Sbrian} 38881634Sbrian 38981634Sbrianint 39081634Sbrianipv6cp_InterfaceUp(struct ipv6cp *ipv6cp) 39181634Sbrian{ 392102558Sbrian if (!ipcp_SetIPv6address(ipv6cp, ipv6cp->my_ifid, ipv6cp->his_ifid)) { 39381634Sbrian log_Printf(LogERROR, "ipv6cp_InterfaceUp: unable to set ipv6 address\n"); 39481634Sbrian return 0; 39581634Sbrian } 39681634Sbrian 39781634Sbrian if (!iface_SetFlags(ipv6cp->fsm.bundle->iface->name, IFF_UP)) { 39881634Sbrian log_Printf(LogERROR, "ipv6cp_InterfaceUp: Can't set the IFF_UP" 39981634Sbrian " flag on %s\n", ipv6cp->fsm.bundle->iface->name); 40081634Sbrian return 0; 40181634Sbrian } 40281634Sbrian 40381634Sbrian return 1; 40481634Sbrian} 40581634Sbrian 40681634Sbriansize_t 40781634Sbrianipv6cp_QueueLen(struct ipv6cp *ipv6cp) 40881634Sbrian{ 40981634Sbrian struct mqueue *q; 41081634Sbrian size_t result; 41181634Sbrian 41281634Sbrian result = 0; 41381634Sbrian for (q = ipv6cp->Queue; q < ipv6cp->Queue + IPV6CP_QUEUES(ipv6cp); q++) 41481634Sbrian result += q->len; 41581634Sbrian 41681634Sbrian return result; 41781634Sbrian} 41881634Sbrian 41981634Sbrianint 42081634Sbrianipv6cp_PushPacket(struct ipv6cp *ipv6cp, struct link *l) 42181634Sbrian{ 42281634Sbrian struct bundle *bundle = ipv6cp->fsm.bundle; 42381634Sbrian struct mqueue *queue; 42481634Sbrian struct mbuf *bp; 42581634Sbrian int m_len; 42681634Sbrian u_int32_t secs = 0; 42781634Sbrian unsigned alivesecs = 0; 42881634Sbrian 42981634Sbrian if (ipv6cp->fsm.state != ST_OPENED) 43081634Sbrian return 0; 43181634Sbrian 43281634Sbrian /* 43381634Sbrian * If ccp is not open but is required, do nothing. 43481634Sbrian */ 43581634Sbrian if (l->ccp.fsm.state != ST_OPENED && ccp_Required(&l->ccp)) { 43681634Sbrian log_Printf(LogPHASE, "%s: Not transmitting... waiting for CCP\n", l->name); 43781634Sbrian return 0; 43881634Sbrian } 43981634Sbrian 44081634Sbrian queue = ipv6cp->Queue + IPV6CP_QUEUES(ipv6cp) - 1; 44181634Sbrian do { 44281634Sbrian if (queue->top) { 44381634Sbrian bp = m_dequeue(queue); 44481634Sbrian bp = mbuf_Read(bp, &secs, sizeof secs); 44581634Sbrian bp = m_pullup(bp); 44681634Sbrian m_len = m_length(bp); 44781634Sbrian if (!FilterCheck(MBUF_CTOP(bp), AF_INET6, &bundle->filter.alive, 44881634Sbrian &alivesecs)) { 44981634Sbrian if (secs == 0) 45081634Sbrian secs = alivesecs; 45181634Sbrian bundle_StartIdleTimer(bundle, secs); 45281634Sbrian } 45381634Sbrian link_PushPacket(l, bp, bundle, 0, PROTO_IPV6); 45481634Sbrian ipv6cp_AddOutOctets(ipv6cp, m_len); 45581634Sbrian return 1; 45681634Sbrian } 45781634Sbrian } while (queue-- != ipv6cp->Queue); 45881634Sbrian 45981634Sbrian return 0; 46081634Sbrian} 46181634Sbrian 46281634Sbrianstatic int 46381634Sbrianipv6cp_LayerUp(struct fsm *fp) 46481634Sbrian{ 46581634Sbrian /* We're now up */ 46681634Sbrian struct ipv6cp *ipv6cp = fsm2ipv6cp(fp); 46781634Sbrian char tbuff[40]; 46881634Sbrian 46981634Sbrian log_Printf(LogIPV6CP, "%s: LayerUp.\n", fp->link->name); 47081634Sbrian if (!ipv6cp_InterfaceUp(ipv6cp)) 47181634Sbrian return 0; 47281634Sbrian 47381634Sbrian snprintf(tbuff, sizeof tbuff, "%s", ncpaddr_ntoa(&ipv6cp->myaddr)); 47481634Sbrian log_Printf(LogIPV6CP, "myaddr %s hisaddr = %s\n", 47581634Sbrian tbuff, ncpaddr_ntoa(&ipv6cp->hisaddr)); 47681634Sbrian 477116588Sume#ifndef NORADIUS 478116588Sume radius_Account_Set_Ipv6(&fp->bundle->radacct6, ipv6cp->his_ifid); 479116588Sume radius_Account(&fp->bundle->radius, &fp->bundle->radacct6, 480116588Sume fp->bundle->links, RAD_START, &ipv6cp->throughput); 48181634Sbrian 482116443Sume /* 483116588Sume * XXX: Avoid duplicate evaluation of filterid between IPCP and 484116588Sume * IPV6CP. When IPCP is enabled and rejected, filterid is not 485116588Sume * evaluated. 486116588Sume */ 487116588Sume if (!Enabled(fp->bundle, OPT_IPCP)) { 488116588Sume if (fp->bundle->radius.cfg.file && fp->bundle->radius.filterid) 489116588Sume system_Select(fp->bundle, fp->bundle->radius.filterid, LINKUPFILE, 490116588Sume NULL, NULL); 491116588Sume } 492116588Sume#endif 493116588Sume 494116588Sume /* 495116443Sume * XXX this stuff should really live in the FSM. Our config should 496116443Sume * associate executable sections in files with events. 497116443Sume */ 498116443Sume if (system_Select(fp->bundle, tbuff, LINKUPFILE, NULL, NULL) < 0) { 499116588Sume /* 500116588Sume * XXX: Avoid duplicate evaluation of label between IPCP and 501116588Sume * IPV6CP. When IPCP is enabled and rejected, label is not 502116588Sume * evaluated. 503116588Sume */ 504116443Sume if (bundle_GetLabel(fp->bundle) && !Enabled(fp->bundle, OPT_IPCP)) { 505116443Sume if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle), 506116443Sume LINKUPFILE, NULL, NULL) < 0) 507112613Sume system_Select(fp->bundle, "MYADDR6", LINKUPFILE, NULL, NULL); 508116443Sume } else 509116443Sume system_Select(fp->bundle, "MYADDR6", LINKUPFILE, NULL, NULL); 510112613Sume } 511112613Sume 51281634Sbrian fp->more.reqs = fp->more.naks = fp->more.rejs = ipv6cp->cfg.fsm.maxreq * 3; 51381634Sbrian log_DisplayPrompts(); 51481634Sbrian 51581634Sbrian return 1; 51681634Sbrian} 51781634Sbrian 51881634Sbrianstatic void 51981634Sbrianipv6cp_LayerDown(struct fsm *fp) 52081634Sbrian{ 52181634Sbrian /* About to come down */ 52281634Sbrian struct ipv6cp *ipv6cp = fsm2ipv6cp(fp); 52381634Sbrian static int recursing; 52481634Sbrian char addr[40]; 52581634Sbrian 52681634Sbrian if (!recursing++) { 52781634Sbrian snprintf(addr, sizeof addr, "%s", ncpaddr_ntoa(&ipv6cp->myaddr)); 52881634Sbrian log_Printf(LogIPV6CP, "%s: LayerDown: %s\n", fp->link->name, addr); 52981634Sbrian 530116588Sume#ifndef NORADIUS 531140905Sbrian radius_Flush(&fp->bundle->radius); 532116588Sume radius_Account(&fp->bundle->radius, &fp->bundle->radacct6, 533116588Sume fp->bundle->links, RAD_STOP, &ipv6cp->throughput); 53481634Sbrian 535116443Sume /* 536116588Sume * XXX: Avoid duplicate evaluation of filterid between IPCP and 537116588Sume * IPV6CP. When IPCP is enabled and rejected, filterid is not 538116588Sume * evaluated. 539116588Sume */ 540116588Sume if (!Enabled(fp->bundle, OPT_IPCP)) { 541116588Sume if (fp->bundle->radius.cfg.file && fp->bundle->radius.filterid) 542116588Sume system_Select(fp->bundle, fp->bundle->radius.filterid, LINKDOWNFILE, 543116588Sume NULL, NULL); 544116588Sume } 545116588Sume#endif 546116588Sume 547116588Sume /* 548116443Sume * XXX this stuff should really live in the FSM. Our config should 549116443Sume * associate executable sections in files with events. 550116443Sume */ 551116443Sume if (system_Select(fp->bundle, addr, LINKDOWNFILE, NULL, NULL) < 0) { 552116588Sume /* 553116588Sume * XXX: Avoid duplicate evaluation of label between IPCP and 554116588Sume * IPV6CP. When IPCP is enabled and rejected, label is not 555116588Sume * evaluated. 556116588Sume */ 557116443Sume if (bundle_GetLabel(fp->bundle) && !Enabled(fp->bundle, OPT_IPCP)) { 558116443Sume if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle), 559116443Sume LINKDOWNFILE, NULL, NULL) < 0) 560112613Sume system_Select(fp->bundle, "MYADDR6", LINKDOWNFILE, NULL, NULL); 561116443Sume } else 562116443Sume system_Select(fp->bundle, "MYADDR6", LINKDOWNFILE, NULL, NULL); 563112613Sume } 564112613Sume 56581634Sbrian ipv6cp_Setup(ipv6cp); 56681634Sbrian } 56781634Sbrian recursing--; 56881634Sbrian} 56981634Sbrian 57081634Sbrianstatic void 57181634Sbrianipv6cp_LayerStart(struct fsm *fp) 57281634Sbrian{ 57381634Sbrian /* We're about to start up ! */ 57481634Sbrian struct ipv6cp *ipv6cp = fsm2ipv6cp(fp); 57581634Sbrian 57681634Sbrian log_Printf(LogIPV6CP, "%s: LayerStart.\n", fp->link->name); 57781634Sbrian throughput_start(&ipv6cp->throughput, "IPV6CP throughput", 57881634Sbrian Enabled(fp->bundle, OPT_THROUGHPUT)); 57981634Sbrian fp->more.reqs = fp->more.naks = fp->more.rejs = ipv6cp->cfg.fsm.maxreq * 3; 58081634Sbrian ipv6cp->peer_tokenreq = 0; 58181634Sbrian} 58281634Sbrian 58381634Sbrianstatic void 58481634Sbrianipv6cp_LayerFinish(struct fsm *fp) 58581634Sbrian{ 58681634Sbrian /* We're now down */ 58781634Sbrian struct ipv6cp *ipv6cp = fsm2ipv6cp(fp); 58881634Sbrian 58981634Sbrian log_Printf(LogIPV6CP, "%s: LayerFinish.\n", fp->link->name); 59081634Sbrian throughput_stop(&ipv6cp->throughput); 59181634Sbrian throughput_log(&ipv6cp->throughput, LogIPV6CP, NULL); 59281634Sbrian} 59381634Sbrian 59481634Sbrianstatic void 59581634Sbrianipv6cp_InitRestartCounter(struct fsm *fp, int what) 59681634Sbrian{ 59781634Sbrian /* Set fsm timer load */ 59881634Sbrian struct ipv6cp *ipv6cp = fsm2ipv6cp(fp); 59981634Sbrian 60081634Sbrian fp->FsmTimer.load = ipv6cp->cfg.fsm.timeout * SECTICKS; 60181634Sbrian switch (what) { 60281634Sbrian case FSM_REQ_TIMER: 60381634Sbrian fp->restart = ipv6cp->cfg.fsm.maxreq; 60481634Sbrian break; 60581634Sbrian case FSM_TRM_TIMER: 60681634Sbrian fp->restart = ipv6cp->cfg.fsm.maxtrm; 60781634Sbrian break; 60881634Sbrian default: 60981634Sbrian fp->restart = 1; 61081634Sbrian break; 61181634Sbrian } 61281634Sbrian} 61381634Sbrian 61481634Sbrianstatic void 61581634Sbrianipv6cp_SendConfigReq(struct fsm *fp) 61681634Sbrian{ 61781634Sbrian /* Send config REQ please */ 61881634Sbrian struct physical *p = link2physical(fp->link); 61981634Sbrian struct ipv6cp *ipv6cp = fsm2ipv6cp(fp); 620102558Sbrian u_char buff[IPV6CP_IFIDLEN+2]; 62194894Sbrian struct fsm_opt *o; 62281634Sbrian 62394894Sbrian o = (struct fsm_opt *)buff; 62481634Sbrian 62581634Sbrian if ((p && !physical_IsSync(p)) || !REJECTED(ipv6cp, TY_TOKEN)) { 626102558Sbrian memcpy(o->data, ipv6cp->my_ifid, IPV6CP_IFIDLEN); 627102558Sbrian INC_FSM_OPT(TY_TOKEN, IPV6CP_IFIDLEN + 2, o); 62881634Sbrian } 62981634Sbrian 63081634Sbrian fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, (u_char *)o - buff, 63181634Sbrian MB_IPV6CPOUT); 63281634Sbrian} 63381634Sbrian 63481634Sbrianstatic void 635134789Sbrianipv6cp_SentTerminateReq(struct fsm *fp __unused) 63681634Sbrian{ 63781634Sbrian /* Term REQ just sent by FSM */ 63881634Sbrian} 63981634Sbrian 64081634Sbrianstatic void 64181634Sbrianipv6cp_SendTerminateAck(struct fsm *fp, u_char id) 64281634Sbrian{ 64381634Sbrian /* Send Term ACK please */ 64481634Sbrian fsm_Output(fp, CODE_TERMACK, id, NULL, 0, MB_IPV6CPOUT); 64581634Sbrian} 64681634Sbrian 64781634Sbrianstatic const char * 648134789Sbrianprotoname(unsigned proto) 64981634Sbrian{ 650102558Sbrian static const char *cftypes[] = { "IFACEID", "COMPPROTO" }; 65181634Sbrian 65281634Sbrian if (proto > 0 && proto <= sizeof cftypes / sizeof *cftypes) 65381634Sbrian return cftypes[proto - 1]; 65481634Sbrian 65581634Sbrian return NumStr(proto, NULL, 0); 65681634Sbrian} 65781634Sbrian 65881634Sbrianstatic void 659102558Sbrianipv6cp_ValidateInterfaceID(struct ipv6cp *ipv6cp, u_char *ifid, 660102558Sbrian struct fsm_decode *dec) 66181634Sbrian{ 66294894Sbrian struct fsm_opt opt; 663102558Sbrian u_char zero[IPV6CP_IFIDLEN]; 66494894Sbrian 665102558Sbrian memset(zero, 0, IPV6CP_IFIDLEN); 66681634Sbrian 667102558Sbrian if (memcmp(ifid, zero, IPV6CP_IFIDLEN) != 0 668102558Sbrian && memcmp(ifid, ipv6cp->my_ifid, IPV6CP_IFIDLEN) != 0) 669102558Sbrian memcpy(ipv6cp->his_ifid, ifid, IPV6CP_IFIDLEN); 670102558Sbrian 67194894Sbrian opt.hdr.id = TY_TOKEN; 672102558Sbrian opt.hdr.len = IPV6CP_IFIDLEN + 2; 673102558Sbrian memcpy(opt.data, &ipv6cp->his_ifid, IPV6CP_IFIDLEN); 674102558Sbrian if (memcmp(ifid, ipv6cp->his_ifid, IPV6CP_IFIDLEN) == 0) 67594894Sbrian fsm_ack(dec, &opt); 67694894Sbrian else 67794894Sbrian fsm_nak(dec, &opt); 67881634Sbrian} 67981634Sbrian 68081634Sbrianstatic void 68194894Sbrianipv6cp_DecodeConfig(struct fsm *fp, u_char *cp, u_char *end, int mode_type, 68281634Sbrian struct fsm_decode *dec) 68381634Sbrian{ 68481634Sbrian /* Deal with incoming PROTO_IPV6CP */ 68581634Sbrian struct ipv6cp *ipv6cp = fsm2ipv6cp(fp); 68694894Sbrian int n; 68781634Sbrian char tbuff[100]; 688102558Sbrian u_char ifid[IPV6CP_IFIDLEN], zero[IPV6CP_IFIDLEN]; 68994894Sbrian struct fsm_opt *opt; 69081634Sbrian 691102558Sbrian memset(zero, 0, IPV6CP_IFIDLEN); 692102558Sbrian 693134789Sbrian while (end - cp >= (int)sizeof(opt->hdr)) { 69494894Sbrian if ((opt = fsm_readopt(&cp)) == NULL) 69581634Sbrian break; 69681634Sbrian 69794894Sbrian snprintf(tbuff, sizeof tbuff, " %s[%d]", protoname(opt->hdr.id), 69894894Sbrian opt->hdr.len); 69981634Sbrian 70094894Sbrian switch (opt->hdr.id) { 70181634Sbrian case TY_TOKEN: 702102558Sbrian memcpy(ifid, opt->data, IPV6CP_IFIDLEN); 703102558Sbrian log_Printf(LogIPV6CP, "%s 0x%02x%02x%02x%02x%02x%02x%02x%02x\n", tbuff, 704102558Sbrian ifid[0], ifid[1], ifid[2], ifid[3], ifid[4], ifid[5], ifid[6], ifid[7]); 70581634Sbrian 70681634Sbrian switch (mode_type) { 70781634Sbrian case MODE_REQ: 70881634Sbrian ipv6cp->peer_tokenreq = 1; 709102558Sbrian ipv6cp_ValidateInterfaceID(ipv6cp, ifid, dec); 71094894Sbrian break; 71181634Sbrian 71281634Sbrian case MODE_NAK: 713102558Sbrian if (memcmp(ifid, zero, IPV6CP_IFIDLEN) == 0) { 71494894Sbrian log_Printf(log_IsKept(LogIPV6CP) ? LogIPV6CP : LogPHASE, 715102558Sbrian "0x0000000000000000: Unacceptable IntefaceID!\n"); 71681634Sbrian fsm_Close(&ipv6cp->fsm); 717102558Sbrian } else if (memcmp(ifid, ipv6cp->his_ifid, IPV6CP_IFIDLEN) == 0) { 71894894Sbrian log_Printf(log_IsKept(LogIPV6CP) ? LogIPV6CP : LogPHASE, 719102558Sbrian "0x%02x%02x%02x%02x%02x%02x%02x%02x: " 720102558Sbrian "Unacceptable IntefaceID!\n", 721102558Sbrian ifid[0], ifid[1], ifid[2], ifid[3], 722102558Sbrian ifid[4], ifid[5], ifid[6], ifid[7]); 723102558Sbrian } else if (memcmp(ifid, ipv6cp->my_ifid, IPV6CP_IFIDLEN) != 0) { 72481634Sbrian n = 100; 725102558Sbrian while (n && !ipcp_SetIPv6address(ipv6cp, ifid, ipv6cp->his_ifid)) { 726102558Sbrian do { 727102558Sbrian n--; 728102558Sbrian SetInterfaceID(ifid, 1); 729102558Sbrian } while (n && memcmp(ifid, ipv6cp->his_ifid, IPV6CP_IFIDLEN) == 0); 730102558Sbrian } 73181634Sbrian 73281634Sbrian if (n == 0) { 73394894Sbrian log_Printf(log_IsKept(LogIPV6CP) ? LogIPV6CP : LogPHASE, 734102558Sbrian "0x0000000000000000: Unacceptable IntefaceID!\n"); 73581634Sbrian fsm_Close(&ipv6cp->fsm); 73681634Sbrian } else { 737102558Sbrian log_Printf(LogIPV6CP, "%s changing IntefaceID: " 738102558Sbrian "0x%02x%02x%02x%02x%02x%02x%02x%02x " 739102558Sbrian "--> 0x%02x%02x%02x%02x%02x%02x%02x%02x\n", tbuff, 740102558Sbrian ipv6cp->my_ifid[0], ipv6cp->my_ifid[1], 741102558Sbrian ipv6cp->my_ifid[2], ipv6cp->my_ifid[3], 742102558Sbrian ipv6cp->my_ifid[4], ipv6cp->my_ifid[5], 743102558Sbrian ipv6cp->my_ifid[6], ipv6cp->my_ifid[7], 744102558Sbrian ifid[0], ifid[1], ifid[2], ifid[3], 745102558Sbrian ifid[4], ifid[5], ifid[6], ifid[7]); 746102558Sbrian memcpy(ipv6cp->my_ifid, ifid, IPV6CP_IFIDLEN); 74781634Sbrian bundle_AdjustFilters(fp->bundle, &ipv6cp->myaddr, NULL); 74881634Sbrian } 74981634Sbrian } 75094894Sbrian break; 75181634Sbrian 75281634Sbrian case MODE_REJ: 75394894Sbrian ipv6cp->his_reject |= (1 << opt->hdr.id); 75494894Sbrian break; 75581634Sbrian } 75681634Sbrian break; 75781634Sbrian 75881634Sbrian default: 75981634Sbrian if (mode_type != MODE_NOP) { 76094894Sbrian ipv6cp->my_reject |= (1 << opt->hdr.id); 76194894Sbrian fsm_rej(dec, opt); 76281634Sbrian } 76381634Sbrian break; 76481634Sbrian } 76581634Sbrian } 76681634Sbrian 76781634Sbrian if (mode_type != MODE_NOP) { 76881634Sbrian if (mode_type == MODE_REQ && !ipv6cp->peer_tokenreq) { 76981634Sbrian if (dec->rejend == dec->rej && dec->nakend == dec->nak) { 77081634Sbrian /* 77181634Sbrian * Pretend the peer has requested a TOKEN. 77281634Sbrian * We do this to ensure that we only send one NAK if the only 77381634Sbrian * reason for the NAK is because the peer isn't sending a 77481634Sbrian * TY_TOKEN REQ. This stops us from repeatedly trying to tell 77581634Sbrian * the peer that we have to have an IP address on their end. 77681634Sbrian */ 77781634Sbrian ipv6cp->peer_tokenreq = 1; 77881634Sbrian } 779102558Sbrian memset(ifid, 0, IPV6CP_IFIDLEN); 780102558Sbrian ipv6cp_ValidateInterfaceID(ipv6cp, ifid, dec); 78181634Sbrian } 78294894Sbrian fsm_opt_normalise(dec); 78381634Sbrian } 78481634Sbrian} 78581634Sbrian#endif 786