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