]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/ppp/ipv6cp.c
This commit was generated by cvs2svn to compensate for changes in r102782,
[FreeBSD/FreeBSD.git] / usr.sbin / ppp / ipv6cp.c
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$
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 static int ipv6cp_LayerUp(struct fsm *);
85 static void ipv6cp_LayerDown(struct fsm *);
86 static void ipv6cp_LayerStart(struct fsm *);
87 static void ipv6cp_LayerFinish(struct fsm *);
88 static void ipv6cp_InitRestartCounter(struct fsm *, int);
89 static void ipv6cp_SendConfigReq(struct fsm *);
90 static void ipv6cp_SentTerminateReq(struct fsm *);
91 static void ipv6cp_SendTerminateAck(struct fsm *, u_char);
92 static void ipv6cp_DecodeConfig(struct fsm *, u_char *, u_char *, int,
93                                 struct fsm_decode *);
94
95 static struct fsm_callbacks ipv6cp_Callbacks = {
96   ipv6cp_LayerUp,
97   ipv6cp_LayerDown,
98   ipv6cp_LayerStart,
99   ipv6cp_LayerFinish,
100   ipv6cp_InitRestartCounter,
101   ipv6cp_SendConfigReq,
102   ipv6cp_SentTerminateReq,
103   ipv6cp_SendTerminateAck,
104   ipv6cp_DecodeConfig,
105   fsm_NullRecvResetReq,
106   fsm_NullRecvResetAck
107 };
108
109 static void
110 SetInterfaceID(u_char *ifid, int userandom)
111 {
112   struct ifaddrs *ifa, *ifap = NULL;
113   struct sockaddr_dl *sdl;
114   const u_long i32_max = 0xffffffff;
115   u_long r1, r2;
116
117   /* configure an interface ID based on Section 4.1 of RFC 2472 */
118   memset(ifid, 0, IPV6CP_IFIDLEN);
119
120   /*
121    * 1) If an IEEE global identifier (EUI-48 or EUI-64) is
122    * available anywhere on the node, it should be used to construct
123    * the tentative Interface-Identifier due to its uniqueness
124    * properties.
125    */
126   if (userandom)
127     goto randomid;
128   if (getifaddrs(&ifap) < 0)
129     goto randomid;
130         
131   for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
132     char *cp;
133
134     if (ifa->ifa_addr->sa_family != AF_LINK)
135       continue;
136
137     sdl = (struct sockaddr_dl *)ifa->ifa_addr;
138     if (sdl->sdl_alen < 6)
139       continue;
140     /* we're only interested in IEEE hardware addresses */
141     switch(sdl->sdl_type) {
142     case IFT_ETHER:
143     case IFT_FDDI:
144       /* XXX need more cases? */
145       break;
146     default:
147       continue;
148     }
149
150     cp = (char *)(sdl->sdl_data + sdl->sdl_nlen);
151     ifid[0] = cp[0];
152     ifid[0] ^= 0x02; /* reverse the u/l bit*/
153     ifid[1] = cp[1];
154     ifid[2] = cp[2];
155     ifid[3] = 0xff;
156     ifid[4] = 0xfe;
157     ifid[5] = cp[3];
158     ifid[6] = cp[4];
159     ifid[7] = cp[5];
160
161     freeifaddrs(ifap);
162     return;
163   }
164
165   freeifaddrs(ifap);
166
167   /*
168    * 2) If an IEEE global identifier is not available a different source
169    * of uniqueness should be used.
170    * XXX: we skip this case.
171    */
172
173   /*
174    * 3) If a good source of uniqueness cannot be found, it is
175    * recommended that a random number be generated.  In this case the
176    * "u" bit of the interface identifier MUST be set to zero (0).
177    */
178  randomid:
179   randinit();
180   r1 = (((u_long)random()) % i32_max) + 1;
181   r2 = (((u_long)random()) % i32_max) + 1;
182   memcpy(ifid, &r1, sizeof(r1));
183   memcpy(ifid + 4, &r2, sizeof(r2));
184   ifid[0] &= 0xfd;
185   return;
186 }
187
188 static int
189 ipcp_SetIPv6address(struct ipv6cp *ipv6cp, u_char *myifid, u_char *hisifid)
190 {
191   struct bundle *bundle = ipv6cp->fsm.bundle;
192   struct in6_addr myaddr, hisaddr;
193   struct ncprange myrange;
194   struct sockaddr_storage ssdst, ssgw, ssmask;
195   struct sockaddr *sadst, *sagw, *samask;
196
197   sadst = (struct sockaddr *)&ssdst;
198   sagw = (struct sockaddr *)&ssgw;
199   samask = (struct sockaddr *)&ssmask;
200
201   memset(&myaddr, '\0', sizeof myaddr);
202   memset(&hisaddr, '\0', sizeof hisaddr);
203
204   myaddr.s6_addr[0] = 0xfe;
205   myaddr.s6_addr[1] = 0x80;
206   memcpy(&myaddr.s6_addr[8], myifid, IPV6CP_IFIDLEN);
207 #if 0
208   myaddr.s6_addr[8] |= 0x02;    /* set 'universal' bit */
209 #endif
210
211   hisaddr.s6_addr[0] = 0xfe;
212   hisaddr.s6_addr[1] = 0x80;
213   memcpy(&hisaddr.s6_addr[8], hisifid, IPV6CP_IFIDLEN);
214 #if 0
215   hisaddr.s6_addr[8] |= 0x02;   /* set 'universal' bit */
216 #endif
217
218   ncpaddr_setip6(&ipv6cp->myaddr, &myaddr);
219   ncpaddr_setip6(&ipv6cp->hisaddr, &hisaddr);
220   ncprange_sethost(&myrange, &ipv6cp->myaddr);
221
222   if (!iface_Add(bundle->iface, &bundle->ncp, &myrange, &ipv6cp->hisaddr,
223                  IFACE_ADD_FIRST|IFACE_FORCE_ADD|IFACE_SYSTEM))
224     return 0;
225
226   if (!Enabled(bundle, OPT_IFACEALIAS))
227     iface_Clear(bundle->iface, &bundle->ncp, AF_INET6,
228                 IFACE_CLEAR_ALIASES|IFACE_SYSTEM);
229
230   if (bundle->ncp.cfg.sendpipe > 0 || bundle->ncp.cfg.recvpipe > 0) {
231     ncprange_getsa(&myrange, &ssgw, &ssmask);
232     if (ncpaddr_isset(&ipv6cp->hisaddr))
233       ncpaddr_getsa(&ipv6cp->hisaddr, &ssdst);
234     else
235       sadst = NULL;
236     rt_Update(bundle, sadst, sagw, samask);
237   }
238
239   if (Enabled(bundle, OPT_SROUTES))
240     route_Change(bundle, bundle->ncp.route, &ipv6cp->myaddr, &ipv6cp->hisaddr);
241
242 #ifndef NORADIUS
243   if (bundle->radius.valid)
244     route_Change(bundle, bundle->radius.routes, &ipv6cp->myaddr,
245                  &ipv6cp->hisaddr);
246 #endif
247
248   return 1;     /* Ok */
249 }
250
251 void
252 ipv6cp_Init(struct ipv6cp *ipv6cp, struct bundle *bundle, struct link *l,
253                  const struct fsm_parent *parent)
254 {
255   static const char * const timer_names[] =
256     {"IPV6CP restart", "IPV6CP openmode", "IPV6CP stopped"};
257   int n;
258
259   fsm_Init(&ipv6cp->fsm, "IPV6CP", PROTO_IPV6CP, 1, IPV6CP_MAXCODE, LogIPV6CP,
260            bundle, l, parent, &ipv6cp_Callbacks, timer_names);
261
262   ipv6cp->cfg.fsm.timeout = DEF_FSMRETRY;
263   ipv6cp->cfg.fsm.maxreq = DEF_FSMTRIES;
264   ipv6cp->cfg.fsm.maxtrm = DEF_FSMTRIES;
265
266   SetInterfaceID(ipv6cp->my_ifid, 0);
267   do {
268     SetInterfaceID(ipv6cp->his_ifid, 1);
269   } while (memcmp(ipv6cp->his_ifid, ipv6cp->my_ifid, IPV6CP_IFIDLEN) == 0);
270
271   if (probe.ipv6_available) {
272     n = 100;
273     while (n &&
274            !ipcp_SetIPv6address(ipv6cp, ipv6cp->my_ifid, ipv6cp->his_ifid)) {
275       do {
276         n--;
277         SetInterfaceID(ipv6cp->my_ifid, 1);
278       } while (n
279         && memcmp(ipv6cp->his_ifid, ipv6cp->my_ifid, IPV6CP_IFIDLEN) == 0);
280     }
281   }
282
283   throughput_init(&ipv6cp->throughput, SAMPLE_PERIOD);
284   memset(ipv6cp->Queue, '\0', sizeof ipv6cp->Queue);
285   ipv6cp_Setup(ipv6cp);
286 }
287
288 void
289 ipv6cp_Destroy(struct ipv6cp *ipv6cp)
290 {
291   throughput_destroy(&ipv6cp->throughput);
292 }
293
294 void
295 ipv6cp_Setup(struct ipv6cp *ipv6cp)
296 {
297   ncpaddr_init(&ipv6cp->myaddr);
298   ncpaddr_init(&ipv6cp->hisaddr);
299
300   ipv6cp->his_reject = 0;
301   ipv6cp->my_reject = 0;
302 }
303
304 void
305 ipv6cp_SetLink(struct ipv6cp *ipv6cp, struct link *l)
306 {
307   ipv6cp->fsm.link = l;
308 }
309
310 int
311 ipv6cp_Show(struct cmdargs const *arg)
312 {
313   struct ipv6cp *ipv6cp = &arg->bundle->ncp.ipv6cp;
314
315   prompt_Printf(arg->prompt, "%s [%s]\n", ipv6cp->fsm.name,
316                 State2Nam(ipv6cp->fsm.state));
317   if (ipv6cp->fsm.state == ST_OPENED) {
318     prompt_Printf(arg->prompt, " His side:        %s\n",
319                   ncpaddr_ntoa(&ipv6cp->hisaddr));
320     prompt_Printf(arg->prompt, " My side:         %s\n",
321                   ncpaddr_ntoa(&ipv6cp->myaddr));
322     prompt_Printf(arg->prompt, " Queued packets:  %lu\n",
323                   (unsigned long)ipv6cp_QueueLen(ipv6cp));
324   }
325
326   prompt_Printf(arg->prompt, "\nDefaults:\n");
327   prompt_Printf(arg->prompt, "  FSM retry = %us, max %u Config"
328                 " REQ%s, %u Term REQ%s\n\n", ipv6cp->cfg.fsm.timeout,
329                 ipv6cp->cfg.fsm.maxreq, ipv6cp->cfg.fsm.maxreq == 1 ? "" : "s",
330                 ipv6cp->cfg.fsm.maxtrm, ipv6cp->cfg.fsm.maxtrm == 1 ? "" : "s");
331
332   throughput_disp(&ipv6cp->throughput, arg->prompt);
333
334   return 0;
335 }
336
337 struct mbuf *
338 ipv6cp_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
339 {
340   /* Got PROTO_IPV6CP from link */
341   m_settype(bp, MB_IPV6CPIN);
342   if (bundle_Phase(bundle) == PHASE_NETWORK)
343     fsm_Input(&bundle->ncp.ipv6cp.fsm, bp);
344   else {
345     if (bundle_Phase(bundle) < PHASE_NETWORK)
346       log_Printf(LogIPV6CP, "%s: Error: Unexpected IPV6CP in phase %s"
347                  " (ignored)\n", l->name, bundle_PhaseName(bundle));
348     m_freem(bp);
349   }
350   return NULL;
351 }
352
353 void
354 ipv6cp_AddInOctets(struct ipv6cp *ipv6cp, int n)
355 {
356   throughput_addin(&ipv6cp->throughput, n);
357 }
358
359 void
360 ipv6cp_AddOutOctets(struct ipv6cp *ipv6cp, int n)
361 {
362   throughput_addout(&ipv6cp->throughput, n);
363 }
364
365 void
366 ipv6cp_IfaceAddrAdded(struct ipv6cp *ipv6cp, const struct iface_addr *addr)
367 {
368 }
369
370 void
371 ipv6cp_IfaceAddrDeleted(struct ipv6cp *ipv6cp, const struct iface_addr *addr)
372 {
373 }
374
375 int
376 ipv6cp_InterfaceUp(struct ipv6cp *ipv6cp)
377 {
378   if (!ipcp_SetIPv6address(ipv6cp, ipv6cp->my_ifid, ipv6cp->his_ifid)) {
379     log_Printf(LogERROR, "ipv6cp_InterfaceUp: unable to set ipv6 address\n");
380     return 0;
381   }
382
383   if (!iface_SetFlags(ipv6cp->fsm.bundle->iface->name, IFF_UP)) {
384     log_Printf(LogERROR, "ipv6cp_InterfaceUp: Can't set the IFF_UP"
385                " flag on %s\n", ipv6cp->fsm.bundle->iface->name);
386     return 0;
387   }
388
389   return 1;
390 }
391
392 size_t
393 ipv6cp_QueueLen(struct ipv6cp *ipv6cp)
394 {
395   struct mqueue *q;
396   size_t result;
397
398   result = 0;
399   for (q = ipv6cp->Queue; q < ipv6cp->Queue + IPV6CP_QUEUES(ipv6cp); q++)
400     result += q->len;
401
402   return result;
403 }
404
405 int
406 ipv6cp_PushPacket(struct ipv6cp *ipv6cp, struct link *l)
407 {
408   struct bundle *bundle = ipv6cp->fsm.bundle;
409   struct mqueue *queue;
410   struct mbuf *bp;
411   int m_len;
412   u_int32_t secs = 0;
413   unsigned alivesecs = 0;
414
415   if (ipv6cp->fsm.state != ST_OPENED)
416     return 0;
417
418   /*
419    * If ccp is not open but is required, do nothing.
420    */
421   if (l->ccp.fsm.state != ST_OPENED && ccp_Required(&l->ccp)) {
422     log_Printf(LogPHASE, "%s: Not transmitting... waiting for CCP\n", l->name);
423     return 0;
424   }
425
426   queue = ipv6cp->Queue + IPV6CP_QUEUES(ipv6cp) - 1;
427   do {
428     if (queue->top) {
429       bp = m_dequeue(queue);
430       bp = mbuf_Read(bp, &secs, sizeof secs);
431       bp = m_pullup(bp);
432       m_len = m_length(bp);
433       if (!FilterCheck(MBUF_CTOP(bp), AF_INET6, &bundle->filter.alive,
434                        &alivesecs)) {
435         if (secs == 0)
436           secs = alivesecs;
437         bundle_StartIdleTimer(bundle, secs);
438       }
439       link_PushPacket(l, bp, bundle, 0, PROTO_IPV6);
440       ipv6cp_AddOutOctets(ipv6cp, m_len);
441       return 1;
442     }
443   } while (queue-- != ipv6cp->Queue);
444
445   return 0;
446 }
447
448 static int
449 ipv6cp_LayerUp(struct fsm *fp)
450 {
451   /* We're now up */
452   struct ipv6cp *ipv6cp = fsm2ipv6cp(fp);
453   char tbuff[40];
454
455   log_Printf(LogIPV6CP, "%s: LayerUp.\n", fp->link->name);
456   if (!ipv6cp_InterfaceUp(ipv6cp))
457     return 0;
458
459   snprintf(tbuff, sizeof tbuff, "%s", ncpaddr_ntoa(&ipv6cp->myaddr));
460   log_Printf(LogIPV6CP, "myaddr %s hisaddr = %s\n",
461              tbuff, ncpaddr_ntoa(&ipv6cp->hisaddr));
462
463   /* XXX: Call radius_Account() and system_Select() */
464
465   fp->more.reqs = fp->more.naks = fp->more.rejs = ipv6cp->cfg.fsm.maxreq * 3;
466   log_DisplayPrompts();
467
468   return 1;
469 }
470
471 static void
472 ipv6cp_LayerDown(struct fsm *fp)
473 {
474   /* About to come down */
475   struct ipv6cp *ipv6cp = fsm2ipv6cp(fp);
476   static int recursing;
477   char addr[40];
478
479   if (!recursing++) {
480     snprintf(addr, sizeof addr, "%s", ncpaddr_ntoa(&ipv6cp->myaddr));
481     log_Printf(LogIPV6CP, "%s: LayerDown: %s\n", fp->link->name, addr);
482
483     /* XXX: Call radius_Account() and system_Select() */
484
485     ipv6cp_Setup(ipv6cp);
486   }
487   recursing--;
488 }
489
490 static void
491 ipv6cp_LayerStart(struct fsm *fp)
492 {
493   /* We're about to start up ! */
494   struct ipv6cp *ipv6cp = fsm2ipv6cp(fp);
495
496   log_Printf(LogIPV6CP, "%s: LayerStart.\n", fp->link->name);
497   throughput_start(&ipv6cp->throughput, "IPV6CP throughput",
498                    Enabled(fp->bundle, OPT_THROUGHPUT));
499   fp->more.reqs = fp->more.naks = fp->more.rejs = ipv6cp->cfg.fsm.maxreq * 3;
500   ipv6cp->peer_tokenreq = 0;
501 }
502
503 static void
504 ipv6cp_LayerFinish(struct fsm *fp)
505 {
506   /* We're now down */
507   struct ipv6cp *ipv6cp = fsm2ipv6cp(fp);
508
509   log_Printf(LogIPV6CP, "%s: LayerFinish.\n", fp->link->name);
510   throughput_stop(&ipv6cp->throughput);
511   throughput_log(&ipv6cp->throughput, LogIPV6CP, NULL);
512 }
513
514 static void
515 ipv6cp_InitRestartCounter(struct fsm *fp, int what)
516 {
517   /* Set fsm timer load */
518   struct ipv6cp *ipv6cp = fsm2ipv6cp(fp);
519
520   fp->FsmTimer.load = ipv6cp->cfg.fsm.timeout * SECTICKS;
521   switch (what) {
522     case FSM_REQ_TIMER:
523       fp->restart = ipv6cp->cfg.fsm.maxreq;
524       break;
525     case FSM_TRM_TIMER:
526       fp->restart = ipv6cp->cfg.fsm.maxtrm;
527       break;
528     default:
529       fp->restart = 1;
530       break;
531   }
532 }
533
534 static void
535 ipv6cp_SendConfigReq(struct fsm *fp)
536 {
537   /* Send config REQ please */
538   struct physical *p = link2physical(fp->link);
539   struct ipv6cp *ipv6cp = fsm2ipv6cp(fp);
540   u_char buff[IPV6CP_IFIDLEN+2];
541   struct fsm_opt *o;
542
543   o = (struct fsm_opt *)buff;
544
545   if ((p && !physical_IsSync(p)) || !REJECTED(ipv6cp, TY_TOKEN)) {
546     memcpy(o->data, ipv6cp->my_ifid, IPV6CP_IFIDLEN);
547     INC_FSM_OPT(TY_TOKEN, IPV6CP_IFIDLEN + 2, o);
548   }
549
550   fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, (u_char *)o - buff,
551              MB_IPV6CPOUT);
552 }
553
554 static void
555 ipv6cp_SentTerminateReq(struct fsm *fp)
556 {
557   /* Term REQ just sent by FSM */
558 }
559
560 static void
561 ipv6cp_SendTerminateAck(struct fsm *fp, u_char id)
562 {
563   /* Send Term ACK please */
564   fsm_Output(fp, CODE_TERMACK, id, NULL, 0, MB_IPV6CPOUT);
565 }
566
567 static const char *
568 protoname(int proto)
569 {
570   static const char *cftypes[] = { "IFACEID", "COMPPROTO" };
571
572   if (proto > 0 && proto <= sizeof cftypes / sizeof *cftypes)
573     return cftypes[proto - 1];
574
575   return NumStr(proto, NULL, 0);
576 }
577
578 static void
579 ipv6cp_ValidateInterfaceID(struct ipv6cp *ipv6cp, u_char *ifid,
580                            struct fsm_decode *dec)
581 {
582   struct fsm_opt opt;
583   u_char zero[IPV6CP_IFIDLEN];
584
585   memset(zero, 0, IPV6CP_IFIDLEN);
586
587   if (memcmp(ifid, zero, IPV6CP_IFIDLEN) != 0
588       && memcmp(ifid, ipv6cp->my_ifid, IPV6CP_IFIDLEN) != 0)
589     memcpy(ipv6cp->his_ifid, ifid, IPV6CP_IFIDLEN);
590
591   opt.hdr.id = TY_TOKEN;
592   opt.hdr.len = IPV6CP_IFIDLEN + 2;
593   memcpy(opt.data, &ipv6cp->his_ifid, IPV6CP_IFIDLEN);
594   if (memcmp(ifid, ipv6cp->his_ifid, IPV6CP_IFIDLEN) == 0)
595     fsm_ack(dec, &opt);
596   else
597     fsm_nak(dec, &opt);
598 }
599
600 static void
601 ipv6cp_DecodeConfig(struct fsm *fp, u_char *cp, u_char *end, int mode_type,
602                     struct fsm_decode *dec)
603 {
604   /* Deal with incoming PROTO_IPV6CP */
605   struct ipv6cp *ipv6cp = fsm2ipv6cp(fp);
606   int n;
607   char tbuff[100];
608   u_char ifid[IPV6CP_IFIDLEN], zero[IPV6CP_IFIDLEN];
609   struct fsm_opt *opt;
610
611   memset(zero, 0, IPV6CP_IFIDLEN);
612
613   while (end - cp >= sizeof(opt->hdr)) {
614     if ((opt = fsm_readopt(&cp)) == NULL)
615       break;
616
617     snprintf(tbuff, sizeof tbuff, " %s[%d]", protoname(opt->hdr.id),
618              opt->hdr.len);
619
620     switch (opt->hdr.id) {
621     case TY_TOKEN:
622       memcpy(ifid, opt->data, IPV6CP_IFIDLEN);
623       log_Printf(LogIPV6CP, "%s 0x%02x%02x%02x%02x%02x%02x%02x%02x\n", tbuff,
624                  ifid[0], ifid[1], ifid[2], ifid[3], ifid[4], ifid[5], ifid[6], ifid[7]);
625
626       switch (mode_type) {
627       case MODE_REQ:
628         ipv6cp->peer_tokenreq = 1;
629         ipv6cp_ValidateInterfaceID(ipv6cp, ifid, dec);
630         break;
631
632       case MODE_NAK:
633         if (memcmp(ifid, zero, IPV6CP_IFIDLEN) == 0) {
634           log_Printf(log_IsKept(LogIPV6CP) ? LogIPV6CP : LogPHASE,
635                      "0x0000000000000000: Unacceptable IntefaceID!\n");
636           fsm_Close(&ipv6cp->fsm);
637         } else if (memcmp(ifid, ipv6cp->his_ifid, IPV6CP_IFIDLEN) == 0) {
638           log_Printf(log_IsKept(LogIPV6CP) ? LogIPV6CP : LogPHASE,
639                      "0x%02x%02x%02x%02x%02x%02x%02x%02x: "
640                      "Unacceptable IntefaceID!\n",
641                      ifid[0], ifid[1], ifid[2], ifid[3],
642                      ifid[4], ifid[5], ifid[6], ifid[7]);
643         } else if (memcmp(ifid, ipv6cp->my_ifid, IPV6CP_IFIDLEN) != 0) {
644           n = 100;
645           while (n && !ipcp_SetIPv6address(ipv6cp, ifid, ipv6cp->his_ifid)) {
646             do {
647               n--;
648               SetInterfaceID(ifid, 1);
649             } while (n && memcmp(ifid, ipv6cp->his_ifid, IPV6CP_IFIDLEN) == 0);
650           }
651
652           if (n == 0) {
653             log_Printf(log_IsKept(LogIPV6CP) ? LogIPV6CP : LogPHASE,
654                        "0x0000000000000000: Unacceptable IntefaceID!\n");
655             fsm_Close(&ipv6cp->fsm);
656           } else {
657             log_Printf(LogIPV6CP, "%s changing IntefaceID: "
658                        "0x%02x%02x%02x%02x%02x%02x%02x%02x "
659                        "--> 0x%02x%02x%02x%02x%02x%02x%02x%02x\n", tbuff,
660                        ipv6cp->my_ifid[0], ipv6cp->my_ifid[1],
661                        ipv6cp->my_ifid[2], ipv6cp->my_ifid[3],
662                        ipv6cp->my_ifid[4], ipv6cp->my_ifid[5],
663                        ipv6cp->my_ifid[6], ipv6cp->my_ifid[7],
664                        ifid[0], ifid[1], ifid[2], ifid[3],
665                        ifid[4], ifid[5], ifid[6], ifid[7]);
666             memcpy(ipv6cp->my_ifid, ifid, IPV6CP_IFIDLEN);
667             bundle_AdjustFilters(fp->bundle, &ipv6cp->myaddr, NULL);
668           }
669         }
670         break;
671
672       case MODE_REJ:
673         ipv6cp->his_reject |= (1 << opt->hdr.id);
674         break;
675       }
676       break;
677
678     default:
679       if (mode_type != MODE_NOP) {
680         ipv6cp->my_reject |= (1 << opt->hdr.id);
681         fsm_rej(dec, opt);
682       }
683       break;
684     }
685   }
686
687   if (mode_type != MODE_NOP) {
688     if (mode_type == MODE_REQ && !ipv6cp->peer_tokenreq) {
689       if (dec->rejend == dec->rej && dec->nakend == dec->nak) {
690         /*
691          * Pretend the peer has requested a TOKEN.
692          * We do this to ensure that we only send one NAK if the only
693          * reason for the NAK is because the peer isn't sending a
694          * TY_TOKEN REQ.  This stops us from repeatedly trying to tell
695          * the peer that we have to have an IP address on their end.
696          */
697         ipv6cp->peer_tokenreq = 1;
698       }
699       memset(ifid, 0, IPV6CP_IFIDLEN);
700       ipv6cp_ValidateInterfaceID(ipv6cp, ifid, dec);
701     }
702     fsm_opt_normalise(dec);
703   }
704 }
705 #endif