1*4f4fe40bSflorian /* $OpenBSD: interface.c,v 1.88 2024/08/21 15:18:00 florian Exp $ */ 2204df0f8Sclaudio 3204df0f8Sclaudio /* 4204df0f8Sclaudio * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org> 5367f601bSnorby * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org> 6204df0f8Sclaudio * 7204df0f8Sclaudio * Permission to use, copy, modify, and distribute this software for any 8204df0f8Sclaudio * purpose with or without fee is hereby granted, provided that the above 9204df0f8Sclaudio * copyright notice and this permission notice appear in all copies. 10204df0f8Sclaudio * 11204df0f8Sclaudio * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12204df0f8Sclaudio * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13204df0f8Sclaudio * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14204df0f8Sclaudio * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15204df0f8Sclaudio * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16204df0f8Sclaudio * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17204df0f8Sclaudio * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18204df0f8Sclaudio */ 19204df0f8Sclaudio 20204df0f8Sclaudio #include <sys/types.h> 21204df0f8Sclaudio #include <sys/ioctl.h> 22204df0f8Sclaudio #include <sys/time.h> 23204df0f8Sclaudio #include <sys/socket.h> 24204df0f8Sclaudio #include <netinet/in.h> 25204df0f8Sclaudio #include <arpa/inet.h> 26204df0f8Sclaudio #include <net/if.h> 27d7a91d7eSclaudio #include <net/if_types.h> 28204df0f8Sclaudio #include <ctype.h> 29204df0f8Sclaudio #include <err.h> 30204df0f8Sclaudio #include <stdio.h> 31204df0f8Sclaudio #include <stdlib.h> 32204df0f8Sclaudio #include <unistd.h> 33204df0f8Sclaudio #include <string.h> 34204df0f8Sclaudio #include <event.h> 35204df0f8Sclaudio 36204df0f8Sclaudio #include "ospfd.h" 37204df0f8Sclaudio #include "ospf.h" 38204df0f8Sclaudio #include "log.h" 39204df0f8Sclaudio #include "ospfe.h" 40204df0f8Sclaudio 41204df0f8Sclaudio void if_hello_timer(int, short, void *); 423aede346Sclaudio void if_start_hello_timer(struct iface *); 433aede346Sclaudio void if_stop_hello_timer(struct iface *); 443aede346Sclaudio void if_stop_wait_timer(struct iface *); 45204df0f8Sclaudio void if_wait_timer(int, short, void *); 463aede346Sclaudio void if_start_wait_timer(struct iface *); 473aede346Sclaudio void if_stop_wait_timer(struct iface *); 48204df0f8Sclaudio struct nbr *if_elect(struct nbr *, struct nbr *); 49204df0f8Sclaudio 50204df0f8Sclaudio struct { 51204df0f8Sclaudio int state; 52204df0f8Sclaudio enum iface_event event; 53204df0f8Sclaudio enum iface_action action; 54204df0f8Sclaudio int new_state; 55204df0f8Sclaudio } iface_fsm[] = { 56204df0f8Sclaudio /* current state event that happened action to take resulting state */ 57204df0f8Sclaudio {IF_STA_DOWN, IF_EVT_UP, IF_ACT_STRT, 0}, 58204df0f8Sclaudio {IF_STA_WAITING, IF_EVT_BACKUP_SEEN, IF_ACT_ELECT, 0}, 59204df0f8Sclaudio {IF_STA_WAITING, IF_EVT_WTIMER, IF_ACT_ELECT, 0}, 60bcecdf6fSclaudio {IF_STA_ANY, IF_EVT_WTIMER, IF_ACT_NOTHING, 0}, 611aaf2c2dSclaudio {IF_STA_WAITING, IF_EVT_NBR_CHNG, IF_ACT_NOTHING, 0}, 62204df0f8Sclaudio {IF_STA_MULTI, IF_EVT_NBR_CHNG, IF_ACT_ELECT, 0}, 631aaf2c2dSclaudio {IF_STA_ANY, IF_EVT_NBR_CHNG, IF_ACT_NOTHING, 0}, 64204df0f8Sclaudio {IF_STA_ANY, IF_EVT_DOWN, IF_ACT_RST, IF_STA_DOWN}, 65204df0f8Sclaudio {IF_STA_ANY, IF_EVT_LOOP, IF_ACT_RST, IF_STA_LOOPBACK}, 661aaf2c2dSclaudio {IF_STA_LOOPBACK, IF_EVT_UNLOOP, IF_ACT_NOTHING, IF_STA_DOWN}, 671aaf2c2dSclaudio {-1, IF_EVT_NOTHING, IF_ACT_NOTHING, 0}, 68204df0f8Sclaudio }; 69204df0f8Sclaudio 70ec4d3955Snorby static int vlink_cnt = 0; 71ec4d3955Snorby 72f769f51dSclaudio const char * const if_event_names[] = { 73f769f51dSclaudio "NOTHING", 74f769f51dSclaudio "UP", 75f769f51dSclaudio "WAITTIMER", 76f769f51dSclaudio "BACKUPSEEN", 77f769f51dSclaudio "NEIGHBORCHANGE", 78f769f51dSclaudio "LOOP", 79f769f51dSclaudio "UNLOOP", 80f769f51dSclaudio "DOWN" 81f769f51dSclaudio }; 82f769f51dSclaudio 83204df0f8Sclaudio const char * const if_action_names[] = { 841aaf2c2dSclaudio "NOTHING", 85204df0f8Sclaudio "START", 86204df0f8Sclaudio "ELECT", 87204df0f8Sclaudio "RESET" 88204df0f8Sclaudio }; 89204df0f8Sclaudio 90204df0f8Sclaudio int 91204df0f8Sclaudio if_fsm(struct iface *iface, enum iface_event event) 92204df0f8Sclaudio { 93204df0f8Sclaudio int old_state; 94204df0f8Sclaudio int new_state = 0; 95204df0f8Sclaudio int i, ret = 0; 96204df0f8Sclaudio 97204df0f8Sclaudio old_state = iface->state; 98204df0f8Sclaudio 99204df0f8Sclaudio for (i = 0; iface_fsm[i].state != -1; i++) 100204df0f8Sclaudio if ((iface_fsm[i].state & old_state) && 101204df0f8Sclaudio (iface_fsm[i].event == event)) { 102204df0f8Sclaudio new_state = iface_fsm[i].new_state; 103204df0f8Sclaudio break; 104204df0f8Sclaudio } 105204df0f8Sclaudio 106204df0f8Sclaudio if (iface_fsm[i].state == -1) { 107aeb9d7c6Sclaudio /* event outside of the defined fsm, ignore it. */ 1085d021e83Smsf log_debug("if_fsm: interface %s, " 109204df0f8Sclaudio "event %s not expected in state %s", iface->name, 110cdd38203Sclaudio if_event_names[event], if_state_name(old_state)); 111204df0f8Sclaudio return (0); 112204df0f8Sclaudio } 113204df0f8Sclaudio 114204df0f8Sclaudio switch (iface_fsm[i].action) { 115204df0f8Sclaudio case IF_ACT_STRT: 116204df0f8Sclaudio ret = if_act_start(iface); 117204df0f8Sclaudio break; 118204df0f8Sclaudio case IF_ACT_ELECT: 119204df0f8Sclaudio ret = if_act_elect(iface); 120204df0f8Sclaudio break; 121204df0f8Sclaudio case IF_ACT_RST: 122204df0f8Sclaudio ret = if_act_reset(iface); 123204df0f8Sclaudio break; 1241aaf2c2dSclaudio case IF_ACT_NOTHING: 125204df0f8Sclaudio /* do nothing */ 126204df0f8Sclaudio break; 127204df0f8Sclaudio } 128204df0f8Sclaudio 129204df0f8Sclaudio if (ret) { 1305d021e83Smsf log_debug("if_fsm: error changing state for interface %s, " 131cdd38203Sclaudio "event %s, state %s", iface->name, if_event_names[event], 132204df0f8Sclaudio if_state_name(old_state)); 133204df0f8Sclaudio return (-1); 134204df0f8Sclaudio } 135204df0f8Sclaudio 136204df0f8Sclaudio if (new_state != 0) 137204df0f8Sclaudio iface->state = new_state; 138204df0f8Sclaudio 13906267228Sclaudio if (iface->state != old_state) { 14006267228Sclaudio area_track(iface->area); 14191cc1f69Sclaudio orig_rtr_lsa(iface->area); 14206267228Sclaudio } 14391cc1f69Sclaudio 144f6f3b5e0Sclaudio if (old_state & (IF_STA_MULTI | IF_STA_POINTTOPOINT) && 145f6f3b5e0Sclaudio (iface->state & (IF_STA_MULTI | IF_STA_POINTTOPOINT)) == 0) 146fba2d3d0Sclaudio ospfe_demote_iface(iface, 0); 147f6f3b5e0Sclaudio if ((old_state & (IF_STA_MULTI | IF_STA_POINTTOPOINT)) == 0 && 148f6f3b5e0Sclaudio iface->state & (IF_STA_MULTI | IF_STA_POINTTOPOINT)) 149fba2d3d0Sclaudio ospfe_demote_iface(iface, 1); 150fba2d3d0Sclaudio 1515d021e83Smsf log_debug("if_fsm: event %s resulted in action %s and changing " 152204df0f8Sclaudio "state for interface %s from %s to %s", 153cdd38203Sclaudio if_event_names[event], if_action_names[iface_fsm[i].action], 154204df0f8Sclaudio iface->name, if_state_name(old_state), if_state_name(iface->state)); 155204df0f8Sclaudio 156204df0f8Sclaudio return (ret); 157204df0f8Sclaudio } 158204df0f8Sclaudio 159204df0f8Sclaudio struct iface * 16066dd3991Sclaudio if_new(struct kif *kif, struct kif_addr *ka) 161204df0f8Sclaudio { 162e9fa2173Sclaudio struct iface *iface; 163204df0f8Sclaudio 164204df0f8Sclaudio if ((iface = calloc(1, sizeof(*iface))) == NULL) 165e9fa2173Sclaudio err(1, "if_new: calloc"); 166204df0f8Sclaudio 167204df0f8Sclaudio iface->state = IF_STA_DOWN; 168204df0f8Sclaudio 169204df0f8Sclaudio LIST_INIT(&iface->nbr_list); 170204df0f8Sclaudio TAILQ_INIT(&iface->ls_ack_list); 17176b51f83Sclaudio TAILQ_INIT(&iface->auth_md_list); 172097ed198Sclaudio RB_INIT(&iface->lsa_tree); 17303431b74Snorby 1742ecbebf2Snorby iface->crypt_seq_num = arc4random() & 0x0fffffff; 175204df0f8Sclaudio 176ec4d3955Snorby if (kif == NULL) { 177ec4d3955Snorby iface->type = IF_TYPE_VIRTUALLINK; 178ec4d3955Snorby snprintf(iface->name, sizeof(iface->name), "vlink%d", 179ec4d3955Snorby vlink_cnt++); 180ec4d3955Snorby iface->flags |= IFF_UP; 181ec4d3955Snorby iface->mtu = IP_MSS; 182ec4d3955Snorby return (iface); 183ec4d3955Snorby } 184ec4d3955Snorby 185e9fa2173Sclaudio strlcpy(iface->name, kif->ifname, sizeof(iface->name)); 186204df0f8Sclaudio 187204df0f8Sclaudio /* get type */ 18818cd8ae7Sclaudio if (kif->flags & IFF_POINTOPOINT) 189204df0f8Sclaudio iface->type = IF_TYPE_POINTOPOINT; 19018cd8ae7Sclaudio if (kif->flags & IFF_BROADCAST && 19118cd8ae7Sclaudio kif->flags & IFF_MULTICAST) 192204df0f8Sclaudio iface->type = IF_TYPE_BROADCAST; 19318cd8ae7Sclaudio if (kif->flags & IFF_LOOPBACK) { 19418cd8ae7Sclaudio iface->type = IF_TYPE_POINTOPOINT; 195e79881faSsthen iface->passive = 1; 19618cd8ae7Sclaudio } 197204df0f8Sclaudio 198e9fa2173Sclaudio /* get mtu, index and flags */ 199e9fa2173Sclaudio iface->mtu = kif->mtu; 200e9fa2173Sclaudio iface->ifindex = kif->ifindex; 201358269bbSclaudio iface->rdomain = kif->rdomain; 202e9fa2173Sclaudio iface->flags = kif->flags; 203e9fa2173Sclaudio iface->linkstate = kif->link_state; 20418ffdd94Sstsp iface->if_type = kif->if_type; 2052e87294eSclaudio iface->baudrate = kif->baudrate; 206204df0f8Sclaudio 20766dd3991Sclaudio /* set address, mask and p2p addr */ 20866dd3991Sclaudio iface->addr = ka->addr; 20966dd3991Sclaudio iface->mask = ka->mask; 21018cd8ae7Sclaudio if (kif->flags & IFF_POINTOPOINT) { 21166dd3991Sclaudio iface->dst = ka->dstbrd; 212feb9f399Snorby } 213feb9f399Snorby 214204df0f8Sclaudio return (iface); 215204df0f8Sclaudio } 216204df0f8Sclaudio 21735277385Sclaudio void 218204df0f8Sclaudio if_del(struct iface *iface) 219204df0f8Sclaudio { 220204df0f8Sclaudio struct nbr *nbr = NULL; 221204df0f8Sclaudio 222fba2d3d0Sclaudio /* revert the demotion when the interface is deleted */ 223fba2d3d0Sclaudio if ((iface->state & (IF_STA_MULTI | IF_STA_POINTTOPOINT)) == 0) 224fba2d3d0Sclaudio ospfe_demote_iface(iface, 1); 225fba2d3d0Sclaudio 226204df0f8Sclaudio /* clear lists etc */ 22735277385Sclaudio while ((nbr = LIST_FIRST(&iface->nbr_list)) != NULL) 228204df0f8Sclaudio nbr_del(nbr); 229204df0f8Sclaudio 230a302a2ceSclaudio if (evtimer_pending(&iface->hello_timer, NULL)) 231a302a2ceSclaudio evtimer_del(&iface->hello_timer); 232a302a2ceSclaudio if (evtimer_pending(&iface->wait_timer, NULL)) 233a302a2ceSclaudio evtimer_del(&iface->wait_timer); 234a302a2ceSclaudio if (evtimer_pending(&iface->lsack_tx_timer, NULL)) 235a302a2ceSclaudio evtimer_del(&iface->lsack_tx_timer); 236a302a2ceSclaudio 237204df0f8Sclaudio ls_ack_list_clr(iface); 23876b51f83Sclaudio md_list_clr(&iface->auth_md_list); 23935277385Sclaudio free(iface); 240204df0f8Sclaudio } 241204df0f8Sclaudio 2421d887742Sclaudio void 2431d887742Sclaudio if_init(struct ospfd_conf *xconf, struct iface *iface) 244204df0f8Sclaudio { 2451d887742Sclaudio /* init the dummy local neighbor */ 2461d887742Sclaudio iface->self = nbr_new(ospfe_router_id(), iface, 1); 247204df0f8Sclaudio 2481d887742Sclaudio /* set event handlers for interface */ 2491d887742Sclaudio evtimer_set(&iface->lsack_tx_timer, ls_ack_tx_timer, iface); 2501d887742Sclaudio evtimer_set(&iface->hello_timer, if_hello_timer, iface); 2511d887742Sclaudio evtimer_set(&iface->wait_timer, if_wait_timer, iface); 2521d887742Sclaudio 253feb9f399Snorby iface->fd = xconf->ospf_socket; 254fba2d3d0Sclaudio 255fba2d3d0Sclaudio ospfe_demote_iface(iface, 0); 256204df0f8Sclaudio } 257204df0f8Sclaudio 258204df0f8Sclaudio /* timers */ 259204df0f8Sclaudio void 260204df0f8Sclaudio if_hello_timer(int fd, short event, void *arg) 261204df0f8Sclaudio { 262204df0f8Sclaudio struct iface *iface = arg; 263204df0f8Sclaudio struct timeval tv; 264204df0f8Sclaudio 265204df0f8Sclaudio send_hello(iface); 266204df0f8Sclaudio 267204df0f8Sclaudio /* reschedule hello_timer */ 268204df0f8Sclaudio timerclear(&tv); 2697afdfd2dSdlg if (iface->dead_interval == FAST_RTR_DEAD_TIME) 2707afdfd2dSdlg tv.tv_usec = iface->fast_hello_interval * 1000; 2717afdfd2dSdlg else 272204df0f8Sclaudio tv.tv_sec = iface->hello_interval; 2733aede346Sclaudio if (evtimer_add(&iface->hello_timer, &tv) == -1) 2743aede346Sclaudio fatal("if_hello_timer"); 275204df0f8Sclaudio } 276204df0f8Sclaudio 2773aede346Sclaudio void 278204df0f8Sclaudio if_start_hello_timer(struct iface *iface) 279204df0f8Sclaudio { 280204df0f8Sclaudio struct timeval tv; 281204df0f8Sclaudio 282204df0f8Sclaudio timerclear(&tv); 2833aede346Sclaudio if (evtimer_add(&iface->hello_timer, &tv) == -1) 2843aede346Sclaudio fatal("if_start_hello_timer"); 285204df0f8Sclaudio } 286204df0f8Sclaudio 2873aede346Sclaudio void 288204df0f8Sclaudio if_stop_hello_timer(struct iface *iface) 289204df0f8Sclaudio { 2903aede346Sclaudio if (evtimer_del(&iface->hello_timer) == -1) 2913aede346Sclaudio fatal("if_stop_hello_timer"); 292204df0f8Sclaudio } 293204df0f8Sclaudio 294204df0f8Sclaudio void 295204df0f8Sclaudio if_wait_timer(int fd, short event, void *arg) 296204df0f8Sclaudio { 297204df0f8Sclaudio struct iface *iface = arg; 298204df0f8Sclaudio 299204df0f8Sclaudio if_fsm(iface, IF_EVT_WTIMER); 300204df0f8Sclaudio } 301204df0f8Sclaudio 3023aede346Sclaudio void 303204df0f8Sclaudio if_start_wait_timer(struct iface *iface) 304204df0f8Sclaudio { 305204df0f8Sclaudio struct timeval tv; 306204df0f8Sclaudio 307204df0f8Sclaudio timerclear(&tv); 308204df0f8Sclaudio tv.tv_sec = iface->dead_interval; 3093aede346Sclaudio if (evtimer_add(&iface->wait_timer, &tv) == -1) 3103aede346Sclaudio fatal("if_start_wait_timer"); 311204df0f8Sclaudio } 312204df0f8Sclaudio 3133aede346Sclaudio void 314204df0f8Sclaudio if_stop_wait_timer(struct iface *iface) 315204df0f8Sclaudio { 3163aede346Sclaudio if (evtimer_del(&iface->wait_timer) == -1) 3173aede346Sclaudio fatal("if_stop_wait_timer"); 318204df0f8Sclaudio } 319204df0f8Sclaudio 320204df0f8Sclaudio /* actions */ 321204df0f8Sclaudio int 322204df0f8Sclaudio if_act_start(struct iface *iface) 323204df0f8Sclaudio { 324204df0f8Sclaudio struct in_addr addr; 3253388a643Snorby struct timeval now; 326204df0f8Sclaudio 3273a9b53d2Sbenno if (!(iface->flags & IFF_UP) || 3283a9b53d2Sbenno (!LINK_STATE_IS_UP(iface->linkstate) && 32918ffdd94Sstsp !(iface->if_type == IFT_CARP && 3303a9b53d2Sbenno iface->linkstate == LINK_STATE_DOWN))) 331e9fa2173Sclaudio return (0); 332e9fa2173Sclaudio 33318ffdd94Sstsp if (iface->if_type == IFT_CARP && iface->passive == 0) { 334d7a91d7eSclaudio /* force passive mode on carp interfaces */ 335d7a91d7eSclaudio log_warnx("if_act_start: forcing interface %s to passive", 336d7a91d7eSclaudio iface->name); 337d7a91d7eSclaudio iface->passive = 1; 338d7a91d7eSclaudio } 339d7a91d7eSclaudio 340aa018143Sclaudio gettimeofday(&now, NULL); 341aa018143Sclaudio iface->uptime = now.tv_sec; 342aa018143Sclaudio 343aa018143Sclaudio /* loopback interfaces have a special state and are passive */ 344aa018143Sclaudio if (iface->flags & IFF_LOOPBACK) 345aa018143Sclaudio iface->state = IF_STA_LOOPBACK; 346aa018143Sclaudio 347d7a91d7eSclaudio if (iface->passive) { 348d7a91d7eSclaudio /* for an update of stub network entries */ 349d7a91d7eSclaudio orig_rtr_lsa(iface->area); 350d7a91d7eSclaudio return (0); 351d7a91d7eSclaudio } 352d7a91d7eSclaudio 353204df0f8Sclaudio switch (iface->type) { 354204df0f8Sclaudio case IF_TYPE_POINTOPOINT: 355*4f4fe40bSflorian inet_pton(AF_INET, AllSPFRouters, &addr); 35666dd3991Sclaudio if (if_join_group(iface, &addr)) 357feb9f399Snorby return (-1); 358feb9f399Snorby iface->state = IF_STA_POINTTOPOINT; 359feb9f399Snorby break; 360204df0f8Sclaudio case IF_TYPE_VIRTUALLINK: 361ec4d3955Snorby iface->state = IF_STA_POINTTOPOINT; 362ec4d3955Snorby break; 363ec4d3955Snorby case IF_TYPE_POINTOMULTIPOINT: 3641aaf2c2dSclaudio case IF_TYPE_NBMA: 365204df0f8Sclaudio log_debug("if_act_start: type %s not supported, interface %s", 366204df0f8Sclaudio if_type_name(iface->type), iface->name); 367204df0f8Sclaudio return (-1); 368204df0f8Sclaudio case IF_TYPE_BROADCAST: 369*4f4fe40bSflorian inet_pton(AF_INET, AllSPFRouters, &addr); 37066dd3991Sclaudio if (if_join_group(iface, &addr)) 3711aaf2c2dSclaudio return (-1); 372204df0f8Sclaudio if (iface->priority == 0) { 373204df0f8Sclaudio iface->state = IF_STA_DROTHER; 374204df0f8Sclaudio } else { 375204df0f8Sclaudio iface->state = IF_STA_WAITING; 3763aede346Sclaudio if_start_wait_timer(iface); 377204df0f8Sclaudio } 378204df0f8Sclaudio break; 379204df0f8Sclaudio default: 380204df0f8Sclaudio fatalx("if_act_start: unknown interface type"); 381204df0f8Sclaudio } 382204df0f8Sclaudio 3833aede346Sclaudio /* hello timer needs to be started in any case */ 3843aede346Sclaudio if_start_hello_timer(iface); 385204df0f8Sclaudio return (0); 386204df0f8Sclaudio } 387204df0f8Sclaudio 388204df0f8Sclaudio struct nbr * 389204df0f8Sclaudio if_elect(struct nbr *a, struct nbr *b) 390204df0f8Sclaudio { 391204df0f8Sclaudio if (a->priority > b->priority) 392204df0f8Sclaudio return (a); 393204df0f8Sclaudio if (a->priority < b->priority) 394204df0f8Sclaudio return (b); 395204df0f8Sclaudio if (ntohl(a->id.s_addr) > ntohl(b->id.s_addr)) 396204df0f8Sclaudio return (a); 397204df0f8Sclaudio return (b); 398204df0f8Sclaudio } 399204df0f8Sclaudio 400204df0f8Sclaudio int 401204df0f8Sclaudio if_act_elect(struct iface *iface) 402204df0f8Sclaudio { 403ae00ee2bSclaudio struct in_addr addr; 404204df0f8Sclaudio struct nbr *nbr, *bdr = NULL, *dr = NULL; 405204df0f8Sclaudio int round = 0; 406204df0f8Sclaudio int changed = 0; 40791cc1f69Sclaudio int old_state; 408204df0f8Sclaudio char b1[16], b2[16], b3[16], b4[16]; 409204df0f8Sclaudio 410204df0f8Sclaudio start: 411204df0f8Sclaudio /* elect backup designated router */ 412204df0f8Sclaudio LIST_FOREACH(nbr, &iface->nbr_list, entry) { 413204df0f8Sclaudio if (nbr->priority == 0 || nbr == dr || /* not electable */ 4141d6faa01Sclaudio nbr->state & NBR_STA_PRELIM || /* not available */ 415204df0f8Sclaudio nbr->dr.s_addr == nbr->addr.s_addr) /* don't elect DR */ 416204df0f8Sclaudio continue; 417204df0f8Sclaudio if (bdr != NULL) { 418a3aad27bSclaudio /* 419611e3786Sclaudio * routers announcing themselves as BDR have higher 420a3aad27bSclaudio * precedence over those routers announcing a 421a3aad27bSclaudio * different BDR. 422a3aad27bSclaudio */ 423204df0f8Sclaudio if (nbr->bdr.s_addr == nbr->addr.s_addr) { 424204df0f8Sclaudio if (bdr->bdr.s_addr == bdr->addr.s_addr) 425204df0f8Sclaudio bdr = if_elect(bdr, nbr); 426204df0f8Sclaudio else 427204df0f8Sclaudio bdr = nbr; 428204df0f8Sclaudio } else if (bdr->bdr.s_addr != bdr->addr.s_addr) 429204df0f8Sclaudio bdr = if_elect(bdr, nbr); 430204df0f8Sclaudio } else 431204df0f8Sclaudio bdr = nbr; 432204df0f8Sclaudio } 4338852c891Snorby 434204df0f8Sclaudio /* elect designated router */ 435204df0f8Sclaudio LIST_FOREACH(nbr, &iface->nbr_list, entry) { 4361d6faa01Sclaudio if (nbr->priority == 0 || nbr->state & NBR_STA_PRELIM || 437bdd037daSclaudio (nbr != dr && nbr->dr.s_addr != nbr->addr.s_addr)) 438204df0f8Sclaudio /* only DR may be elected check priority too */ 439204df0f8Sclaudio continue; 440a3aad27bSclaudio if (dr == NULL) 441204df0f8Sclaudio dr = nbr; 442204df0f8Sclaudio else 443bdd037daSclaudio dr = if_elect(dr, nbr); 444204df0f8Sclaudio } 4458852c891Snorby 446204df0f8Sclaudio if (dr == NULL) { 447cc63418dSsthen /* no designated router found use backup DR */ 448204df0f8Sclaudio dr = bdr; 449204df0f8Sclaudio bdr = NULL; 450204df0f8Sclaudio } 451204df0f8Sclaudio 452204df0f8Sclaudio /* 453204df0f8Sclaudio * if we are involved in the election (e.g. new DR or no 454204df0f8Sclaudio * longer BDR) redo the election 455204df0f8Sclaudio */ 456204df0f8Sclaudio if (round == 0 && 457204df0f8Sclaudio ((iface->self == dr && iface->self != iface->dr) || 458204df0f8Sclaudio (iface->self != dr && iface->self == iface->dr) || 459204df0f8Sclaudio (iface->self == bdr && iface->self != iface->bdr) || 460204df0f8Sclaudio (iface->self != bdr && iface->self == iface->bdr))) { 461a3aad27bSclaudio /* 462611e3786Sclaudio * Reset announced DR/BDR to calculated one, so 463a3aad27bSclaudio * that we may get elected in the second round. 464a3aad27bSclaudio * This is needed to drop from a DR to a BDR. 465a3aad27bSclaudio */ 466a3aad27bSclaudio iface->self->dr.s_addr = dr->addr.s_addr; 467a3aad27bSclaudio if (bdr) 46861741bc7Sclaudio iface->self->bdr.s_addr = bdr->addr.s_addr; 469204df0f8Sclaudio round = 1; 470204df0f8Sclaudio goto start; 471204df0f8Sclaudio } 472204df0f8Sclaudio 473204df0f8Sclaudio log_debug("if_act_elect: interface %s old dr %s new dr %s, " 474204df0f8Sclaudio "old bdr %s new bdr %s", iface->name, 475204df0f8Sclaudio iface->dr ? inet_ntop(AF_INET, &iface->dr->addr, b1, sizeof(b1)) : 476204df0f8Sclaudio "none", dr ? inet_ntop(AF_INET, &dr->addr, b2, sizeof(b2)) : "none", 477204df0f8Sclaudio iface->bdr ? inet_ntop(AF_INET, &iface->bdr->addr, b3, sizeof(b3)) : 478204df0f8Sclaudio "none", bdr ? inet_ntop(AF_INET, &bdr->addr, b4, sizeof(b4)) : 479204df0f8Sclaudio "none"); 480204df0f8Sclaudio 481204df0f8Sclaudio /* 482204df0f8Sclaudio * After the second round still DR or BDR change state to DR or BDR, 483204df0f8Sclaudio * etc. 484204df0f8Sclaudio */ 48591cc1f69Sclaudio old_state = iface->state; 486204df0f8Sclaudio if (dr == iface->self) 487204df0f8Sclaudio iface->state = IF_STA_DR; 488204df0f8Sclaudio else if (bdr == iface->self) 489204df0f8Sclaudio iface->state = IF_STA_BACKUP; 490204df0f8Sclaudio else 491204df0f8Sclaudio iface->state = IF_STA_DROTHER; 492204df0f8Sclaudio 493204df0f8Sclaudio /* TODO if iface is NBMA send all non eligible neighbors event Start */ 494204df0f8Sclaudio 495204df0f8Sclaudio /* 496204df0f8Sclaudio * if DR or BDR changed issue a AdjOK? event for all neighbors > 2-Way 497204df0f8Sclaudio */ 498204df0f8Sclaudio if (iface->dr != dr || iface->bdr != bdr) 499204df0f8Sclaudio changed = 1; 500204df0f8Sclaudio 501204df0f8Sclaudio iface->dr = dr; 502204df0f8Sclaudio iface->bdr = bdr; 503204df0f8Sclaudio 50491cc1f69Sclaudio if (changed) { 505*4f4fe40bSflorian inet_pton(AF_INET, AllDRouters, &addr); 506ae00ee2bSclaudio if (old_state & IF_STA_DRORBDR && 507ae00ee2bSclaudio (iface->state & IF_STA_DRORBDR) == 0) { 50866dd3991Sclaudio if (if_leave_group(iface, &addr)) 509ae00ee2bSclaudio return (-1); 510ae00ee2bSclaudio } else if ((old_state & IF_STA_DRORBDR) == 0 && 511ae00ee2bSclaudio iface->state & IF_STA_DRORBDR) { 51266dd3991Sclaudio if (if_join_group(iface, &addr)) 513ae00ee2bSclaudio return (-1); 514ae00ee2bSclaudio } 515ae00ee2bSclaudio 516204df0f8Sclaudio LIST_FOREACH(nbr, &iface->nbr_list, entry) { 517204df0f8Sclaudio if (nbr->state & NBR_STA_BIDIR) 518204df0f8Sclaudio nbr_fsm(nbr, NBR_EVT_ADJ_OK); 519204df0f8Sclaudio } 520ae00ee2bSclaudio 52191cc1f69Sclaudio orig_rtr_lsa(iface->area); 52291cc1f69Sclaudio if (iface->state & IF_STA_DR || old_state & IF_STA_DR) 52391cc1f69Sclaudio orig_net_lsa(iface); 52491cc1f69Sclaudio } 525204df0f8Sclaudio 5263aede346Sclaudio if_start_hello_timer(iface); 527204df0f8Sclaudio return (0); 528204df0f8Sclaudio } 529204df0f8Sclaudio 530204df0f8Sclaudio int 531204df0f8Sclaudio if_act_reset(struct iface *iface) 532204df0f8Sclaudio { 533204df0f8Sclaudio struct nbr *nbr = NULL; 534204df0f8Sclaudio struct in_addr addr; 535204df0f8Sclaudio 536d7a91d7eSclaudio if (iface->passive) { 537d7a91d7eSclaudio /* for an update of stub network entries */ 538d7a91d7eSclaudio orig_rtr_lsa(iface->area); 539d7a91d7eSclaudio return (0); 540d7a91d7eSclaudio } 541d7a91d7eSclaudio 542204df0f8Sclaudio switch (iface->type) { 543204df0f8Sclaudio case IF_TYPE_POINTOPOINT: 544204df0f8Sclaudio case IF_TYPE_BROADCAST: 54545daa23aSclaudio /* try to cleanup */ 546*4f4fe40bSflorian inet_pton(AF_INET, AllSPFRouters, &addr); 54745daa23aSclaudio if_leave_group(iface, &addr); 5484804db9fSclaudio if (iface->state & IF_STA_DRORBDR) { 549*4f4fe40bSflorian inet_pton(AF_INET, AllDRouters, &addr); 55045daa23aSclaudio if_leave_group(iface, &addr); 5514804db9fSclaudio } 552204df0f8Sclaudio break; 553ec4d3955Snorby case IF_TYPE_VIRTUALLINK: 554ec4d3955Snorby /* nothing */ 555ec4d3955Snorby break; 556204df0f8Sclaudio case IF_TYPE_NBMA: 557204df0f8Sclaudio case IF_TYPE_POINTOMULTIPOINT: 558204df0f8Sclaudio log_debug("if_act_reset: type %s not supported, interface %s", 559204df0f8Sclaudio if_type_name(iface->type), iface->name); 560204df0f8Sclaudio return (-1); 561204df0f8Sclaudio default: 562204df0f8Sclaudio fatalx("if_act_reset: unknown interface type"); 563204df0f8Sclaudio } 564204df0f8Sclaudio 565204df0f8Sclaudio LIST_FOREACH(nbr, &iface->nbr_list, entry) { 566204df0f8Sclaudio if (nbr_fsm(nbr, NBR_EVT_KILL_NBR)) { 567204df0f8Sclaudio log_debug("if_act_reset: error killing neighbor %s", 568204df0f8Sclaudio inet_ntoa(nbr->id)); 569204df0f8Sclaudio } 570204df0f8Sclaudio } 571204df0f8Sclaudio 572204df0f8Sclaudio iface->dr = NULL; 573204df0f8Sclaudio iface->bdr = NULL; 574204df0f8Sclaudio 575a7d8ed20Sclaudio ls_ack_list_clr(iface); 5763aede346Sclaudio stop_ls_ack_tx_timer(iface); 5773aede346Sclaudio if_stop_hello_timer(iface); 5783aede346Sclaudio if_stop_wait_timer(iface); 579a7d8ed20Sclaudio 5804d12edf6Sclaudio /* send empty hello to tell everybody that we are going down */ 5814d12edf6Sclaudio send_hello(iface); 5824d12edf6Sclaudio 583204df0f8Sclaudio return (0); 584204df0f8Sclaudio } 585204df0f8Sclaudio 586204df0f8Sclaudio struct ctl_iface * 587204df0f8Sclaudio if_to_ctl(struct iface *iface) 588204df0f8Sclaudio { 589204df0f8Sclaudio static struct ctl_iface ictl; 590204df0f8Sclaudio struct timeval tv, now, res; 591204df0f8Sclaudio struct nbr *nbr; 592204df0f8Sclaudio 593204df0f8Sclaudio memcpy(ictl.name, iface->name, sizeof(ictl.name)); 594204df0f8Sclaudio memcpy(&ictl.addr, &iface->addr, sizeof(ictl.addr)); 595204df0f8Sclaudio memcpy(&ictl.mask, &iface->mask, sizeof(ictl.mask)); 596f12637e5Smsf ictl.rtr_id.s_addr = ospfe_router_id(); 597204df0f8Sclaudio memcpy(&ictl.area, &iface->area->id, sizeof(ictl.area)); 598204df0f8Sclaudio if (iface->dr) { 599204df0f8Sclaudio memcpy(&ictl.dr_id, &iface->dr->id, sizeof(ictl.dr_id)); 600204df0f8Sclaudio memcpy(&ictl.dr_addr, &iface->dr->addr, sizeof(ictl.dr_addr)); 601204df0f8Sclaudio } else { 602204df0f8Sclaudio bzero(&ictl.dr_id, sizeof(ictl.dr_id)); 603204df0f8Sclaudio bzero(&ictl.dr_addr, sizeof(ictl.dr_addr)); 604204df0f8Sclaudio } 605204df0f8Sclaudio if (iface->bdr) { 606204df0f8Sclaudio memcpy(&ictl.bdr_id, &iface->bdr->id, sizeof(ictl.bdr_id)); 607204df0f8Sclaudio memcpy(&ictl.bdr_addr, &iface->bdr->addr, 608204df0f8Sclaudio sizeof(ictl.bdr_addr)); 609204df0f8Sclaudio } else { 610204df0f8Sclaudio bzero(&ictl.bdr_id, sizeof(ictl.bdr_id)); 611204df0f8Sclaudio bzero(&ictl.bdr_addr, sizeof(ictl.bdr_addr)); 612204df0f8Sclaudio } 613204df0f8Sclaudio ictl.ifindex = iface->ifindex; 614204df0f8Sclaudio ictl.state = iface->state; 615204df0f8Sclaudio ictl.mtu = iface->mtu; 616204df0f8Sclaudio ictl.nbr_cnt = 0; 617204df0f8Sclaudio ictl.adj_cnt = 0; 618204df0f8Sclaudio ictl.baudrate = iface->baudrate; 619204df0f8Sclaudio ictl.dead_interval = iface->dead_interval; 6207afdfd2dSdlg ictl.fast_hello_interval = iface->fast_hello_interval; 6211d3a1c7dSnorby ictl.transmit_delay = iface->transmit_delay; 622204df0f8Sclaudio ictl.hello_interval = iface->hello_interval; 623204df0f8Sclaudio ictl.flags = iface->flags; 624204df0f8Sclaudio ictl.metric = iface->metric; 625204df0f8Sclaudio ictl.rxmt_interval = iface->rxmt_interval; 626204df0f8Sclaudio ictl.type = iface->type; 627204df0f8Sclaudio ictl.linkstate = iface->linkstate; 62818ffdd94Sstsp ictl.if_type = iface->if_type; 629204df0f8Sclaudio ictl.priority = iface->priority; 630204df0f8Sclaudio ictl.passive = iface->passive; 631a4aef966Smsf ictl.auth_type = iface->auth_type; 632a4aef966Smsf ictl.auth_keyid = iface->auth_keyid; 633204df0f8Sclaudio 63427198fecSdlg memcpy(ictl.dependon, iface->dependon, sizeof(ictl.dependon)); 63527198fecSdlg ictl.depend_ok = iface->depend_ok; 63627198fecSdlg 637204df0f8Sclaudio gettimeofday(&now, NULL); 638204df0f8Sclaudio if (evtimer_pending(&iface->hello_timer, &tv)) { 639204df0f8Sclaudio timersub(&tv, &now, &res); 6407afdfd2dSdlg ictl.hello_timer = res; 6417afdfd2dSdlg } else { 6427afdfd2dSdlg ictl.hello_timer.tv_sec = -1; 6437afdfd2dSdlg } 644204df0f8Sclaudio 645df38c63bSsthen if (iface->state != IF_STA_DOWN && 646df38c63bSsthen iface->uptime != 0) { 6473388a643Snorby ictl.uptime = now.tv_sec - iface->uptime; 6483388a643Snorby } else 6493388a643Snorby ictl.uptime = 0; 6503388a643Snorby 651204df0f8Sclaudio LIST_FOREACH(nbr, &iface->nbr_list, entry) { 652204df0f8Sclaudio if (nbr == iface->self) 653204df0f8Sclaudio continue; 654204df0f8Sclaudio ictl.nbr_cnt++; 655204df0f8Sclaudio if (nbr->state & NBR_STA_ADJFORM) 656204df0f8Sclaudio ictl.adj_cnt++; 657204df0f8Sclaudio } 658204df0f8Sclaudio 659204df0f8Sclaudio return (&ictl); 660204df0f8Sclaudio } 661204df0f8Sclaudio 662204df0f8Sclaudio /* misc */ 663204df0f8Sclaudio int 664e29a452cSclaudio if_set_recvif(int fd, int enable) 665e29a452cSclaudio { 666e29a452cSclaudio if (setsockopt(fd, IPPROTO_IP, IP_RECVIF, &enable, 667df69c215Sderaadt sizeof(enable)) == -1) { 668e29a452cSclaudio log_warn("if_set_recvif: error setting IP_RECVIF"); 669e29a452cSclaudio return (-1); 670e29a452cSclaudio } 671e29a452cSclaudio return (0); 672e29a452cSclaudio } 673e29a452cSclaudio 674cfb36fa8Snorby void 675b07e4035Sclaudio if_set_sockbuf(int fd) 676cfb36fa8Snorby { 677cfb36fa8Snorby int bsize; 678cfb36fa8Snorby 6798e4254b8Sclaudio bsize = 256 * 1024; 680cfb36fa8Snorby while (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bsize, 681cfb36fa8Snorby sizeof(bsize)) == -1) 682cfb36fa8Snorby bsize /= 2; 683b07e4035Sclaudio 6848e4254b8Sclaudio if (bsize != 256 * 1024) 685b07e4035Sclaudio log_warnx("if_set_sockbuf: recvbuf size only %d", bsize); 686b07e4035Sclaudio 6878e4254b8Sclaudio bsize = 64 * 1024; 688b07e4035Sclaudio while (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &bsize, 689b07e4035Sclaudio sizeof(bsize)) == -1) 690b07e4035Sclaudio bsize /= 2; 691b07e4035Sclaudio 6928e4254b8Sclaudio if (bsize != 64 * 1024) 693b07e4035Sclaudio log_warnx("if_set_sockbuf: sendbuf size only %d", bsize); 694cfb36fa8Snorby } 695cfb36fa8Snorby 69666dd3991Sclaudio /* 69766dd3991Sclaudio * only one JOIN or DROP per interface and address is allowed so we need 69866dd3991Sclaudio * to keep track of what is added and removed. 69966dd3991Sclaudio */ 70066dd3991Sclaudio struct if_group_count { 70166dd3991Sclaudio LIST_ENTRY(if_group_count) entry; 70266dd3991Sclaudio struct in_addr addr; 70366dd3991Sclaudio unsigned int ifindex; 70466dd3991Sclaudio int count; 70566dd3991Sclaudio }; 70666dd3991Sclaudio 70766dd3991Sclaudio LIST_HEAD(,if_group_count) ifglist = LIST_HEAD_INITIALIZER(ifglist); 70866dd3991Sclaudio 709204df0f8Sclaudio int 710204df0f8Sclaudio if_join_group(struct iface *iface, struct in_addr *addr) 711204df0f8Sclaudio { 712b3a8ee7dSclaudio struct ip_mreqn mreq; 71366dd3991Sclaudio struct if_group_count *ifg; 714204df0f8Sclaudio 715204df0f8Sclaudio switch (iface->type) { 716feb9f399Snorby case IF_TYPE_POINTOPOINT: 717204df0f8Sclaudio case IF_TYPE_BROADCAST: 71866dd3991Sclaudio LIST_FOREACH(ifg, &ifglist, entry) 71966dd3991Sclaudio if (iface->ifindex == ifg->ifindex && 72066dd3991Sclaudio addr->s_addr == ifg->addr.s_addr) 72166dd3991Sclaudio break; 72266dd3991Sclaudio if (ifg == NULL) { 72366dd3991Sclaudio if ((ifg = calloc(1, sizeof(*ifg))) == NULL) 72466dd3991Sclaudio fatal("if_join_group"); 72566dd3991Sclaudio ifg->addr.s_addr = addr->s_addr; 72666dd3991Sclaudio ifg->ifindex = iface->ifindex; 72766dd3991Sclaudio LIST_INSERT_HEAD(&ifglist, ifg, entry); 72866dd3991Sclaudio } 72966dd3991Sclaudio 73066dd3991Sclaudio if (ifg->count++ != 0) 73166dd3991Sclaudio /* already joined */ 73266dd3991Sclaudio return (0); 73366dd3991Sclaudio 734263652a1Sclaudio memset(&mreq, 0, sizeof(mreq)); 735204df0f8Sclaudio mreq.imr_multiaddr.s_addr = addr->s_addr; 736b3a8ee7dSclaudio mreq.imr_ifindex = iface->ifindex; 737204df0f8Sclaudio 738204df0f8Sclaudio if (setsockopt(iface->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, 739df69c215Sderaadt (void *)&mreq, sizeof(mreq)) == -1) { 74066dd3991Sclaudio log_warn("if_join_group: error IP_ADD_MEMBERSHIP, " 74166dd3991Sclaudio "interface %s address %s", iface->name, 74266dd3991Sclaudio inet_ntoa(*addr)); 743204df0f8Sclaudio return (-1); 744204df0f8Sclaudio } 745204df0f8Sclaudio break; 746204df0f8Sclaudio case IF_TYPE_POINTOMULTIPOINT: 747204df0f8Sclaudio case IF_TYPE_VIRTUALLINK: 748204df0f8Sclaudio case IF_TYPE_NBMA: 749204df0f8Sclaudio log_debug("if_join_group: type %s not supported, interface %s", 750204df0f8Sclaudio if_type_name(iface->type), iface->name); 751204df0f8Sclaudio return (-1); 752204df0f8Sclaudio default: 753204df0f8Sclaudio fatalx("if_join_group: unknown interface type"); 754204df0f8Sclaudio } 755204df0f8Sclaudio 756204df0f8Sclaudio return (0); 757204df0f8Sclaudio } 758204df0f8Sclaudio 759204df0f8Sclaudio int 760204df0f8Sclaudio if_leave_group(struct iface *iface, struct in_addr *addr) 761204df0f8Sclaudio { 762b3a8ee7dSclaudio struct ip_mreqn mreq; 76366dd3991Sclaudio struct if_group_count *ifg; 764204df0f8Sclaudio 765204df0f8Sclaudio switch (iface->type) { 766feb9f399Snorby case IF_TYPE_POINTOPOINT: 767204df0f8Sclaudio case IF_TYPE_BROADCAST: 76866dd3991Sclaudio LIST_FOREACH(ifg, &ifglist, entry) 76966dd3991Sclaudio if (iface->ifindex == ifg->ifindex && 77066dd3991Sclaudio addr->s_addr == ifg->addr.s_addr) 77166dd3991Sclaudio break; 77266dd3991Sclaudio 77366dd3991Sclaudio /* if interface is not found just try to drop membership */ 77445daa23aSclaudio if (ifg) { 77545daa23aSclaudio if (--ifg->count != 0) 77666dd3991Sclaudio /* others still joined */ 77766dd3991Sclaudio return (0); 77866dd3991Sclaudio 77945daa23aSclaudio LIST_REMOVE(ifg, entry); 78045daa23aSclaudio free(ifg); 78145daa23aSclaudio } 78245daa23aSclaudio 783263652a1Sclaudio memset(&mreq, 0, sizeof(mreq)); 784204df0f8Sclaudio mreq.imr_multiaddr.s_addr = addr->s_addr; 785b3a8ee7dSclaudio mreq.imr_ifindex = iface->ifindex; 786204df0f8Sclaudio 787204df0f8Sclaudio if (setsockopt(iface->fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, 788df69c215Sderaadt (void *)&mreq, sizeof(mreq)) == -1) { 78966dd3991Sclaudio log_warn("if_leave_group: error IP_DROP_MEMBERSHIP, " 79066dd3991Sclaudio "interface %s address %s", iface->name, 79166dd3991Sclaudio inet_ntoa(*addr)); 792204df0f8Sclaudio return (-1); 793204df0f8Sclaudio } 794204df0f8Sclaudio break; 795204df0f8Sclaudio case IF_TYPE_POINTOMULTIPOINT: 796204df0f8Sclaudio case IF_TYPE_VIRTUALLINK: 797204df0f8Sclaudio case IF_TYPE_NBMA: 798204df0f8Sclaudio log_debug("if_leave_group: type %s not supported, interface %s", 799204df0f8Sclaudio if_type_name(iface->type), iface->name); 800204df0f8Sclaudio return (-1); 801204df0f8Sclaudio default: 802204df0f8Sclaudio fatalx("if_leave_group: unknown interface type"); 803204df0f8Sclaudio } 804204df0f8Sclaudio 805204df0f8Sclaudio return (0); 806204df0f8Sclaudio } 807204df0f8Sclaudio 808204df0f8Sclaudio int 809204df0f8Sclaudio if_set_mcast(struct iface *iface) 810204df0f8Sclaudio { 811263652a1Sclaudio struct ip_mreqn mreq; 812263652a1Sclaudio 813204df0f8Sclaudio switch (iface->type) { 814feb9f399Snorby case IF_TYPE_POINTOPOINT: 815204df0f8Sclaudio case IF_TYPE_BROADCAST: 816263652a1Sclaudio memset(&mreq, 0, sizeof(mreq)); 817263652a1Sclaudio mreq.imr_ifindex = iface->ifindex; 818204df0f8Sclaudio if (setsockopt(iface->fd, IPPROTO_IP, IP_MULTICAST_IF, 819263652a1Sclaudio &mreq, sizeof(mreq)) == -1) { 82045daa23aSclaudio log_warn("if_set_mcast: error setting " 821204df0f8Sclaudio "IP_MULTICAST_IF, interface %s", iface->name); 822204df0f8Sclaudio return (-1); 823204df0f8Sclaudio } 824204df0f8Sclaudio break; 825204df0f8Sclaudio case IF_TYPE_POINTOMULTIPOINT: 826204df0f8Sclaudio case IF_TYPE_VIRTUALLINK: 827204df0f8Sclaudio case IF_TYPE_NBMA: 828204df0f8Sclaudio log_debug("if_set_mcast: type %s not supported, interface %s", 829204df0f8Sclaudio if_type_name(iface->type), iface->name); 830204df0f8Sclaudio return (-1); 831204df0f8Sclaudio default: 832204df0f8Sclaudio fatalx("if_set_mcast: unknown interface type"); 833204df0f8Sclaudio } 834204df0f8Sclaudio 835204df0f8Sclaudio return (0); 836204df0f8Sclaudio } 837204df0f8Sclaudio 838204df0f8Sclaudio int 839204df0f8Sclaudio if_set_mcast_loop(int fd) 840204df0f8Sclaudio { 841204df0f8Sclaudio u_int8_t loop = 0; 842204df0f8Sclaudio 843204df0f8Sclaudio if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, 844df69c215Sderaadt (char *)&loop, sizeof(loop)) == -1) { 845204df0f8Sclaudio log_warn("if_set_mcast_loop: error setting IP_MULTICAST_LOOP"); 846204df0f8Sclaudio return (-1); 847204df0f8Sclaudio } 848204df0f8Sclaudio 849204df0f8Sclaudio return (0); 850204df0f8Sclaudio } 85166dd3991Sclaudio 85266dd3991Sclaudio int 85366dd3991Sclaudio if_set_ip_hdrincl(int fd) 85466dd3991Sclaudio { 85566dd3991Sclaudio int hincl = 1; 85666dd3991Sclaudio 857df69c215Sderaadt if (setsockopt(fd, IPPROTO_IP, IP_HDRINCL, &hincl, sizeof(hincl)) == -1) { 85866dd3991Sclaudio log_warn("if_set_ip_hdrincl: error setting IP_HDRINCL"); 85966dd3991Sclaudio return (-1); 86066dd3991Sclaudio } 86166dd3991Sclaudio 86266dd3991Sclaudio return (0); 86366dd3991Sclaudio } 864