1 /* $OpenBSD: interface.c,v 1.1 2006/06/01 14:12:20 norby Exp $ */ 2 3 /* 4 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org> 5 * Copyright (c) 2004, 2005, 2006 Esben Norby <norby@openbsd.org> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <sys/types.h> 21 #include <sys/ioctl.h> 22 #include <sys/time.h> 23 #include <sys/socket.h> 24 25 #include <netinet/in.h> 26 #include <netinet/ip_mroute.h> 27 #include <arpa/inet.h> 28 #include <net/if.h> 29 30 #include <ctype.h> 31 #include <err.h> 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <unistd.h> 35 #include <string.h> 36 #include <event.h> 37 38 #include "igmp.h" 39 #include "dvmrpd.h" 40 #include "dvmrp.h" 41 #include "log.h" 42 #include "dvmrpe.h" 43 44 void if_probe_timer(int, short, void *); 45 int if_start_probe_timer(struct iface *); 46 int if_stop_probe_timer(struct iface *); 47 void if_query_timer(int, short, void *); 48 int if_start_query_timer(struct iface *); 49 int if_stop_query_timer(struct iface *); 50 void if_querier_present_timer(int, short, void *); 51 int if_start_querier_present_timer(struct iface *); 52 int if_stop_querier_present_timer(struct iface *); 53 int if_reset_querier_present_timer(struct iface *); 54 int if_act_start(struct iface *); 55 int if_act_query_seen(struct iface *); 56 int if_act_reset(struct iface *); 57 58 struct { 59 int state; 60 enum iface_event event; 61 enum iface_action action; 62 int new_state; 63 } iface_fsm[] = { 64 /* current state event that happened action to take resulting state */ 65 {IF_STA_DOWN, IF_EVT_UP, IF_ACT_STRT, 0}, 66 {IF_STA_ACTIVE, IF_EVT_QRECVD, IF_ACT_QPRSNT, 0}, 67 {IF_STA_NONQUERIER, IF_EVT_QPRSNTTMOUT, IF_ACT_STRT, 0}, 68 {IF_STA_ANY, IF_EVT_DOWN, IF_ACT_RST, IF_STA_DOWN}, 69 {-1, IF_EVT_NOTHING, IF_ACT_NOTHING, 0}, 70 }; 71 72 const char * const if_action_names[] = { 73 "NOTHING", 74 "START", 75 "QPRSNT", 76 "RESET" 77 }; 78 79 static const char * const if_event_names[] = { 80 "NOTHING", 81 "UP", 82 "QTMOUT", 83 "QRECVD", 84 "QPRSNTTMOUT", 85 "DOWN" 86 }; 87 88 int 89 if_fsm(struct iface *iface, enum iface_event event) 90 { 91 int old_state; 92 int new_state = 0; 93 int i, ret = 0; 94 95 old_state = iface->state; 96 97 for (i = 0; iface_fsm[i].state != -1; i++) 98 if ((iface_fsm[i].state & old_state) && 99 (iface_fsm[i].event == event)) { 100 new_state = iface_fsm[i].new_state; 101 break; 102 } 103 104 if (iface_fsm[i].state == -1) { 105 /* XXX event outside of the defined fsm, ignore it. */ 106 log_debug("fsm_if: interface %s, " 107 "event '%s' not expected in state '%s'", iface->name, 108 if_event_name(event), if_state_name(old_state)); 109 return (0); 110 } 111 112 switch (iface_fsm[i].action) { 113 case IF_ACT_STRT: 114 ret = if_act_start(iface); 115 break; 116 case IF_ACT_QPRSNT: 117 ret = if_act_query_seen(iface); 118 break; 119 case IF_ACT_RST: 120 ret = if_act_reset(iface); 121 break; 122 case IF_ACT_NOTHING: 123 /* do nothing */ 124 break; 125 } 126 127 if (ret) { 128 log_debug("fsm_if: error changing state for interface %s, " 129 "event '%s', state '%s'", iface->name, if_event_name(event), 130 if_state_name(old_state)); 131 return (-1); 132 } 133 134 if (new_state != 0) 135 iface->state = new_state; 136 137 log_debug("fsm_if: event '%s' resulted in action '%s' and changing " 138 "state for interface %s from '%s' to '%s'", 139 if_event_name(event), if_action_name(iface_fsm[i].action), 140 iface->name, if_state_name(old_state), if_state_name(iface->state)); 141 142 return (ret); 143 } 144 145 struct iface * 146 if_new(struct kif *kif) 147 { 148 struct sockaddr_in *sain; 149 struct iface *iface; 150 struct ifreq *ifr; 151 int s; 152 153 if ((iface = calloc(1, sizeof(*iface))) == NULL) 154 err(1, "if_new: calloc"); 155 156 iface->state = IF_STA_DOWN; 157 iface->passive = 1; 158 159 LIST_INIT(&iface->nbr_list); 160 TAILQ_INIT(&iface->group_list); 161 strlcpy(iface->name, kif->ifname, sizeof(iface->name)); 162 163 if ((ifr = calloc(1, sizeof(*ifr))) == NULL) 164 err(1, "if_new: calloc"); 165 166 /* set up ifreq */ 167 strlcpy(ifr->ifr_name, kif->ifname, sizeof(ifr->ifr_name)); 168 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 169 err(1, "if_new: socket"); 170 171 /* get type */ 172 if ((kif->flags & IFF_POINTOPOINT)) 173 iface->type = IF_TYPE_POINTOPOINT; 174 if ((kif->flags & IFF_BROADCAST) && 175 (kif->flags & IFF_MULTICAST)) 176 iface->type = IF_TYPE_BROADCAST; 177 178 /* get mtu, index and flags */ 179 iface->mtu = kif->mtu; 180 iface->ifindex = kif->ifindex; 181 iface->flags = kif->flags; 182 iface->linkstate = kif->link_state; 183 iface->media_type = kif->media_type; 184 185 /* get address */ 186 if (ioctl(s, SIOCGIFADDR, (caddr_t)ifr) < 0) 187 err(1, "if_new: cannot get address"); 188 sain = (struct sockaddr_in *) &ifr->ifr_addr; 189 iface->addr = sain->sin_addr; 190 191 /* get mask */ 192 if (ioctl(s, SIOCGIFNETMASK, (caddr_t)ifr) < 0) 193 err(1, "if_new: cannot get mask"); 194 sain = (struct sockaddr_in *) &ifr->ifr_addr; 195 iface->mask = sain->sin_addr; 196 197 /* get p2p dst address */ 198 if (iface->type == IF_TYPE_POINTOPOINT) { 199 if (ioctl(s, SIOCGIFDSTADDR, (caddr_t)ifr) < 0) 200 err(1, "if_new: cannot get dst addr"); 201 sain = (struct sockaddr_in *) &ifr->ifr_addr; 202 iface->dst = sain->sin_addr; 203 } 204 205 free(ifr); 206 close(s); 207 208 return (iface); 209 } 210 211 void 212 if_init(struct dvmrpd_conf *xconf, struct iface *iface) 213 { 214 /* set event handlers for interface */ 215 evtimer_set(&iface->probe_timer, if_probe_timer, iface); 216 evtimer_set(&iface->query_timer, if_query_timer, iface); 217 evtimer_set(&iface->querier_present_timer, if_querier_present_timer, 218 iface); 219 220 TAILQ_INIT(&iface->rr_list); 221 222 iface->fd = xconf->dvmrp_socket; 223 iface->gen_id = xconf->gen_id; 224 } 225 226 int 227 if_del(struct iface *iface) 228 { 229 struct nbr *nbr = NULL; 230 231 /* clear lists etc */ 232 while ((nbr = LIST_FIRST(&iface->nbr_list)) != NULL) { 233 LIST_REMOVE(nbr, entry); 234 nbr_del(nbr); 235 } 236 group_list_clr(iface); 237 238 return (-1); 239 } 240 241 int 242 if_nbr_list_empty(struct iface *iface) 243 { 244 return (LIST_EMPTY(&iface->nbr_list)); 245 } 246 247 /* timers */ 248 void 249 if_probe_timer(int fd, short event, void *arg) 250 { 251 struct iface *iface = arg; 252 struct timeval tv; 253 254 send_probe(iface); 255 256 /* reschedule probe_timer */ 257 if (!iface->passive) { 258 timerclear(&tv); 259 tv.tv_sec = iface->probe_interval; 260 evtimer_add(&iface->probe_timer, &tv); 261 } 262 } 263 264 int 265 if_start_probe_timer(struct iface *iface) 266 { 267 struct timeval tv; 268 269 timerclear(&tv); 270 return (evtimer_add(&iface->probe_timer, &tv)); 271 } 272 273 int 274 if_stop_probe_timer(struct iface *iface) 275 { 276 return (evtimer_del(&iface->probe_timer)); 277 } 278 279 void 280 if_query_timer(int fd, short event, void *arg) 281 { 282 struct iface *iface = arg; 283 struct timeval tv; 284 285 /* send a general query */ 286 send_igmp_query(iface, NULL); 287 288 /* reschedule query_timer */ 289 if (!iface->passive) { 290 timerclear(&tv); 291 if (iface->startup_query_counter != 0) { 292 tv.tv_sec = iface->startup_query_interval; 293 iface->startup_query_counter--; 294 } else 295 tv.tv_sec = iface->query_interval; 296 297 evtimer_add(&iface->query_timer, &tv); 298 } 299 } 300 301 int 302 if_start_query_timer(struct iface *iface) 303 { 304 struct timeval tv; 305 306 timerclear(&tv); 307 return (evtimer_add(&iface->query_timer, &tv)); 308 } 309 310 int 311 if_stop_query_timer(struct iface *iface) 312 { 313 return (evtimer_del(&iface->query_timer)); 314 } 315 316 void 317 if_querier_present_timer(int fd, short event, void *arg) 318 { 319 struct iface *iface = arg; 320 321 if_fsm(iface, IF_EVT_QPRSNTTMOUT); 322 } 323 324 int 325 if_start_querier_present_timer(struct iface *iface) 326 { 327 struct timeval tv; 328 329 /* Other Querier Present Interval */ 330 timerclear(&tv); 331 tv.tv_sec = iface->robustness * iface->query_interval + 332 (iface->query_resp_interval / 2); 333 334 return (evtimer_add(&iface->querier_present_timer, &tv)); 335 } 336 337 int 338 if_stop_querier_present_timer(struct iface *iface) 339 { 340 return (evtimer_del(&iface->querier_present_timer)); 341 } 342 343 int 344 if_reset_querier_present_timer(struct iface *iface) 345 { 346 struct timeval tv; 347 348 /* Other Querier Present Interval */ 349 timerclear(&tv); 350 tv.tv_sec = iface->robustness * iface->query_interval + 351 (iface->query_resp_interval / 2); 352 353 return (evtimer_add(&iface->querier_present_timer, &tv)); 354 } 355 356 /* actions */ 357 int 358 if_act_start(struct iface *iface) 359 { 360 struct in_addr addr; 361 struct timeval now; 362 363 if (iface->passive) { 364 log_debug("if_act_start: cannot start passive interface %s", 365 iface->name); 366 return (-1); 367 } 368 369 if (!((iface->flags & IFF_UP) && 370 (iface->linkstate != LINK_STATE_DOWN))) { 371 log_debug("if_act_start: interface %s link down", 372 iface->name); 373 return (0); 374 } 375 376 gettimeofday(&now, NULL); 377 iface->uptime = now.tv_sec; 378 379 switch (iface->type) { 380 case IF_TYPE_POINTOPOINT: 381 case IF_TYPE_BROADCAST: 382 inet_aton(AllSystems, &addr); 383 if (if_join_group(iface, &addr)) { 384 log_warnx("if_act_start: error joining group %s, " 385 "interface %s", inet_ntoa(addr), iface->name); 386 return (-1); 387 } 388 inet_aton(AllRouters, &addr); 389 if (if_join_group(iface, &addr)) { 390 log_warnx("if_act_start: error joining group %s, " 391 "interface %s", inet_ntoa(addr), iface->name); 392 return (-1); 393 } 394 inet_aton(AllDVMRPRouters, &addr); 395 if (if_join_group(iface, &addr)) { 396 log_warnx("if_act_start: error joining group %s, " 397 "interface %s", inet_ntoa(addr), iface->name); 398 return (-1); 399 } 400 401 iface->state = IF_STA_QUERIER; 402 if_start_query_timer(iface); 403 if_start_probe_timer(iface); 404 iface->startup_query_counter = iface->startup_query_cnt; 405 break; 406 default: 407 fatalx("if_act_start: unknown type"); 408 } 409 410 return (0); 411 } 412 413 int 414 if_act_query_seen(struct iface *iface) 415 { 416 log_debug("if_act_query_seen: interface %s", iface->name); 417 418 switch (iface->type) { 419 case IF_TYPE_POINTOPOINT: 420 /* XXX iface p2p */ 421 break; 422 case IF_TYPE_BROADCAST: 423 iface->state = IF_STA_NONQUERIER; 424 if_stop_query_timer(iface); 425 if_reset_querier_present_timer(iface); 426 break; 427 default: 428 fatalx("if_act_querier_seen: unknown type"); 429 } 430 431 return (0); 432 } 433 434 int 435 if_act_reset(struct iface *iface) 436 { 437 struct in_addr addr; 438 struct nbr *nbr; 439 440 switch (iface->type) { 441 case IF_TYPE_POINTOPOINT: 442 case IF_TYPE_BROADCAST: 443 inet_aton(AllSystems, &addr); 444 if (if_leave_group(iface, &addr)) { 445 log_warnx("if_act_reset: error leaving group %s, " 446 "interface %s", inet_ntoa(addr), iface->name); 447 return (-1); 448 } 449 inet_aton(AllRouters, &addr); 450 if (if_leave_group(iface, &addr)) { 451 log_warnx("if_act_reset: error leaving group %s, " 452 "interface %s", inet_ntoa(addr), iface->name); 453 return (-1); 454 } 455 inet_aton(AllDVMRPRouters, &addr); 456 if (if_leave_group(iface, &addr)) { 457 log_warnx("if_act_reset: error leaving group %s, " 458 "interface %s", inet_ntoa(addr), iface->name); 459 return (-1); 460 } 461 462 iface->state = IF_STA_DOWN; 463 iface->gen_id++; 464 if_stop_query_timer(iface); 465 if_stop_querier_present_timer(iface); 466 /* XXX clear nbr list? */ 467 break; 468 default: 469 fatalx("if_act_reset: unknown type"); 470 } 471 472 LIST_FOREACH(nbr, &iface->nbr_list, entry) { 473 if (nbr_fsm(nbr, NBR_EVT_KILL_NBR)) { 474 log_debug("if_act_reset: error killing neighbor %s", 475 inet_ntoa(nbr->id)); 476 } 477 } 478 479 group_list_clr(iface); /* XXX clear group list? */ 480 481 return (0); 482 } 483 484 const char * 485 if_event_name(int event) 486 { 487 return (if_event_names[event]); 488 } 489 490 const char * 491 if_action_name(int action) 492 { 493 return (if_action_names[action]); 494 } 495 496 /* misc */ 497 int 498 if_set_mcast_ttl(int fd, u_int8_t ttl) 499 { 500 if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, 501 (char *)&ttl, sizeof(ttl)) < 0) { 502 log_warn("if_set_mcast_ttl: error setting " 503 "IP_MULTICAST_TTL to %d", ttl); 504 return (-1); 505 } 506 507 return (0); 508 } 509 510 int 511 if_set_tos(int fd, int tos) 512 { 513 if (setsockopt(fd, IPPROTO_IP, IP_TOS, 514 (int *)&tos, sizeof(tos)) < 0) { 515 log_warn("if_set_tos: error setting IP_TOS to 0x%x", tos); 516 return (-1); 517 } 518 519 return (0); 520 } 521 522 void 523 if_set_recvbuf(int fd) 524 { 525 int bsize; 526 527 bsize = 65535; 528 while (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bsize, 529 sizeof(bsize)) == -1) 530 bsize /= 2; 531 } 532 533 int 534 if_join_group(struct iface *iface, struct in_addr *addr) 535 { 536 struct ip_mreq mreq; 537 538 switch (iface->type) { 539 case IF_TYPE_POINTOPOINT: 540 case IF_TYPE_BROADCAST: 541 mreq.imr_multiaddr.s_addr = addr->s_addr; 542 mreq.imr_interface.s_addr = iface->addr.s_addr; 543 544 if (setsockopt(iface->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, 545 (void *)&mreq, sizeof(mreq)) < 0) { 546 log_debug("if_join_group: error IP_ADD_MEMBERSHIP, " 547 "interface %s", iface->name); 548 return (-1); 549 } 550 break; 551 default: 552 fatalx("if_join_group: unknown interface type"); 553 } 554 555 return (0); 556 } 557 558 int 559 if_leave_group(struct iface *iface, struct in_addr *addr) 560 { 561 struct ip_mreq mreq; 562 563 switch (iface->type) { 564 case IF_TYPE_POINTOPOINT: 565 case IF_TYPE_BROADCAST: 566 mreq.imr_multiaddr.s_addr = addr->s_addr; 567 mreq.imr_interface.s_addr = iface->addr.s_addr; 568 569 if (setsockopt(iface->fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, 570 (void *)&mreq, sizeof(mreq)) < 0) { 571 log_debug("if_leave_group: error IP_DROP_MEMBERSHIP, " 572 "interface %s", iface->name); 573 return (-1); 574 } 575 break; 576 default: 577 fatalx("if_leave_group: unknown interface type"); 578 } 579 580 return (0); 581 } 582 583 int 584 if_set_mcast(struct iface *iface) 585 { 586 switch (iface->type) { 587 case IF_TYPE_POINTOPOINT: 588 case IF_TYPE_BROADCAST: 589 if (setsockopt(iface->fd, IPPROTO_IP, IP_MULTICAST_IF, 590 (char *)&iface->addr.s_addr, 591 sizeof(iface->addr.s_addr)) < 0) { 592 log_debug("if_set_mcast: error setting " 593 "IP_MULTICAST_IF, interface %s", iface->name); 594 return (-1); 595 } 596 break; 597 default: 598 fatalx("if_set_mcast: unknown interface type"); 599 } 600 601 return (0); 602 } 603 604 int 605 if_set_mcast_loop(int fd) 606 { 607 u_int8_t loop = 0; 608 609 if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, 610 (char *)&loop, sizeof(loop)) < 0) { 611 log_warn("if_set_mcast_loop: error setting IP_MULTICAST_LOOP"); 612 return (-1); 613 } 614 615 return (0); 616 } 617 618 struct ctl_iface * 619 if_to_ctl(struct iface *iface) 620 { 621 static struct ctl_iface ictl; 622 struct timeval tv, now, res; 623 624 memcpy(ictl.name, iface->name, sizeof(ictl.name)); 625 memcpy(&ictl.addr, &iface->addr, sizeof(ictl.addr)); 626 memcpy(&ictl.mask, &iface->mask, sizeof(ictl.mask)); 627 memcpy(&ictl.querier, &iface->querier, sizeof(ictl.querier)); 628 629 ictl.ifindex = iface->ifindex; 630 ictl.state = iface->state; 631 ictl.mtu = iface->mtu; 632 ictl.nbr_cnt = 0; /* XXX */ 633 ictl.adj_cnt = 0; /* XXX */ 634 635 ictl.gen_id = iface->gen_id; 636 ictl.group_cnt = iface->group_cnt; 637 ictl.baudrate = iface->baudrate; 638 ictl.probe_interval = iface->probe_interval; 639 ictl.query_interval = iface->query_interval; 640 ictl.query_resp_interval = iface->query_resp_interval; 641 ictl.recv_query_resp_interval = iface->recv_query_resp_interval; 642 ictl.group_member_interval = iface->group_member_interval; 643 ictl.querier_present_interval = iface->querier_present_interval; 644 ictl.startup_query_interval = iface->startup_query_interval; 645 ictl.startup_query_cnt = iface->startup_query_cnt; 646 ictl.last_member_query_interval = iface->last_member_query_interval; 647 ictl.last_member_query_cnt = iface->last_member_query_cnt; 648 ictl.last_member_query_time = iface->last_member_query_time; 649 ictl.v1_querier_present_tmout = iface->v1_querier_present_tmout; 650 ictl.v1_host_present_interval = iface->v1_host_present_interval; 651 ictl.dead_interval = iface->dead_interval; 652 653 ictl.baudrate = iface->baudrate; 654 ictl.flags = iface->flags; 655 ictl.metric = iface->metric; 656 ictl.type = iface->type; 657 ictl.robustness = iface->robustness; 658 ictl.linkstate = iface->linkstate; 659 ictl.passive = iface->passive; 660 ictl.igmp_version = iface->igmp_version; 661 ictl.mediatype = iface->media_type; 662 663 gettimeofday(&now, NULL); 664 if (evtimer_pending(&iface->probe_timer, &tv)) { 665 timersub(&tv, &now, &res); 666 ictl.probe_timer = res.tv_sec; 667 } else 668 ictl.probe_timer = -1; 669 670 if (evtimer_pending(&iface->query_timer, &tv)) { 671 timersub(&tv, &now, &res); 672 ictl.query_timer = res.tv_sec; 673 } else 674 ictl.query_timer = -1; 675 676 if (evtimer_pending(&iface->querier_present_timer, &tv)) { 677 timersub(&tv, &now, &res); 678 ictl.querier_present_timer = res.tv_sec; 679 } else 680 ictl.querier_present_timer = -1; 681 682 if (iface->state != IF_STA_DOWN) { 683 ictl.uptime = now.tv_sec - iface->uptime; 684 } else 685 ictl.uptime = 0; 686 687 return (&ictl); 688 } 689