ipv6cp.c revision 81634
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 81634 2001-08-14 16:05:52Z brian $
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 <sys/un.h>
37
38#include <stdio.h>
39#include <stdlib.h>
40#include <string.h>
41#include <termios.h>
42
43#include "layer.h"
44#include "defs.h"
45#include "mbuf.h"
46#include "timer.h"
47#include "fsm.h"
48#include "iplist.h"
49#include "throughput.h"
50#include "slcompress.h"
51#include "lqr.h"
52#include "hdlc.h"
53#include "lcp.h"
54#include "ncpaddr.h"
55#include "ip.h"
56#include "ipcp.h"
57#include "ipv6cp.h"
58#include "filter.h"
59#include "descriptor.h"
60#include "ccp.h"
61#include "link.h"
62#include "mp.h"
63#ifndef NORADIUS
64#include "radius.h"
65#endif
66#include "ncp.h"
67#include "bundle.h"
68#include "route.h"
69#include "iface.h"
70#include "log.h"
71#include "proto.h"
72#include "command.h"
73#include "prompt.h"
74#include "async.h"
75#include "physical.h"
76
77
78#ifndef NOINET6
79static int ipv6cp_LayerUp(struct fsm *);
80static void ipv6cp_LayerDown(struct fsm *);
81static void ipv6cp_LayerStart(struct fsm *);
82static void ipv6cp_LayerFinish(struct fsm *);
83static void ipv6cp_InitRestartCounter(struct fsm *, int);
84static void ipv6cp_SendConfigReq(struct fsm *);
85static void ipv6cp_SentTerminateReq(struct fsm *);
86static void ipv6cp_SendTerminateAck(struct fsm *, u_char);
87static void ipv6cp_DecodeConfig(struct fsm *, u_char *, int, int,
88                                struct fsm_decode *);
89
90static struct fsm_callbacks ipv6cp_Callbacks = {
91  ipv6cp_LayerUp,
92  ipv6cp_LayerDown,
93  ipv6cp_LayerStart,
94  ipv6cp_LayerFinish,
95  ipv6cp_InitRestartCounter,
96  ipv6cp_SendConfigReq,
97  ipv6cp_SentTerminateReq,
98  ipv6cp_SendTerminateAck,
99  ipv6cp_DecodeConfig,
100  fsm_NullRecvResetReq,
101  fsm_NullRecvResetAck
102};
103
104static u_int32_t
105GenerateToken(void)
106{
107  /* Generate random number which will be used as negotiation token */
108  randinit();
109
110  return random() + 1;
111}
112
113static int
114ipcp_SetIPv6address(struct ipv6cp *ipv6cp, u_int32_t mytok, u_int32_t histok)
115{
116  struct bundle *bundle = ipv6cp->fsm.bundle;
117  struct in6_addr myaddr, hisaddr;
118  struct ncprange myrange, dst;
119
120  memset(&myaddr, '\0', sizeof myaddr);
121  memset(&hisaddr, '\0', sizeof hisaddr);
122
123  myaddr.s6_addr[0] = 0xfe;
124  myaddr.s6_addr[1] = 0x80;
125  *(u_int32_t *)(myaddr.s6_addr + 12) = htonl(mytok);
126
127  hisaddr.s6_addr[0] = 0xfe;
128  hisaddr.s6_addr[1] = 0x80;
129  *(u_int32_t *)(hisaddr.s6_addr + 12) = htonl(histok);
130
131  ncpaddr_setip6(&ipv6cp->myaddr, &myaddr);
132  ncpaddr_setip6(&ipv6cp->hisaddr, &hisaddr);
133  ncprange_sethost(&myrange, &ipv6cp->myaddr);
134
135  if (!iface_Add(bundle->iface, &bundle->ncp, &myrange, &ipv6cp->hisaddr,
136                 IFACE_ADD_FIRST|IFACE_FORCE_ADD|IFACE_SYSTEM))
137    return 0;
138
139  if (!Enabled(bundle, OPT_IFACEALIAS))
140    iface_Clear(bundle->iface, &bundle->ncp, AF_INET6,
141                IFACE_CLEAR_ALIASES|IFACE_SYSTEM);
142
143  if (bundle->ncp.cfg.sendpipe > 0 || bundle->ncp.cfg.recvpipe > 0) {
144    ncprange_sethost(&dst, &ipv6cp->hisaddr);
145    rt_Update(bundle, &dst);
146  }
147
148  if (Enabled(bundle, OPT_SROUTES))
149    route_Change(bundle, bundle->ncp.route, &ipv6cp->myaddr, &ipv6cp->hisaddr);
150
151#ifndef NORADIUS
152  if (bundle->radius.valid)
153    route_Change(bundle, bundle->radius.routes, &ipv6cp->myaddr,
154                 &ipv6cp->hisaddr);
155#endif
156
157  return 1;	/* Ok */
158}
159
160void
161ipv6cp_Init(struct ipv6cp *ipv6cp, struct bundle *bundle, struct link *l,
162                 const struct fsm_parent *parent)
163{
164  static const char * const timer_names[] =
165    {"IPV6CP restart", "IPV6CP openmode", "IPV6CP stopped"};
166  int n;
167
168  fsm_Init(&ipv6cp->fsm, "IPV6CP", PROTO_IPV6CP, 1, IPV6CP_MAXCODE, LogIPV6CP,
169           bundle, l, parent, &ipv6cp_Callbacks, timer_names);
170
171  ipv6cp->cfg.fsm.timeout = DEF_FSMRETRY;
172  ipv6cp->cfg.fsm.maxreq = DEF_FSMTRIES;
173  ipv6cp->cfg.fsm.maxtrm = DEF_FSMTRIES;
174
175  ipv6cp->my_token = GenerateToken();
176  while ((ipv6cp->peer_token = GenerateToken()) == ipv6cp->my_token)
177    ;
178
179  n = 100;
180  while (n &&
181         !ipcp_SetIPv6address(ipv6cp, ipv6cp->my_token, ipv6cp->peer_token))
182    while (n && (ipv6cp->my_token = GenerateToken()) == ipv6cp->peer_token)
183      n--;
184
185  throughput_init(&ipv6cp->throughput, SAMPLE_PERIOD);
186  memset(ipv6cp->Queue, '\0', sizeof ipv6cp->Queue);
187  ipv6cp_Setup(ipv6cp);
188}
189
190void
191ipv6cp_Destroy(struct ipv6cp *ipv6cp)
192{
193  throughput_destroy(&ipv6cp->throughput);
194}
195
196void
197ipv6cp_Setup(struct ipv6cp *ipv6cp)
198{
199  ncpaddr_init(&ipv6cp->myaddr);
200  ncpaddr_init(&ipv6cp->hisaddr);
201
202  ipv6cp->his_reject = 0;
203  ipv6cp->my_reject = 0;
204}
205
206void
207ipv6cp_SetLink(struct ipv6cp *ipv6cp, struct link *l)
208{
209  ipv6cp->fsm.link = l;
210}
211
212int
213ipv6cp_Show(struct cmdargs const *arg)
214{
215  struct ipv6cp *ipv6cp = &arg->bundle->ncp.ipv6cp;
216
217  prompt_Printf(arg->prompt, "%s [%s]\n", ipv6cp->fsm.name,
218                State2Nam(ipv6cp->fsm.state));
219  if (ipv6cp->fsm.state == ST_OPENED) {
220    prompt_Printf(arg->prompt, " His side:        %s\n",
221	          ncpaddr_ntoa(&ipv6cp->hisaddr));
222    prompt_Printf(arg->prompt, " My side:         %s\n",
223	          ncpaddr_ntoa(&ipv6cp->myaddr));
224    prompt_Printf(arg->prompt, " Queued packets:  %lu\n",
225                  (unsigned long)ipv6cp_QueueLen(ipv6cp));
226  }
227
228  prompt_Printf(arg->prompt, "\nDefaults:\n");
229  prompt_Printf(arg->prompt, "  FSM retry = %us, max %u Config"
230                " REQ%s, %u Term REQ%s\n\n", ipv6cp->cfg.fsm.timeout,
231                ipv6cp->cfg.fsm.maxreq, ipv6cp->cfg.fsm.maxreq == 1 ? "" : "s",
232                ipv6cp->cfg.fsm.maxtrm, ipv6cp->cfg.fsm.maxtrm == 1 ? "" : "s");
233
234  throughput_disp(&ipv6cp->throughput, arg->prompt);
235
236  return 0;
237}
238
239struct mbuf *
240ipv6cp_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
241{
242  /* Got PROTO_IPV6CP from link */
243  m_settype(bp, MB_IPV6CPIN);
244  if (bundle_Phase(bundle) == PHASE_NETWORK)
245    fsm_Input(&bundle->ncp.ipv6cp.fsm, bp);
246  else {
247    if (bundle_Phase(bundle) < PHASE_NETWORK)
248      log_Printf(LogIPV6CP, "%s: Error: Unexpected IPV6CP in phase %s"
249                 " (ignored)\n", l->name, bundle_PhaseName(bundle));
250    m_freem(bp);
251  }
252  return NULL;
253}
254
255void
256ipv6cp_AddInOctets(struct ipv6cp *ipv6cp, int n)
257{
258  throughput_addin(&ipv6cp->throughput, n);
259}
260
261void
262ipv6cp_AddOutOctets(struct ipv6cp *ipv6cp, int n)
263{
264  throughput_addout(&ipv6cp->throughput, n);
265}
266
267void
268ipv6cp_IfaceAddrAdded(struct ipv6cp *ipv6cp, const struct iface_addr *addr)
269{
270}
271
272void
273ipv6cp_IfaceAddrDeleted(struct ipv6cp *ipv6cp, const struct iface_addr *addr)
274{
275}
276
277int
278ipv6cp_InterfaceUp(struct ipv6cp *ipv6cp)
279{
280  if (!ipcp_SetIPv6address(ipv6cp, ipv6cp->my_token, ipv6cp->peer_token)) {
281    log_Printf(LogERROR, "ipv6cp_InterfaceUp: unable to set ipv6 address\n");
282    return 0;
283  }
284
285  if (!iface_SetFlags(ipv6cp->fsm.bundle->iface->name, IFF_UP)) {
286    log_Printf(LogERROR, "ipv6cp_InterfaceUp: Can't set the IFF_UP"
287               " flag on %s\n", ipv6cp->fsm.bundle->iface->name);
288    return 0;
289  }
290
291  return 1;
292}
293
294size_t
295ipv6cp_QueueLen(struct ipv6cp *ipv6cp)
296{
297  struct mqueue *q;
298  size_t result;
299
300  result = 0;
301  for (q = ipv6cp->Queue; q < ipv6cp->Queue + IPV6CP_QUEUES(ipv6cp); q++)
302    result += q->len;
303
304  return result;
305}
306
307int
308ipv6cp_PushPacket(struct ipv6cp *ipv6cp, struct link *l)
309{
310  struct bundle *bundle = ipv6cp->fsm.bundle;
311  struct mqueue *queue;
312  struct mbuf *bp;
313  int m_len;
314  u_int32_t secs = 0;
315  unsigned alivesecs = 0;
316
317  if (ipv6cp->fsm.state != ST_OPENED)
318    return 0;
319
320  /*
321   * If ccp is not open but is required, do nothing.
322   */
323  if (l->ccp.fsm.state != ST_OPENED && ccp_Required(&l->ccp)) {
324    log_Printf(LogPHASE, "%s: Not transmitting... waiting for CCP\n", l->name);
325    return 0;
326  }
327
328  queue = ipv6cp->Queue + IPV6CP_QUEUES(ipv6cp) - 1;
329  do {
330    if (queue->top) {
331      bp = m_dequeue(queue);
332      bp = mbuf_Read(bp, &secs, sizeof secs);
333      bp = m_pullup(bp);
334      m_len = m_length(bp);
335      if (!FilterCheck(MBUF_CTOP(bp), AF_INET6, &bundle->filter.alive,
336                       &alivesecs)) {
337        if (secs == 0)
338          secs = alivesecs;
339        bundle_StartIdleTimer(bundle, secs);
340      }
341      link_PushPacket(l, bp, bundle, 0, PROTO_IPV6);
342      ipv6cp_AddOutOctets(ipv6cp, m_len);
343      return 1;
344    }
345  } while (queue-- != ipv6cp->Queue);
346
347  return 0;
348}
349
350static int
351ipv6cp_LayerUp(struct fsm *fp)
352{
353  /* We're now up */
354  struct ipv6cp *ipv6cp = fsm2ipv6cp(fp);
355  char tbuff[40];
356
357  log_Printf(LogIPV6CP, "%s: LayerUp.\n", fp->link->name);
358  if (!ipv6cp_InterfaceUp(ipv6cp))
359    return 0;
360
361  snprintf(tbuff, sizeof tbuff, "%s", ncpaddr_ntoa(&ipv6cp->myaddr));
362  log_Printf(LogIPV6CP, "myaddr %s hisaddr = %s\n",
363             tbuff, ncpaddr_ntoa(&ipv6cp->hisaddr));
364
365  /* XXX: Call radius_Account() and system_Select() */
366
367  fp->more.reqs = fp->more.naks = fp->more.rejs = ipv6cp->cfg.fsm.maxreq * 3;
368  log_DisplayPrompts();
369
370  return 1;
371}
372
373static void
374ipv6cp_LayerDown(struct fsm *fp)
375{
376  /* About to come down */
377  struct ipv6cp *ipv6cp = fsm2ipv6cp(fp);
378  static int recursing;
379  char addr[40];
380
381  if (!recursing++) {
382    snprintf(addr, sizeof addr, "%s", ncpaddr_ntoa(&ipv6cp->myaddr));
383    log_Printf(LogIPV6CP, "%s: LayerDown: %s\n", fp->link->name, addr);
384
385    /* XXX: Call radius_Account() and system_Select() */
386
387    ipv6cp_Setup(ipv6cp);
388  }
389  recursing--;
390}
391
392static void
393ipv6cp_LayerStart(struct fsm *fp)
394{
395  /* We're about to start up ! */
396  struct ipv6cp *ipv6cp = fsm2ipv6cp(fp);
397
398  log_Printf(LogIPV6CP, "%s: LayerStart.\n", fp->link->name);
399  throughput_start(&ipv6cp->throughput, "IPV6CP throughput",
400                   Enabled(fp->bundle, OPT_THROUGHPUT));
401  fp->more.reqs = fp->more.naks = fp->more.rejs = ipv6cp->cfg.fsm.maxreq * 3;
402  ipv6cp->peer_tokenreq = 0;
403}
404
405static void
406ipv6cp_LayerFinish(struct fsm *fp)
407{
408  /* We're now down */
409  struct ipv6cp *ipv6cp = fsm2ipv6cp(fp);
410
411  log_Printf(LogIPV6CP, "%s: LayerFinish.\n", fp->link->name);
412  throughput_stop(&ipv6cp->throughput);
413  throughput_log(&ipv6cp->throughput, LogIPV6CP, NULL);
414}
415
416static void
417ipv6cp_InitRestartCounter(struct fsm *fp, int what)
418{
419  /* Set fsm timer load */
420  struct ipv6cp *ipv6cp = fsm2ipv6cp(fp);
421
422  fp->FsmTimer.load = ipv6cp->cfg.fsm.timeout * SECTICKS;
423  switch (what) {
424    case FSM_REQ_TIMER:
425      fp->restart = ipv6cp->cfg.fsm.maxreq;
426      break;
427    case FSM_TRM_TIMER:
428      fp->restart = ipv6cp->cfg.fsm.maxtrm;
429      break;
430    default:
431      fp->restart = 1;
432      break;
433  }
434}
435
436static void
437ipv6cp_SendConfigReq(struct fsm *fp)
438{
439  /* Send config REQ please */
440  struct physical *p = link2physical(fp->link);
441  struct ipv6cp *ipv6cp = fsm2ipv6cp(fp);
442  u_char buff[6];
443  struct lcp_opt *o;
444
445  o = (struct lcp_opt *)buff;
446
447  if ((p && !physical_IsSync(p)) || !REJECTED(ipv6cp, TY_TOKEN)) {
448    memcpy(o->data, &ipv6cp->my_token, 4);
449    INC_LCP_OPT(TY_TOKEN, 6, o);
450  }
451
452  fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, (u_char *)o - buff,
453             MB_IPV6CPOUT);
454}
455
456static void
457ipv6cp_SentTerminateReq(struct fsm *fp)
458{
459  /* Term REQ just sent by FSM */
460}
461
462static void
463ipv6cp_SendTerminateAck(struct fsm *fp, u_char id)
464{
465  /* Send Term ACK please */
466  fsm_Output(fp, CODE_TERMACK, id, NULL, 0, MB_IPV6CPOUT);
467}
468
469static const char *
470protoname(int proto)
471{
472  static const char *cftypes[] = { "TOKEN", "COMPPROTO" };
473
474  if (proto > 0 && proto <= sizeof cftypes / sizeof *cftypes)
475    return cftypes[proto - 1];
476
477  return NumStr(proto, NULL, 0);
478}
479
480static void
481ipv6cp_ValidateToken(struct ipv6cp *ipv6cp, u_int32_t token,
482                     struct fsm_decode *dec)
483{
484  if (token != 0 && token != ipv6cp->my_token)
485    ipv6cp->peer_token = token;
486
487  if (token == ipv6cp->peer_token) {
488    *dec->ackend++ = TY_TOKEN;
489    *dec->ackend++ = 6;
490    memcpy(dec->ackend, &ipv6cp->peer_token, 4);
491    dec->ackend += 4;
492  } else {
493    *dec->nakend++ = TY_TOKEN;
494    *dec->nakend++ = 6;
495    memcpy(dec->nakend, &ipv6cp->peer_token, 4);
496    dec->nakend += 4;
497  }
498}
499
500static void
501ipv6cp_DecodeConfig(struct fsm *fp, u_char *cp, int plen, int mode_type,
502                    struct fsm_decode *dec)
503{
504  /* Deal with incoming PROTO_IPV6CP */
505  struct ipv6cp *ipv6cp = fsm2ipv6cp(fp);
506  int type, length, n;
507  char tbuff[100];
508  u_int32_t token;
509
510  while (plen >= sizeof(struct fsmconfig)) {
511    type = *cp;
512    length = cp[1];
513
514    if (length == 0) {
515      log_Printf(LogIPV6CP, "%s: IPV6CP size zero\n", fp->link->name);
516      break;
517    }
518
519    snprintf(tbuff, sizeof tbuff, " %s[%d] ", protoname(type), length);
520
521    switch (type) {
522    case TY_TOKEN:
523      memcpy(&token, cp + 2, 4);
524      log_Printf(LogIPV6CP, "%s 0x%08lx\n", tbuff, (unsigned long)token);
525
526      switch (mode_type) {
527      case MODE_REQ:
528        ipv6cp->peer_tokenreq = 1;
529        ipv6cp_ValidateToken(ipv6cp, token, dec);
530	break;
531
532      case MODE_NAK:
533        if (token == 0) {
534	  log_Printf(log_IsKept(LogIPV6CP) ? LogIPV6CP : LogPHASE,
535                     "0x00000000: Unacceptable token!\n");
536          fsm_Close(&ipv6cp->fsm);
537        } else if (token == ipv6cp->peer_token)
538	  log_Printf(log_IsKept(LogIPV6CP) ? LogIPV6CP : LogPHASE,
539                    "0x08lx: Unacceptable token!\n", (unsigned long)token);
540        else if (token != ipv6cp->my_token) {
541          n = 100;
542          while (n && !ipcp_SetIPv6address(ipv6cp, token, ipv6cp->peer_token))
543            while (n && (token = GenerateToken()) == ipv6cp->peer_token)
544              n--;
545
546          if (n == 0) {
547	    log_Printf(log_IsKept(LogIPV6CP) ? LogIPV6CP : LogPHASE,
548                       "0x00000000: Unacceptable token!\n");
549            fsm_Close(&ipv6cp->fsm);
550          } else {
551	    log_Printf(LogIPV6CP, "%s changing token: 0x%08lx --> 0x%08lx\n",
552                       tbuff, (unsigned long)ipv6cp->my_token,
553                       (unsigned long)token);
554            ipv6cp->my_token = token;
555            bundle_AdjustFilters(fp->bundle, &ipv6cp->myaddr, NULL);
556          }
557        }
558	break;
559
560      case MODE_REJ:
561	ipv6cp->his_reject |= (1 << type);
562	break;
563      }
564      break;
565
566    default:
567      if (mode_type != MODE_NOP) {
568        ipv6cp->my_reject |= (1 << type);
569        memcpy(dec->rejend, cp, length);
570        dec->rejend += length;
571      }
572      break;
573    }
574    plen -= length;
575    cp += length;
576  }
577
578  if (mode_type != MODE_NOP) {
579    if (mode_type == MODE_REQ && !ipv6cp->peer_tokenreq) {
580      if (dec->rejend == dec->rej && dec->nakend == dec->nak) {
581        /*
582         * Pretend the peer has requested a TOKEN.
583         * We do this to ensure that we only send one NAK if the only
584         * reason for the NAK is because the peer isn't sending a
585         * TY_TOKEN REQ.  This stops us from repeatedly trying to tell
586         * the peer that we have to have an IP address on their end.
587         */
588        ipv6cp->peer_tokenreq = 1;
589      }
590      ipv6cp_ValidateToken(ipv6cp, 0, dec);
591    }
592    if (dec->rejend != dec->rej) {
593      /* rejects are preferred */
594      dec->ackend = dec->ack;
595      dec->nakend = dec->nak;
596    } else if (dec->nakend != dec->nak)
597      /* then NAKs */
598      dec->ackend = dec->ack;
599  }
600}
601#endif
602