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