interface.c revision 1.37
1/* $OpenBSD: interface.c,v 1.37 2016/05/23 18:28:22 renato 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 44void if_hello_timer(int, short, void *); 45void if_start_hello_timer(struct iface *); 46void if_stop_hello_timer(struct iface *); 47 48struct iface * 49if_new(struct kif *kif) 50{ 51 struct iface *iface; 52 53 if ((iface = calloc(1, sizeof(*iface))) == NULL) 54 fatal("if_new: calloc"); 55 56 iface->state = IF_STA_DOWN; 57 58 LIST_INIT(&iface->addr_list); 59 LIST_INIT(&iface->adj_list); 60 61 strlcpy(iface->name, kif->ifname, sizeof(iface->name)); 62 63 /* get type */ 64 if (kif->flags & IFF_POINTOPOINT) 65 iface->type = IF_TYPE_POINTOPOINT; 66 if (kif->flags & IFF_BROADCAST && 67 kif->flags & IFF_MULTICAST) 68 iface->type = IF_TYPE_BROADCAST; 69 70 /* get index and flags */ 71 iface->ifindex = kif->ifindex; 72 iface->flags = kif->flags; 73 iface->linkstate = kif->link_state; 74 iface->if_type = kif->if_type; 75 76 return (iface); 77} 78 79void 80if_del(struct iface *iface) 81{ 82 struct if_addr *if_addr; 83 84 if (iface->state == IF_STA_ACTIVE) 85 if_reset(iface); 86 87 log_debug("%s: interface %s", __func__, iface->name); 88 89 while ((if_addr = LIST_FIRST(&iface->addr_list)) != NULL) { 90 LIST_REMOVE(if_addr, entry); 91 free(if_addr); 92 } 93 94 free(iface); 95} 96 97void 98if_init(struct iface *iface) 99{ 100 /* set event handlers for interface */ 101 evtimer_set(&iface->hello_timer, if_hello_timer, iface); 102} 103 104struct iface * 105if_lookup(struct ldpd_conf *xconf, unsigned short ifindex) 106{ 107 struct iface *iface; 108 109 LIST_FOREACH(iface, &xconf->iface_list, entry) 110 if (iface->ifindex == ifindex) 111 return (iface); 112 113 return (NULL); 114} 115 116struct if_addr * 117if_addr_new(struct kaddr *ka) 118{ 119 struct if_addr *if_addr; 120 121 if ((if_addr = calloc(1, sizeof(*if_addr))) == NULL) 122 fatal(__func__); 123 124 if_addr->addr = ka->addr; 125 if_addr->mask = ka->mask; 126 if_addr->dstbrd = ka->dstbrd; 127 128 return (if_addr); 129} 130 131struct if_addr * 132if_addr_lookup(struct if_addr_head *addr_list, struct kaddr *ka) 133{ 134 struct if_addr *if_addr; 135 136 LIST_FOREACH(if_addr, addr_list, entry) 137 if (if_addr->addr.s_addr == ka->addr.s_addr && 138 if_addr->mask.s_addr == ka->mask.s_addr && 139 if_addr->dstbrd.s_addr == ka->dstbrd.s_addr) 140 return (if_addr); 141 142 return (NULL); 143} 144 145void 146if_addr_add(struct kaddr *ka) 147{ 148 struct iface *iface; 149 struct if_addr *if_addr; 150 struct nbr *nbr; 151 152 if (if_addr_lookup(&global.addr_list, ka) == NULL) { 153 if_addr = if_addr_new(ka); 154 155 LIST_INSERT_HEAD(&global.addr_list, if_addr, entry); 156 RB_FOREACH(nbr, nbr_id_head, &nbrs_by_id) { 157 if (nbr->state != NBR_STA_OPER) 158 continue; 159 160 send_address(nbr, if_addr, 0); 161 } 162 } 163 164 iface = if_lookup(leconf, ka->ifindex); 165 if (iface && 166 if_addr_lookup(&iface->addr_list, ka) == NULL) { 167 if_addr = if_addr_new(ka); 168 LIST_INSERT_HEAD(&iface->addr_list, if_addr, entry); 169 if_update(iface); 170 } 171} 172 173void 174if_addr_del(struct kaddr *ka) 175{ 176 struct iface *iface; 177 struct if_addr *if_addr; 178 struct nbr *nbr; 179 180 iface = if_lookup(leconf, ka->ifindex); 181 if (iface) { 182 if_addr = if_addr_lookup(&iface->addr_list, ka); 183 if (if_addr) { 184 LIST_REMOVE(if_addr, entry); 185 free(if_addr); 186 if_update(iface); 187 } 188 } 189 190 if_addr = if_addr_lookup(&global.addr_list, ka); 191 if (if_addr) { 192 RB_FOREACH(nbr, nbr_id_head, &nbrs_by_id) { 193 if (nbr->state != NBR_STA_OPER) 194 continue; 195 send_address(nbr, if_addr, 1); 196 } 197 LIST_REMOVE(if_addr, entry); 198 free(if_addr); 199 } 200} 201 202int 203if_start(struct iface *iface) 204{ 205 struct in_addr addr; 206 struct timeval now; 207 208 log_debug("%s: %s", __func__, iface->name); 209 210 gettimeofday(&now, NULL); 211 iface->uptime = now.tv_sec; 212 213 inet_aton(AllRouters, &addr); 214 if (if_join_group(iface, &addr)) 215 return (-1); 216 217 send_hello(HELLO_LINK, iface, NULL); 218 if_start_hello_timer(iface); 219 return (0); 220} 221 222int 223if_reset(struct iface *iface) 224{ 225 struct in_addr addr; 226 struct adj *adj; 227 228 log_debug("%s: %s", __func__, iface->name); 229 230 while ((adj = LIST_FIRST(&iface->adj_list)) != NULL) 231 adj_del(adj); 232 233 if_stop_hello_timer(iface); 234 235 /* try to cleanup */ 236 inet_aton(AllRouters, &addr); 237 if_leave_group(iface, &addr); 238 239 return (0); 240} 241 242int 243if_update(struct iface *iface) 244{ 245 int ret; 246 247 if (iface->state == IF_STA_DOWN) { 248 if (!(iface->flags & IFF_UP) || 249 !LINK_STATE_IS_UP(iface->linkstate) || 250 LIST_EMPTY(&iface->addr_list)) 251 return (0); 252 253 iface->state = IF_STA_ACTIVE; 254 ret = if_start(iface); 255 } else { 256 if ((iface->flags & IFF_UP) && 257 LINK_STATE_IS_UP(iface->linkstate) && 258 !LIST_EMPTY(&iface->addr_list)) 259 return (0); 260 261 iface->state = IF_STA_DOWN; 262 ret = if_reset(iface); 263 } 264 265 return (ret); 266} 267 268/* timers */ 269/* ARGSUSED */ 270void 271if_hello_timer(int fd, short event, void *arg) 272{ 273 struct iface *iface = arg; 274 275 send_hello(HELLO_LINK, iface, NULL); 276 if_start_hello_timer(iface); 277} 278 279void 280if_start_hello_timer(struct iface *iface) 281{ 282 struct timeval tv; 283 284 timerclear(&tv); 285 tv.tv_sec = iface->hello_interval; 286 if (evtimer_add(&iface->hello_timer, &tv) == -1) 287 fatal(__func__); 288} 289 290void 291if_stop_hello_timer(struct iface *iface) 292{ 293 if (evtimer_pending(&iface->hello_timer, NULL) && 294 evtimer_del(&iface->hello_timer) == -1) 295 fatal(__func__); 296} 297 298struct ctl_iface * 299if_to_ctl(struct iface *iface) 300{ 301 static struct ctl_iface ictl; 302 struct timeval now; 303 struct adj *adj; 304 305 memcpy(ictl.name, iface->name, sizeof(ictl.name)); 306 ictl.ifindex = iface->ifindex; 307 ictl.state = iface->state; 308 ictl.hello_holdtime = iface->hello_holdtime; 309 ictl.hello_interval = iface->hello_interval; 310 ictl.flags = iface->flags; 311 ictl.type = iface->type; 312 ictl.linkstate = iface->linkstate; 313 ictl.if_type = iface->if_type; 314 315 gettimeofday(&now, NULL); 316 if (iface->state != IF_STA_DOWN && 317 iface->uptime != 0) { 318 ictl.uptime = now.tv_sec - iface->uptime; 319 } else 320 ictl.uptime = 0; 321 322 ictl.adj_cnt = 0; 323 LIST_FOREACH(adj, &iface->adj_list, iface_entry) 324 ictl.adj_cnt++; 325 326 return (&ictl); 327} 328 329/* misc */ 330int 331if_join_group(struct iface *iface, struct in_addr *addr) 332{ 333 struct ip_mreq mreq; 334 struct if_addr *if_addr; 335 336 log_debug("%s: interface %s addr %s", __func__, iface->name, 337 inet_ntoa(*addr)); 338 339 if_addr = LIST_FIRST(&iface->addr_list); 340 mreq.imr_multiaddr = *addr; 341 mreq.imr_interface = if_addr->addr; 342 343 if (setsockopt(global.ldp_disc_socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, 344 (void *)&mreq, sizeof(mreq)) < 0) { 345 log_warn("%s: error IP_ADD_MEMBERSHIP, interface %s address %s", 346 __func__, iface->name, inet_ntoa(*addr)); 347 return (-1); 348 } 349 return (0); 350} 351 352int 353if_leave_group(struct iface *iface, struct in_addr *addr) 354{ 355 struct ip_mreq mreq; 356 struct if_addr *if_addr; 357 358 log_debug("%s: interface %s addr %s", __func__, iface->name, 359 inet_ntoa(*addr)); 360 361 if_addr = LIST_FIRST(&iface->addr_list); 362 if (!if_addr) 363 return (0); 364 365 mreq.imr_multiaddr = *addr; 366 mreq.imr_interface = if_addr->addr; 367 368 if (setsockopt(global.ldp_disc_socket, IPPROTO_IP, IP_DROP_MEMBERSHIP, 369 (void *)&mreq, sizeof(mreq)) < 0) { 370 log_warn("%s: error IP_DROP_MEMBERSHIP, interface %s " 371 "address %s", __func__, iface->name, inet_ntoa(*addr)); 372 return (-1); 373 } 374 375 return (0); 376} 377