interface.c revision 1.22
1214152Sed/* $OpenBSD: interface.c,v 1.22 2015/03/21 18:32:01 renato Exp $ */ 2214152Sed 3214152Sed/* 4214152Sed * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org> 5214152Sed * Copyright (c) 2004, 2005, 2008 Esben Norby <norby@openbsd.org> 6214152Sed * 7214152Sed * Permission to use, copy, modify, and distribute this software for any 8214152Sed * purpose with or without fee is hereby granted, provided that the above 9214152Sed * copyright notice and this permission notice appear in all copies. 10214152Sed * 11214152Sed * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12214152Sed * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13214152Sed * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14214152Sed * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15214152Sed * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16214152Sed * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17214152Sed * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18214152Sed */ 19214152Sed 20214152Sed#include <sys/types.h> 21214152Sed#include <sys/ioctl.h> 22214152Sed#include <sys/time.h> 23214152Sed#include <sys/socket.h> 24214152Sed#include <netinet/in.h> 25214152Sed#include <arpa/inet.h> 26214152Sed#include <net/if.h> 27214152Sed#include <net/if_types.h> 28214152Sed#include <fcntl.h> 29214152Sed#include <ctype.h> 30214152Sed#include <err.h> 31214152Sed#include <stdio.h> 32214152Sed#include <stdlib.h> 33214152Sed#include <unistd.h> 34214152Sed#include <string.h> 35214152Sed#include <event.h> 36214152Sed 37214152Sed#include "ldpd.h" 38214152Sed#include "ldp.h" 39214152Sed#include "log.h" 40214152Sed#include "ldpe.h" 41214152Sed 42214152Sedextern struct ldpd_conf *leconf; 43214152Sed 44214152Sedvoid if_hello_timer(int, short, void *); 45214152Sedvoid if_start_hello_timer(struct iface *); 46214152Sedvoid if_stop_hello_timer(struct iface *); 47214152Sed 48214152Sedstruct iface * 49214152Sedif_new(struct kif *kif) 50214152Sed{ 51214152Sed struct iface *iface; 52214152Sed 53214152Sed if ((iface = calloc(1, sizeof(*iface))) == NULL) 54214152Sed err(1, "if_new: calloc"); 55214152Sed 56214152Sed iface->state = IF_STA_DOWN; 57214152Sed 58214152Sed strlcpy(iface->name, kif->ifname, sizeof(iface->name)); 59214152Sed 60 /* get type */ 61 if (kif->flags & IFF_POINTOPOINT) 62 iface->type = IF_TYPE_POINTOPOINT; 63 if (kif->flags & IFF_BROADCAST && 64 kif->flags & IFF_MULTICAST) 65 iface->type = IF_TYPE_BROADCAST; 66 67 /* get index and flags */ 68 iface->ifindex = kif->ifindex; 69 iface->flags = kif->flags; 70 iface->linkstate = kif->link_state; 71 iface->media_type = kif->media_type; 72 73 return (iface); 74} 75 76void 77if_del(struct iface *iface) 78{ 79 struct if_addr *if_addr; 80 81 if (iface->state == IF_STA_ACTIVE) 82 if_reset(iface); 83 84 log_debug("if_del: interface %s", iface->name); 85 86 while ((if_addr = LIST_FIRST(&iface->addr_list)) != NULL) 87 LIST_REMOVE(if_addr, iface_entry); 88 89 free(iface); 90} 91 92void 93if_init(struct ldpd_conf *xconf, struct iface *iface) 94{ 95 /* set event handlers for interface */ 96 evtimer_set(&iface->hello_timer, if_hello_timer, iface); 97 98 iface->discovery_fd = xconf->ldp_discovery_socket; 99} 100 101struct iface * 102if_lookup(u_short ifindex) 103{ 104 struct iface *iface; 105 106 LIST_FOREACH(iface, &leconf->iface_list, entry) 107 if (iface->ifindex == ifindex) 108 return (iface); 109 110 return (NULL); 111} 112 113/* timers */ 114/* ARGSUSED */ 115void 116if_hello_timer(int fd, short event, void *arg) 117{ 118 struct iface *iface = arg; 119 struct timeval tv; 120 121 send_hello(HELLO_LINK, iface, NULL); 122 123 /* reschedule hello_timer */ 124 timerclear(&tv); 125 tv.tv_sec = iface->hello_interval; 126 if (evtimer_add(&iface->hello_timer, &tv) == -1) 127 fatal("if_hello_timer"); 128} 129 130void 131if_start_hello_timer(struct iface *iface) 132{ 133 struct timeval tv; 134 135 send_hello(HELLO_LINK, iface, NULL); 136 137 timerclear(&tv); 138 tv.tv_sec = iface->hello_interval; 139 if (evtimer_add(&iface->hello_timer, &tv) == -1) 140 fatal("if_start_hello_timer"); 141} 142 143void 144if_stop_hello_timer(struct iface *iface) 145{ 146 if (evtimer_pending(&iface->hello_timer, NULL) && 147 evtimer_del(&iface->hello_timer) == -1) 148 fatal("if_stop_hello_timer"); 149} 150 151int 152if_start(struct iface *iface) 153{ 154 struct in_addr addr; 155 struct timeval now; 156 157 log_debug("if_start: %s", iface->name); 158 159 gettimeofday(&now, NULL); 160 iface->uptime = now.tv_sec; 161 162 inet_aton(AllRouters, &addr); 163 if (if_join_group(iface, &addr)) 164 return (-1); 165 166 /* hello timer needs to be started in any case */ 167 if_start_hello_timer(iface); 168 return (0); 169} 170 171int 172if_reset(struct iface *iface) 173{ 174 struct in_addr addr; 175 struct adj *adj; 176 177 log_debug("if_reset: %s", iface->name); 178 179 while ((adj = LIST_FIRST(&iface->adj_list)) != NULL) { 180 LIST_REMOVE(adj, iface_entry); 181 adj_del(adj); 182 } 183 184 if_stop_hello_timer(iface); 185 186 /* try to cleanup */ 187 inet_aton(AllRouters, &addr); 188 if_leave_group(iface, &addr); 189 190 return (0); 191} 192 193int 194if_update(struct iface *iface) 195{ 196 int ret; 197 198 if (iface->state == IF_STA_DOWN) { 199 if (!(iface->flags & IFF_UP) || 200 !LINK_STATE_IS_UP(iface->linkstate) || 201 LIST_EMPTY(&iface->addr_list)) 202 return (0); 203 204 iface->state = IF_STA_ACTIVE; 205 ret = if_start(iface); 206 } else { 207 if ((iface->flags & IFF_UP) && 208 LINK_STATE_IS_UP(iface->linkstate) && 209 !LIST_EMPTY(&iface->addr_list)) 210 return (0); 211 212 iface->state = IF_STA_DOWN; 213 ret = if_reset(iface); 214 } 215 216 return (ret); 217} 218 219struct ctl_iface * 220if_to_ctl(struct iface *iface) 221{ 222 static struct ctl_iface ictl; 223 struct timeval now; 224 struct adj *adj; 225 226 memcpy(ictl.name, iface->name, sizeof(ictl.name)); 227 ictl.ifindex = iface->ifindex; 228 ictl.state = iface->state; 229 ictl.hello_holdtime = iface->hello_holdtime; 230 ictl.hello_interval = iface->hello_interval; 231 ictl.flags = iface->flags; 232 ictl.type = iface->type; 233 ictl.linkstate = iface->linkstate; 234 ictl.mediatype = iface->media_type; 235 236 gettimeofday(&now, NULL); 237 if (iface->state != IF_STA_DOWN && 238 iface->uptime != 0) { 239 ictl.uptime = now.tv_sec - iface->uptime; 240 } else 241 ictl.uptime = 0; 242 243 ictl.adj_cnt = 0; 244 LIST_FOREACH(adj, &iface->adj_list, iface_entry) 245 ictl.adj_cnt++; 246 247 return (&ictl); 248} 249 250/* misc */ 251int 252if_set_mcast_ttl(int fd, u_int8_t ttl) 253{ 254 if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, 255 (char *)&ttl, sizeof(ttl)) < 0) { 256 log_warn("if_set_mcast_ttl: error setting " 257 "IP_MULTICAST_TTL to %d", ttl); 258 return (-1); 259 } 260 261 return (0); 262} 263 264int 265if_set_tos(int fd, int tos) 266{ 267 if (setsockopt(fd, IPPROTO_IP, IP_TOS, (int *)&tos, sizeof(tos)) < 0) { 268 log_warn("if_set_tos: error setting IP_TOS to 0x%x", tos); 269 return (-1); 270 } 271 272 return (0); 273} 274 275int 276if_set_recvif(int fd, int enable) 277{ 278 if (setsockopt(fd, IPPROTO_IP, IP_RECVIF, &enable, 279 sizeof(enable)) < 0) { 280 log_warn("if_set_recvif: error setting IP_RECVIF"); 281 return (-1); 282 } 283 return (0); 284} 285 286void 287if_set_recvbuf(int fd) 288{ 289 int bsize; 290 291 bsize = 65535; 292 while (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bsize, 293 sizeof(bsize)) == -1) 294 bsize /= 2; 295} 296 297int 298if_set_reuse(int fd, int enable) 299{ 300 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &enable, 301 sizeof(int)) < 0) { 302 log_warn("if_set_reuse: error setting SO_REUSEADDR"); 303 return (-1); 304 } 305 306 return (0); 307} 308 309/* 310 * only one JOIN or DROP per interface and address is allowed so we need 311 * to keep track of what is added and removed. 312 */ 313struct if_group_count { 314 LIST_ENTRY(if_group_count) entry; 315 struct in_addr addr; 316 unsigned int ifindex; 317 int count; 318}; 319 320LIST_HEAD(,if_group_count) ifglist = LIST_HEAD_INITIALIZER(ifglist); 321 322int 323if_join_group(struct iface *iface, struct in_addr *addr) 324{ 325 struct ip_mreq mreq; 326 struct if_group_count *ifg; 327 struct if_addr *if_addr; 328 329 LIST_FOREACH(ifg, &ifglist, entry) 330 if (iface->ifindex == ifg->ifindex && 331 addr->s_addr == ifg->addr.s_addr) 332 break; 333 if (ifg == NULL) { 334 if ((ifg = calloc(1, sizeof(*ifg))) == NULL) 335 fatal("if_join_group"); 336 ifg->addr.s_addr = addr->s_addr; 337 ifg->ifindex = iface->ifindex; 338 LIST_INSERT_HEAD(&ifglist, ifg, entry); 339 } 340 341 if (ifg->count++ != 0) 342 /* already joined */ 343 return (0); 344 345 if_addr = LIST_FIRST(&iface->addr_list); 346 mreq.imr_multiaddr.s_addr = addr->s_addr; 347 mreq.imr_interface.s_addr = if_addr->addr.s_addr; 348 349 if (setsockopt(iface->discovery_fd, IPPROTO_IP, 350 IP_ADD_MEMBERSHIP, (void *)&mreq, sizeof(mreq)) < 0) { 351 log_warn("if_join_group: error IP_ADD_MEMBERSHIP, " 352 "interface %s address %s", iface->name, 353 inet_ntoa(*addr)); 354 LIST_REMOVE(ifg, entry); 355 free(ifg); 356 return (-1); 357 } 358 return (0); 359} 360 361int 362if_leave_group(struct iface *iface, struct in_addr *addr) 363{ 364 struct ip_mreq mreq; 365 struct if_group_count *ifg; 366 struct if_addr *if_addr; 367 368 LIST_FOREACH(ifg, &ifglist, entry) 369 if (iface->ifindex == ifg->ifindex && 370 addr->s_addr == ifg->addr.s_addr) 371 break; 372 373 /* if interface is not found just try to drop membership */ 374 if (ifg) { 375 if (--ifg->count != 0) 376 /* others still joined */ 377 return (0); 378 379 LIST_REMOVE(ifg, entry); 380 free(ifg); 381 } 382 383 if_addr = LIST_FIRST(&iface->addr_list); 384 if (!if_addr) 385 return (0); 386 387 mreq.imr_multiaddr.s_addr = addr->s_addr; 388 mreq.imr_interface.s_addr = if_addr->addr.s_addr; 389 390 if (setsockopt(iface->discovery_fd, IPPROTO_IP, 391 IP_DROP_MEMBERSHIP, (void *)&mreq, sizeof(mreq)) < 0) { 392 log_warn("if_leave_group: error IP_DROP_MEMBERSHIP, " 393 "interface %s address %s", iface->name, 394 inet_ntoa(*addr)); 395 return (-1); 396 } 397 398 return (0); 399} 400 401int 402if_set_mcast(struct iface *iface) 403{ 404 struct if_addr *if_addr; 405 406 if_addr = LIST_FIRST(&iface->addr_list); 407 408 if (setsockopt(iface->discovery_fd, IPPROTO_IP, IP_MULTICAST_IF, 409 &if_addr->addr.s_addr, sizeof(if_addr->addr.s_addr)) < 0) { 410 log_debug("if_set_mcast: error setting " 411 "IP_MULTICAST_IF, interface %s", iface->name); 412 return (-1); 413 } 414 415 return (0); 416} 417 418int 419if_set_mcast_loop(int fd) 420{ 421 u_int8_t loop = 0; 422 423 if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, 424 (char *)&loop, sizeof(loop)) < 0) { 425 log_warn("if_set_mcast_loop: error setting IP_MULTICAST_LOOP"); 426 return (-1); 427 } 428 429 return (0); 430} 431