interface.c revision 1.15
1/* $OpenBSD: interface.c,v 1.15 2013/06/03 17:01:59 claudio 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 42extern struct ldpd_conf *leconf; 43 44int if_act_start(struct iface *); 45int if_act_reset(struct iface *); 46int if_act_update(struct iface *); 47void if_hello_timer(int, short, void *); 48void if_start_hello_timer(struct iface *); 49void if_stop_hello_timer(struct iface *); 50struct nbr *if_elect(struct nbr *, struct nbr *); 51 52struct { 53 int state; 54 enum iface_event event; 55 enum iface_action action; 56 int new_state; 57} iface_fsm[] = { 58 /* current state event that happened action to take resulting state */ 59 {IF_STA_DOWN, IF_EVT_DOWN, IF_ACT_NOTHING, 0}, 60 {IF_STA_DOWN, IF_EVT_UP, IF_ACT_UPDATE, 0}, 61 {IF_STA_DOWN, IF_EVT_NEWADDR, IF_ACT_UPDATE, 0}, 62 {IF_STA_DOWN, IF_EVT_DELADDR, IF_ACT_NOTHING, 0}, 63 {IF_STA_ACTIVE, IF_EVT_DOWN, IF_ACT_RST, IF_STA_DOWN}, 64 {IF_STA_ACTIVE, IF_EVT_NEWADDR, IF_ACT_NOTHING, 0}, 65 {IF_STA_ACTIVE, IF_EVT_DELADDR, IF_ACT_UPDATE, 0}, 66 {-1, IF_EVT_NOTHING, IF_ACT_NOTHING, 0}, 67}; 68 69const char * const if_event_names[] = { 70 "NOTHING", 71 "UP", 72 "DOWN", 73 "NEWADDR", 74 "DELADDR" 75}; 76 77const char * const if_action_names[] = { 78 "NOTHING", 79 "UPDATE", 80 "RESET" 81}; 82 83int 84if_fsm(struct iface *iface, enum iface_event event) 85{ 86 int old_state; 87 int new_state = 0; 88 int i, ret = 0; 89 90 old_state = iface->state; 91 92 for (i = 0; iface_fsm[i].state != -1; i++) 93 if ((iface_fsm[i].state & old_state) && 94 (iface_fsm[i].event == event)) { 95 new_state = iface_fsm[i].new_state; 96 break; 97 } 98 99 if (iface_fsm[i].state == -1) { 100 /* event outside of the defined fsm, ignore it. */ 101 log_debug("if_fsm: interface %s, " 102 "event %s not expected in state %s", iface->name, 103 if_event_names[event], if_state_name(old_state)); 104 return (0); 105 } 106 107 switch (iface_fsm[i].action) { 108 case IF_ACT_UPDATE: 109 ret = if_act_update(iface); 110 break; 111 case IF_ACT_RST: 112 ret = if_act_reset(iface); 113 break; 114 case IF_ACT_NOTHING: 115 /* do nothing */ 116 break; 117 } 118 119 if (ret) { 120 log_debug("if_fsm: error changing state for interface %s, " 121 "event %s, state %s", iface->name, if_event_names[event], 122 if_state_name(old_state)); 123 return (-1); 124 } 125 126 if (new_state != 0) 127 iface->state = new_state; 128 129 log_debug("if_fsm: event %s resulted in action %s and changing " 130 "state for interface %s from %s to %s", 131 if_event_names[event], if_action_names[iface_fsm[i].action], 132 iface->name, if_state_name(old_state), if_state_name(iface->state)); 133 134 return (ret); 135} 136 137struct iface * 138if_new(struct kif *kif) 139{ 140 struct iface *iface; 141 142 if ((iface = calloc(1, sizeof(*iface))) == NULL) 143 err(1, "if_new: calloc"); 144 145 iface->state = IF_STA_DOWN; 146 147 strlcpy(iface->name, kif->ifname, sizeof(iface->name)); 148 149 /* get type */ 150 if (kif->flags & IFF_POINTOPOINT) 151 iface->type = IF_TYPE_POINTOPOINT; 152 if (kif->flags & IFF_BROADCAST && 153 kif->flags & IFF_MULTICAST) 154 iface->type = IF_TYPE_BROADCAST; 155 156 /* get mtu, index and flags */ 157 iface->mtu = kif->mtu; 158 iface->ifindex = kif->ifindex; 159 iface->flags = kif->flags; 160 iface->linkstate = kif->link_state; 161 iface->media_type = kif->media_type; 162 iface->baudrate = kif->baudrate; 163 164 return (iface); 165} 166 167void 168if_del(struct iface *iface) 169{ 170 struct if_addr *if_addr; 171 172 log_debug("if_del: interface %s", iface->name); 173 174 if_stop_hello_timer(iface); 175 176 while ((if_addr = LIST_FIRST(&iface->addr_list)) != NULL) 177 LIST_REMOVE(if_addr, iface_entry); 178 179 free(iface); 180} 181 182void 183if_init(struct ldpd_conf *xconf, struct iface *iface) 184{ 185 /* set event handlers for interface */ 186 evtimer_set(&iface->hello_timer, if_hello_timer, iface); 187 188 iface->discovery_fd = xconf->ldp_discovery_socket; 189} 190 191struct iface * 192if_lookup(u_short ifindex) 193{ 194 struct iface *iface; 195 196 LIST_FOREACH(iface, &leconf->iface_list, entry) 197 if (iface->ifindex == ifindex) 198 return (iface); 199 200 return (NULL); 201} 202 203/* timers */ 204/* ARGSUSED */ 205void 206if_hello_timer(int fd, short event, void *arg) 207{ 208 struct iface *iface = arg; 209 struct timeval tv; 210 211 send_hello(iface); 212 213 /* reschedule hello_timer */ 214 timerclear(&tv); 215 tv.tv_sec = iface->hello_interval; 216 if (evtimer_add(&iface->hello_timer, &tv) == -1) 217 fatal("if_hello_timer"); 218} 219 220void 221if_start_hello_timer(struct iface *iface) 222{ 223 struct timeval tv; 224 225 timerclear(&tv); 226 tv.tv_sec = iface->hello_interval; 227 if (evtimer_add(&iface->hello_timer, &tv) == -1) 228 fatal("if_start_hello_timer"); 229} 230 231void 232if_stop_hello_timer(struct iface *iface) 233{ 234 if (evtimer_pending(&iface->hello_timer, NULL) && 235 evtimer_del(&iface->hello_timer) == -1) 236 fatal("if_stop_hello_timer"); 237} 238 239/* actions */ 240int 241if_act_start(struct iface *iface) 242{ 243 struct in_addr addr; 244 struct timeval now; 245 246 if (!((iface->flags & IFF_UP) && 247 LINK_STATE_IS_UP(iface->linkstate))) { 248 log_debug("if_act_start: interface %s link down", 249 iface->name); 250 return (0); 251 } 252 253 gettimeofday(&now, NULL); 254 iface->uptime = now.tv_sec; 255 256 inet_aton(AllRouters, &addr); 257 if (if_join_group(iface, &addr)) 258 return (-1); 259 iface->state = IF_STA_ACTIVE; 260 261 /* hello timer needs to be started in any case */ 262 if_start_hello_timer(iface); 263 return (0); 264} 265 266int 267if_act_reset(struct iface *iface) 268{ 269 struct in_addr addr; 270 271 if_stop_hello_timer(iface); 272 273 /* try to cleanup */ 274 inet_aton(AllRouters, &addr); 275 if_leave_group(iface, &addr); 276 277 return (0); 278} 279 280int 281if_act_update(struct iface *iface) 282{ 283 int ret; 284 285 if (iface->state == IF_STA_DOWN) { 286 if (!((iface->flags & IFF_UP) && 287 LINK_STATE_IS_UP(iface->linkstate))) 288 return (0); 289 290 if (LIST_EMPTY(&iface->addr_list)) 291 return (0); 292 293 iface->state = IF_STA_ACTIVE; 294 ret = if_act_start(iface); 295 } else { 296 if (!LIST_EMPTY(&iface->addr_list)) 297 return (0); 298 299 iface->state = IF_STA_DOWN; 300 ret = if_act_reset(iface); 301 } 302 303 return (ret); 304} 305 306struct ctl_iface * 307if_to_ctl(struct iface *iface) 308{ 309 static struct ctl_iface ictl; 310 struct timeval tv, now, res; 311 312 memcpy(ictl.name, iface->name, sizeof(ictl.name)); 313 ictl.rtr_id.s_addr = ldpe_router_id(); 314 ictl.ifindex = iface->ifindex; 315 ictl.state = iface->state; 316 ictl.mtu = iface->mtu; 317 ictl.baudrate = iface->baudrate; 318 ictl.holdtime = iface->holdtime; 319 ictl.hello_interval = iface->hello_interval; 320 ictl.flags = iface->flags; 321 ictl.type = iface->type; 322 ictl.linkstate = iface->linkstate; 323 ictl.mediatype = iface->media_type; 324 ictl.priority = iface->priority; 325 326 gettimeofday(&now, NULL); 327 if (evtimer_pending(&iface->hello_timer, &tv)) { 328 timersub(&tv, &now, &res); 329 ictl.hello_timer = res.tv_sec; 330 } else 331 ictl.hello_timer = -1; 332 333 if (iface->state != IF_STA_DOWN && 334 iface->uptime != 0) { 335 ictl.uptime = now.tv_sec - iface->uptime; 336 } else 337 ictl.uptime = 0; 338 339 return (&ictl); 340} 341 342/* misc */ 343int 344if_set_mcast_ttl(int fd, u_int8_t ttl) 345{ 346 if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, 347 (char *)&ttl, sizeof(ttl)) < 0) { 348 log_warn("if_set_mcast_ttl: error setting " 349 "IP_MULTICAST_TTL to %d", ttl); 350 return (-1); 351 } 352 353 return (0); 354} 355 356int 357if_set_tos(int fd, int tos) 358{ 359 if (setsockopt(fd, IPPROTO_IP, IP_TOS, (int *)&tos, sizeof(tos)) < 0) { 360 log_warn("if_set_tos: error setting IP_TOS to 0x%x", tos); 361 return (-1); 362 } 363 364 return (0); 365} 366 367int 368if_set_recvif(int fd, int enable) 369{ 370 if (setsockopt(fd, IPPROTO_IP, IP_RECVIF, &enable, 371 sizeof(enable)) < 0) { 372 log_warn("if_set_recvif: error setting IP_RECVIF"); 373 return (-1); 374 } 375 return (0); 376} 377 378void 379if_set_recvbuf(int fd) 380{ 381 int bsize; 382 383 bsize = 65535; 384 while (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bsize, 385 sizeof(bsize)) == -1) 386 bsize /= 2; 387} 388 389int 390if_set_reuse(int fd, int enable) 391{ 392 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &enable, 393 sizeof(int)) < 0) { 394 log_warn("if_set_reuse: error setting SO_REUSEADDR"); 395 return (-1); 396 } 397 398 return (0); 399} 400 401/* 402 * only one JOIN or DROP per interface and address is allowed so we need 403 * to keep track of what is added and removed. 404 */ 405struct if_group_count { 406 LIST_ENTRY(if_group_count) entry; 407 struct in_addr addr; 408 unsigned int ifindex; 409 int count; 410}; 411 412LIST_HEAD(,if_group_count) ifglist = LIST_HEAD_INITIALIZER(ifglist); 413 414int 415if_join_group(struct iface *iface, struct in_addr *addr) 416{ 417 struct ip_mreq mreq; 418 struct if_group_count *ifg; 419 struct if_addr *if_addr; 420 421 LIST_FOREACH(ifg, &ifglist, entry) 422 if (iface->ifindex == ifg->ifindex && 423 addr->s_addr == ifg->addr.s_addr) 424 break; 425 if (ifg == NULL) { 426 if ((ifg = calloc(1, sizeof(*ifg))) == NULL) 427 fatal("if_join_group"); 428 ifg->addr.s_addr = addr->s_addr; 429 ifg->ifindex = iface->ifindex; 430 LIST_INSERT_HEAD(&ifglist, ifg, entry); 431 } 432 433 if (ifg->count++ != 0) 434 /* already joined */ 435 return (0); 436 437 if_addr = LIST_FIRST(&iface->addr_list); 438 mreq.imr_multiaddr.s_addr = addr->s_addr; 439 mreq.imr_interface.s_addr = if_addr->addr.s_addr; 440 441 if (setsockopt(iface->discovery_fd, IPPROTO_IP, 442 IP_ADD_MEMBERSHIP, (void *)&mreq, sizeof(mreq)) < 0) { 443 log_warn("if_join_group: error IP_ADD_MEMBERSHIP, " 444 "interface %s address %s", iface->name, 445 inet_ntoa(*addr)); 446 LIST_REMOVE(ifg, entry); 447 free(ifg); 448 return (-1); 449 } 450 return (0); 451} 452 453int 454if_leave_group(struct iface *iface, struct in_addr *addr) 455{ 456 struct ip_mreq mreq; 457 struct if_group_count *ifg; 458 struct if_addr *if_addr; 459 460 LIST_FOREACH(ifg, &ifglist, entry) 461 if (iface->ifindex == ifg->ifindex && 462 addr->s_addr == ifg->addr.s_addr) 463 break; 464 465 /* if interface is not found just try to drop membership */ 466 if (ifg) { 467 if (--ifg->count != 0) 468 /* others still joined */ 469 return (0); 470 471 LIST_REMOVE(ifg, entry); 472 free(ifg); 473 } 474 475 if_addr = LIST_FIRST(&iface->addr_list); 476 if (!if_addr) 477 return (0); 478 479 mreq.imr_multiaddr.s_addr = addr->s_addr; 480 mreq.imr_interface.s_addr = if_addr->addr.s_addr; 481 482 if (setsockopt(iface->discovery_fd, IPPROTO_IP, 483 IP_DROP_MEMBERSHIP, (void *)&mreq, sizeof(mreq)) < 0) { 484 log_warn("if_leave_group: error IP_DROP_MEMBERSHIP, " 485 "interface %s address %s", iface->name, 486 inet_ntoa(*addr)); 487 return (-1); 488 } 489 490 return (0); 491} 492 493int 494if_set_mcast(struct iface *iface) 495{ 496 struct if_addr *if_addr; 497 498 if_addr = LIST_FIRST(&iface->addr_list); 499 500 if (setsockopt(iface->discovery_fd, IPPROTO_IP, IP_MULTICAST_IF, 501 &if_addr->addr.s_addr, sizeof(if_addr->addr.s_addr)) < 0) { 502 log_debug("if_set_mcast: error setting " 503 "IP_MULTICAST_IF, interface %s", iface->name); 504 return (-1); 505 } 506 507 return (0); 508} 509 510int 511if_set_mcast_loop(int fd) 512{ 513 u_int8_t loop = 0; 514 515 if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, 516 (char *)&loop, sizeof(loop)) < 0) { 517 log_warn("if_set_mcast_loop: error setting IP_MULTICAST_LOOP"); 518 return (-1); 519 } 520 521 return (0); 522} 523