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