1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2001 Brian Somers <brian@Awfulhak.org>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 * $FreeBSD: stable/11/usr.sbin/ppp/ipv6cp.c 330804 2018-03-12 17:36:37Z eugen $
29 */
30
31#include <sys/param.h>
32#include <netinet/in_systm.h>
33#include <netinet/in.h>
34#include <netinet/ip.h>
35#include <sys/socket.h>
36#include <net/route.h>
37#include <net/if.h>
38#include <net/if_types.h>
39#include <net/if_dl.h>
40#include <sys/un.h>
41
42#include <stdarg.h>
43#include <stdio.h>
44#include <stdlib.h>
45#include <string.h>
46#include <termios.h>
47#include <ifaddrs.h>
48
49#include "layer.h"
50#include "defs.h"
51#include "mbuf.h"
52#include "timer.h"
53#include "fsm.h"
54#include "iplist.h"
55#include "throughput.h"
56#include "slcompress.h"
57#include "lqr.h"
58#include "hdlc.h"
59#include "lcp.h"
60#include "ncpaddr.h"
61#include "ip.h"
62#include "ipcp.h"
63#include "ipv6cp.h"
64#include "filter.h"
65#include "descriptor.h"
66#include "ccp.h"
67#include "link.h"
68#include "mp.h"
69#ifndef NORADIUS
70#include "radius.h"
71#endif
72#include "ncp.h"
73#include "bundle.h"
74#include "route.h"
75#include "iface.h"
76#include "log.h"
77#include "proto.h"
78#include "command.h"
79#include "prompt.h"
80#include "async.h"
81#include "physical.h"
82#include "probe.h"
83#include "systems.h"
84
85
86#ifndef NOINET6
87#define IN6ADDR_LINKLOCAL_MCAST_INIT \
88	{{{ 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
89	    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}}
90static const struct in6_addr in6addr_linklocal_mcast =
91	IN6ADDR_LINKLOCAL_MCAST_INIT;
92
93static int ipv6cp_LayerUp(struct fsm *);
94static void ipv6cp_LayerDown(struct fsm *);
95static void ipv6cp_LayerStart(struct fsm *);
96static void ipv6cp_LayerFinish(struct fsm *);
97static void ipv6cp_InitRestartCounter(struct fsm *, int);
98static void ipv6cp_SendConfigReq(struct fsm *);
99static void ipv6cp_SentTerminateReq(struct fsm *);
100static void ipv6cp_SendTerminateAck(struct fsm *, u_char);
101static void ipv6cp_DecodeConfig(struct fsm *, u_char *, u_char *, int,
102                                struct fsm_decode *);
103
104static struct fsm_callbacks ipv6cp_Callbacks = {
105  ipv6cp_LayerUp,
106  ipv6cp_LayerDown,
107  ipv6cp_LayerStart,
108  ipv6cp_LayerFinish,
109  ipv6cp_InitRestartCounter,
110  ipv6cp_SendConfigReq,
111  ipv6cp_SentTerminateReq,
112  ipv6cp_SendTerminateAck,
113  ipv6cp_DecodeConfig,
114  fsm_NullRecvResetReq,
115  fsm_NullRecvResetAck
116};
117
118static void
119SetInterfaceID(u_char *ifid, int userandom)
120{
121  struct ifaddrs *ifa, *ifap = NULL;
122  struct sockaddr_dl *sdl;
123  const u_long i32_max = 0xffffffff;
124  u_long r1, r2;
125
126  /* configure an interface ID based on Section 4.1 of RFC 2472 */
127  memset(ifid, 0, IPV6CP_IFIDLEN);
128
129  /*
130   * 1) If an IEEE global identifier (EUI-48 or EUI-64) is
131   * available anywhere on the node, it should be used to construct
132   * the tentative Interface-Identifier due to its uniqueness
133   * properties.
134   */
135  if (userandom)
136    goto randomid;
137  if (getifaddrs(&ifap) < 0)
138    goto randomid;
139
140  for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
141    char *cp;
142
143    if (ifa->ifa_addr->sa_family != AF_LINK)
144      continue;
145
146    sdl = (struct sockaddr_dl *)ifa->ifa_addr;
147    if (sdl->sdl_alen < 6)
148      continue;
149    /* we're only interested in IEEE hardware addresses */
150    switch(sdl->sdl_type) {
151    case IFT_ETHER:
152    case IFT_FDDI:
153    case IFT_L2VLAN:
154      /* XXX need more cases? */
155      break;
156    default:
157      continue;
158    }
159
160    cp = (char *)(sdl->sdl_data + sdl->sdl_nlen);
161    ifid[0] = cp[0];
162    ifid[0] ^= 0x02; /* reverse the u/l bit*/
163    ifid[1] = cp[1];
164    ifid[2] = cp[2];
165    ifid[3] = 0xff;
166    ifid[4] = 0xfe;
167    ifid[5] = cp[3];
168    ifid[6] = cp[4];
169    ifid[7] = cp[5];
170
171    freeifaddrs(ifap);
172    return;
173  }
174
175  freeifaddrs(ifap);
176
177  /*
178   * 2) If an IEEE global identifier is not available a different source
179   * of uniqueness should be used.
180   * XXX: we skip this case.
181   */
182
183  /*
184   * 3) If a good source of uniqueness cannot be found, it is
185   * recommended that a random number be generated.  In this case the
186   * "u" bit of the interface identifier MUST be set to zero (0).
187   */
188 randomid:
189  randinit();
190  r1 = (((u_long)random()) % i32_max) + 1;
191  r2 = (((u_long)random()) % i32_max) + 1;
192  memcpy(ifid, &r1, sizeof(r1));
193  memcpy(ifid + 4, &r2, sizeof(r2));
194  ifid[0] &= 0xfd;
195  return;
196}
197
198static int
199ipcp_SetIPv6address(struct ipv6cp *ipv6cp, u_char *myifid, u_char *hisifid)
200{
201  struct bundle *bundle = ipv6cp->fsm.bundle;
202  struct in6_addr myaddr, hisaddr;
203  struct ncprange myrange, range;
204  struct ncpaddr addr;
205  struct sockaddr_storage ssdst, ssgw, ssmask;
206  struct sockaddr *sadst, *sagw, *samask;
207
208  sadst = (struct sockaddr *)&ssdst;
209  sagw = (struct sockaddr *)&ssgw;
210  samask = (struct sockaddr *)&ssmask;
211
212  memset(&myaddr, '\0', sizeof myaddr);
213  memset(&hisaddr, '\0', sizeof hisaddr);
214
215  myaddr.s6_addr[0] = 0xfe;
216  myaddr.s6_addr[1] = 0x80;
217  memcpy(&myaddr.s6_addr[8], myifid, IPV6CP_IFIDLEN);
218#if 0
219  myaddr.s6_addr[8] |= 0x02;	/* set 'universal' bit */
220#endif
221
222  hisaddr.s6_addr[0] = 0xfe;
223  hisaddr.s6_addr[1] = 0x80;
224  memcpy(&hisaddr.s6_addr[8], hisifid, IPV6CP_IFIDLEN);
225#if 0
226  hisaddr.s6_addr[8] |= 0x02;	/* set 'universal' bit */
227#endif
228
229  ncpaddr_setip6(&ipv6cp->myaddr, &myaddr);
230  ncpaddr_setip6(&ipv6cp->hisaddr, &hisaddr);
231  ncprange_set(&myrange, &ipv6cp->myaddr, 64);
232
233  if (!iface_Add(bundle->iface, &bundle->ncp, &myrange, &ipv6cp->hisaddr,
234                 IFACE_ADD_FIRST|IFACE_FORCE_ADD|IFACE_SYSTEM))
235    return 0;
236
237  if (!Enabled(bundle, OPT_IFACEALIAS))
238    iface_Clear(bundle->iface, &bundle->ncp, AF_INET6,
239                IFACE_CLEAR_ALIASES|IFACE_SYSTEM);
240
241  ncpaddr_setip6(&addr, &in6addr_linklocal_mcast);
242  ncprange_set(&range, &addr, 32);
243  rt_Set(bundle, RTM_ADD, &range, &ipv6cp->myaddr, 1, 0);
244
245  if (bundle->ncp.cfg.sendpipe > 0 || bundle->ncp.cfg.recvpipe > 0) {
246    ncprange_getsa(&myrange, &ssgw, &ssmask);
247    if (ncpaddr_isset(&ipv6cp->hisaddr))
248      ncpaddr_getsa(&ipv6cp->hisaddr, &ssdst);
249    else
250      sadst = NULL;
251    rt_Update(bundle, sadst, sagw, samask, NULL, NULL);
252  }
253
254  if (Enabled(bundle, OPT_SROUTES))
255    route_Change(bundle, bundle->ncp.route, &ipv6cp->myaddr, &ipv6cp->hisaddr);
256
257#ifndef NORADIUS
258  if (bundle->radius.valid)
259    route_Change(bundle, bundle->radius.ipv6routes, &ipv6cp->myaddr,
260                 &ipv6cp->hisaddr);
261#endif
262
263  return 1;	/* Ok */
264}
265
266void
267ipv6cp_Init(struct ipv6cp *ipv6cp, struct bundle *bundle, struct link *l,
268                 const struct fsm_parent *parent)
269{
270  static const char * const timer_names[] =
271    {"IPV6CP restart", "IPV6CP openmode", "IPV6CP stopped"};
272  int n;
273
274  fsm_Init(&ipv6cp->fsm, "IPV6CP", PROTO_IPV6CP, 1, IPV6CP_MAXCODE, LogIPV6CP,
275           bundle, l, parent, &ipv6cp_Callbacks, timer_names);
276
277  ipv6cp->cfg.fsm.timeout = DEF_FSMRETRY;
278  ipv6cp->cfg.fsm.maxreq = DEF_FSMTRIES;
279  ipv6cp->cfg.fsm.maxtrm = DEF_FSMTRIES;
280
281  SetInterfaceID(ipv6cp->my_ifid, 0);
282  do {
283    SetInterfaceID(ipv6cp->his_ifid, 1);
284  } while (memcmp(ipv6cp->his_ifid, ipv6cp->my_ifid, IPV6CP_IFIDLEN) == 0);
285
286  if (probe.ipv6_available) {
287    n = 100;
288    while (n &&
289           !ipcp_SetIPv6address(ipv6cp, ipv6cp->my_ifid, ipv6cp->his_ifid)) {
290      do {
291	n--;
292    	SetInterfaceID(ipv6cp->my_ifid, 1);
293      } while (n
294	&& memcmp(ipv6cp->his_ifid, ipv6cp->my_ifid, IPV6CP_IFIDLEN) == 0);
295    }
296  }
297
298  throughput_init(&ipv6cp->throughput, SAMPLE_PERIOD);
299  memset(ipv6cp->Queue, '\0', sizeof ipv6cp->Queue);
300  ipv6cp_Setup(ipv6cp);
301}
302
303void
304ipv6cp_Destroy(struct ipv6cp *ipv6cp)
305{
306  throughput_destroy(&ipv6cp->throughput);
307}
308
309void
310ipv6cp_Setup(struct ipv6cp *ipv6cp)
311{
312  ncpaddr_init(&ipv6cp->myaddr);
313  ncpaddr_init(&ipv6cp->hisaddr);
314
315  ipv6cp->his_reject = 0;
316  ipv6cp->my_reject = 0;
317}
318
319void
320ipv6cp_SetLink(struct ipv6cp *ipv6cp, struct link *l)
321{
322  ipv6cp->fsm.link = l;
323}
324
325int
326ipv6cp_Show(struct cmdargs const *arg)
327{
328  struct ipv6cp *ipv6cp = &arg->bundle->ncp.ipv6cp;
329
330  prompt_Printf(arg->prompt, "%s [%s]\n", ipv6cp->fsm.name,
331                State2Nam(ipv6cp->fsm.state));
332  if (ipv6cp->fsm.state == ST_OPENED) {
333    prompt_Printf(arg->prompt, " His side:        %s\n",
334                  ncpaddr_ntoa(&ipv6cp->hisaddr));
335    prompt_Printf(arg->prompt, " My side:         %s\n",
336                  ncpaddr_ntoa(&ipv6cp->myaddr));
337    prompt_Printf(arg->prompt, " Queued packets:  %lu\n",
338                  (unsigned long)ipv6cp_QueueLen(ipv6cp));
339  }
340
341  prompt_Printf(arg->prompt, "\nDefaults:\n");
342  prompt_Printf(arg->prompt, "  FSM retry = %us, max %u Config"
343                " REQ%s, %u Term REQ%s\n\n", ipv6cp->cfg.fsm.timeout,
344                ipv6cp->cfg.fsm.maxreq, ipv6cp->cfg.fsm.maxreq == 1 ? "" : "s",
345                ipv6cp->cfg.fsm.maxtrm, ipv6cp->cfg.fsm.maxtrm == 1 ? "" : "s");
346
347  throughput_disp(&ipv6cp->throughput, arg->prompt);
348
349  return 0;
350}
351
352struct mbuf *
353ipv6cp_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
354{
355  /* Got PROTO_IPV6CP from link */
356  m_settype(bp, MB_IPV6CPIN);
357  if (bundle_Phase(bundle) == PHASE_NETWORK)
358    fsm_Input(&bundle->ncp.ipv6cp.fsm, bp);
359  else {
360    if (bundle_Phase(bundle) < PHASE_NETWORK)
361      log_Printf(LogIPV6CP, "%s: Error: Unexpected IPV6CP in phase %s"
362                 " (ignored)\n", l->name, bundle_PhaseName(bundle));
363    m_freem(bp);
364  }
365  return NULL;
366}
367
368void
369ipv6cp_AddInOctets(struct ipv6cp *ipv6cp, int n)
370{
371  throughput_addin(&ipv6cp->throughput, n);
372}
373
374void
375ipv6cp_AddOutOctets(struct ipv6cp *ipv6cp, int n)
376{
377  throughput_addout(&ipv6cp->throughput, n);
378}
379
380void
381ipv6cp_IfaceAddrAdded(struct ipv6cp *ipv6cp __unused,
382		      const struct iface_addr *addr __unused)
383{
384}
385
386void
387ipv6cp_IfaceAddrDeleted(struct ipv6cp *ipv6cp __unused,
388			const struct iface_addr *addr __unused)
389{
390}
391
392int
393ipv6cp_InterfaceUp(struct ipv6cp *ipv6cp)
394{
395  if (!ipcp_SetIPv6address(ipv6cp, ipv6cp->my_ifid, ipv6cp->his_ifid)) {
396    log_Printf(LogERROR, "ipv6cp_InterfaceUp: unable to set ipv6 address\n");
397    return 0;
398  }
399
400  if (!iface_SetFlags(ipv6cp->fsm.bundle->iface->name, IFF_UP)) {
401    log_Printf(LogERROR, "ipv6cp_InterfaceUp: Can't set the IFF_UP"
402               " flag on %s\n", ipv6cp->fsm.bundle->iface->name);
403    return 0;
404  }
405
406  return 1;
407}
408
409size_t
410ipv6cp_QueueLen(struct ipv6cp *ipv6cp)
411{
412  struct mqueue *q;
413  size_t result;
414
415  result = 0;
416  for (q = ipv6cp->Queue; q < ipv6cp->Queue + IPV6CP_QUEUES(ipv6cp); q++)
417    result += q->len;
418
419  return result;
420}
421
422int
423ipv6cp_PushPacket(struct ipv6cp *ipv6cp, struct link *l)
424{
425  struct bundle *bundle = ipv6cp->fsm.bundle;
426  struct mqueue *queue;
427  struct mbuf *bp;
428  int m_len;
429  u_int32_t secs = 0;
430  unsigned alivesecs = 0;
431
432  if (ipv6cp->fsm.state != ST_OPENED)
433    return 0;
434
435  /*
436   * If ccp is not open but is required, do nothing.
437   */
438  if (l->ccp.fsm.state != ST_OPENED && ccp_Required(&l->ccp)) {
439    log_Printf(LogPHASE, "%s: Not transmitting... waiting for CCP\n", l->name);
440    return 0;
441  }
442
443  queue = ipv6cp->Queue + IPV6CP_QUEUES(ipv6cp) - 1;
444  do {
445    if (queue->top) {
446      bp = m_dequeue(queue);
447      bp = mbuf_Read(bp, &secs, sizeof secs);
448      bp = m_pullup(bp);
449      m_len = m_length(bp);
450      if (!FilterCheck(MBUF_CTOP(bp), AF_INET6, &bundle->filter.alive,
451                       &alivesecs)) {
452        if (secs == 0)
453          secs = alivesecs;
454        bundle_StartIdleTimer(bundle, secs);
455      }
456      link_PushPacket(l, bp, bundle, 0, PROTO_IPV6);
457      ipv6cp_AddOutOctets(ipv6cp, m_len);
458      return 1;
459    }
460  } while (queue-- != ipv6cp->Queue);
461
462  return 0;
463}
464
465static int
466ipv6cp_LayerUp(struct fsm *fp)
467{
468  /* We're now up */
469  struct ipv6cp *ipv6cp = fsm2ipv6cp(fp);
470  char tbuff[NCP_ASCIIBUFFERSIZE];
471
472  log_Printf(LogIPV6CP, "%s: LayerUp.\n", fp->link->name);
473  if (!ipv6cp_InterfaceUp(ipv6cp))
474    return 0;
475
476  snprintf(tbuff, sizeof tbuff, "%s", ncpaddr_ntoa(&ipv6cp->myaddr));
477  log_Printf(LogIPV6CP, "myaddr %s hisaddr = %s\n",
478             tbuff, ncpaddr_ntoa(&ipv6cp->hisaddr));
479
480#ifndef NORADIUS
481  radius_Account_Set_Ipv6(&fp->bundle->radacct6, ipv6cp->his_ifid);
482  radius_Account(&fp->bundle->radius, &fp->bundle->radacct6,
483		 fp->bundle->links, RAD_START, &ipv6cp->throughput);
484
485  /*
486   * XXX: Avoid duplicate evaluation of filterid between IPCP and
487   * IPV6CP.  When IPCP is enabled and rejected, filterid is not
488   * evaluated.
489   */
490  if (!Enabled(fp->bundle, OPT_IPCP)) {
491    if (*fp->bundle->radius.cfg.file && fp->bundle->radius.filterid)
492      system_Select(fp->bundle, fp->bundle->radius.filterid, LINKUPFILE,
493		    NULL, NULL);
494  }
495#endif
496
497  /*
498   * XXX this stuff should really live in the FSM.  Our config should
499   * associate executable sections in files with events.
500   */
501  if (system_Select(fp->bundle, tbuff, LINKUPFILE, NULL, NULL) < 0) {
502    /*
503     * XXX: Avoid duplicate evaluation of label between IPCP and
504     * IPV6CP.  When IPCP is enabled and rejected, label is not
505     * evaluated.
506     */
507    if (bundle_GetLabel(fp->bundle) && !Enabled(fp->bundle, OPT_IPCP)) {
508      if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle),
509			LINKUPFILE, NULL, NULL) < 0)
510	system_Select(fp->bundle, "MYADDR6", LINKUPFILE, NULL, NULL);
511    } else
512      system_Select(fp->bundle, "MYADDR6", LINKUPFILE, NULL, NULL);
513  }
514
515  fp->more.reqs = fp->more.naks = fp->more.rejs = ipv6cp->cfg.fsm.maxreq * 3;
516  log_DisplayPrompts();
517
518  return 1;
519}
520
521static void
522ipv6cp_LayerDown(struct fsm *fp)
523{
524  /* About to come down */
525  struct ipv6cp *ipv6cp = fsm2ipv6cp(fp);
526  static int recursing;
527  char addr[NCP_ASCIIBUFFERSIZE];
528
529  if (!recursing++) {
530    snprintf(addr, sizeof addr, "%s", ncpaddr_ntoa(&ipv6cp->myaddr));
531    log_Printf(LogIPV6CP, "%s: LayerDown: %s\n", fp->link->name, addr);
532
533#ifndef NORADIUS
534    radius_Flush(&fp->bundle->radius);
535    radius_Account(&fp->bundle->radius, &fp->bundle->radacct6,
536		   fp->bundle->links, RAD_STOP, &ipv6cp->throughput);
537
538    /*
539     * XXX: Avoid duplicate evaluation of filterid between IPCP and
540     * IPV6CP.  When IPCP is enabled and rejected, filterid is not
541     * evaluated.
542     */
543    if (!Enabled(fp->bundle, OPT_IPCP)) {
544      if (*fp->bundle->radius.cfg.file && fp->bundle->radius.filterid)
545	system_Select(fp->bundle, fp->bundle->radius.filterid, LINKDOWNFILE,
546		      NULL, NULL);
547    }
548#endif
549
550    /*
551     * XXX this stuff should really live in the FSM.  Our config should
552     * associate executable sections in files with events.
553     */
554    if (system_Select(fp->bundle, addr, LINKDOWNFILE, NULL, NULL) < 0) {
555      /*
556       * XXX: Avoid duplicate evaluation of label between IPCP and
557       * IPV6CP.  When IPCP is enabled and rejected, label is not
558       * evaluated.
559       */
560      if (bundle_GetLabel(fp->bundle) && !Enabled(fp->bundle, OPT_IPCP)) {
561	if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle),
562			  LINKDOWNFILE, NULL, NULL) < 0)
563	  system_Select(fp->bundle, "MYADDR6", LINKDOWNFILE, NULL, NULL);
564      } else
565	system_Select(fp->bundle, "MYADDR6", LINKDOWNFILE, NULL, NULL);
566    }
567
568    ipv6cp_Setup(ipv6cp);
569  }
570  recursing--;
571}
572
573static void
574ipv6cp_LayerStart(struct fsm *fp)
575{
576  /* We're about to start up ! */
577  struct ipv6cp *ipv6cp = fsm2ipv6cp(fp);
578
579  log_Printf(LogIPV6CP, "%s: LayerStart.\n", fp->link->name);
580  throughput_start(&ipv6cp->throughput, "IPV6CP throughput",
581                   Enabled(fp->bundle, OPT_THROUGHPUT));
582  fp->more.reqs = fp->more.naks = fp->more.rejs = ipv6cp->cfg.fsm.maxreq * 3;
583  ipv6cp->peer_tokenreq = 0;
584}
585
586static void
587ipv6cp_LayerFinish(struct fsm *fp)
588{
589  /* We're now down */
590  struct ipv6cp *ipv6cp = fsm2ipv6cp(fp);
591
592  log_Printf(LogIPV6CP, "%s: LayerFinish.\n", fp->link->name);
593  throughput_stop(&ipv6cp->throughput);
594  throughput_log(&ipv6cp->throughput, LogIPV6CP, NULL);
595}
596
597static void
598ipv6cp_InitRestartCounter(struct fsm *fp, int what)
599{
600  /* Set fsm timer load */
601  struct ipv6cp *ipv6cp = fsm2ipv6cp(fp);
602
603  fp->FsmTimer.load = ipv6cp->cfg.fsm.timeout * SECTICKS;
604  switch (what) {
605    case FSM_REQ_TIMER:
606      fp->restart = ipv6cp->cfg.fsm.maxreq;
607      break;
608    case FSM_TRM_TIMER:
609      fp->restart = ipv6cp->cfg.fsm.maxtrm;
610      break;
611    default:
612      fp->restart = 1;
613      break;
614  }
615}
616
617static void
618ipv6cp_SendConfigReq(struct fsm *fp)
619{
620  /* Send config REQ please */
621  struct physical *p = link2physical(fp->link);
622  struct ipv6cp *ipv6cp = fsm2ipv6cp(fp);
623  u_char buff[IPV6CP_IFIDLEN+2];
624  struct fsm_opt *o;
625
626  o = (struct fsm_opt *)buff;
627
628  if ((p && !physical_IsSync(p)) || !REJECTED(ipv6cp, TY_TOKEN)) {
629    memcpy(o->data, ipv6cp->my_ifid, IPV6CP_IFIDLEN);
630    INC_FSM_OPT(TY_TOKEN, IPV6CP_IFIDLEN + 2, o);
631  }
632
633  fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, (u_char *)o - buff,
634             MB_IPV6CPOUT);
635}
636
637static void
638ipv6cp_SentTerminateReq(struct fsm *fp __unused)
639{
640  /* Term REQ just sent by FSM */
641}
642
643static void
644ipv6cp_SendTerminateAck(struct fsm *fp, u_char id)
645{
646  /* Send Term ACK please */
647  fsm_Output(fp, CODE_TERMACK, id, NULL, 0, MB_IPV6CPOUT);
648}
649
650static const char *
651protoname(unsigned proto)
652{
653  static const char *cftypes[] = { "IFACEID", "COMPPROTO" };
654
655  if (proto > 0 && proto <= sizeof cftypes / sizeof *cftypes)
656    return cftypes[proto - 1];
657
658  return NumStr(proto, NULL, 0);
659}
660
661static void
662ipv6cp_ValidateInterfaceID(struct ipv6cp *ipv6cp, u_char *ifid,
663			   struct fsm_decode *dec)
664{
665  struct fsm_opt opt;
666  u_char zero[IPV6CP_IFIDLEN];
667
668  memset(zero, 0, IPV6CP_IFIDLEN);
669
670  if (memcmp(ifid, zero, IPV6CP_IFIDLEN) != 0
671      && memcmp(ifid, ipv6cp->my_ifid, IPV6CP_IFIDLEN) != 0)
672    memcpy(ipv6cp->his_ifid, ifid, IPV6CP_IFIDLEN);
673
674  opt.hdr.id = TY_TOKEN;
675  opt.hdr.len = IPV6CP_IFIDLEN + 2;
676  memcpy(opt.data, &ipv6cp->his_ifid, IPV6CP_IFIDLEN);
677  if (memcmp(ifid, ipv6cp->his_ifid, IPV6CP_IFIDLEN) == 0)
678    fsm_ack(dec, &opt);
679  else
680    fsm_nak(dec, &opt);
681}
682
683static void
684ipv6cp_DecodeConfig(struct fsm *fp, u_char *cp, u_char *end, int mode_type,
685                    struct fsm_decode *dec)
686{
687  /* Deal with incoming PROTO_IPV6CP */
688  struct ipv6cp *ipv6cp = fsm2ipv6cp(fp);
689  int n;
690  char tbuff[100];
691  u_char ifid[IPV6CP_IFIDLEN], zero[IPV6CP_IFIDLEN];
692  struct fsm_opt *opt;
693
694  memset(zero, 0, IPV6CP_IFIDLEN);
695
696  while (end - cp >= (int)sizeof(opt->hdr)) {
697    if ((opt = fsm_readopt(&cp)) == NULL)
698      break;
699
700    snprintf(tbuff, sizeof tbuff, " %s[%d]", protoname(opt->hdr.id),
701             opt->hdr.len);
702
703    switch (opt->hdr.id) {
704    case TY_TOKEN:
705      memcpy(ifid, opt->data, IPV6CP_IFIDLEN);
706      log_Printf(LogIPV6CP, "%s 0x%02x%02x%02x%02x%02x%02x%02x%02x\n", tbuff,
707		 ifid[0], ifid[1], ifid[2], ifid[3], ifid[4], ifid[5], ifid[6], ifid[7]);
708
709      switch (mode_type) {
710      case MODE_REQ:
711        ipv6cp->peer_tokenreq = 1;
712        ipv6cp_ValidateInterfaceID(ipv6cp, ifid, dec);
713        break;
714
715      case MODE_NAK:
716        if (memcmp(ifid, zero, IPV6CP_IFIDLEN) == 0) {
717          log_Printf(log_IsKept(LogIPV6CP) ? LogIPV6CP : LogPHASE,
718		     "0x0000000000000000: Unacceptable IntefaceID!\n");
719          fsm_Close(&ipv6cp->fsm);
720        } else if (memcmp(ifid, ipv6cp->his_ifid, IPV6CP_IFIDLEN) == 0) {
721          log_Printf(log_IsKept(LogIPV6CP) ? LogIPV6CP : LogPHASE,
722		     "0x%02x%02x%02x%02x%02x%02x%02x%02x: "
723		     "Unacceptable IntefaceID!\n",
724		     ifid[0], ifid[1], ifid[2], ifid[3],
725		     ifid[4], ifid[5], ifid[6], ifid[7]);
726        } else if (memcmp(ifid, ipv6cp->my_ifid, IPV6CP_IFIDLEN) != 0) {
727          n = 100;
728	  while (n && !ipcp_SetIPv6address(ipv6cp, ifid, ipv6cp->his_ifid)) {
729	    do {
730	      n--;
731	      SetInterfaceID(ifid, 1);
732	    } while (n && memcmp(ifid, ipv6cp->his_ifid, IPV6CP_IFIDLEN) == 0);
733	  }
734
735          if (n == 0) {
736            log_Printf(log_IsKept(LogIPV6CP) ? LogIPV6CP : LogPHASE,
737                       "0x0000000000000000: Unacceptable IntefaceID!\n");
738            fsm_Close(&ipv6cp->fsm);
739          } else {
740	    log_Printf(LogIPV6CP, "%s changing IntefaceID: "
741		       "0x%02x%02x%02x%02x%02x%02x%02x%02x "
742		       "--> 0x%02x%02x%02x%02x%02x%02x%02x%02x\n", tbuff,
743		       ipv6cp->my_ifid[0], ipv6cp->my_ifid[1],
744		       ipv6cp->my_ifid[2], ipv6cp->my_ifid[3],
745		       ipv6cp->my_ifid[4], ipv6cp->my_ifid[5],
746		       ipv6cp->my_ifid[6], ipv6cp->my_ifid[7],
747		       ifid[0], ifid[1], ifid[2], ifid[3],
748		       ifid[4], ifid[5], ifid[6], ifid[7]);
749            memcpy(ipv6cp->my_ifid, ifid, IPV6CP_IFIDLEN);
750            bundle_AdjustFilters(fp->bundle, &ipv6cp->myaddr, NULL);
751          }
752        }
753        break;
754
755      case MODE_REJ:
756        ipv6cp->his_reject |= (1 << opt->hdr.id);
757        break;
758      }
759      break;
760
761    default:
762      if (mode_type != MODE_NOP) {
763        ipv6cp->my_reject |= (1 << opt->hdr.id);
764        fsm_rej(dec, opt);
765      }
766      break;
767    }
768  }
769
770  if (mode_type != MODE_NOP) {
771    if (mode_type == MODE_REQ && !ipv6cp->peer_tokenreq) {
772      if (dec->rejend == dec->rej && dec->nakend == dec->nak) {
773        /*
774         * Pretend the peer has requested a TOKEN.
775         * We do this to ensure that we only send one NAK if the only
776         * reason for the NAK is because the peer isn't sending a
777         * TY_TOKEN REQ.  This stops us from repeatedly trying to tell
778         * the peer that we have to have an IP address on their end.
779         */
780        ipv6cp->peer_tokenreq = 1;
781      }
782      memset(ifid, 0, IPV6CP_IFIDLEN);
783      ipv6cp_ValidateInterfaceID(ipv6cp, ifid, dec);
784    }
785    fsm_opt_normalise(dec);
786  }
787}
788#endif
789