ipv6cp.c revision 134789
18097Sjkh/*- 28097Sjkh * Copyright (c) 2001 Brian Somers <brian@Awfulhak.org> 38097Sjkh * All rights reserved. 48097Sjkh * 58097Sjkh * Redistribution and use in source and binary forms, with or without 68097Sjkh * modification, are permitted provided that the following conditions 716366Sjkh * are met: 88097Sjkh * 1. Redistributions of source code must retain the above copyright 98097Sjkh * notice, this list of conditions and the following disclaimer. 108097Sjkh * 2. Redistributions in binary form must reproduce the above copyright 118097Sjkh * notice, this list of conditions and the following disclaimer in the 128097Sjkh * documentation and/or other materials provided with the distribution. 138097Sjkh * 148097Sjkh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 158097Sjkh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 168881Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 178881Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 188097Sjkh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 198097Sjkh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 208097Sjkh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 218097Sjkh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 228097Sjkh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 238097Sjkh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 248097Sjkh * SUCH DAMAGE. 258097Sjkh * 268097Sjkh * $FreeBSD: head/usr.sbin/ppp/ipv6cp.c 134789 2004-09-05 01:46:52Z brian $ 278097Sjkh */ 288097Sjkh 298097Sjkh#include <sys/param.h> 308097Sjkh#include <netinet/in_systm.h> 318097Sjkh#include <netinet/in.h> 328097Sjkh#include <netinet/ip.h> 338097Sjkh#include <sys/socket.h> 348097Sjkh#include <net/route.h> 358097Sjkh#include <net/if.h> 368097Sjkh#include <net/if_types.h> 378097Sjkh#include <net/if_dl.h> 388097Sjkh#include <sys/un.h> 398825Sjkh 408825Sjkh#include <stdarg.h> 418097Sjkh#include <stdio.h> 428702Sjkh#include <stdlib.h> 438702Sjkh#include <string.h> 448702Sjkh#include <termios.h> 458837Sjkh#include <ifaddrs.h> 468837Sjkh 478837Sjkh#include "layer.h" 4812661Speter#include "defs.h" 4912661Speter#include "mbuf.h" 5012661Speter#include "timer.h" 518837Sjkh#include "fsm.h" 528837Sjkh#include "iplist.h" 538262Sjkh#include "throughput.h" 548262Sjkh#include "slcompress.h" 558262Sjkh#include "lqr.h" 568262Sjkh#include "hdlc.h" 578262Sjkh#include "lcp.h" 588262Sjkh#include "ncpaddr.h" 598262Sjkh#include "ip.h" 608262Sjkh#include "ipcp.h" 6115416Sjkh#include "ipv6cp.h" 628262Sjkh#include "filter.h" 638347Sjkh#include "descriptor.h" 648262Sjkh#include "ccp.h" 658262Sjkh#include "link.h" 668314Sjkh#include "mp.h" 678702Sjkh#ifndef NORADIUS 688262Sjkh#include "radius.h" 698262Sjkh#endif 708262Sjkh#include "ncp.h" 718262Sjkh#include "bundle.h" 728097Sjkh#include "route.h" 738097Sjkh#include "iface.h" 748097Sjkh#include "log.h" 758097Sjkh#include "proto.h" 768097Sjkh#include "command.h" 778097Sjkh#include "prompt.h" 788705Sjkh#include "async.h" 798705Sjkh#include "physical.h" 808097Sjkh#include "probe.h" 818705Sjkh#include "systems.h" 828641Sjkh 838641Sjkh 848702Sjkh#ifndef NOINET6 8515883Sjkh#define IN6ADDR_LINKLOCAL_MCAST_INIT \ 868641Sjkh {{{ 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 878705Sjkh 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}} 888641Sjkhstatic const struct in6_addr in6addr_linklocal_mcast = 898641Sjkh IN6ADDR_LINKLOCAL_MCAST_INIT; 9015416Sjkh 918097Sjkhstatic int ipv6cp_LayerUp(struct fsm *); 928347Sjkhstatic void ipv6cp_LayerDown(struct fsm *); 938097Sjkhstatic void ipv6cp_LayerStart(struct fsm *); 948705Sjkhstatic void ipv6cp_LayerFinish(struct fsm *); 958705Sjkhstatic void ipv6cp_InitRestartCounter(struct fsm *, int); 968705Sjkhstatic void ipv6cp_SendConfigReq(struct fsm *); 978705Sjkhstatic void ipv6cp_SentTerminateReq(struct fsm *); 988705Sjkhstatic void ipv6cp_SendTerminateAck(struct fsm *, u_char); 998705Sjkhstatic void ipv6cp_DecodeConfig(struct fsm *, u_char *, u_char *, int, 1008705Sjkh struct fsm_decode *); 1018705Sjkh 10216366Sjkhstatic struct fsm_callbacks ipv6cp_Callbacks = { 1038705Sjkh ipv6cp_LayerUp, 1048262Sjkh ipv6cp_LayerDown, 1058722Sjkh ipv6cp_LayerStart, 1068262Sjkh ipv6cp_LayerFinish, 1078097Sjkh ipv6cp_InitRestartCounter, 1088097Sjkh ipv6cp_SendConfigReq, 1098097Sjkh ipv6cp_SentTerminateReq, 1108097Sjkh ipv6cp_SendTerminateAck, 1118097Sjkh ipv6cp_DecodeConfig, 1128097Sjkh fsm_NullRecvResetReq, 1138097Sjkh fsm_NullRecvResetAck 1148097Sjkh}; 1158262Sjkh 1168097Sjkhstatic void 11715416SjkhSetInterfaceID(u_char *ifid, int userandom) 1188097Sjkh{ 1198097Sjkh struct ifaddrs *ifa, *ifap = NULL; 1208097Sjkh struct sockaddr_dl *sdl; 1218097Sjkh const u_long i32_max = 0xffffffff; 1228262Sjkh u_long r1, r2; 1238097Sjkh 12416366Sjkh /* configure an interface ID based on Section 4.1 of RFC 2472 */ 1258702Sjkh memset(ifid, 0, IPV6CP_IFIDLEN); 1268262Sjkh 1278262Sjkh /* 1288837Sjkh * 1) If an IEEE global identifier (EUI-48 or EUI-64) is 1298628Sjkh * available anywhere on the node, it should be used to construct 1308097Sjkh * the tentative Interface-Identifier due to its uniqueness 1318097Sjkh * properties. 1328097Sjkh */ 1338097Sjkh if (userandom) 1348097Sjkh goto randomid; 1358097Sjkh if (getifaddrs(&ifap) < 0) 1368097Sjkh goto randomid; 1378097Sjkh 1388262Sjkh for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 1398097Sjkh char *cp; 14015416Sjkh 1418097Sjkh if (ifa->ifa_addr->sa_family != AF_LINK) 1428097Sjkh continue; 1438097Sjkh 1448097Sjkh sdl = (struct sockaddr_dl *)ifa->ifa_addr; 1458097Sjkh if (sdl->sdl_alen < 6) 1468262Sjkh continue; 14716366Sjkh /* we're only interested in IEEE hardware addresses */ 1488702Sjkh switch(sdl->sdl_type) { 1498262Sjkh case IFT_ETHER: 1508262Sjkh case IFT_FDDI: 1518837Sjkh /* XXX need more cases? */ 1528628Sjkh break; 1538097Sjkh default: 1548097Sjkh continue; 1558097Sjkh } 1568097Sjkh 1578097Sjkh cp = (char *)(sdl->sdl_data + sdl->sdl_nlen); 1588097Sjkh ifid[0] = cp[0]; 1598097Sjkh ifid[0] ^= 0x02; /* reverse the u/l bit*/ 1608097Sjkh ifid[1] = cp[1]; 1618262Sjkh ifid[2] = cp[2]; 1628097Sjkh ifid[3] = 0xff; 16315416Sjkh ifid[4] = 0xfe; 1648097Sjkh ifid[5] = cp[3]; 1658097Sjkh ifid[6] = cp[4]; 1668097Sjkh ifid[7] = cp[5]; 1678097Sjkh 1688097Sjkh freeifaddrs(ifap); 1698262Sjkh return; 17016366Sjkh } 1718702Sjkh 1728097Sjkh freeifaddrs(ifap); 1738097Sjkh 1748097Sjkh /* 1758097Sjkh * 2) If an IEEE global identifier is not available a different source 1768097Sjkh * of uniqueness should be used. 1778097Sjkh * XXX: we skip this case. 1788262Sjkh */ 1798262Sjkh 1808628Sjkh /* 1818628Sjkh * 3) If a good source of uniqueness cannot be found, it is 1828097Sjkh * recommended that a random number be generated. In this case the 18315788Sjkh * "u" bit of the interface identifier MUST be set to zero (0). 1848097Sjkh */ 1858097Sjkh randomid: 1868208Sjkh randinit(); 1878208Sjkh r1 = (((u_long)random()) % i32_max) + 1; 1888208Sjkh r2 = (((u_long)random()) % i32_max) + 1; 1898208Sjkh memcpy(ifid, &r1, sizeof(r1)); 1908208Sjkh memcpy(ifid + 4, &r2, sizeof(r2)); 1918208Sjkh ifid[0] &= 0xfd; 1928649Sjkh return; 1938208Sjkh} 19415416Sjkh 1958208Sjkhstatic int 1968208Sjkhipcp_SetIPv6address(struct ipv6cp *ipv6cp, u_char *myifid, u_char *hisifid) 1978208Sjkh{ 1988208Sjkh struct bundle *bundle = ipv6cp->fsm.bundle; 1998208Sjkh struct in6_addr myaddr, hisaddr; 20015242Sjkh struct ncprange myrange, range; 2018640Sjkh struct ncpaddr addr; 20212661Speter struct sockaddr_storage ssdst, ssgw, ssmask; 2039202Srgrimes struct sockaddr *sadst, *sagw, *samask; 2048641Sjkh 2058640Sjkh sadst = (struct sockaddr *)&ssdst; 2068556Sjkh sagw = (struct sockaddr *)&ssgw; 20715242Sjkh samask = (struct sockaddr *)&ssmask; 2088208Sjkh 2098208Sjkh memset(&myaddr, '\0', sizeof myaddr); 2108302Sjkh memset(&hisaddr, '\0', sizeof hisaddr); 2118302Sjkh 2128302Sjkh myaddr.s6_addr[0] = 0xfe; 2138302Sjkh myaddr.s6_addr[1] = 0x80; 2148302Sjkh memcpy(&myaddr.s6_addr[8], myifid, IPV6CP_IFIDLEN); 2158302Sjkh#if 0 2168302Sjkh myaddr.s6_addr[8] |= 0x02; /* set 'universal' bit */ 21715416Sjkh#endif 2188302Sjkh 2198302Sjkh hisaddr.s6_addr[0] = 0xfe; 2208302Sjkh hisaddr.s6_addr[1] = 0x80; 2218302Sjkh memcpy(&hisaddr.s6_addr[8], hisifid, IPV6CP_IFIDLEN); 2228302Sjkh#if 0 2238837Sjkh hisaddr.s6_addr[8] |= 0x02; /* set 'universal' bit */ 2248837Sjkh#endif 2258649Sjkh 2268438Sjkh ncpaddr_setip6(&ipv6cp->myaddr, &myaddr); 2278302Sjkh ncpaddr_setip6(&ipv6cp->hisaddr, &hisaddr); 2288302Sjkh ncprange_set(&myrange, &ipv6cp->myaddr, 64); 2298208Sjkh 2308208Sjkh if (!iface_Add(bundle->iface, &bundle->ncp, &myrange, &ipv6cp->hisaddr, 2318208Sjkh IFACE_ADD_FIRST|IFACE_FORCE_ADD|IFACE_SYSTEM)) 2328208Sjkh return 0; 2338208Sjkh 2348208Sjkh if (!Enabled(bundle, OPT_IFACEALIAS)) 2358208Sjkh iface_Clear(bundle->iface, &bundle->ncp, AF_INET6, 2368556Sjkh IFACE_CLEAR_ALIASES|IFACE_SYSTEM); 2378208Sjkh 23815416Sjkh ncpaddr_setip6(&addr, &in6addr_linklocal_mcast); 2398208Sjkh ncprange_set(&range, &addr, 32); 2408208Sjkh rt_Set(bundle, RTM_ADD, &range, &ipv6cp->myaddr, 1, 0); 2418208Sjkh 2428208Sjkh if (bundle->ncp.cfg.sendpipe > 0 || bundle->ncp.cfg.recvpipe > 0) { 2438208Sjkh ncprange_getsa(&myrange, &ssgw, &ssmask); 24415242Sjkh if (ncpaddr_isset(&ipv6cp->hisaddr)) 2458640Sjkh ncpaddr_getsa(&ipv6cp->hisaddr, &ssdst); 24612661Speter else 2479202Srgrimes sadst = NULL; 2488641Sjkh rt_Update(bundle, sadst, sagw, samask); 2498640Sjkh } 2508281Sjkh 25115242Sjkh if (Enabled(bundle, OPT_SROUTES)) 2528208Sjkh route_Change(bundle, bundle->ncp.route, &ipv6cp->myaddr, &ipv6cp->hisaddr); 2538208Sjkh 2548262Sjkh#ifndef NORADIUS 2558262Sjkh if (bundle->radius.valid) 2568262Sjkh route_Change(bundle, bundle->radius.ipv6routes, &ipv6cp->myaddr, 2578262Sjkh &ipv6cp->hisaddr); 2588262Sjkh#endif 2598262Sjkh 2608262Sjkh return 1; /* Ok */ 2618278Sjkh} 2628262Sjkh 2638556Sjkhvoid 2648262Sjkhipv6cp_Init(struct ipv6cp *ipv6cp, struct bundle *bundle, struct link *l, 26515416Sjkh const struct fsm_parent *parent) 2668262Sjkh{ 2678262Sjkh static const char * const timer_names[] = 2688262Sjkh {"IPV6CP restart", "IPV6CP openmode", "IPV6CP stopped"}; 2698262Sjkh int n; 2708262Sjkh 2718302Sjkh fsm_Init(&ipv6cp->fsm, "IPV6CP", PROTO_IPV6CP, 1, IPV6CP_MAXCODE, LogIPV6CP, 2728302Sjkh bundle, l, parent, &ipv6cp_Callbacks, timer_names); 2738302Sjkh 2748302Sjkh ipv6cp->cfg.fsm.timeout = DEF_FSMRETRY; 27515242Sjkh ipv6cp->cfg.fsm.maxreq = DEF_FSMTRIES; 2768640Sjkh ipv6cp->cfg.fsm.maxtrm = DEF_FSMTRIES; 27712661Speter 2789202Srgrimes SetInterfaceID(ipv6cp->my_ifid, 0); 2798641Sjkh do { 2808640Sjkh SetInterfaceID(ipv6cp->his_ifid, 1); 2818262Sjkh } while (memcmp(ipv6cp->his_ifid, ipv6cp->my_ifid, IPV6CP_IFIDLEN) == 0); 28215242Sjkh 2838262Sjkh if (probe.ipv6_available) { 2848262Sjkh n = 100; 2858262Sjkh while (n && 2868262Sjkh !ipcp_SetIPv6address(ipv6cp, ipv6cp->my_ifid, ipv6cp->his_ifid)) { 2878262Sjkh do { 2888262Sjkh n--; 2898347Sjkh SetInterfaceID(ipv6cp->my_ifid, 1); 2908347Sjkh } while (n 2918347Sjkh && memcmp(ipv6cp->his_ifid, ipv6cp->my_ifid, IPV6CP_IFIDLEN) == 0); 2928347Sjkh } 2938347Sjkh } 2948347Sjkh 2958347Sjkh throughput_init(&ipv6cp->throughput, SAMPLE_PERIOD); 2968594Sjkh memset(ipv6cp->Queue, '\0', sizeof ipv6cp->Queue); 2978594Sjkh ipv6cp_Setup(ipv6cp); 29815416Sjkh} 2998347Sjkh 3008347Sjkhvoid 3018347Sjkhipv6cp_Destroy(struct ipv6cp *ipv6cp) 3028347Sjkh{ 3038347Sjkh throughput_destroy(&ipv6cp->throughput); 3048347Sjkh} 3058705Sjkh 3068705Sjkhvoid 3078705Sjkhipv6cp_Setup(struct ipv6cp *ipv6cp) 3088705Sjkh{ 3098705Sjkh ncpaddr_init(&ipv6cp->myaddr); 3108705Sjkh ncpaddr_init(&ipv6cp->hisaddr); 3118705Sjkh 3128705Sjkh ipv6cp->his_reject = 0; 31315416Sjkh ipv6cp->my_reject = 0; 3148705Sjkh} 3158705Sjkh 3168705Sjkhvoid 3178705Sjkhipv6cp_SetLink(struct ipv6cp *ipv6cp, struct link *l) 3188705Sjkh{ 3198705Sjkh ipv6cp->fsm.link = l; 3208705Sjkh} 3218705Sjkh 3228705Sjkhint 32312661Speteripv6cp_Show(struct cmdargs const *arg) 3248705Sjkh{ 32512661Speter struct ipv6cp *ipv6cp = &arg->bundle->ncp.ipv6cp; 32612661Speter 32712661Speter prompt_Printf(arg->prompt, "%s [%s]\n", ipv6cp->fsm.name, 32812661Speter State2Nam(ipv6cp->fsm.state)); 32912661Speter if (ipv6cp->fsm.state == ST_OPENED) { 33012661Speter prompt_Printf(arg->prompt, " His side: %s\n", 33115242Sjkh ncpaddr_ntoa(&ipv6cp->hisaddr)); 33212661Speter prompt_Printf(arg->prompt, " My side: %s\n", 33312661Speter ncpaddr_ntoa(&ipv6cp->myaddr)); 33412661Speter prompt_Printf(arg->prompt, " Queued packets: %lu\n", 33512661Speter (unsigned long)ipv6cp_QueueLen(ipv6cp)); 33612661Speter } 33712661Speter 33815242Sjkh prompt_Printf(arg->prompt, "\nDefaults:\n"); 33912661Speter prompt_Printf(arg->prompt, " FSM retry = %us, max %u Config" 340 " REQ%s, %u Term REQ%s\n\n", ipv6cp->cfg.fsm.timeout, 341 ipv6cp->cfg.fsm.maxreq, ipv6cp->cfg.fsm.maxreq == 1 ? "" : "s", 342 ipv6cp->cfg.fsm.maxtrm, ipv6cp->cfg.fsm.maxtrm == 1 ? "" : "s"); 343 344 throughput_disp(&ipv6cp->throughput, arg->prompt); 345 346 return 0; 347} 348 349struct mbuf * 350ipv6cp_Input(struct bundle *bundle, struct link *l, struct mbuf *bp) 351{ 352 /* Got PROTO_IPV6CP from link */ 353 m_settype(bp, MB_IPV6CPIN); 354 if (bundle_Phase(bundle) == PHASE_NETWORK) 355 fsm_Input(&bundle->ncp.ipv6cp.fsm, bp); 356 else { 357 if (bundle_Phase(bundle) < PHASE_NETWORK) 358 log_Printf(LogIPV6CP, "%s: Error: Unexpected IPV6CP in phase %s" 359 " (ignored)\n", l->name, bundle_PhaseName(bundle)); 360 m_freem(bp); 361 } 362 return NULL; 363} 364 365void 366ipv6cp_AddInOctets(struct ipv6cp *ipv6cp, int n) 367{ 368 throughput_addin(&ipv6cp->throughput, n); 369} 370 371void 372ipv6cp_AddOutOctets(struct ipv6cp *ipv6cp, int n) 373{ 374 throughput_addout(&ipv6cp->throughput, n); 375} 376 377void 378ipv6cp_IfaceAddrAdded(struct ipv6cp *ipv6cp __unused, 379 const struct iface_addr *addr __unused) 380{ 381} 382 383void 384ipv6cp_IfaceAddrDeleted(struct ipv6cp *ipv6cp __unused, 385 const struct iface_addr *addr __unused) 386{ 387} 388 389int 390ipv6cp_InterfaceUp(struct ipv6cp *ipv6cp) 391{ 392 if (!ipcp_SetIPv6address(ipv6cp, ipv6cp->my_ifid, ipv6cp->his_ifid)) { 393 log_Printf(LogERROR, "ipv6cp_InterfaceUp: unable to set ipv6 address\n"); 394 return 0; 395 } 396 397 if (!iface_SetFlags(ipv6cp->fsm.bundle->iface->name, IFF_UP)) { 398 log_Printf(LogERROR, "ipv6cp_InterfaceUp: Can't set the IFF_UP" 399 " flag on %s\n", ipv6cp->fsm.bundle->iface->name); 400 return 0; 401 } 402 403 return 1; 404} 405 406size_t 407ipv6cp_QueueLen(struct ipv6cp *ipv6cp) 408{ 409 struct mqueue *q; 410 size_t result; 411 412 result = 0; 413 for (q = ipv6cp->Queue; q < ipv6cp->Queue + IPV6CP_QUEUES(ipv6cp); q++) 414 result += q->len; 415 416 return result; 417} 418 419int 420ipv6cp_PushPacket(struct ipv6cp *ipv6cp, struct link *l) 421{ 422 struct bundle *bundle = ipv6cp->fsm.bundle; 423 struct mqueue *queue; 424 struct mbuf *bp; 425 int m_len; 426 u_int32_t secs = 0; 427 unsigned alivesecs = 0; 428 429 if (ipv6cp->fsm.state != ST_OPENED) 430 return 0; 431 432 /* 433 * If ccp is not open but is required, do nothing. 434 */ 435 if (l->ccp.fsm.state != ST_OPENED && ccp_Required(&l->ccp)) { 436 log_Printf(LogPHASE, "%s: Not transmitting... waiting for CCP\n", l->name); 437 return 0; 438 } 439 440 queue = ipv6cp->Queue + IPV6CP_QUEUES(ipv6cp) - 1; 441 do { 442 if (queue->top) { 443 bp = m_dequeue(queue); 444 bp = mbuf_Read(bp, &secs, sizeof secs); 445 bp = m_pullup(bp); 446 m_len = m_length(bp); 447 if (!FilterCheck(MBUF_CTOP(bp), AF_INET6, &bundle->filter.alive, 448 &alivesecs)) { 449 if (secs == 0) 450 secs = alivesecs; 451 bundle_StartIdleTimer(bundle, secs); 452 } 453 link_PushPacket(l, bp, bundle, 0, PROTO_IPV6); 454 ipv6cp_AddOutOctets(ipv6cp, m_len); 455 return 1; 456 } 457 } while (queue-- != ipv6cp->Queue); 458 459 return 0; 460} 461 462static int 463ipv6cp_LayerUp(struct fsm *fp) 464{ 465 /* We're now up */ 466 struct ipv6cp *ipv6cp = fsm2ipv6cp(fp); 467 char tbuff[40]; 468 469 log_Printf(LogIPV6CP, "%s: LayerUp.\n", fp->link->name); 470 if (!ipv6cp_InterfaceUp(ipv6cp)) 471 return 0; 472 473 snprintf(tbuff, sizeof tbuff, "%s", ncpaddr_ntoa(&ipv6cp->myaddr)); 474 log_Printf(LogIPV6CP, "myaddr %s hisaddr = %s\n", 475 tbuff, ncpaddr_ntoa(&ipv6cp->hisaddr)); 476 477#ifndef NORADIUS 478 radius_Account_Set_Ipv6(&fp->bundle->radacct6, ipv6cp->his_ifid); 479 radius_Account(&fp->bundle->radius, &fp->bundle->radacct6, 480 fp->bundle->links, RAD_START, &ipv6cp->throughput); 481 482 /* 483 * XXX: Avoid duplicate evaluation of filterid between IPCP and 484 * IPV6CP. When IPCP is enabled and rejected, filterid is not 485 * evaluated. 486 */ 487 if (!Enabled(fp->bundle, OPT_IPCP)) { 488 if (fp->bundle->radius.cfg.file && fp->bundle->radius.filterid) 489 system_Select(fp->bundle, fp->bundle->radius.filterid, LINKUPFILE, 490 NULL, NULL); 491 } 492#endif 493 494 /* 495 * XXX this stuff should really live in the FSM. Our config should 496 * associate executable sections in files with events. 497 */ 498 if (system_Select(fp->bundle, tbuff, LINKUPFILE, NULL, NULL) < 0) { 499 /* 500 * XXX: Avoid duplicate evaluation of label between IPCP and 501 * IPV6CP. When IPCP is enabled and rejected, label is not 502 * evaluated. 503 */ 504 if (bundle_GetLabel(fp->bundle) && !Enabled(fp->bundle, OPT_IPCP)) { 505 if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle), 506 LINKUPFILE, NULL, NULL) < 0) 507 system_Select(fp->bundle, "MYADDR6", LINKUPFILE, NULL, NULL); 508 } else 509 system_Select(fp->bundle, "MYADDR6", LINKUPFILE, NULL, NULL); 510 } 511 512 fp->more.reqs = fp->more.naks = fp->more.rejs = ipv6cp->cfg.fsm.maxreq * 3; 513 log_DisplayPrompts(); 514 515 return 1; 516} 517 518static void 519ipv6cp_LayerDown(struct fsm *fp) 520{ 521 /* About to come down */ 522 struct ipv6cp *ipv6cp = fsm2ipv6cp(fp); 523 static int recursing; 524 char addr[40]; 525 526 if (!recursing++) { 527 snprintf(addr, sizeof addr, "%s", ncpaddr_ntoa(&ipv6cp->myaddr)); 528 log_Printf(LogIPV6CP, "%s: LayerDown: %s\n", fp->link->name, addr); 529 530#ifndef NORADIUS 531 radius_Account(&fp->bundle->radius, &fp->bundle->radacct6, 532 fp->bundle->links, RAD_STOP, &ipv6cp->throughput); 533 534 /* 535 * XXX: Avoid duplicate evaluation of filterid between IPCP and 536 * IPV6CP. When IPCP is enabled and rejected, filterid is not 537 * evaluated. 538 */ 539 if (!Enabled(fp->bundle, OPT_IPCP)) { 540 if (fp->bundle->radius.cfg.file && fp->bundle->radius.filterid) 541 system_Select(fp->bundle, fp->bundle->radius.filterid, LINKDOWNFILE, 542 NULL, NULL); 543 } 544#endif 545 546 /* 547 * XXX this stuff should really live in the FSM. Our config should 548 * associate executable sections in files with events. 549 */ 550 if (system_Select(fp->bundle, addr, LINKDOWNFILE, NULL, NULL) < 0) { 551 /* 552 * XXX: Avoid duplicate evaluation of label between IPCP and 553 * IPV6CP. When IPCP is enabled and rejected, label is not 554 * evaluated. 555 */ 556 if (bundle_GetLabel(fp->bundle) && !Enabled(fp->bundle, OPT_IPCP)) { 557 if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle), 558 LINKDOWNFILE, NULL, NULL) < 0) 559 system_Select(fp->bundle, "MYADDR6", LINKDOWNFILE, NULL, NULL); 560 } else 561 system_Select(fp->bundle, "MYADDR6", LINKDOWNFILE, NULL, NULL); 562 } 563 564 ipv6cp_Setup(ipv6cp); 565 } 566 recursing--; 567} 568 569static void 570ipv6cp_LayerStart(struct fsm *fp) 571{ 572 /* We're about to start up ! */ 573 struct ipv6cp *ipv6cp = fsm2ipv6cp(fp); 574 575 log_Printf(LogIPV6CP, "%s: LayerStart.\n", fp->link->name); 576 throughput_start(&ipv6cp->throughput, "IPV6CP throughput", 577 Enabled(fp->bundle, OPT_THROUGHPUT)); 578 fp->more.reqs = fp->more.naks = fp->more.rejs = ipv6cp->cfg.fsm.maxreq * 3; 579 ipv6cp->peer_tokenreq = 0; 580} 581 582static void 583ipv6cp_LayerFinish(struct fsm *fp) 584{ 585 /* We're now down */ 586 struct ipv6cp *ipv6cp = fsm2ipv6cp(fp); 587 588 log_Printf(LogIPV6CP, "%s: LayerFinish.\n", fp->link->name); 589 throughput_stop(&ipv6cp->throughput); 590 throughput_log(&ipv6cp->throughput, LogIPV6CP, NULL); 591} 592 593static void 594ipv6cp_InitRestartCounter(struct fsm *fp, int what) 595{ 596 /* Set fsm timer load */ 597 struct ipv6cp *ipv6cp = fsm2ipv6cp(fp); 598 599 fp->FsmTimer.load = ipv6cp->cfg.fsm.timeout * SECTICKS; 600 switch (what) { 601 case FSM_REQ_TIMER: 602 fp->restart = ipv6cp->cfg.fsm.maxreq; 603 break; 604 case FSM_TRM_TIMER: 605 fp->restart = ipv6cp->cfg.fsm.maxtrm; 606 break; 607 default: 608 fp->restart = 1; 609 break; 610 } 611} 612 613static void 614ipv6cp_SendConfigReq(struct fsm *fp) 615{ 616 /* Send config REQ please */ 617 struct physical *p = link2physical(fp->link); 618 struct ipv6cp *ipv6cp = fsm2ipv6cp(fp); 619 u_char buff[IPV6CP_IFIDLEN+2]; 620 struct fsm_opt *o; 621 622 o = (struct fsm_opt *)buff; 623 624 if ((p && !physical_IsSync(p)) || !REJECTED(ipv6cp, TY_TOKEN)) { 625 memcpy(o->data, ipv6cp->my_ifid, IPV6CP_IFIDLEN); 626 INC_FSM_OPT(TY_TOKEN, IPV6CP_IFIDLEN + 2, o); 627 } 628 629 fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, (u_char *)o - buff, 630 MB_IPV6CPOUT); 631} 632 633static void 634ipv6cp_SentTerminateReq(struct fsm *fp __unused) 635{ 636 /* Term REQ just sent by FSM */ 637} 638 639static void 640ipv6cp_SendTerminateAck(struct fsm *fp, u_char id) 641{ 642 /* Send Term ACK please */ 643 fsm_Output(fp, CODE_TERMACK, id, NULL, 0, MB_IPV6CPOUT); 644} 645 646static const char * 647protoname(unsigned proto) 648{ 649 static const char *cftypes[] = { "IFACEID", "COMPPROTO" }; 650 651 if (proto > 0 && proto <= sizeof cftypes / sizeof *cftypes) 652 return cftypes[proto - 1]; 653 654 return NumStr(proto, NULL, 0); 655} 656 657static void 658ipv6cp_ValidateInterfaceID(struct ipv6cp *ipv6cp, u_char *ifid, 659 struct fsm_decode *dec) 660{ 661 struct fsm_opt opt; 662 u_char zero[IPV6CP_IFIDLEN]; 663 664 memset(zero, 0, IPV6CP_IFIDLEN); 665 666 if (memcmp(ifid, zero, IPV6CP_IFIDLEN) != 0 667 && memcmp(ifid, ipv6cp->my_ifid, IPV6CP_IFIDLEN) != 0) 668 memcpy(ipv6cp->his_ifid, ifid, IPV6CP_IFIDLEN); 669 670 opt.hdr.id = TY_TOKEN; 671 opt.hdr.len = IPV6CP_IFIDLEN + 2; 672 memcpy(opt.data, &ipv6cp->his_ifid, IPV6CP_IFIDLEN); 673 if (memcmp(ifid, ipv6cp->his_ifid, IPV6CP_IFIDLEN) == 0) 674 fsm_ack(dec, &opt); 675 else 676 fsm_nak(dec, &opt); 677} 678 679static void 680ipv6cp_DecodeConfig(struct fsm *fp, u_char *cp, u_char *end, int mode_type, 681 struct fsm_decode *dec) 682{ 683 /* Deal with incoming PROTO_IPV6CP */ 684 struct ipv6cp *ipv6cp = fsm2ipv6cp(fp); 685 int n; 686 char tbuff[100]; 687 u_char ifid[IPV6CP_IFIDLEN], zero[IPV6CP_IFIDLEN]; 688 struct fsm_opt *opt; 689 690 memset(zero, 0, IPV6CP_IFIDLEN); 691 692 while (end - cp >= (int)sizeof(opt->hdr)) { 693 if ((opt = fsm_readopt(&cp)) == NULL) 694 break; 695 696 snprintf(tbuff, sizeof tbuff, " %s[%d]", protoname(opt->hdr.id), 697 opt->hdr.len); 698 699 switch (opt->hdr.id) { 700 case TY_TOKEN: 701 memcpy(ifid, opt->data, IPV6CP_IFIDLEN); 702 log_Printf(LogIPV6CP, "%s 0x%02x%02x%02x%02x%02x%02x%02x%02x\n", tbuff, 703 ifid[0], ifid[1], ifid[2], ifid[3], ifid[4], ifid[5], ifid[6], ifid[7]); 704 705 switch (mode_type) { 706 case MODE_REQ: 707 ipv6cp->peer_tokenreq = 1; 708 ipv6cp_ValidateInterfaceID(ipv6cp, ifid, dec); 709 break; 710 711 case MODE_NAK: 712 if (memcmp(ifid, zero, IPV6CP_IFIDLEN) == 0) { 713 log_Printf(log_IsKept(LogIPV6CP) ? LogIPV6CP : LogPHASE, 714 "0x0000000000000000: Unacceptable IntefaceID!\n"); 715 fsm_Close(&ipv6cp->fsm); 716 } else if (memcmp(ifid, ipv6cp->his_ifid, IPV6CP_IFIDLEN) == 0) { 717 log_Printf(log_IsKept(LogIPV6CP) ? LogIPV6CP : LogPHASE, 718 "0x%02x%02x%02x%02x%02x%02x%02x%02x: " 719 "Unacceptable IntefaceID!\n", 720 ifid[0], ifid[1], ifid[2], ifid[3], 721 ifid[4], ifid[5], ifid[6], ifid[7]); 722 } else if (memcmp(ifid, ipv6cp->my_ifid, IPV6CP_IFIDLEN) != 0) { 723 n = 100; 724 while (n && !ipcp_SetIPv6address(ipv6cp, ifid, ipv6cp->his_ifid)) { 725 do { 726 n--; 727 SetInterfaceID(ifid, 1); 728 } while (n && memcmp(ifid, ipv6cp->his_ifid, IPV6CP_IFIDLEN) == 0); 729 } 730 731 if (n == 0) { 732 log_Printf(log_IsKept(LogIPV6CP) ? LogIPV6CP : LogPHASE, 733 "0x0000000000000000: Unacceptable IntefaceID!\n"); 734 fsm_Close(&ipv6cp->fsm); 735 } else { 736 log_Printf(LogIPV6CP, "%s changing IntefaceID: " 737 "0x%02x%02x%02x%02x%02x%02x%02x%02x " 738 "--> 0x%02x%02x%02x%02x%02x%02x%02x%02x\n", tbuff, 739 ipv6cp->my_ifid[0], ipv6cp->my_ifid[1], 740 ipv6cp->my_ifid[2], ipv6cp->my_ifid[3], 741 ipv6cp->my_ifid[4], ipv6cp->my_ifid[5], 742 ipv6cp->my_ifid[6], ipv6cp->my_ifid[7], 743 ifid[0], ifid[1], ifid[2], ifid[3], 744 ifid[4], ifid[5], ifid[6], ifid[7]); 745 memcpy(ipv6cp->my_ifid, ifid, IPV6CP_IFIDLEN); 746 bundle_AdjustFilters(fp->bundle, &ipv6cp->myaddr, NULL); 747 } 748 } 749 break; 750 751 case MODE_REJ: 752 ipv6cp->his_reject |= (1 << opt->hdr.id); 753 break; 754 } 755 break; 756 757 default: 758 if (mode_type != MODE_NOP) { 759 ipv6cp->my_reject |= (1 << opt->hdr.id); 760 fsm_rej(dec, opt); 761 } 762 break; 763 } 764 } 765 766 if (mode_type != MODE_NOP) { 767 if (mode_type == MODE_REQ && !ipv6cp->peer_tokenreq) { 768 if (dec->rejend == dec->rej && dec->nakend == dec->nak) { 769 /* 770 * Pretend the peer has requested a TOKEN. 771 * We do this to ensure that we only send one NAK if the only 772 * reason for the NAK is because the peer isn't sending a 773 * TY_TOKEN REQ. This stops us from repeatedly trying to tell 774 * the peer that we have to have an IP address on their end. 775 */ 776 ipv6cp->peer_tokenreq = 1; 777 } 778 memset(ifid, 0, IPV6CP_IFIDLEN); 779 ipv6cp_ValidateInterfaceID(ipv6cp, ifid, dec); 780 } 781 fsm_opt_normalise(dec); 782 } 783} 784#endif 785