ipv6cp.c revision 81897
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 81897 2001-08-18 19:07:13Z 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> 3681634Sbrian#include <sys/un.h> 3781634Sbrian 3881634Sbrian#include <stdio.h> 3981634Sbrian#include <stdlib.h> 4081634Sbrian#include <string.h> 4181634Sbrian#include <termios.h> 4281634Sbrian 4381634Sbrian#include "layer.h" 4481634Sbrian#include "defs.h" 4581634Sbrian#include "mbuf.h" 4681634Sbrian#include "timer.h" 4781634Sbrian#include "fsm.h" 4881634Sbrian#include "iplist.h" 4981634Sbrian#include "throughput.h" 5081634Sbrian#include "slcompress.h" 5181634Sbrian#include "lqr.h" 5281634Sbrian#include "hdlc.h" 5381634Sbrian#include "lcp.h" 5481634Sbrian#include "ncpaddr.h" 5581634Sbrian#include "ip.h" 5681634Sbrian#include "ipcp.h" 5781634Sbrian#include "ipv6cp.h" 5881634Sbrian#include "filter.h" 5981634Sbrian#include "descriptor.h" 6081634Sbrian#include "ccp.h" 6181634Sbrian#include "link.h" 6281634Sbrian#include "mp.h" 6381634Sbrian#ifndef NORADIUS 6481634Sbrian#include "radius.h" 6581634Sbrian#endif 6681634Sbrian#include "ncp.h" 6781634Sbrian#include "bundle.h" 6881634Sbrian#include "route.h" 6981634Sbrian#include "iface.h" 7081634Sbrian#include "log.h" 7181634Sbrian#include "proto.h" 7281634Sbrian#include "command.h" 7381634Sbrian#include "prompt.h" 7481634Sbrian#include "async.h" 7581634Sbrian#include "physical.h" 7681888Sbrian#include "probe.h" 7781634Sbrian 7881634Sbrian 7981634Sbrian#ifndef NOINET6 8081634Sbrianstatic int ipv6cp_LayerUp(struct fsm *); 8181634Sbrianstatic void ipv6cp_LayerDown(struct fsm *); 8281634Sbrianstatic void ipv6cp_LayerStart(struct fsm *); 8381634Sbrianstatic void ipv6cp_LayerFinish(struct fsm *); 8481634Sbrianstatic void ipv6cp_InitRestartCounter(struct fsm *, int); 8581634Sbrianstatic void ipv6cp_SendConfigReq(struct fsm *); 8681634Sbrianstatic void ipv6cp_SentTerminateReq(struct fsm *); 8781634Sbrianstatic void ipv6cp_SendTerminateAck(struct fsm *, u_char); 8881634Sbrianstatic void ipv6cp_DecodeConfig(struct fsm *, u_char *, int, int, 8981634Sbrian struct fsm_decode *); 9081634Sbrian 9181634Sbrianstatic struct fsm_callbacks ipv6cp_Callbacks = { 9281634Sbrian ipv6cp_LayerUp, 9381634Sbrian ipv6cp_LayerDown, 9481634Sbrian ipv6cp_LayerStart, 9581634Sbrian ipv6cp_LayerFinish, 9681634Sbrian ipv6cp_InitRestartCounter, 9781634Sbrian ipv6cp_SendConfigReq, 9881634Sbrian ipv6cp_SentTerminateReq, 9981634Sbrian ipv6cp_SendTerminateAck, 10081634Sbrian ipv6cp_DecodeConfig, 10181634Sbrian fsm_NullRecvResetReq, 10281634Sbrian fsm_NullRecvResetAck 10381634Sbrian}; 10481634Sbrian 10581634Sbrianstatic u_int32_t 10681634SbrianGenerateToken(void) 10781634Sbrian{ 10881634Sbrian /* Generate random number which will be used as negotiation token */ 10981634Sbrian randinit(); 11081634Sbrian 11181634Sbrian return random() + 1; 11281634Sbrian} 11381634Sbrian 11481634Sbrianstatic int 11581634Sbrianipcp_SetIPv6address(struct ipv6cp *ipv6cp, u_int32_t mytok, u_int32_t histok) 11681634Sbrian{ 11781634Sbrian struct bundle *bundle = ipv6cp->fsm.bundle; 11881634Sbrian struct in6_addr myaddr, hisaddr; 11981739Sbrian struct ncprange myrange; 12081739Sbrian struct sockaddr_storage ssdst, ssgw, ssmask; 12181739Sbrian struct sockaddr *sadst, *sagw, *samask; 12281634Sbrian 12381739Sbrian sadst = (struct sockaddr *)&ssdst; 12481739Sbrian sagw = (struct sockaddr *)&ssgw; 12581739Sbrian samask = (struct sockaddr *)&ssmask; 12681739Sbrian 12781634Sbrian memset(&myaddr, '\0', sizeof myaddr); 12881634Sbrian memset(&hisaddr, '\0', sizeof hisaddr); 12981634Sbrian 13081634Sbrian myaddr.s6_addr[0] = 0xfe; 13181634Sbrian myaddr.s6_addr[1] = 0x80; 13281634Sbrian *(u_int32_t *)(myaddr.s6_addr + 12) = htonl(mytok); 13381634Sbrian 13481634Sbrian hisaddr.s6_addr[0] = 0xfe; 13581634Sbrian hisaddr.s6_addr[1] = 0x80; 13681634Sbrian *(u_int32_t *)(hisaddr.s6_addr + 12) = htonl(histok); 13781634Sbrian 13881634Sbrian ncpaddr_setip6(&ipv6cp->myaddr, &myaddr); 13981634Sbrian ncpaddr_setip6(&ipv6cp->hisaddr, &hisaddr); 14081634Sbrian ncprange_sethost(&myrange, &ipv6cp->myaddr); 14181634Sbrian 14281634Sbrian if (!iface_Add(bundle->iface, &bundle->ncp, &myrange, &ipv6cp->hisaddr, 14381634Sbrian IFACE_ADD_FIRST|IFACE_FORCE_ADD|IFACE_SYSTEM)) 14481634Sbrian return 0; 14581634Sbrian 14681634Sbrian if (!Enabled(bundle, OPT_IFACEALIAS)) 14781634Sbrian iface_Clear(bundle->iface, &bundle->ncp, AF_INET6, 14881634Sbrian IFACE_CLEAR_ALIASES|IFACE_SYSTEM); 14981634Sbrian 15081634Sbrian if (bundle->ncp.cfg.sendpipe > 0 || bundle->ncp.cfg.recvpipe > 0) { 15181739Sbrian ncprange_getsa(&myrange, &ssgw, &ssmask); 15281739Sbrian if (ncpaddr_isset(&ipv6cp->hisaddr)) 15381739Sbrian ncpaddr_getsa(&ipv6cp->hisaddr, &ssdst); 15481739Sbrian else 15581739Sbrian sadst = NULL; 15681739Sbrian rt_Update(bundle, sadst, sagw, samask); 15781634Sbrian } 15881634Sbrian 15981634Sbrian if (Enabled(bundle, OPT_SROUTES)) 16081634Sbrian route_Change(bundle, bundle->ncp.route, &ipv6cp->myaddr, &ipv6cp->hisaddr); 16181634Sbrian 16281634Sbrian#ifndef NORADIUS 16381634Sbrian if (bundle->radius.valid) 16481634Sbrian route_Change(bundle, bundle->radius.routes, &ipv6cp->myaddr, 16581634Sbrian &ipv6cp->hisaddr); 16681634Sbrian#endif 16781634Sbrian 16881634Sbrian return 1; /* Ok */ 16981634Sbrian} 17081634Sbrian 17181634Sbrianvoid 17281634Sbrianipv6cp_Init(struct ipv6cp *ipv6cp, struct bundle *bundle, struct link *l, 17381634Sbrian const struct fsm_parent *parent) 17481634Sbrian{ 17581634Sbrian static const char * const timer_names[] = 17681634Sbrian {"IPV6CP restart", "IPV6CP openmode", "IPV6CP stopped"}; 17781634Sbrian int n; 17881634Sbrian 17981634Sbrian fsm_Init(&ipv6cp->fsm, "IPV6CP", PROTO_IPV6CP, 1, IPV6CP_MAXCODE, LogIPV6CP, 18081634Sbrian bundle, l, parent, &ipv6cp_Callbacks, timer_names); 18181634Sbrian 18281634Sbrian ipv6cp->cfg.fsm.timeout = DEF_FSMRETRY; 18381634Sbrian ipv6cp->cfg.fsm.maxreq = DEF_FSMTRIES; 18481634Sbrian ipv6cp->cfg.fsm.maxtrm = DEF_FSMTRIES; 18581634Sbrian 18681634Sbrian ipv6cp->my_token = GenerateToken(); 18781634Sbrian while ((ipv6cp->peer_token = GenerateToken()) == ipv6cp->my_token) 18881634Sbrian ; 18981634Sbrian 19081897Sbrian if (probe.ipv6_available) { 19181897Sbrian n = 100; 19281897Sbrian while (n && 19381897Sbrian !ipcp_SetIPv6address(ipv6cp, ipv6cp->my_token, ipv6cp->peer_token)) { 19481634Sbrian n--; 19581897Sbrian while (n && (ipv6cp->my_token = GenerateToken()) == ipv6cp->peer_token) 19681897Sbrian n--; 19781897Sbrian } 19881897Sbrian } 19981634Sbrian 20081634Sbrian throughput_init(&ipv6cp->throughput, SAMPLE_PERIOD); 20181634Sbrian memset(ipv6cp->Queue, '\0', sizeof ipv6cp->Queue); 20281634Sbrian ipv6cp_Setup(ipv6cp); 20381634Sbrian} 20481634Sbrian 20581634Sbrianvoid 20681634Sbrianipv6cp_Destroy(struct ipv6cp *ipv6cp) 20781634Sbrian{ 20881634Sbrian throughput_destroy(&ipv6cp->throughput); 20981634Sbrian} 21081634Sbrian 21181634Sbrianvoid 21281634Sbrianipv6cp_Setup(struct ipv6cp *ipv6cp) 21381634Sbrian{ 21481634Sbrian ncpaddr_init(&ipv6cp->myaddr); 21581634Sbrian ncpaddr_init(&ipv6cp->hisaddr); 21681634Sbrian 21781634Sbrian ipv6cp->his_reject = 0; 21881634Sbrian ipv6cp->my_reject = 0; 21981634Sbrian} 22081634Sbrian 22181634Sbrianvoid 22281634Sbrianipv6cp_SetLink(struct ipv6cp *ipv6cp, struct link *l) 22381634Sbrian{ 22481634Sbrian ipv6cp->fsm.link = l; 22581634Sbrian} 22681634Sbrian 22781634Sbrianint 22881634Sbrianipv6cp_Show(struct cmdargs const *arg) 22981634Sbrian{ 23081634Sbrian struct ipv6cp *ipv6cp = &arg->bundle->ncp.ipv6cp; 23181634Sbrian 23281634Sbrian prompt_Printf(arg->prompt, "%s [%s]\n", ipv6cp->fsm.name, 23381634Sbrian State2Nam(ipv6cp->fsm.state)); 23481634Sbrian if (ipv6cp->fsm.state == ST_OPENED) { 23581634Sbrian prompt_Printf(arg->prompt, " His side: %s\n", 23681634Sbrian ncpaddr_ntoa(&ipv6cp->hisaddr)); 23781634Sbrian prompt_Printf(arg->prompt, " My side: %s\n", 23881634Sbrian ncpaddr_ntoa(&ipv6cp->myaddr)); 23981634Sbrian prompt_Printf(arg->prompt, " Queued packets: %lu\n", 24081634Sbrian (unsigned long)ipv6cp_QueueLen(ipv6cp)); 24181634Sbrian } 24281634Sbrian 24381634Sbrian prompt_Printf(arg->prompt, "\nDefaults:\n"); 24481634Sbrian prompt_Printf(arg->prompt, " FSM retry = %us, max %u Config" 24581634Sbrian " REQ%s, %u Term REQ%s\n\n", ipv6cp->cfg.fsm.timeout, 24681634Sbrian ipv6cp->cfg.fsm.maxreq, ipv6cp->cfg.fsm.maxreq == 1 ? "" : "s", 24781634Sbrian ipv6cp->cfg.fsm.maxtrm, ipv6cp->cfg.fsm.maxtrm == 1 ? "" : "s"); 24881634Sbrian 24981634Sbrian throughput_disp(&ipv6cp->throughput, arg->prompt); 25081634Sbrian 25181634Sbrian return 0; 25281634Sbrian} 25381634Sbrian 25481634Sbrianstruct mbuf * 25581634Sbrianipv6cp_Input(struct bundle *bundle, struct link *l, struct mbuf *bp) 25681634Sbrian{ 25781634Sbrian /* Got PROTO_IPV6CP from link */ 25881634Sbrian m_settype(bp, MB_IPV6CPIN); 25981897Sbrian if (bundle_Phase(bundle) == PHASE_NETWORK) 26081634Sbrian fsm_Input(&bundle->ncp.ipv6cp.fsm, bp); 26181634Sbrian else { 26281634Sbrian if (bundle_Phase(bundle) < PHASE_NETWORK) 26381634Sbrian log_Printf(LogIPV6CP, "%s: Error: Unexpected IPV6CP in phase %s" 26481634Sbrian " (ignored)\n", l->name, bundle_PhaseName(bundle)); 26581634Sbrian m_freem(bp); 26681634Sbrian } 26781634Sbrian return NULL; 26881634Sbrian} 26981634Sbrian 27081634Sbrianvoid 27181634Sbrianipv6cp_AddInOctets(struct ipv6cp *ipv6cp, int n) 27281634Sbrian{ 27381634Sbrian throughput_addin(&ipv6cp->throughput, n); 27481634Sbrian} 27581634Sbrian 27681634Sbrianvoid 27781634Sbrianipv6cp_AddOutOctets(struct ipv6cp *ipv6cp, int n) 27881634Sbrian{ 27981634Sbrian throughput_addout(&ipv6cp->throughput, n); 28081634Sbrian} 28181634Sbrian 28281634Sbrianvoid 28381634Sbrianipv6cp_IfaceAddrAdded(struct ipv6cp *ipv6cp, const struct iface_addr *addr) 28481634Sbrian{ 28581634Sbrian} 28681634Sbrian 28781634Sbrianvoid 28881634Sbrianipv6cp_IfaceAddrDeleted(struct ipv6cp *ipv6cp, const struct iface_addr *addr) 28981634Sbrian{ 29081634Sbrian} 29181634Sbrian 29281634Sbrianint 29381634Sbrianipv6cp_InterfaceUp(struct ipv6cp *ipv6cp) 29481634Sbrian{ 29581634Sbrian if (!ipcp_SetIPv6address(ipv6cp, ipv6cp->my_token, ipv6cp->peer_token)) { 29681634Sbrian log_Printf(LogERROR, "ipv6cp_InterfaceUp: unable to set ipv6 address\n"); 29781634Sbrian return 0; 29881634Sbrian } 29981634Sbrian 30081634Sbrian if (!iface_SetFlags(ipv6cp->fsm.bundle->iface->name, IFF_UP)) { 30181634Sbrian log_Printf(LogERROR, "ipv6cp_InterfaceUp: Can't set the IFF_UP" 30281634Sbrian " flag on %s\n", ipv6cp->fsm.bundle->iface->name); 30381634Sbrian return 0; 30481634Sbrian } 30581634Sbrian 30681634Sbrian return 1; 30781634Sbrian} 30881634Sbrian 30981634Sbriansize_t 31081634Sbrianipv6cp_QueueLen(struct ipv6cp *ipv6cp) 31181634Sbrian{ 31281634Sbrian struct mqueue *q; 31381634Sbrian size_t result; 31481634Sbrian 31581634Sbrian result = 0; 31681634Sbrian for (q = ipv6cp->Queue; q < ipv6cp->Queue + IPV6CP_QUEUES(ipv6cp); q++) 31781634Sbrian result += q->len; 31881634Sbrian 31981634Sbrian return result; 32081634Sbrian} 32181634Sbrian 32281634Sbrianint 32381634Sbrianipv6cp_PushPacket(struct ipv6cp *ipv6cp, struct link *l) 32481634Sbrian{ 32581634Sbrian struct bundle *bundle = ipv6cp->fsm.bundle; 32681634Sbrian struct mqueue *queue; 32781634Sbrian struct mbuf *bp; 32881634Sbrian int m_len; 32981634Sbrian u_int32_t secs = 0; 33081634Sbrian unsigned alivesecs = 0; 33181634Sbrian 33281634Sbrian if (ipv6cp->fsm.state != ST_OPENED) 33381634Sbrian return 0; 33481634Sbrian 33581634Sbrian /* 33681634Sbrian * If ccp is not open but is required, do nothing. 33781634Sbrian */ 33881634Sbrian if (l->ccp.fsm.state != ST_OPENED && ccp_Required(&l->ccp)) { 33981634Sbrian log_Printf(LogPHASE, "%s: Not transmitting... waiting for CCP\n", l->name); 34081634Sbrian return 0; 34181634Sbrian } 34281634Sbrian 34381634Sbrian queue = ipv6cp->Queue + IPV6CP_QUEUES(ipv6cp) - 1; 34481634Sbrian do { 34581634Sbrian if (queue->top) { 34681634Sbrian bp = m_dequeue(queue); 34781634Sbrian bp = mbuf_Read(bp, &secs, sizeof secs); 34881634Sbrian bp = m_pullup(bp); 34981634Sbrian m_len = m_length(bp); 35081634Sbrian if (!FilterCheck(MBUF_CTOP(bp), AF_INET6, &bundle->filter.alive, 35181634Sbrian &alivesecs)) { 35281634Sbrian if (secs == 0) 35381634Sbrian secs = alivesecs; 35481634Sbrian bundle_StartIdleTimer(bundle, secs); 35581634Sbrian } 35681634Sbrian link_PushPacket(l, bp, bundle, 0, PROTO_IPV6); 35781634Sbrian ipv6cp_AddOutOctets(ipv6cp, m_len); 35881634Sbrian return 1; 35981634Sbrian } 36081634Sbrian } while (queue-- != ipv6cp->Queue); 36181634Sbrian 36281634Sbrian return 0; 36381634Sbrian} 36481634Sbrian 36581634Sbrianstatic int 36681634Sbrianipv6cp_LayerUp(struct fsm *fp) 36781634Sbrian{ 36881634Sbrian /* We're now up */ 36981634Sbrian struct ipv6cp *ipv6cp = fsm2ipv6cp(fp); 37081634Sbrian char tbuff[40]; 37181634Sbrian 37281634Sbrian log_Printf(LogIPV6CP, "%s: LayerUp.\n", fp->link->name); 37381634Sbrian if (!ipv6cp_InterfaceUp(ipv6cp)) 37481634Sbrian return 0; 37581634Sbrian 37681634Sbrian snprintf(tbuff, sizeof tbuff, "%s", ncpaddr_ntoa(&ipv6cp->myaddr)); 37781634Sbrian log_Printf(LogIPV6CP, "myaddr %s hisaddr = %s\n", 37881634Sbrian tbuff, ncpaddr_ntoa(&ipv6cp->hisaddr)); 37981634Sbrian 38081634Sbrian /* XXX: Call radius_Account() and system_Select() */ 38181634Sbrian 38281634Sbrian fp->more.reqs = fp->more.naks = fp->more.rejs = ipv6cp->cfg.fsm.maxreq * 3; 38381634Sbrian log_DisplayPrompts(); 38481634Sbrian 38581634Sbrian return 1; 38681634Sbrian} 38781634Sbrian 38881634Sbrianstatic void 38981634Sbrianipv6cp_LayerDown(struct fsm *fp) 39081634Sbrian{ 39181634Sbrian /* About to come down */ 39281634Sbrian struct ipv6cp *ipv6cp = fsm2ipv6cp(fp); 39381634Sbrian static int recursing; 39481634Sbrian char addr[40]; 39581634Sbrian 39681634Sbrian if (!recursing++) { 39781634Sbrian snprintf(addr, sizeof addr, "%s", ncpaddr_ntoa(&ipv6cp->myaddr)); 39881634Sbrian log_Printf(LogIPV6CP, "%s: LayerDown: %s\n", fp->link->name, addr); 39981634Sbrian 40081634Sbrian /* XXX: Call radius_Account() and system_Select() */ 40181634Sbrian 40281634Sbrian ipv6cp_Setup(ipv6cp); 40381634Sbrian } 40481634Sbrian recursing--; 40581634Sbrian} 40681634Sbrian 40781634Sbrianstatic void 40881634Sbrianipv6cp_LayerStart(struct fsm *fp) 40981634Sbrian{ 41081634Sbrian /* We're about to start up ! */ 41181634Sbrian struct ipv6cp *ipv6cp = fsm2ipv6cp(fp); 41281634Sbrian 41381634Sbrian log_Printf(LogIPV6CP, "%s: LayerStart.\n", fp->link->name); 41481634Sbrian throughput_start(&ipv6cp->throughput, "IPV6CP throughput", 41581634Sbrian Enabled(fp->bundle, OPT_THROUGHPUT)); 41681634Sbrian fp->more.reqs = fp->more.naks = fp->more.rejs = ipv6cp->cfg.fsm.maxreq * 3; 41781634Sbrian ipv6cp->peer_tokenreq = 0; 41881634Sbrian} 41981634Sbrian 42081634Sbrianstatic void 42181634Sbrianipv6cp_LayerFinish(struct fsm *fp) 42281634Sbrian{ 42381634Sbrian /* We're now down */ 42481634Sbrian struct ipv6cp *ipv6cp = fsm2ipv6cp(fp); 42581634Sbrian 42681634Sbrian log_Printf(LogIPV6CP, "%s: LayerFinish.\n", fp->link->name); 42781634Sbrian throughput_stop(&ipv6cp->throughput); 42881634Sbrian throughput_log(&ipv6cp->throughput, LogIPV6CP, NULL); 42981634Sbrian} 43081634Sbrian 43181634Sbrianstatic void 43281634Sbrianipv6cp_InitRestartCounter(struct fsm *fp, int what) 43381634Sbrian{ 43481634Sbrian /* Set fsm timer load */ 43581634Sbrian struct ipv6cp *ipv6cp = fsm2ipv6cp(fp); 43681634Sbrian 43781634Sbrian fp->FsmTimer.load = ipv6cp->cfg.fsm.timeout * SECTICKS; 43881634Sbrian switch (what) { 43981634Sbrian case FSM_REQ_TIMER: 44081634Sbrian fp->restart = ipv6cp->cfg.fsm.maxreq; 44181634Sbrian break; 44281634Sbrian case FSM_TRM_TIMER: 44381634Sbrian fp->restart = ipv6cp->cfg.fsm.maxtrm; 44481634Sbrian break; 44581634Sbrian default: 44681634Sbrian fp->restart = 1; 44781634Sbrian break; 44881634Sbrian } 44981634Sbrian} 45081634Sbrian 45181634Sbrianstatic void 45281634Sbrianipv6cp_SendConfigReq(struct fsm *fp) 45381634Sbrian{ 45481634Sbrian /* Send config REQ please */ 45581634Sbrian struct physical *p = link2physical(fp->link); 45681634Sbrian struct ipv6cp *ipv6cp = fsm2ipv6cp(fp); 45781634Sbrian u_char buff[6]; 45881634Sbrian struct lcp_opt *o; 45981634Sbrian 46081634Sbrian o = (struct lcp_opt *)buff; 46181634Sbrian 46281634Sbrian if ((p && !physical_IsSync(p)) || !REJECTED(ipv6cp, TY_TOKEN)) { 46381634Sbrian memcpy(o->data, &ipv6cp->my_token, 4); 46481634Sbrian INC_LCP_OPT(TY_TOKEN, 6, o); 46581634Sbrian } 46681634Sbrian 46781634Sbrian fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, (u_char *)o - buff, 46881634Sbrian MB_IPV6CPOUT); 46981634Sbrian} 47081634Sbrian 47181634Sbrianstatic void 47281634Sbrianipv6cp_SentTerminateReq(struct fsm *fp) 47381634Sbrian{ 47481634Sbrian /* Term REQ just sent by FSM */ 47581634Sbrian} 47681634Sbrian 47781634Sbrianstatic void 47881634Sbrianipv6cp_SendTerminateAck(struct fsm *fp, u_char id) 47981634Sbrian{ 48081634Sbrian /* Send Term ACK please */ 48181634Sbrian fsm_Output(fp, CODE_TERMACK, id, NULL, 0, MB_IPV6CPOUT); 48281634Sbrian} 48381634Sbrian 48481634Sbrianstatic const char * 48581634Sbrianprotoname(int proto) 48681634Sbrian{ 48781634Sbrian static const char *cftypes[] = { "TOKEN", "COMPPROTO" }; 48881634Sbrian 48981634Sbrian if (proto > 0 && proto <= sizeof cftypes / sizeof *cftypes) 49081634Sbrian return cftypes[proto - 1]; 49181634Sbrian 49281634Sbrian return NumStr(proto, NULL, 0); 49381634Sbrian} 49481634Sbrian 49581634Sbrianstatic void 49681634Sbrianipv6cp_ValidateToken(struct ipv6cp *ipv6cp, u_int32_t token, 49781634Sbrian struct fsm_decode *dec) 49881634Sbrian{ 49981634Sbrian if (token != 0 && token != ipv6cp->my_token) 50081634Sbrian ipv6cp->peer_token = token; 50181634Sbrian 50281634Sbrian if (token == ipv6cp->peer_token) { 50381634Sbrian *dec->ackend++ = TY_TOKEN; 50481634Sbrian *dec->ackend++ = 6; 50581634Sbrian memcpy(dec->ackend, &ipv6cp->peer_token, 4); 50681634Sbrian dec->ackend += 4; 50781634Sbrian } else { 50881634Sbrian *dec->nakend++ = TY_TOKEN; 50981634Sbrian *dec->nakend++ = 6; 51081634Sbrian memcpy(dec->nakend, &ipv6cp->peer_token, 4); 51181634Sbrian dec->nakend += 4; 51281634Sbrian } 51381634Sbrian} 51481634Sbrian 51581634Sbrianstatic void 51681634Sbrianipv6cp_DecodeConfig(struct fsm *fp, u_char *cp, int plen, int mode_type, 51781634Sbrian struct fsm_decode *dec) 51881634Sbrian{ 51981634Sbrian /* Deal with incoming PROTO_IPV6CP */ 52081634Sbrian struct ipv6cp *ipv6cp = fsm2ipv6cp(fp); 52181634Sbrian int type, length, n; 52281634Sbrian char tbuff[100]; 52381634Sbrian u_int32_t token; 52481634Sbrian 52581634Sbrian while (plen >= sizeof(struct fsmconfig)) { 52681634Sbrian type = *cp; 52781634Sbrian length = cp[1]; 52881634Sbrian 52981634Sbrian if (length == 0) { 53081634Sbrian log_Printf(LogIPV6CP, "%s: IPV6CP size zero\n", fp->link->name); 53181634Sbrian break; 53281634Sbrian } 53381634Sbrian 53481634Sbrian snprintf(tbuff, sizeof tbuff, " %s[%d] ", protoname(type), length); 53581634Sbrian 53681634Sbrian switch (type) { 53781634Sbrian case TY_TOKEN: 53881634Sbrian memcpy(&token, cp + 2, 4); 53981634Sbrian log_Printf(LogIPV6CP, "%s 0x%08lx\n", tbuff, (unsigned long)token); 54081634Sbrian 54181634Sbrian switch (mode_type) { 54281634Sbrian case MODE_REQ: 54381634Sbrian ipv6cp->peer_tokenreq = 1; 54481634Sbrian ipv6cp_ValidateToken(ipv6cp, token, dec); 54581634Sbrian break; 54681634Sbrian 54781634Sbrian case MODE_NAK: 54881634Sbrian if (token == 0) { 54981634Sbrian log_Printf(log_IsKept(LogIPV6CP) ? LogIPV6CP : LogPHASE, 55081634Sbrian "0x00000000: Unacceptable token!\n"); 55181634Sbrian fsm_Close(&ipv6cp->fsm); 55281634Sbrian } else if (token == ipv6cp->peer_token) 55381634Sbrian log_Printf(log_IsKept(LogIPV6CP) ? LogIPV6CP : LogPHASE, 55481634Sbrian "0x08lx: Unacceptable token!\n", (unsigned long)token); 55581634Sbrian else if (token != ipv6cp->my_token) { 55681634Sbrian n = 100; 55781897Sbrian while (n && !ipcp_SetIPv6address(ipv6cp, token, ipv6cp->peer_token)) { 55881897Sbrian n--; 55981634Sbrian while (n && (token = GenerateToken()) == ipv6cp->peer_token) 56081634Sbrian n--; 56181897Sbrian } 56281634Sbrian 56381634Sbrian if (n == 0) { 56481634Sbrian log_Printf(log_IsKept(LogIPV6CP) ? LogIPV6CP : LogPHASE, 56581634Sbrian "0x00000000: Unacceptable token!\n"); 56681634Sbrian fsm_Close(&ipv6cp->fsm); 56781634Sbrian } else { 56881634Sbrian log_Printf(LogIPV6CP, "%s changing token: 0x%08lx --> 0x%08lx\n", 56981634Sbrian tbuff, (unsigned long)ipv6cp->my_token, 57081634Sbrian (unsigned long)token); 57181634Sbrian ipv6cp->my_token = token; 57281634Sbrian bundle_AdjustFilters(fp->bundle, &ipv6cp->myaddr, NULL); 57381634Sbrian } 57481634Sbrian } 57581634Sbrian break; 57681634Sbrian 57781634Sbrian case MODE_REJ: 57881634Sbrian ipv6cp->his_reject |= (1 << type); 57981634Sbrian break; 58081634Sbrian } 58181634Sbrian break; 58281634Sbrian 58381634Sbrian default: 58481634Sbrian if (mode_type != MODE_NOP) { 58581634Sbrian ipv6cp->my_reject |= (1 << type); 58681634Sbrian memcpy(dec->rejend, cp, length); 58781634Sbrian dec->rejend += length; 58881634Sbrian } 58981634Sbrian break; 59081634Sbrian } 59181634Sbrian plen -= length; 59281634Sbrian cp += length; 59381634Sbrian } 59481634Sbrian 59581634Sbrian if (mode_type != MODE_NOP) { 59681634Sbrian if (mode_type == MODE_REQ && !ipv6cp->peer_tokenreq) { 59781634Sbrian if (dec->rejend == dec->rej && dec->nakend == dec->nak) { 59881634Sbrian /* 59981634Sbrian * Pretend the peer has requested a TOKEN. 60081634Sbrian * We do this to ensure that we only send one NAK if the only 60181634Sbrian * reason for the NAK is because the peer isn't sending a 60281634Sbrian * TY_TOKEN REQ. This stops us from repeatedly trying to tell 60381634Sbrian * the peer that we have to have an IP address on their end. 60481634Sbrian */ 60581634Sbrian ipv6cp->peer_tokenreq = 1; 60681634Sbrian } 60781634Sbrian ipv6cp_ValidateToken(ipv6cp, 0, dec); 60881634Sbrian } 60981634Sbrian if (dec->rejend != dec->rej) { 61081634Sbrian /* rejects are preferred */ 61181634Sbrian dec->ackend = dec->ack; 61281634Sbrian dec->nakend = dec->nak; 61381634Sbrian } else if (dec->nakend != dec->nak) 61481634Sbrian /* then NAKs */ 61581634Sbrian dec->ackend = dec->ack; 61681634Sbrian } 61781634Sbrian} 61881634Sbrian#endif 619