1226031Sstas/*- 2226031Sstas * Copyright (c) 2001 Brian Somers <brian@Awfulhak.org> 3226031Sstas * All rights reserved. 4226031Sstas * 5226031Sstas * Redistribution and use in source and binary forms, with or without 6226031Sstas * modification, are permitted provided that the following conditions 7226031Sstas * are met: 8226031Sstas * 1. Redistributions of source code must retain the above copyright 9226031Sstas * notice, this list of conditions and the following disclaimer. 10226031Sstas * 2. Redistributions in binary form must reproduce the above copyright 11226031Sstas * notice, this list of conditions and the following disclaimer in the 12226031Sstas * documentation and/or other materials provided with the distribution. 13226031Sstas * 14226031Sstas * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15226031Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16226031Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17226031Sstas * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18226031Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19226031Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20226031Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21226031Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22226031Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23226031Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24226031Sstas * SUCH DAMAGE. 25226031Sstas * 26226031Sstas * $FreeBSD$ 27226031Sstas */ 28226031Sstas 29226031Sstas#include <sys/param.h> 30226031Sstas#include <netinet/in_systm.h> 31226031Sstas#include <netinet/in.h> 32226031Sstas#include <netinet/ip.h> 33226031Sstas#include <sys/socket.h> 34226031Sstas#include <net/route.h> 35226031Sstas#include <net/if.h> 36226031Sstas#include <net/if_types.h> 37226031Sstas#include <net/if_dl.h> 38226031Sstas#include <sys/un.h> 39226031Sstas 40226031Sstas#include <stdarg.h> 41226031Sstas#include <stdio.h> 42226031Sstas#include <stdlib.h> 43226031Sstas#include <string.h> 44226031Sstas#include <termios.h> 45226031Sstas#include <ifaddrs.h> 46226031Sstas 47226031Sstas#include "layer.h" 48226031Sstas#include "defs.h" 49226031Sstas#include "mbuf.h" 50226031Sstas#include "timer.h" 51226031Sstas#include "fsm.h" 52226031Sstas#include "iplist.h" 53226031Sstas#include "throughput.h" 54226031Sstas#include "slcompress.h" 55226031Sstas#include "lqr.h" 56226031Sstas#include "hdlc.h" 57226031Sstas#include "lcp.h" 58226031Sstas#include "ncpaddr.h" 59226031Sstas#include "ip.h" 60226031Sstas#include "ipcp.h" 61226031Sstas#include "ipv6cp.h" 62226031Sstas#include "filter.h" 63226031Sstas#include "descriptor.h" 64226031Sstas#include "ccp.h" 65226031Sstas#include "link.h" 66226031Sstas#include "mp.h" 67226031Sstas#ifndef NORADIUS 68226031Sstas#include "radius.h" 69226031Sstas#endif 70226031Sstas#include "ncp.h" 71226031Sstas#include "bundle.h" 72226031Sstas#include "route.h" 73226031Sstas#include "iface.h" 74226031Sstas#include "log.h" 75226031Sstas#include "proto.h" 76226031Sstas#include "command.h" 77226031Sstas#include "prompt.h" 78226031Sstas#include "async.h" 79226031Sstas#include "physical.h" 80226031Sstas#include "probe.h" 81226031Sstas#include "systems.h" 82226031Sstas 83226031Sstas 84226031Sstas#ifndef NOINET6 85226031Sstas#define IN6ADDR_LINKLOCAL_MCAST_INIT \ 86226031Sstas {{{ 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 87226031Sstas 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}} 88226031Sstasstatic const struct in6_addr in6addr_linklocal_mcast = 89226031Sstas IN6ADDR_LINKLOCAL_MCAST_INIT; 90226031Sstas 91226031Sstasstatic int ipv6cp_LayerUp(struct fsm *); 92226031Sstasstatic void ipv6cp_LayerDown(struct fsm *); 93226031Sstasstatic void ipv6cp_LayerStart(struct fsm *); 94226031Sstasstatic void ipv6cp_LayerFinish(struct fsm *); 95226031Sstasstatic void ipv6cp_InitRestartCounter(struct fsm *, int); 96226031Sstasstatic void ipv6cp_SendConfigReq(struct fsm *); 97226031Sstasstatic void ipv6cp_SentTerminateReq(struct fsm *); 98226031Sstasstatic void ipv6cp_SendTerminateAck(struct fsm *, u_char); 99226031Sstasstatic void ipv6cp_DecodeConfig(struct fsm *, u_char *, u_char *, int, 100226031Sstas struct fsm_decode *); 101226031Sstas 102226031Sstasstatic struct fsm_callbacks ipv6cp_Callbacks = { 103226031Sstas ipv6cp_LayerUp, 104226031Sstas ipv6cp_LayerDown, 105226031Sstas ipv6cp_LayerStart, 106226031Sstas ipv6cp_LayerFinish, 107226031Sstas ipv6cp_InitRestartCounter, 108226031Sstas ipv6cp_SendConfigReq, 109226031Sstas ipv6cp_SentTerminateReq, 110226031Sstas ipv6cp_SendTerminateAck, 111226031Sstas ipv6cp_DecodeConfig, 112226031Sstas fsm_NullRecvResetReq, 113226031Sstas fsm_NullRecvResetAck 114226031Sstas}; 115226031Sstas 116226031Sstasstatic void 117226031SstasSetInterfaceID(u_char *ifid, int userandom) 118226031Sstas{ 119226031Sstas struct ifaddrs *ifa, *ifap = NULL; 120226031Sstas struct sockaddr_dl *sdl; 121226031Sstas const u_long i32_max = 0xffffffff; 122226031Sstas u_long r1, r2; 123226031Sstas 124226031Sstas /* configure an interface ID based on Section 4.1 of RFC 2472 */ 125226031Sstas memset(ifid, 0, IPV6CP_IFIDLEN); 126226031Sstas 127226031Sstas /* 128226031Sstas * 1) If an IEEE global identifier (EUI-48 or EUI-64) is 129226031Sstas * available anywhere on the node, it should be used to construct 130226031Sstas * the tentative Interface-Identifier due to its uniqueness 131226031Sstas * properties. 132226031Sstas */ 133226031Sstas if (userandom) 134226031Sstas goto randomid; 135226031Sstas if (getifaddrs(&ifap) < 0) 136226031Sstas goto randomid; 137226031Sstas 138226031Sstas for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 139226031Sstas char *cp; 140226031Sstas 141226031Sstas if (ifa->ifa_addr->sa_family != AF_LINK) 142226031Sstas continue; 143226031Sstas 144226031Sstas sdl = (struct sockaddr_dl *)ifa->ifa_addr; 145226031Sstas if (sdl->sdl_alen < 6) 146226031Sstas continue; 147226031Sstas /* we're only interested in IEEE hardware addresses */ 148226031Sstas switch(sdl->sdl_type) { 149226031Sstas case IFT_ETHER: 150226031Sstas case IFT_FDDI: 151226031Sstas case IFT_L2VLAN: 152226031Sstas /* XXX need more cases? */ 153226031Sstas break; 154226031Sstas default: 155226031Sstas continue; 156226031Sstas } 157226031Sstas 158226031Sstas cp = (char *)(sdl->sdl_data + sdl->sdl_nlen); 159226031Sstas ifid[0] = cp[0]; 160226031Sstas ifid[0] ^= 0x02; /* reverse the u/l bit*/ 161226031Sstas ifid[1] = cp[1]; 162226031Sstas ifid[2] = cp[2]; 163226031Sstas ifid[3] = 0xff; 164226031Sstas ifid[4] = 0xfe; 165226031Sstas ifid[5] = cp[3]; 166226031Sstas ifid[6] = cp[4]; 167226031Sstas ifid[7] = cp[5]; 168226031Sstas 169226031Sstas freeifaddrs(ifap); 170226031Sstas return; 171226031Sstas } 172226031Sstas 173226031Sstas freeifaddrs(ifap); 174226031Sstas 175226031Sstas /* 176226031Sstas * 2) If an IEEE global identifier is not available a different source 177226031Sstas * of uniqueness should be used. 178226031Sstas * XXX: we skip this case. 179226031Sstas */ 180226031Sstas 181226031Sstas /* 182226031Sstas * 3) If a good source of uniqueness cannot be found, it is 183226031Sstas * recommended that a random number be generated. In this case the 184226031Sstas * "u" bit of the interface identifier MUST be set to zero (0). 185226031Sstas */ 186226031Sstas randomid: 187226031Sstas randinit(); 188226031Sstas r1 = (((u_long)random()) % i32_max) + 1; 189226031Sstas r2 = (((u_long)random()) % i32_max) + 1; 190226031Sstas memcpy(ifid, &r1, sizeof(r1)); 191226031Sstas memcpy(ifid + 4, &r2, sizeof(r2)); 192226031Sstas ifid[0] &= 0xfd; 193226031Sstas return; 194226031Sstas} 195226031Sstas 196226031Sstasstatic int 197226031Sstasipcp_SetIPv6address(struct ipv6cp *ipv6cp, u_char *myifid, u_char *hisifid) 198226031Sstas{ 199226031Sstas struct bundle *bundle = ipv6cp->fsm.bundle; 200226031Sstas struct in6_addr myaddr, hisaddr; 201226031Sstas struct ncprange myrange, range; 202226031Sstas struct ncpaddr addr; 203226031Sstas struct sockaddr_storage ssdst, ssgw, ssmask; 204226031Sstas struct sockaddr *sadst, *sagw, *samask; 205226031Sstas 206226031Sstas sadst = (struct sockaddr *)&ssdst; 207226031Sstas sagw = (struct sockaddr *)&ssgw; 208226031Sstas samask = (struct sockaddr *)&ssmask; 209226031Sstas 210226031Sstas memset(&myaddr, '\0', sizeof myaddr); 211226031Sstas memset(&hisaddr, '\0', sizeof hisaddr); 212226031Sstas 213226031Sstas myaddr.s6_addr[0] = 0xfe; 214226031Sstas myaddr.s6_addr[1] = 0x80; 215226031Sstas memcpy(&myaddr.s6_addr[8], myifid, IPV6CP_IFIDLEN); 216226031Sstas#if 0 217226031Sstas myaddr.s6_addr[8] |= 0x02; /* set 'universal' bit */ 218226031Sstas#endif 219226031Sstas 220226031Sstas hisaddr.s6_addr[0] = 0xfe; 221226031Sstas hisaddr.s6_addr[1] = 0x80; 222226031Sstas memcpy(&hisaddr.s6_addr[8], hisifid, IPV6CP_IFIDLEN); 223226031Sstas#if 0 224226031Sstas hisaddr.s6_addr[8] |= 0x02; /* set 'universal' bit */ 225226031Sstas#endif 226226031Sstas 227226031Sstas ncpaddr_setip6(&ipv6cp->myaddr, &myaddr); 228226031Sstas ncpaddr_setip6(&ipv6cp->hisaddr, &hisaddr); 229226031Sstas ncprange_set(&myrange, &ipv6cp->myaddr, 64); 230226031Sstas 231226031Sstas if (!iface_Add(bundle->iface, &bundle->ncp, &myrange, &ipv6cp->hisaddr, 232226031Sstas IFACE_ADD_FIRST|IFACE_FORCE_ADD|IFACE_SYSTEM)) 233226031Sstas return 0; 234226031Sstas 235226031Sstas if (!Enabled(bundle, OPT_IFACEALIAS)) 236226031Sstas iface_Clear(bundle->iface, &bundle->ncp, AF_INET6, 237226031Sstas IFACE_CLEAR_ALIASES|IFACE_SYSTEM); 238226031Sstas 239226031Sstas ncpaddr_setip6(&addr, &in6addr_linklocal_mcast); 240226031Sstas ncprange_set(&range, &addr, 32); 241226031Sstas rt_Set(bundle, RTM_ADD, &range, &ipv6cp->myaddr, 1, 0); 242226031Sstas 243226031Sstas if (bundle->ncp.cfg.sendpipe > 0 || bundle->ncp.cfg.recvpipe > 0) { 244226031Sstas ncprange_getsa(&myrange, &ssgw, &ssmask); 245226031Sstas if (ncpaddr_isset(&ipv6cp->hisaddr)) 246226031Sstas ncpaddr_getsa(&ipv6cp->hisaddr, &ssdst); 247226031Sstas else 248226031Sstas sadst = NULL; 249226031Sstas rt_Update(bundle, sadst, sagw, samask, NULL, NULL); 250226031Sstas } 251226031Sstas 252226031Sstas if (Enabled(bundle, OPT_SROUTES)) 253226031Sstas route_Change(bundle, bundle->ncp.route, &ipv6cp->myaddr, &ipv6cp->hisaddr); 254226031Sstas 255226031Sstas#ifndef NORADIUS 256226031Sstas if (bundle->radius.valid) 257226031Sstas route_Change(bundle, bundle->radius.ipv6routes, &ipv6cp->myaddr, 258226031Sstas &ipv6cp->hisaddr); 259226031Sstas#endif 260226031Sstas 261226031Sstas return 1; /* Ok */ 262226031Sstas} 263226031Sstas 264226031Sstasvoid 265226031Sstasipv6cp_Init(struct ipv6cp *ipv6cp, struct bundle *bundle, struct link *l, 266226031Sstas const struct fsm_parent *parent) 267226031Sstas{ 268226031Sstas static const char * const timer_names[] = 269226031Sstas {"IPV6CP restart", "IPV6CP openmode", "IPV6CP stopped"}; 270226031Sstas int n; 271226031Sstas 272226031Sstas fsm_Init(&ipv6cp->fsm, "IPV6CP", PROTO_IPV6CP, 1, IPV6CP_MAXCODE, LogIPV6CP, 273226031Sstas bundle, l, parent, &ipv6cp_Callbacks, timer_names); 274226031Sstas 275226031Sstas ipv6cp->cfg.fsm.timeout = DEF_FSMRETRY; 276226031Sstas ipv6cp->cfg.fsm.maxreq = DEF_FSMTRIES; 277226031Sstas ipv6cp->cfg.fsm.maxtrm = DEF_FSMTRIES; 278226031Sstas 279226031Sstas SetInterfaceID(ipv6cp->my_ifid, 0); 280226031Sstas do { 281226031Sstas SetInterfaceID(ipv6cp->his_ifid, 1); 282226031Sstas } while (memcmp(ipv6cp->his_ifid, ipv6cp->my_ifid, IPV6CP_IFIDLEN) == 0); 283226031Sstas 284226031Sstas if (probe.ipv6_available) { 285226031Sstas n = 100; 286226031Sstas while (n && 287226031Sstas !ipcp_SetIPv6address(ipv6cp, ipv6cp->my_ifid, ipv6cp->his_ifid)) { 288226031Sstas do { 289226031Sstas n--; 290226031Sstas SetInterfaceID(ipv6cp->my_ifid, 1); 291226031Sstas } while (n 292226031Sstas && memcmp(ipv6cp->his_ifid, ipv6cp->my_ifid, IPV6CP_IFIDLEN) == 0); 293226031Sstas } 294226031Sstas } 295226031Sstas 296226031Sstas throughput_init(&ipv6cp->throughput, SAMPLE_PERIOD); 297226031Sstas memset(ipv6cp->Queue, '\0', sizeof ipv6cp->Queue); 298226031Sstas ipv6cp_Setup(ipv6cp); 299226031Sstas} 300226031Sstas 301226031Sstasvoid 302226031Sstasipv6cp_Destroy(struct ipv6cp *ipv6cp) 303226031Sstas{ 304226031Sstas throughput_destroy(&ipv6cp->throughput); 305226031Sstas} 306226031Sstas 307226031Sstasvoid 308226031Sstasipv6cp_Setup(struct ipv6cp *ipv6cp) 309226031Sstas{ 310226031Sstas ncpaddr_init(&ipv6cp->myaddr); 311226031Sstas ncpaddr_init(&ipv6cp->hisaddr); 312226031Sstas 313226031Sstas ipv6cp->his_reject = 0; 314226031Sstas ipv6cp->my_reject = 0; 315226031Sstas} 316226031Sstas 317226031Sstasvoid 318226031Sstasipv6cp_SetLink(struct ipv6cp *ipv6cp, struct link *l) 319226031Sstas{ 320226031Sstas ipv6cp->fsm.link = l; 321226031Sstas} 322226031Sstas 323226031Sstasint 324226031Sstasipv6cp_Show(struct cmdargs const *arg) 325226031Sstas{ 326226031Sstas struct ipv6cp *ipv6cp = &arg->bundle->ncp.ipv6cp; 327226031Sstas 328226031Sstas prompt_Printf(arg->prompt, "%s [%s]\n", ipv6cp->fsm.name, 329226031Sstas State2Nam(ipv6cp->fsm.state)); 330226031Sstas if (ipv6cp->fsm.state == ST_OPENED) { 331226031Sstas prompt_Printf(arg->prompt, " His side: %s\n", 332226031Sstas ncpaddr_ntoa(&ipv6cp->hisaddr)); 333226031Sstas prompt_Printf(arg->prompt, " My side: %s\n", 334226031Sstas ncpaddr_ntoa(&ipv6cp->myaddr)); 335226031Sstas prompt_Printf(arg->prompt, " Queued packets: %lu\n", 336226031Sstas (unsigned long)ipv6cp_QueueLen(ipv6cp)); 337226031Sstas } 338226031Sstas 339226031Sstas prompt_Printf(arg->prompt, "\nDefaults:\n"); 340226031Sstas prompt_Printf(arg->prompt, " FSM retry = %us, max %u Config" 341226031Sstas " REQ%s, %u Term REQ%s\n\n", ipv6cp->cfg.fsm.timeout, 342226031Sstas ipv6cp->cfg.fsm.maxreq, ipv6cp->cfg.fsm.maxreq == 1 ? "" : "s", 343226031Sstas ipv6cp->cfg.fsm.maxtrm, ipv6cp->cfg.fsm.maxtrm == 1 ? "" : "s"); 344226031Sstas 345226031Sstas throughput_disp(&ipv6cp->throughput, arg->prompt); 346226031Sstas 347226031Sstas return 0; 348226031Sstas} 349226031Sstas 350226031Sstasstruct mbuf * 351226031Sstasipv6cp_Input(struct bundle *bundle, struct link *l, struct mbuf *bp) 352226031Sstas{ 353226031Sstas /* Got PROTO_IPV6CP from link */ 354226031Sstas m_settype(bp, MB_IPV6CPIN); 355226031Sstas if (bundle_Phase(bundle) == PHASE_NETWORK) 356226031Sstas fsm_Input(&bundle->ncp.ipv6cp.fsm, bp); 357226031Sstas else { 358226031Sstas if (bundle_Phase(bundle) < PHASE_NETWORK) 359226031Sstas log_Printf(LogIPV6CP, "%s: Error: Unexpected IPV6CP in phase %s" 360226031Sstas " (ignored)\n", l->name, bundle_PhaseName(bundle)); 361226031Sstas m_freem(bp); 362226031Sstas } 363226031Sstas return NULL; 364226031Sstas} 365226031Sstas 366226031Sstasvoid 367226031Sstasipv6cp_AddInOctets(struct ipv6cp *ipv6cp, int n) 368226031Sstas{ 369226031Sstas throughput_addin(&ipv6cp->throughput, n); 370226031Sstas} 371226031Sstas 372226031Sstasvoid 373226031Sstasipv6cp_AddOutOctets(struct ipv6cp *ipv6cp, int n) 374226031Sstas{ 375226031Sstas throughput_addout(&ipv6cp->throughput, n); 376226031Sstas} 377226031Sstas 378226031Sstasvoid 379226031Sstasipv6cp_IfaceAddrAdded(struct ipv6cp *ipv6cp __unused, 380226031Sstas const struct iface_addr *addr __unused) 381226031Sstas{ 382226031Sstas} 383226031Sstas 384226031Sstasvoid 385226031Sstasipv6cp_IfaceAddrDeleted(struct ipv6cp *ipv6cp __unused, 386226031Sstas const struct iface_addr *addr __unused) 387226031Sstas{ 388226031Sstas} 389226031Sstas 390226031Sstasint 391226031Sstasipv6cp_InterfaceUp(struct ipv6cp *ipv6cp) 392226031Sstas{ 393226031Sstas if (!ipcp_SetIPv6address(ipv6cp, ipv6cp->my_ifid, ipv6cp->his_ifid)) { 394226031Sstas log_Printf(LogERROR, "ipv6cp_InterfaceUp: unable to set ipv6 address\n"); 395226031Sstas return 0; 396226031Sstas } 397226031Sstas 398226031Sstas if (!iface_SetFlags(ipv6cp->fsm.bundle->iface->name, IFF_UP)) { 399226031Sstas log_Printf(LogERROR, "ipv6cp_InterfaceUp: Can't set the IFF_UP" 400226031Sstas " flag on %s\n", ipv6cp->fsm.bundle->iface->name); 401226031Sstas return 0; 402226031Sstas } 403226031Sstas 404226031Sstas return 1; 405226031Sstas} 406226031Sstas 407226031Sstassize_t 408226031Sstasipv6cp_QueueLen(struct ipv6cp *ipv6cp) 409226031Sstas{ 410226031Sstas struct mqueue *q; 411226031Sstas size_t result; 412226031Sstas 413226031Sstas result = 0; 414226031Sstas for (q = ipv6cp->Queue; q < ipv6cp->Queue + IPV6CP_QUEUES(ipv6cp); q++) 415226031Sstas result += q->len; 416226031Sstas 417226031Sstas return result; 418226031Sstas} 419226031Sstas 420226031Sstasint 421226031Sstasipv6cp_PushPacket(struct ipv6cp *ipv6cp, struct link *l) 422226031Sstas{ 423226031Sstas struct bundle *bundle = ipv6cp->fsm.bundle; 424226031Sstas struct mqueue *queue; 425226031Sstas struct mbuf *bp; 426226031Sstas int m_len; 427226031Sstas u_int32_t secs = 0; 428226031Sstas unsigned alivesecs = 0; 429226031Sstas 430226031Sstas if (ipv6cp->fsm.state != ST_OPENED) 431226031Sstas return 0; 432226031Sstas 433226031Sstas /* 434226031Sstas * If ccp is not open but is required, do nothing. 435226031Sstas */ 436226031Sstas if (l->ccp.fsm.state != ST_OPENED && ccp_Required(&l->ccp)) { 437226031Sstas log_Printf(LogPHASE, "%s: Not transmitting... waiting for CCP\n", l->name); 438226031Sstas return 0; 439226031Sstas } 440226031Sstas 441226031Sstas queue = ipv6cp->Queue + IPV6CP_QUEUES(ipv6cp) - 1; 442226031Sstas do { 443226031Sstas if (queue->top) { 444226031Sstas bp = m_dequeue(queue); 445226031Sstas bp = mbuf_Read(bp, &secs, sizeof secs); 446226031Sstas bp = m_pullup(bp); 447226031Sstas m_len = m_length(bp); 448226031Sstas if (!FilterCheck(MBUF_CTOP(bp), AF_INET6, &bundle->filter.alive, 449226031Sstas &alivesecs)) { 450226031Sstas if (secs == 0) 451226031Sstas secs = alivesecs; 452226031Sstas bundle_StartIdleTimer(bundle, secs); 453226031Sstas } 454226031Sstas link_PushPacket(l, bp, bundle, 0, PROTO_IPV6); 455226031Sstas ipv6cp_AddOutOctets(ipv6cp, m_len); 456226031Sstas return 1; 457226031Sstas } 458226031Sstas } while (queue-- != ipv6cp->Queue); 459226031Sstas 460226031Sstas return 0; 461226031Sstas} 462226031Sstas 463226031Sstasstatic int 464226031Sstasipv6cp_LayerUp(struct fsm *fp) 465226031Sstas{ 466226031Sstas /* We're now up */ 467226031Sstas struct ipv6cp *ipv6cp = fsm2ipv6cp(fp); 468226031Sstas char tbuff[40]; 469226031Sstas 470226031Sstas log_Printf(LogIPV6CP, "%s: LayerUp.\n", fp->link->name); 471226031Sstas if (!ipv6cp_InterfaceUp(ipv6cp)) 472226031Sstas return 0; 473226031Sstas 474226031Sstas snprintf(tbuff, sizeof tbuff, "%s", ncpaddr_ntoa(&ipv6cp->myaddr)); 475226031Sstas log_Printf(LogIPV6CP, "myaddr %s hisaddr = %s\n", 476226031Sstas tbuff, ncpaddr_ntoa(&ipv6cp->hisaddr)); 477226031Sstas 478226031Sstas#ifndef NORADIUS 479226031Sstas radius_Account_Set_Ipv6(&fp->bundle->radacct6, ipv6cp->his_ifid); 480226031Sstas radius_Account(&fp->bundle->radius, &fp->bundle->radacct6, 481226031Sstas fp->bundle->links, RAD_START, &ipv6cp->throughput); 482226031Sstas 483226031Sstas /* 484226031Sstas * XXX: Avoid duplicate evaluation of filterid between IPCP and 485226031Sstas * IPV6CP. When IPCP is enabled and rejected, filterid is not 486226031Sstas * evaluated. 487226031Sstas */ 488226031Sstas if (!Enabled(fp->bundle, OPT_IPCP)) { 489226031Sstas if (fp->bundle->radius.cfg.file && fp->bundle->radius.filterid) 490226031Sstas system_Select(fp->bundle, fp->bundle->radius.filterid, LINKUPFILE, 491226031Sstas NULL, NULL); 492226031Sstas } 493226031Sstas#endif 494226031Sstas 495226031Sstas /* 496226031Sstas * XXX this stuff should really live in the FSM. Our config should 497226031Sstas * associate executable sections in files with events. 498226031Sstas */ 499226031Sstas if (system_Select(fp->bundle, tbuff, LINKUPFILE, NULL, NULL) < 0) { 500226031Sstas /* 501226031Sstas * XXX: Avoid duplicate evaluation of label between IPCP and 502226031Sstas * IPV6CP. When IPCP is enabled and rejected, label is not 503226031Sstas * evaluated. 504226031Sstas */ 505226031Sstas if (bundle_GetLabel(fp->bundle) && !Enabled(fp->bundle, OPT_IPCP)) { 506226031Sstas if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle), 507226031Sstas LINKUPFILE, NULL, NULL) < 0) 508226031Sstas system_Select(fp->bundle, "MYADDR6", LINKUPFILE, NULL, NULL); 509226031Sstas } else 510226031Sstas system_Select(fp->bundle, "MYADDR6", LINKUPFILE, NULL, NULL); 511226031Sstas } 512226031Sstas 513226031Sstas fp->more.reqs = fp->more.naks = fp->more.rejs = ipv6cp->cfg.fsm.maxreq * 3; 514226031Sstas log_DisplayPrompts(); 515226031Sstas 516226031Sstas return 1; 517226031Sstas} 518226031Sstas 519226031Sstasstatic void 520226031Sstasipv6cp_LayerDown(struct fsm *fp) 521226031Sstas{ 522226031Sstas /* About to come down */ 523226031Sstas struct ipv6cp *ipv6cp = fsm2ipv6cp(fp); 524226031Sstas static int recursing; 525226031Sstas char addr[40]; 526226031Sstas 527226031Sstas if (!recursing++) { 528226031Sstas snprintf(addr, sizeof addr, "%s", ncpaddr_ntoa(&ipv6cp->myaddr)); 529226031Sstas log_Printf(LogIPV6CP, "%s: LayerDown: %s\n", fp->link->name, addr); 530226031Sstas 531226031Sstas#ifndef NORADIUS 532226031Sstas radius_Flush(&fp->bundle->radius); 533226031Sstas radius_Account(&fp->bundle->radius, &fp->bundle->radacct6, 534226031Sstas fp->bundle->links, RAD_STOP, &ipv6cp->throughput); 535226031Sstas 536226031Sstas /* 537226031Sstas * XXX: Avoid duplicate evaluation of filterid between IPCP and 538226031Sstas * IPV6CP. When IPCP is enabled and rejected, filterid is not 539226031Sstas * evaluated. 540226031Sstas */ 541226031Sstas if (!Enabled(fp->bundle, OPT_IPCP)) { 542226031Sstas if (fp->bundle->radius.cfg.file && fp->bundle->radius.filterid) 543226031Sstas system_Select(fp->bundle, fp->bundle->radius.filterid, LINKDOWNFILE, 544226031Sstas NULL, NULL); 545226031Sstas } 546226031Sstas#endif 547226031Sstas 548226031Sstas /* 549226031Sstas * XXX this stuff should really live in the FSM. Our config should 550226031Sstas * associate executable sections in files with events. 551226031Sstas */ 552226031Sstas if (system_Select(fp->bundle, addr, LINKDOWNFILE, NULL, NULL) < 0) { 553226031Sstas /* 554226031Sstas * XXX: Avoid duplicate evaluation of label between IPCP and 555226031Sstas * IPV6CP. When IPCP is enabled and rejected, label is not 556226031Sstas * evaluated. 557226031Sstas */ 558226031Sstas if (bundle_GetLabel(fp->bundle) && !Enabled(fp->bundle, OPT_IPCP)) { 559226031Sstas if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle), 560226031Sstas LINKDOWNFILE, NULL, NULL) < 0) 561226031Sstas system_Select(fp->bundle, "MYADDR6", LINKDOWNFILE, NULL, NULL); 562226031Sstas } else 563226031Sstas system_Select(fp->bundle, "MYADDR6", LINKDOWNFILE, NULL, NULL); 564226031Sstas } 565226031Sstas 566226031Sstas ipv6cp_Setup(ipv6cp); 567226031Sstas } 568226031Sstas recursing--; 569226031Sstas} 570226031Sstas 571226031Sstasstatic void 572226031Sstasipv6cp_LayerStart(struct fsm *fp) 573226031Sstas{ 574226031Sstas /* We're about to start up ! */ 575226031Sstas struct ipv6cp *ipv6cp = fsm2ipv6cp(fp); 576226031Sstas 577226031Sstas log_Printf(LogIPV6CP, "%s: LayerStart.\n", fp->link->name); 578226031Sstas throughput_start(&ipv6cp->throughput, "IPV6CP throughput", 579226031Sstas Enabled(fp->bundle, OPT_THROUGHPUT)); 580226031Sstas fp->more.reqs = fp->more.naks = fp->more.rejs = ipv6cp->cfg.fsm.maxreq * 3; 581226031Sstas ipv6cp->peer_tokenreq = 0; 582226031Sstas} 583226031Sstas 584226031Sstasstatic void 585226031Sstasipv6cp_LayerFinish(struct fsm *fp) 586226031Sstas{ 587226031Sstas /* We're now down */ 588226031Sstas struct ipv6cp *ipv6cp = fsm2ipv6cp(fp); 589226031Sstas 590226031Sstas log_Printf(LogIPV6CP, "%s: LayerFinish.\n", fp->link->name); 591226031Sstas throughput_stop(&ipv6cp->throughput); 592226031Sstas throughput_log(&ipv6cp->throughput, LogIPV6CP, NULL); 593226031Sstas} 594226031Sstas 595226031Sstasstatic void 596226031Sstasipv6cp_InitRestartCounter(struct fsm *fp, int what) 597226031Sstas{ 598226031Sstas /* Set fsm timer load */ 599226031Sstas struct ipv6cp *ipv6cp = fsm2ipv6cp(fp); 600226031Sstas 601226031Sstas fp->FsmTimer.load = ipv6cp->cfg.fsm.timeout * SECTICKS; 602226031Sstas switch (what) { 603226031Sstas case FSM_REQ_TIMER: 604226031Sstas fp->restart = ipv6cp->cfg.fsm.maxreq; 605226031Sstas break; 606226031Sstas case FSM_TRM_TIMER: 607226031Sstas fp->restart = ipv6cp->cfg.fsm.maxtrm; 608226031Sstas break; 609226031Sstas default: 610226031Sstas fp->restart = 1; 611226031Sstas break; 612226031Sstas } 613226031Sstas} 614226031Sstas 615226031Sstasstatic void 616226031Sstasipv6cp_SendConfigReq(struct fsm *fp) 617226031Sstas{ 618226031Sstas /* Send config REQ please */ 619226031Sstas struct physical *p = link2physical(fp->link); 620226031Sstas struct ipv6cp *ipv6cp = fsm2ipv6cp(fp); 621226031Sstas u_char buff[IPV6CP_IFIDLEN+2]; 622226031Sstas struct fsm_opt *o; 623226031Sstas 624226031Sstas o = (struct fsm_opt *)buff; 625226031Sstas 626226031Sstas if ((p && !physical_IsSync(p)) || !REJECTED(ipv6cp, TY_TOKEN)) { 627226031Sstas memcpy(o->data, ipv6cp->my_ifid, IPV6CP_IFIDLEN); 628226031Sstas INC_FSM_OPT(TY_TOKEN, IPV6CP_IFIDLEN + 2, o); 629226031Sstas } 630226031Sstas 631226031Sstas fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, (u_char *)o - buff, 632226031Sstas MB_IPV6CPOUT); 633226031Sstas} 634226031Sstas 635226031Sstasstatic void 636226031Sstasipv6cp_SentTerminateReq(struct fsm *fp __unused) 637226031Sstas{ 638226031Sstas /* Term REQ just sent by FSM */ 639226031Sstas} 640226031Sstas 641226031Sstasstatic void 642226031Sstasipv6cp_SendTerminateAck(struct fsm *fp, u_char id) 643226031Sstas{ 644226031Sstas /* Send Term ACK please */ 645226031Sstas fsm_Output(fp, CODE_TERMACK, id, NULL, 0, MB_IPV6CPOUT); 646226031Sstas} 647226031Sstas 648226031Sstasstatic const char * 649226031Sstasprotoname(unsigned proto) 650226031Sstas{ 651226031Sstas static const char *cftypes[] = { "IFACEID", "COMPPROTO" }; 652226031Sstas 653226031Sstas if (proto > 0 && proto <= sizeof cftypes / sizeof *cftypes) 654226031Sstas return cftypes[proto - 1]; 655226031Sstas 656226031Sstas return NumStr(proto, NULL, 0); 657226031Sstas} 658226031Sstas 659226031Sstasstatic void 660226031Sstasipv6cp_ValidateInterfaceID(struct ipv6cp *ipv6cp, u_char *ifid, 661226031Sstas struct fsm_decode *dec) 662226031Sstas{ 663226031Sstas struct fsm_opt opt; 664226031Sstas u_char zero[IPV6CP_IFIDLEN]; 665226031Sstas 666226031Sstas memset(zero, 0, IPV6CP_IFIDLEN); 667226031Sstas 668226031Sstas if (memcmp(ifid, zero, IPV6CP_IFIDLEN) != 0 669226031Sstas && memcmp(ifid, ipv6cp->my_ifid, IPV6CP_IFIDLEN) != 0) 670226031Sstas memcpy(ipv6cp->his_ifid, ifid, IPV6CP_IFIDLEN); 671226031Sstas 672226031Sstas opt.hdr.id = TY_TOKEN; 673226031Sstas opt.hdr.len = IPV6CP_IFIDLEN + 2; 674226031Sstas memcpy(opt.data, &ipv6cp->his_ifid, IPV6CP_IFIDLEN); 675226031Sstas if (memcmp(ifid, ipv6cp->his_ifid, IPV6CP_IFIDLEN) == 0) 676226031Sstas fsm_ack(dec, &opt); 677226031Sstas else 678226031Sstas fsm_nak(dec, &opt); 679226031Sstas} 680226031Sstas 681226031Sstasstatic void 682226031Sstasipv6cp_DecodeConfig(struct fsm *fp, u_char *cp, u_char *end, int mode_type, 683226031Sstas struct fsm_decode *dec) 684226031Sstas{ 685226031Sstas /* Deal with incoming PROTO_IPV6CP */ 686226031Sstas struct ipv6cp *ipv6cp = fsm2ipv6cp(fp); 687226031Sstas int n; 688226031Sstas char tbuff[100]; 689226031Sstas u_char ifid[IPV6CP_IFIDLEN], zero[IPV6CP_IFIDLEN]; 690226031Sstas struct fsm_opt *opt; 691226031Sstas 692226031Sstas memset(zero, 0, IPV6CP_IFIDLEN); 693226031Sstas 694226031Sstas while (end - cp >= (int)sizeof(opt->hdr)) { 695226031Sstas if ((opt = fsm_readopt(&cp)) == NULL) 696226031Sstas break; 697226031Sstas 698226031Sstas snprintf(tbuff, sizeof tbuff, " %s[%d]", protoname(opt->hdr.id), 699226031Sstas opt->hdr.len); 700226031Sstas 701226031Sstas switch (opt->hdr.id) { 702226031Sstas case TY_TOKEN: 703226031Sstas memcpy(ifid, opt->data, IPV6CP_IFIDLEN); 704226031Sstas log_Printf(LogIPV6CP, "%s 0x%02x%02x%02x%02x%02x%02x%02x%02x\n", tbuff, 705226031Sstas ifid[0], ifid[1], ifid[2], ifid[3], ifid[4], ifid[5], ifid[6], ifid[7]); 706226031Sstas 707226031Sstas switch (mode_type) { 708226031Sstas case MODE_REQ: 709226031Sstas ipv6cp->peer_tokenreq = 1; 710226031Sstas ipv6cp_ValidateInterfaceID(ipv6cp, ifid, dec); 711226031Sstas break; 712226031Sstas 713226031Sstas case MODE_NAK: 714226031Sstas if (memcmp(ifid, zero, IPV6CP_IFIDLEN) == 0) { 715226031Sstas log_Printf(log_IsKept(LogIPV6CP) ? LogIPV6CP : LogPHASE, 716226031Sstas "0x0000000000000000: Unacceptable IntefaceID!\n"); 717226031Sstas fsm_Close(&ipv6cp->fsm); 718226031Sstas } else if (memcmp(ifid, ipv6cp->his_ifid, IPV6CP_IFIDLEN) == 0) { 719226031Sstas log_Printf(log_IsKept(LogIPV6CP) ? LogIPV6CP : LogPHASE, 720226031Sstas "0x%02x%02x%02x%02x%02x%02x%02x%02x: " 721226031Sstas "Unacceptable IntefaceID!\n", 722226031Sstas ifid[0], ifid[1], ifid[2], ifid[3], 723226031Sstas ifid[4], ifid[5], ifid[6], ifid[7]); 724226031Sstas } else if (memcmp(ifid, ipv6cp->my_ifid, IPV6CP_IFIDLEN) != 0) { 725226031Sstas n = 100; 726226031Sstas while (n && !ipcp_SetIPv6address(ipv6cp, ifid, ipv6cp->his_ifid)) { 727226031Sstas do { 728226031Sstas n--; 729226031Sstas SetInterfaceID(ifid, 1); 730226031Sstas } while (n && memcmp(ifid, ipv6cp->his_ifid, IPV6CP_IFIDLEN) == 0); 731226031Sstas } 732226031Sstas 733226031Sstas if (n == 0) { 734226031Sstas log_Printf(log_IsKept(LogIPV6CP) ? LogIPV6CP : LogPHASE, 735226031Sstas "0x0000000000000000: Unacceptable IntefaceID!\n"); 736226031Sstas fsm_Close(&ipv6cp->fsm); 737226031Sstas } else { 738226031Sstas log_Printf(LogIPV6CP, "%s changing IntefaceID: " 739226031Sstas "0x%02x%02x%02x%02x%02x%02x%02x%02x " 740226031Sstas "--> 0x%02x%02x%02x%02x%02x%02x%02x%02x\n", tbuff, 741226031Sstas ipv6cp->my_ifid[0], ipv6cp->my_ifid[1], 742226031Sstas ipv6cp->my_ifid[2], ipv6cp->my_ifid[3], 743226031Sstas ipv6cp->my_ifid[4], ipv6cp->my_ifid[5], 744226031Sstas ipv6cp->my_ifid[6], ipv6cp->my_ifid[7], 745226031Sstas ifid[0], ifid[1], ifid[2], ifid[3], 746226031Sstas ifid[4], ifid[5], ifid[6], ifid[7]); 747226031Sstas memcpy(ipv6cp->my_ifid, ifid, IPV6CP_IFIDLEN); 748226031Sstas bundle_AdjustFilters(fp->bundle, &ipv6cp->myaddr, NULL); 749226031Sstas } 750226031Sstas } 751226031Sstas break; 752226031Sstas 753226031Sstas case MODE_REJ: 754226031Sstas ipv6cp->his_reject |= (1 << opt->hdr.id); 755226031Sstas break; 756226031Sstas } 757226031Sstas break; 758226031Sstas 759226031Sstas default: 760226031Sstas if (mode_type != MODE_NOP) { 761226031Sstas ipv6cp->my_reject |= (1 << opt->hdr.id); 762226031Sstas fsm_rej(dec, opt); 763226031Sstas } 764226031Sstas break; 765226031Sstas } 766226031Sstas } 767226031Sstas 768226031Sstas if (mode_type != MODE_NOP) { 769226031Sstas if (mode_type == MODE_REQ && !ipv6cp->peer_tokenreq) { 770226031Sstas if (dec->rejend == dec->rej && dec->nakend == dec->nak) { 771226031Sstas /* 772226031Sstas * Pretend the peer has requested a TOKEN. 773226031Sstas * We do this to ensure that we only send one NAK if the only 774226031Sstas * reason for the NAK is because the peer isn't sending a 775226031Sstas * TY_TOKEN REQ. This stops us from repeatedly trying to tell 776226031Sstas * the peer that we have to have an IP address on their end. 777226031Sstas */ 778226031Sstas ipv6cp->peer_tokenreq = 1; 779226031Sstas } 780226031Sstas memset(ifid, 0, IPV6CP_IFIDLEN); 781226031Sstas ipv6cp_ValidateInterfaceID(ipv6cp, ifid, dec); 782226031Sstas } 783226031Sstas fsm_opt_normalise(dec); 784226031Sstas } 785226031Sstas} 786226031Sstas#endif 787226031Sstas