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