1 /* $OpenBSD: interface.c,v 1.1 2009/06/01 20:59:45 michele Exp $ */ 2 3 /* 4 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org> 5 * Copyright (c) 2004, 2005, 2008 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 #include <netinet/in.h> 25 #include <arpa/inet.h> 26 #include <net/if.h> 27 #include <net/if_types.h> 28 #include <fcntl.h> 29 #include <ctype.h> 30 #include <err.h> 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <unistd.h> 34 #include <string.h> 35 #include <event.h> 36 37 #include "ldpd.h" 38 #include "ldp.h" 39 #include "log.h" 40 #include "ldpe.h" 41 42 void if_hello_timer(int, short, void *); 43 void if_start_hello_timer(struct iface *); 44 void if_stop_hello_timer(struct iface *); 45 struct nbr *if_elect(struct nbr *, struct nbr *); 46 47 struct { 48 int state; 49 enum iface_event event; 50 enum iface_action action; 51 int new_state; 52 } iface_fsm[] = { 53 /* current state event that happened action to take resulting state */ 54 {IF_STA_DOWN, IF_EVT_UP, IF_ACT_STRT, IF_STA_ACTIVE}, 55 {IF_STA_ANY, IF_EVT_DOWN, IF_ACT_RST, IF_STA_DOWN}, 56 {-1, IF_EVT_NOTHING, IF_ACT_NOTHING, 0}, 57 }; 58 59 static int vlink_cnt = 0; 60 61 const char * const if_event_names[] = { 62 "NOTHING", 63 "UP", 64 "DOWN" 65 }; 66 67 const char * const if_action_names[] = { 68 "NOTHING", 69 "START", 70 "RESET" 71 }; 72 73 int 74 if_fsm(struct iface *iface, enum iface_event event) 75 { 76 int old_state; 77 int new_state = 0; 78 int i, ret = 0; 79 80 old_state = iface->state; 81 82 for (i = 0; iface_fsm[i].state != -1; i++) 83 if ((iface_fsm[i].state & old_state) && 84 (iface_fsm[i].event == event)) { 85 new_state = iface_fsm[i].new_state; 86 break; 87 } 88 89 if (iface_fsm[i].state == -1) { 90 /* event outside of the defined fsm, ignore it. */ 91 log_debug("if_fsm: interface %s, " 92 "event %s not expected in state %s", iface->name, 93 if_event_names[event], if_state_name(old_state)); 94 return (0); 95 } 96 97 switch (iface_fsm[i].action) { 98 case IF_ACT_STRT: 99 ret = if_act_start(iface); 100 break; 101 case IF_ACT_RST: 102 ret = if_act_reset(iface); 103 break; 104 case IF_ACT_NOTHING: 105 /* do nothing */ 106 break; 107 } 108 109 if (ret) { 110 log_debug("if_fsm: error changing state for interface %s, " 111 "event %s, state %s", iface->name, if_event_names[event], 112 if_state_name(old_state)); 113 return (-1); 114 } 115 116 if (new_state != 0) 117 iface->state = new_state; 118 119 log_debug("if_fsm: event %s resulted in action %s and changing " 120 "state for interface %s from %s to %s", 121 if_event_names[event], if_action_names[iface_fsm[i].action], 122 iface->name, if_state_name(old_state), if_state_name(iface->state)); 123 124 return (ret); 125 } 126 127 struct iface * 128 if_new(struct kif *kif, struct kif_addr *ka) 129 { 130 struct iface *iface; 131 132 if ((iface = calloc(1, sizeof(*iface))) == NULL) 133 err(1, "if_new: calloc"); 134 135 iface->state = IF_STA_DOWN; 136 137 LIST_INIT(&iface->nbr_list); 138 LIST_INIT(&iface->lde_nbr_list); 139 140 if (kif == NULL) { 141 iface->type = IF_TYPE_VIRTUALLINK; 142 snprintf(iface->name, sizeof(iface->name), "vlink%d", 143 vlink_cnt++); 144 iface->flags |= IFF_UP; 145 iface->mtu = IP_MSS; 146 return (iface); 147 } 148 149 strlcpy(iface->name, kif->ifname, sizeof(iface->name)); 150 151 /* get type */ 152 if (kif->flags & IFF_POINTOPOINT) 153 iface->type = IF_TYPE_POINTOPOINT; 154 if (kif->flags & IFF_BROADCAST && 155 kif->flags & IFF_MULTICAST) 156 iface->type = IF_TYPE_BROADCAST; 157 if (kif->flags & IFF_LOOPBACK) { 158 iface->type = IF_TYPE_POINTOPOINT; 159 iface->state = IF_STA_LOOPBACK; 160 } 161 162 /* get mtu, index and flags */ 163 iface->mtu = kif->mtu; 164 iface->ifindex = kif->ifindex; 165 iface->flags = kif->flags; 166 iface->linkstate = kif->link_state; 167 iface->media_type = kif->media_type; 168 iface->baudrate = kif->baudrate; 169 170 /* set address, mask and p2p addr */ 171 iface->addr = ka->addr; 172 iface->mask = ka->mask; 173 if (kif->flags & IFF_POINTOPOINT) { 174 iface->dst = ka->dstbrd; 175 } 176 177 return (iface); 178 } 179 180 void 181 if_del(struct iface *iface) 182 { 183 struct nbr *nbr = NULL; 184 185 log_debug("if_del: interface %s", iface->name); 186 187 /* clear lists etc */ 188 while ((nbr = LIST_FIRST(&iface->nbr_list)) != NULL) 189 nbr_del(nbr); 190 191 if (evtimer_pending(&iface->hello_timer, NULL)) 192 evtimer_del(&iface->hello_timer); 193 194 free(iface); 195 } 196 197 void 198 if_init(struct ldpd_conf *xconf, struct iface *iface) 199 { 200 /* init the dummy local neighbor */ 201 iface->self = nbr_new(ldpe_router_id(), iface->ifindex, iface, 1); 202 203 /* set event handlers for interface */ 204 evtimer_set(&iface->hello_timer, if_hello_timer, iface); 205 206 iface->discovery_fd = xconf->ldp_discovery_socket; 207 } 208 209 /* timers */ 210 /* ARGSUSED */ 211 void 212 if_hello_timer(int fd, short event, void *arg) 213 { 214 struct iface *iface = arg; 215 struct timeval tv; 216 217 send_hello(iface); 218 219 /* reschedule hello_timer */ 220 timerclear(&tv); 221 tv.tv_sec = iface->hello_interval; 222 if (evtimer_add(&iface->hello_timer, &tv) == -1) 223 fatal("if_hello_timer"); 224 } 225 226 void 227 if_start_hello_timer(struct iface *iface) 228 { 229 struct timeval tv; 230 231 timerclear(&tv); 232 tv.tv_sec = iface->hello_interval; 233 if (evtimer_add(&iface->hello_timer, &tv) == -1) 234 fatal("if_start_hello_timer"); 235 } 236 237 void 238 if_stop_hello_timer(struct iface *iface) 239 { 240 if (evtimer_del(&iface->hello_timer) == -1) 241 fatal("if_stop_hello_timer"); 242 } 243 244 /* actions */ 245 int 246 if_act_start(struct iface *iface) 247 { 248 struct in_addr addr; 249 struct timeval now; 250 251 if (!((iface->flags & IFF_UP) && 252 (LINK_STATE_IS_UP(iface->linkstate) || 253 (iface->linkstate == LINK_STATE_UNKNOWN && 254 iface->media_type != IFT_CARP)))) { 255 log_debug("if_act_start: interface %s link down", 256 iface->name); 257 return (0); 258 } 259 260 if (iface->media_type == IFT_CARP && iface->passive == 0) { 261 /* force passive mode on carp interfaces */ 262 log_warnx("if_act_start: forcing interface %s to passive", 263 iface->name); 264 iface->passive = 1; 265 } 266 267 gettimeofday(&now, NULL); 268 iface->uptime = now.tv_sec; 269 270 switch (iface->type) { 271 case IF_TYPE_POINTOPOINT: 272 inet_aton(AllRouters, &addr); 273 if (if_join_group(iface, &addr)) 274 return (-1); 275 iface->state = IF_STA_POINTTOPOINT; 276 break; 277 case IF_TYPE_VIRTUALLINK: 278 iface->state = IF_STA_POINTTOPOINT; 279 break; 280 case IF_TYPE_POINTOMULTIPOINT: 281 case IF_TYPE_NBMA: 282 log_debug("if_act_start: type %s not supported, interface %s", 283 if_type_name(iface->type), iface->name); 284 return (-1); 285 case IF_TYPE_BROADCAST: 286 inet_aton(AllRouters, &addr); 287 if (if_join_group(iface, &addr)) 288 return (-1); 289 iface->state = IF_STA_DOWN; 290 break; 291 default: 292 fatalx("if_act_start: unknown interface type"); 293 } 294 295 /* hello timer needs to be started in any case */ 296 if_start_hello_timer(iface); 297 return (0); 298 } 299 300 int 301 if_act_reset(struct iface *iface) 302 { 303 /* struct nbr *nbr = NULL; */ 304 struct in_addr addr; 305 306 switch (iface->type) { 307 case IF_TYPE_POINTOPOINT: 308 case IF_TYPE_BROADCAST: 309 inet_aton(AllRouters, &addr); 310 if (if_leave_group(iface, &addr)) { 311 log_warnx("if_act_reset: error leaving group %s, " 312 "interface %s", inet_ntoa(addr), iface->name); 313 } 314 break; 315 case IF_TYPE_VIRTUALLINK: 316 /* nothing */ 317 break; 318 case IF_TYPE_NBMA: 319 case IF_TYPE_POINTOMULTIPOINT: 320 log_debug("if_act_reset: type %s not supported, interface %s", 321 if_type_name(iface->type), iface->name); 322 return (-1); 323 default: 324 fatalx("if_act_reset: unknown interface type"); 325 } 326 /* 327 LIST_FOREACH(nbr, &iface->nbr_list, entry) { 328 if (nbr_fsm(nbr, NBR_EVT_KILL_NBR)) { 329 log_debug("if_act_reset: error killing neighbor %s", 330 inet_ntoa(nbr->id)); 331 } 332 } 333 */ 334 return (0); 335 } 336 337 struct ctl_iface * 338 if_to_ctl(struct iface *iface) 339 { 340 static struct ctl_iface ictl; 341 struct timeval tv, now, res; 342 struct nbr *nbr; 343 344 memcpy(ictl.name, iface->name, sizeof(ictl.name)); 345 memcpy(&ictl.addr, &iface->addr, sizeof(ictl.addr)); 346 memcpy(&ictl.mask, &iface->mask, sizeof(ictl.mask)); 347 ictl.rtr_id.s_addr = ldpe_router_id(); 348 ictl.ifindex = iface->ifindex; 349 ictl.state = iface->state; 350 ictl.mtu = iface->mtu; 351 ictl.nbr_cnt = 0; 352 ictl.adj_cnt = 0; 353 ictl.baudrate = iface->baudrate; 354 ictl.holdtime = iface->holdtime; 355 ictl.hello_interval = iface->hello_interval; 356 ictl.flags = iface->flags; 357 ictl.type = iface->type; 358 ictl.linkstate = iface->linkstate; 359 ictl.mediatype = iface->media_type; 360 ictl.priority = iface->priority; 361 ictl.passive = iface->passive; 362 363 gettimeofday(&now, NULL); 364 if (evtimer_pending(&iface->hello_timer, &tv)) { 365 timersub(&tv, &now, &res); 366 ictl.hello_timer = res.tv_sec; 367 } else 368 ictl.hello_timer = -1; 369 370 if (iface->state != IF_STA_DOWN) { 371 ictl.uptime = now.tv_sec - iface->uptime; 372 } else 373 ictl.uptime = 0; 374 375 LIST_FOREACH(nbr, &iface->nbr_list, entry) { 376 if (nbr == iface->self) 377 continue; 378 ictl.nbr_cnt++; 379 } 380 381 return (&ictl); 382 } 383 384 /* misc */ 385 int 386 if_set_mcast_ttl(int fd, u_int8_t ttl) 387 { 388 if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, 389 (char *)&ttl, sizeof(ttl)) < 0) { 390 log_warn("if_set_mcast_ttl: error setting " 391 "IP_MULTICAST_TTL to %d", ttl); 392 return (-1); 393 } 394 395 return (0); 396 } 397 398 int 399 if_set_tos(int fd, int tos) 400 { 401 if (setsockopt(fd, IPPROTO_IP, IP_TOS, (int *)&tos, sizeof(tos)) < 0) { 402 log_warn("if_set_tos: error setting IP_TOS to 0x%x", tos); 403 return (-1); 404 } 405 406 return (0); 407 } 408 409 int 410 if_set_recvif(int fd, int enable) 411 { 412 if (setsockopt(fd, IPPROTO_IP, IP_RECVIF, &enable, 413 sizeof(enable)) < 0) { 414 log_warn("if_set_recvif: error setting IP_RECVIF"); 415 return (-1); 416 } 417 return (0); 418 } 419 420 void 421 if_set_recvbuf(int fd) 422 { 423 int bsize; 424 425 bsize = 65535; 426 while (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bsize, 427 sizeof(bsize)) == -1) 428 bsize /= 2; 429 } 430 431 int 432 if_set_reuse(int fd, int enable) 433 { 434 if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &enable, 435 sizeof(int)) < 0) { 436 log_warn("if_set_reuse: error setting SO_REUSEPORT"); 437 return (-1); 438 } 439 440 return (0); 441 } 442 443 int 444 if_set_nonblock(int fd) 445 { 446 if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) { 447 log_warn("if_set_nonblock: error setting O_NONBLOCK"); 448 return (-1); 449 } 450 451 return (0); 452 } 453 454 455 /* 456 * only one JOIN or DROP per interface and address is allowed so we need 457 * to keep track of what is added and removed. 458 */ 459 struct if_group_count { 460 LIST_ENTRY(if_group_count) entry; 461 struct in_addr addr; 462 unsigned int ifindex; 463 int count; 464 }; 465 466 LIST_HEAD(,if_group_count) ifglist = LIST_HEAD_INITIALIZER(ifglist); 467 468 int 469 if_join_group(struct iface *iface, struct in_addr *addr) 470 { 471 struct ip_mreq mreq; 472 struct if_group_count *ifg; 473 474 switch (iface->type) { 475 case IF_TYPE_POINTOPOINT: 476 case IF_TYPE_BROADCAST: 477 LIST_FOREACH(ifg, &ifglist, entry) 478 if (iface->ifindex == ifg->ifindex && 479 addr->s_addr == ifg->addr.s_addr) 480 break; 481 if (ifg == NULL) { 482 if ((ifg = calloc(1, sizeof(*ifg))) == NULL) 483 fatal("if_join_group"); 484 ifg->addr.s_addr = addr->s_addr; 485 ifg->ifindex = iface->ifindex; 486 LIST_INSERT_HEAD(&ifglist, ifg, entry); 487 } 488 489 if (ifg->count++ != 0) 490 /* already joined */ 491 return (0); 492 493 mreq.imr_multiaddr.s_addr = addr->s_addr; 494 mreq.imr_interface.s_addr = iface->addr.s_addr; 495 496 if (setsockopt(iface->discovery_fd, IPPROTO_IP, 497 IP_ADD_MEMBERSHIP, (void *)&mreq, sizeof(mreq)) < 0) { 498 log_warn("if_join_group: error IP_ADD_MEMBERSHIP, " 499 "interface %s address %s", iface->name, 500 inet_ntoa(*addr)); 501 return (-1); 502 } 503 break; 504 case IF_TYPE_POINTOMULTIPOINT: 505 case IF_TYPE_VIRTUALLINK: 506 case IF_TYPE_NBMA: 507 log_debug("if_join_group: type %s not supported, interface %s", 508 if_type_name(iface->type), iface->name); 509 return (-1); 510 default: 511 fatalx("if_join_group: unknown interface type"); 512 } 513 514 return (0); 515 } 516 517 int 518 if_leave_group(struct iface *iface, struct in_addr *addr) 519 { 520 struct ip_mreq mreq; 521 struct if_group_count *ifg; 522 523 switch (iface->type) { 524 case IF_TYPE_POINTOPOINT: 525 case IF_TYPE_BROADCAST: 526 LIST_FOREACH(ifg, &ifglist, entry) 527 if (iface->ifindex == ifg->ifindex && 528 addr->s_addr == ifg->addr.s_addr) 529 break; 530 531 /* if interface is not found just try to drop membership */ 532 if (ifg && --ifg->count != 0) 533 /* others still joined */ 534 return (0); 535 536 mreq.imr_multiaddr.s_addr = addr->s_addr; 537 mreq.imr_interface.s_addr = iface->addr.s_addr; 538 539 if (setsockopt(iface->discovery_fd, IPPROTO_IP, 540 IP_DROP_MEMBERSHIP, (void *)&mreq, sizeof(mreq)) < 0) { 541 log_warn("if_leave_group: error IP_DROP_MEMBERSHIP, " 542 "interface %s address %s", iface->name, 543 inet_ntoa(*addr)); 544 return (-1); 545 } 546 547 if (ifg) { 548 LIST_REMOVE(ifg, entry); 549 free(ifg); 550 } 551 break; 552 case IF_TYPE_POINTOMULTIPOINT: 553 case IF_TYPE_VIRTUALLINK: 554 case IF_TYPE_NBMA: 555 log_debug("if_leave_group: type %s not supported, interface %s", 556 if_type_name(iface->type), iface->name); 557 return (-1); 558 default: 559 fatalx("if_leave_group: unknown interface type"); 560 } 561 562 return (0); 563 } 564 565 int 566 if_set_mcast(struct iface *iface) 567 { 568 switch (iface->type) { 569 case IF_TYPE_POINTOPOINT: 570 case IF_TYPE_BROADCAST: 571 if (setsockopt(iface->discovery_fd, IPPROTO_IP, IP_MULTICAST_IF, 572 &iface->addr.s_addr, sizeof(iface->addr.s_addr)) < 0) { 573 log_debug("if_set_mcast: error setting " 574 "IP_MULTICAST_IF, interface %s", iface->name); 575 return (-1); 576 } 577 break; 578 case IF_TYPE_POINTOMULTIPOINT: 579 case IF_TYPE_VIRTUALLINK: 580 case IF_TYPE_NBMA: 581 log_debug("if_set_mcast: type %s not supported, interface %s", 582 if_type_name(iface->type), iface->name); 583 return (-1); 584 default: 585 fatalx("if_set_mcast: unknown interface type"); 586 } 587 588 return (0); 589 } 590 591 int 592 if_set_mcast_loop(int fd) 593 { 594 u_int8_t loop = 0; 595 596 if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, 597 (char *)&loop, sizeof(loop)) < 0) { 598 log_warn("if_set_mcast_loop: error setting IP_MULTICAST_LOOP"); 599 return (-1); 600 } 601 602 return (0); 603 } 604