1*2471dd62Sflorian /* $OpenBSD: interface.c,v 1.13 2024/08/21 09:18:47 florian Exp $ */ 2978e5cffSnorby 3978e5cffSnorby /* 4978e5cffSnorby * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org> 5978e5cffSnorby * Copyright (c) 2004, 2005, 2006 Esben Norby <norby@openbsd.org> 6978e5cffSnorby * 7978e5cffSnorby * Permission to use, copy, modify, and distribute this software for any 8978e5cffSnorby * purpose with or without fee is hereby granted, provided that the above 9978e5cffSnorby * copyright notice and this permission notice appear in all copies. 10978e5cffSnorby * 11978e5cffSnorby * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12978e5cffSnorby * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13978e5cffSnorby * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14978e5cffSnorby * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15978e5cffSnorby * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16978e5cffSnorby * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17978e5cffSnorby * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18978e5cffSnorby */ 19978e5cffSnorby 20978e5cffSnorby #include <sys/types.h> 21978e5cffSnorby #include <sys/ioctl.h> 22978e5cffSnorby #include <sys/time.h> 23978e5cffSnorby #include <sys/socket.h> 24978e5cffSnorby 25978e5cffSnorby #include <netinet/in.h> 26978e5cffSnorby #include <netinet/ip_mroute.h> 27978e5cffSnorby #include <arpa/inet.h> 28978e5cffSnorby #include <net/if.h> 29007f2c42Smichele #include <net/if_types.h> 30978e5cffSnorby 31978e5cffSnorby #include <ctype.h> 32978e5cffSnorby #include <err.h> 33978e5cffSnorby #include <stdio.h> 34978e5cffSnorby #include <stdlib.h> 35978e5cffSnorby #include <unistd.h> 36978e5cffSnorby #include <string.h> 37978e5cffSnorby #include <event.h> 38978e5cffSnorby 39978e5cffSnorby #include "igmp.h" 40978e5cffSnorby #include "dvmrpd.h" 41978e5cffSnorby #include "dvmrp.h" 42978e5cffSnorby #include "log.h" 43978e5cffSnorby #include "dvmrpe.h" 44978e5cffSnorby 45a2ed222dSmichele extern struct dvmrpd_conf *conf; 46a2ed222dSmichele 47978e5cffSnorby void if_probe_timer(int, short, void *); 48978e5cffSnorby int if_start_probe_timer(struct iface *); 49978e5cffSnorby int if_stop_probe_timer(struct iface *); 50978e5cffSnorby void if_query_timer(int, short, void *); 51978e5cffSnorby int if_start_query_timer(struct iface *); 52978e5cffSnorby int if_stop_query_timer(struct iface *); 53978e5cffSnorby void if_querier_present_timer(int, short, void *); 54978e5cffSnorby int if_start_querier_present_timer(struct iface *); 55978e5cffSnorby int if_stop_querier_present_timer(struct iface *); 56978e5cffSnorby int if_reset_querier_present_timer(struct iface *); 57978e5cffSnorby int if_act_start(struct iface *); 58978e5cffSnorby int if_act_query_seen(struct iface *); 59978e5cffSnorby int if_act_reset(struct iface *); 60978e5cffSnorby 61978e5cffSnorby struct { 62978e5cffSnorby int state; 63978e5cffSnorby enum iface_event event; 64978e5cffSnorby enum iface_action action; 65978e5cffSnorby int new_state; 66978e5cffSnorby } iface_fsm[] = { 67978e5cffSnorby /* current state event that happened action to take resulting state */ 68978e5cffSnorby {IF_STA_DOWN, IF_EVT_UP, IF_ACT_STRT, 0}, 69978e5cffSnorby {IF_STA_ACTIVE, IF_EVT_QRECVD, IF_ACT_QPRSNT, 0}, 70978e5cffSnorby {IF_STA_NONQUERIER, IF_EVT_QPRSNTTMOUT, IF_ACT_STRT, 0}, 71978e5cffSnorby {IF_STA_ANY, IF_EVT_DOWN, IF_ACT_RST, IF_STA_DOWN}, 72978e5cffSnorby {-1, IF_EVT_NOTHING, IF_ACT_NOTHING, 0}, 73978e5cffSnorby }; 74978e5cffSnorby 75978e5cffSnorby const char * const if_action_names[] = { 76978e5cffSnorby "NOTHING", 77978e5cffSnorby "START", 78978e5cffSnorby "QPRSNT", 79978e5cffSnorby "RESET" 80978e5cffSnorby }; 81978e5cffSnorby 82978e5cffSnorby static const char * const if_event_names[] = { 83978e5cffSnorby "NOTHING", 84978e5cffSnorby "UP", 85978e5cffSnorby "QTMOUT", 86978e5cffSnorby "QRECVD", 87978e5cffSnorby "QPRSNTTMOUT", 88978e5cffSnorby "DOWN" 89978e5cffSnorby }; 90978e5cffSnorby 91978e5cffSnorby int 92978e5cffSnorby if_fsm(struct iface *iface, enum iface_event event) 93978e5cffSnorby { 94978e5cffSnorby int old_state; 95978e5cffSnorby int new_state = 0; 96978e5cffSnorby int i, ret = 0; 97978e5cffSnorby 98978e5cffSnorby old_state = iface->state; 99978e5cffSnorby 100978e5cffSnorby for (i = 0; iface_fsm[i].state != -1; i++) 101978e5cffSnorby if ((iface_fsm[i].state & old_state) && 102978e5cffSnorby (iface_fsm[i].event == event)) { 103978e5cffSnorby new_state = iface_fsm[i].new_state; 104978e5cffSnorby break; 105978e5cffSnorby } 106978e5cffSnorby 107978e5cffSnorby if (iface_fsm[i].state == -1) { 108978e5cffSnorby /* XXX event outside of the defined fsm, ignore it. */ 109978e5cffSnorby log_debug("fsm_if: interface %s, " 110978e5cffSnorby "event '%s' not expected in state '%s'", iface->name, 111978e5cffSnorby if_event_name(event), if_state_name(old_state)); 112978e5cffSnorby return (0); 113978e5cffSnorby } 114978e5cffSnorby 115978e5cffSnorby switch (iface_fsm[i].action) { 116978e5cffSnorby case IF_ACT_STRT: 117978e5cffSnorby ret = if_act_start(iface); 118978e5cffSnorby break; 119978e5cffSnorby case IF_ACT_QPRSNT: 120978e5cffSnorby ret = if_act_query_seen(iface); 121978e5cffSnorby break; 122978e5cffSnorby case IF_ACT_RST: 123978e5cffSnorby ret = if_act_reset(iface); 124978e5cffSnorby break; 125978e5cffSnorby case IF_ACT_NOTHING: 126978e5cffSnorby /* do nothing */ 127978e5cffSnorby break; 128978e5cffSnorby } 129978e5cffSnorby 130978e5cffSnorby if (ret) { 131978e5cffSnorby log_debug("fsm_if: error changing state for interface %s, " 132978e5cffSnorby "event '%s', state '%s'", iface->name, if_event_name(event), 133978e5cffSnorby if_state_name(old_state)); 134978e5cffSnorby return (-1); 135978e5cffSnorby } 136978e5cffSnorby 137978e5cffSnorby if (new_state != 0) 138978e5cffSnorby iface->state = new_state; 139978e5cffSnorby 140978e5cffSnorby log_debug("fsm_if: event '%s' resulted in action '%s' and changing " 141978e5cffSnorby "state for interface %s from '%s' to '%s'", 142978e5cffSnorby if_event_name(event), if_action_name(iface_fsm[i].action), 143978e5cffSnorby iface->name, if_state_name(old_state), if_state_name(iface->state)); 144978e5cffSnorby 145978e5cffSnorby return (ret); 146978e5cffSnorby } 147978e5cffSnorby 148978e5cffSnorby struct iface * 149a2ed222dSmichele if_find_index(u_short ifindex) 150a2ed222dSmichele { 151a2ed222dSmichele struct iface *iface; 152a2ed222dSmichele 153a2ed222dSmichele LIST_FOREACH(iface, &conf->iface_list, entry) { 154a2ed222dSmichele if (iface->ifindex == ifindex) 155a2ed222dSmichele return (iface); 156a2ed222dSmichele } 157a2ed222dSmichele 158a2ed222dSmichele return (NULL); 159a2ed222dSmichele } 160a2ed222dSmichele 161a2ed222dSmichele struct iface * 162978e5cffSnorby if_new(struct kif *kif) 163978e5cffSnorby { 164978e5cffSnorby struct sockaddr_in *sain; 165978e5cffSnorby struct iface *iface; 166978e5cffSnorby struct ifreq *ifr; 167978e5cffSnorby int s; 168978e5cffSnorby 169978e5cffSnorby if ((iface = calloc(1, sizeof(*iface))) == NULL) 170978e5cffSnorby err(1, "if_new: calloc"); 171978e5cffSnorby 172978e5cffSnorby iface->state = IF_STA_DOWN; 173978e5cffSnorby iface->passive = 1; 174978e5cffSnorby 175978e5cffSnorby LIST_INIT(&iface->nbr_list); 176978e5cffSnorby TAILQ_INIT(&iface->group_list); 17763b350beSmichele TAILQ_INIT(&iface->rde_group_list); 178978e5cffSnorby strlcpy(iface->name, kif->ifname, sizeof(iface->name)); 179978e5cffSnorby 180978e5cffSnorby if ((ifr = calloc(1, sizeof(*ifr))) == NULL) 181978e5cffSnorby err(1, "if_new: calloc"); 182978e5cffSnorby 183978e5cffSnorby /* set up ifreq */ 184978e5cffSnorby strlcpy(ifr->ifr_name, kif->ifname, sizeof(ifr->ifr_name)); 185df69c215Sderaadt if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) 186978e5cffSnorby err(1, "if_new: socket"); 187978e5cffSnorby 188978e5cffSnorby /* get type */ 189978e5cffSnorby if ((kif->flags & IFF_POINTOPOINT)) 190978e5cffSnorby iface->type = IF_TYPE_POINTOPOINT; 191978e5cffSnorby if ((kif->flags & IFF_BROADCAST) && 192978e5cffSnorby (kif->flags & IFF_MULTICAST)) 193978e5cffSnorby iface->type = IF_TYPE_BROADCAST; 194978e5cffSnorby 195978e5cffSnorby /* get mtu, index and flags */ 196978e5cffSnorby iface->mtu = kif->mtu; 197978e5cffSnorby iface->ifindex = kif->ifindex; 198978e5cffSnorby iface->flags = kif->flags; 199978e5cffSnorby iface->linkstate = kif->link_state; 2009f69273fSstsp iface->if_type = kif->if_type; 201ff83d30fSclaudio iface->baudrate = kif->baudrate; 202978e5cffSnorby 203978e5cffSnorby /* get address */ 204df69c215Sderaadt if (ioctl(s, SIOCGIFADDR, (caddr_t)ifr) == -1) 205978e5cffSnorby err(1, "if_new: cannot get address"); 206978e5cffSnorby sain = (struct sockaddr_in *) &ifr->ifr_addr; 207978e5cffSnorby iface->addr = sain->sin_addr; 208978e5cffSnorby 209978e5cffSnorby /* get mask */ 210df69c215Sderaadt if (ioctl(s, SIOCGIFNETMASK, (caddr_t)ifr) == -1) 211978e5cffSnorby err(1, "if_new: cannot get mask"); 212978e5cffSnorby sain = (struct sockaddr_in *) &ifr->ifr_addr; 213978e5cffSnorby iface->mask = sain->sin_addr; 214978e5cffSnorby 215978e5cffSnorby /* get p2p dst address */ 216978e5cffSnorby if (iface->type == IF_TYPE_POINTOPOINT) { 217df69c215Sderaadt if (ioctl(s, SIOCGIFDSTADDR, (caddr_t)ifr) == -1) 218978e5cffSnorby err(1, "if_new: cannot get dst addr"); 219978e5cffSnorby sain = (struct sockaddr_in *) &ifr->ifr_addr; 220978e5cffSnorby iface->dst = sain->sin_addr; 221978e5cffSnorby } 222978e5cffSnorby 223978e5cffSnorby free(ifr); 224978e5cffSnorby close(s); 225978e5cffSnorby 226978e5cffSnorby return (iface); 227978e5cffSnorby } 228978e5cffSnorby 229978e5cffSnorby void 230978e5cffSnorby if_init(struct dvmrpd_conf *xconf, struct iface *iface) 231978e5cffSnorby { 232978e5cffSnorby /* set event handlers for interface */ 233978e5cffSnorby evtimer_set(&iface->probe_timer, if_probe_timer, iface); 234978e5cffSnorby evtimer_set(&iface->query_timer, if_query_timer, iface); 235978e5cffSnorby evtimer_set(&iface->querier_present_timer, if_querier_present_timer, 236978e5cffSnorby iface); 237978e5cffSnorby 238978e5cffSnorby TAILQ_INIT(&iface->rr_list); 239978e5cffSnorby 240978e5cffSnorby iface->fd = xconf->dvmrp_socket; 241978e5cffSnorby iface->gen_id = xconf->gen_id; 242978e5cffSnorby } 243978e5cffSnorby 244978e5cffSnorby int 245978e5cffSnorby if_del(struct iface *iface) 246978e5cffSnorby { 247978e5cffSnorby struct nbr *nbr = NULL; 248978e5cffSnorby 249978e5cffSnorby /* clear lists etc */ 250978e5cffSnorby while ((nbr = LIST_FIRST(&iface->nbr_list)) != NULL) { 251978e5cffSnorby LIST_REMOVE(nbr, entry); 252978e5cffSnorby nbr_del(nbr); 253978e5cffSnorby } 254978e5cffSnorby group_list_clr(iface); 255978e5cffSnorby 256978e5cffSnorby return (-1); 257978e5cffSnorby } 258978e5cffSnorby 259978e5cffSnorby int 260978e5cffSnorby if_nbr_list_empty(struct iface *iface) 261978e5cffSnorby { 262978e5cffSnorby return (LIST_EMPTY(&iface->nbr_list)); 263978e5cffSnorby } 264978e5cffSnorby 265978e5cffSnorby /* timers */ 266978e5cffSnorby void 267978e5cffSnorby if_probe_timer(int fd, short event, void *arg) 268978e5cffSnorby { 269978e5cffSnorby struct iface *iface = arg; 270978e5cffSnorby struct timeval tv; 271978e5cffSnorby 272978e5cffSnorby send_probe(iface); 273978e5cffSnorby 274978e5cffSnorby /* reschedule probe_timer */ 275978e5cffSnorby if (!iface->passive) { 276978e5cffSnorby timerclear(&tv); 277978e5cffSnorby tv.tv_sec = iface->probe_interval; 278978e5cffSnorby evtimer_add(&iface->probe_timer, &tv); 279978e5cffSnorby } 280978e5cffSnorby } 281978e5cffSnorby 282978e5cffSnorby int 283978e5cffSnorby if_start_probe_timer(struct iface *iface) 284978e5cffSnorby { 285978e5cffSnorby struct timeval tv; 286978e5cffSnorby 287978e5cffSnorby timerclear(&tv); 288978e5cffSnorby return (evtimer_add(&iface->probe_timer, &tv)); 289978e5cffSnorby } 290978e5cffSnorby 291978e5cffSnorby int 292978e5cffSnorby if_stop_probe_timer(struct iface *iface) 293978e5cffSnorby { 294978e5cffSnorby return (evtimer_del(&iface->probe_timer)); 295978e5cffSnorby } 296978e5cffSnorby 297978e5cffSnorby void 298978e5cffSnorby if_query_timer(int fd, short event, void *arg) 299978e5cffSnorby { 300978e5cffSnorby struct iface *iface = arg; 301978e5cffSnorby struct timeval tv; 302978e5cffSnorby 303978e5cffSnorby /* send a general query */ 304978e5cffSnorby send_igmp_query(iface, NULL); 305978e5cffSnorby 306978e5cffSnorby /* reschedule query_timer */ 307978e5cffSnorby if (!iface->passive) { 308978e5cffSnorby timerclear(&tv); 309978e5cffSnorby if (iface->startup_query_counter != 0) { 310978e5cffSnorby tv.tv_sec = iface->startup_query_interval; 311978e5cffSnorby iface->startup_query_counter--; 312978e5cffSnorby } else 313978e5cffSnorby tv.tv_sec = iface->query_interval; 314978e5cffSnorby 315978e5cffSnorby evtimer_add(&iface->query_timer, &tv); 316978e5cffSnorby } 317978e5cffSnorby } 318978e5cffSnorby 319978e5cffSnorby int 320978e5cffSnorby if_start_query_timer(struct iface *iface) 321978e5cffSnorby { 322978e5cffSnorby struct timeval tv; 323978e5cffSnorby 324978e5cffSnorby timerclear(&tv); 325978e5cffSnorby return (evtimer_add(&iface->query_timer, &tv)); 326978e5cffSnorby } 327978e5cffSnorby 328978e5cffSnorby int 329978e5cffSnorby if_stop_query_timer(struct iface *iface) 330978e5cffSnorby { 331978e5cffSnorby return (evtimer_del(&iface->query_timer)); 332978e5cffSnorby } 333978e5cffSnorby 334978e5cffSnorby void 335978e5cffSnorby if_querier_present_timer(int fd, short event, void *arg) 336978e5cffSnorby { 337978e5cffSnorby struct iface *iface = arg; 338978e5cffSnorby 339978e5cffSnorby if_fsm(iface, IF_EVT_QPRSNTTMOUT); 340978e5cffSnorby } 341978e5cffSnorby 342978e5cffSnorby int 343978e5cffSnorby if_start_querier_present_timer(struct iface *iface) 344978e5cffSnorby { 345978e5cffSnorby struct timeval tv; 346978e5cffSnorby 347978e5cffSnorby /* Other Querier Present Interval */ 348978e5cffSnorby timerclear(&tv); 349978e5cffSnorby tv.tv_sec = iface->robustness * iface->query_interval + 350978e5cffSnorby (iface->query_resp_interval / 2); 351978e5cffSnorby 352978e5cffSnorby return (evtimer_add(&iface->querier_present_timer, &tv)); 353978e5cffSnorby } 354978e5cffSnorby 355978e5cffSnorby int 356978e5cffSnorby if_stop_querier_present_timer(struct iface *iface) 357978e5cffSnorby { 358978e5cffSnorby return (evtimer_del(&iface->querier_present_timer)); 359978e5cffSnorby } 360978e5cffSnorby 361978e5cffSnorby int 362978e5cffSnorby if_reset_querier_present_timer(struct iface *iface) 363978e5cffSnorby { 364978e5cffSnorby struct timeval tv; 365978e5cffSnorby 366978e5cffSnorby /* Other Querier Present Interval */ 367978e5cffSnorby timerclear(&tv); 368978e5cffSnorby tv.tv_sec = iface->robustness * iface->query_interval + 369978e5cffSnorby (iface->query_resp_interval / 2); 370978e5cffSnorby 371978e5cffSnorby return (evtimer_add(&iface->querier_present_timer, &tv)); 372978e5cffSnorby } 373978e5cffSnorby 374978e5cffSnorby /* actions */ 375978e5cffSnorby int 376978e5cffSnorby if_act_start(struct iface *iface) 377978e5cffSnorby { 378978e5cffSnorby struct in_addr addr; 379978e5cffSnorby struct timeval now; 380978e5cffSnorby 381978e5cffSnorby if (iface->passive) { 382978e5cffSnorby log_debug("if_act_start: cannot start passive interface %s", 383978e5cffSnorby iface->name); 384978e5cffSnorby return (-1); 385978e5cffSnorby } 386978e5cffSnorby 3879a2e0324Sclaudio if (!((iface->flags & IFF_UP) && LINK_STATE_IS_UP(iface->linkstate))) { 388978e5cffSnorby log_debug("if_act_start: interface %s link down", 389978e5cffSnorby iface->name); 390978e5cffSnorby return (0); 391978e5cffSnorby } 392978e5cffSnorby 393978e5cffSnorby gettimeofday(&now, NULL); 394978e5cffSnorby iface->uptime = now.tv_sec; 395978e5cffSnorby 396978e5cffSnorby switch (iface->type) { 397978e5cffSnorby case IF_TYPE_POINTOPOINT: 398978e5cffSnorby case IF_TYPE_BROADCAST: 399*2471dd62Sflorian inet_pton(AF_INET, AllSystems, &addr); 400978e5cffSnorby if (if_join_group(iface, &addr)) { 401978e5cffSnorby log_warnx("if_act_start: error joining group %s, " 402978e5cffSnorby "interface %s", inet_ntoa(addr), iface->name); 403978e5cffSnorby return (-1); 404978e5cffSnorby } 405*2471dd62Sflorian inet_pton(AF_INET, AllRouters, &addr); 406978e5cffSnorby if (if_join_group(iface, &addr)) { 407978e5cffSnorby log_warnx("if_act_start: error joining group %s, " 408978e5cffSnorby "interface %s", inet_ntoa(addr), iface->name); 409978e5cffSnorby return (-1); 410978e5cffSnorby } 411*2471dd62Sflorian inet_pton(AF_INET, AllDVMRPRouters, &addr); 412978e5cffSnorby if (if_join_group(iface, &addr)) { 413978e5cffSnorby log_warnx("if_act_start: error joining group %s, " 414978e5cffSnorby "interface %s", inet_ntoa(addr), iface->name); 415978e5cffSnorby return (-1); 416978e5cffSnorby } 417978e5cffSnorby 418978e5cffSnorby iface->state = IF_STA_QUERIER; 419978e5cffSnorby if_start_query_timer(iface); 420978e5cffSnorby if_start_probe_timer(iface); 421978e5cffSnorby iface->startup_query_counter = iface->startup_query_cnt; 422978e5cffSnorby break; 423978e5cffSnorby default: 424978e5cffSnorby fatalx("if_act_start: unknown type"); 425978e5cffSnorby } 426978e5cffSnorby 427978e5cffSnorby return (0); 428978e5cffSnorby } 429978e5cffSnorby 430978e5cffSnorby int 431978e5cffSnorby if_act_query_seen(struct iface *iface) 432978e5cffSnorby { 433978e5cffSnorby log_debug("if_act_query_seen: interface %s", iface->name); 434978e5cffSnorby 435978e5cffSnorby switch (iface->type) { 436978e5cffSnorby case IF_TYPE_POINTOPOINT: 437978e5cffSnorby case IF_TYPE_BROADCAST: 438978e5cffSnorby iface->state = IF_STA_NONQUERIER; 439978e5cffSnorby if_stop_query_timer(iface); 440978e5cffSnorby if_reset_querier_present_timer(iface); 441978e5cffSnorby break; 442978e5cffSnorby default: 443978e5cffSnorby fatalx("if_act_querier_seen: unknown type"); 444978e5cffSnorby } 445978e5cffSnorby 446978e5cffSnorby return (0); 447978e5cffSnorby } 448978e5cffSnorby 449978e5cffSnorby int 450978e5cffSnorby if_act_reset(struct iface *iface) 451978e5cffSnorby { 452978e5cffSnorby struct in_addr addr; 453978e5cffSnorby struct nbr *nbr; 454978e5cffSnorby 455978e5cffSnorby switch (iface->type) { 456978e5cffSnorby case IF_TYPE_POINTOPOINT: 457978e5cffSnorby case IF_TYPE_BROADCAST: 458*2471dd62Sflorian inet_pton(AF_INET, AllSystems, &addr); 459978e5cffSnorby if (if_leave_group(iface, &addr)) { 460978e5cffSnorby log_warnx("if_act_reset: error leaving group %s, " 461978e5cffSnorby "interface %s", inet_ntoa(addr), iface->name); 462978e5cffSnorby return (-1); 463978e5cffSnorby } 464*2471dd62Sflorian inet_pton(AF_INET, AllRouters, &addr); 465978e5cffSnorby if (if_leave_group(iface, &addr)) { 466978e5cffSnorby log_warnx("if_act_reset: error leaving group %s, " 467978e5cffSnorby "interface %s", inet_ntoa(addr), iface->name); 468978e5cffSnorby return (-1); 469978e5cffSnorby } 470*2471dd62Sflorian inet_pton(AF_INET, AllDVMRPRouters, &addr); 471978e5cffSnorby if (if_leave_group(iface, &addr)) { 472978e5cffSnorby log_warnx("if_act_reset: error leaving group %s, " 473978e5cffSnorby "interface %s", inet_ntoa(addr), iface->name); 474978e5cffSnorby return (-1); 475978e5cffSnorby } 476978e5cffSnorby 477978e5cffSnorby iface->state = IF_STA_DOWN; 478978e5cffSnorby iface->gen_id++; 479978e5cffSnorby if_stop_query_timer(iface); 480978e5cffSnorby if_stop_querier_present_timer(iface); 481978e5cffSnorby /* XXX clear nbr list? */ 482978e5cffSnorby break; 483978e5cffSnorby default: 484978e5cffSnorby fatalx("if_act_reset: unknown type"); 485978e5cffSnorby } 486978e5cffSnorby 487978e5cffSnorby LIST_FOREACH(nbr, &iface->nbr_list, entry) { 488978e5cffSnorby if (nbr_fsm(nbr, NBR_EVT_KILL_NBR)) { 489978e5cffSnorby log_debug("if_act_reset: error killing neighbor %s", 490978e5cffSnorby inet_ntoa(nbr->id)); 491978e5cffSnorby } 492978e5cffSnorby } 493978e5cffSnorby 494978e5cffSnorby group_list_clr(iface); /* XXX clear group list? */ 495978e5cffSnorby 496978e5cffSnorby return (0); 497978e5cffSnorby } 498978e5cffSnorby 499978e5cffSnorby const char * 500978e5cffSnorby if_event_name(int event) 501978e5cffSnorby { 502978e5cffSnorby return (if_event_names[event]); 503978e5cffSnorby } 504978e5cffSnorby 505978e5cffSnorby const char * 506978e5cffSnorby if_action_name(int action) 507978e5cffSnorby { 508978e5cffSnorby return (if_action_names[action]); 509978e5cffSnorby } 510978e5cffSnorby 511978e5cffSnorby /* misc */ 512978e5cffSnorby int 513978e5cffSnorby if_set_mcast_ttl(int fd, u_int8_t ttl) 514978e5cffSnorby { 515978e5cffSnorby if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, 516df69c215Sderaadt (char *)&ttl, sizeof(ttl)) == -1) { 517978e5cffSnorby log_warn("if_set_mcast_ttl: error setting " 518978e5cffSnorby "IP_MULTICAST_TTL to %d", ttl); 519978e5cffSnorby return (-1); 520978e5cffSnorby } 521978e5cffSnorby 522978e5cffSnorby return (0); 523978e5cffSnorby } 524978e5cffSnorby 525978e5cffSnorby int 526978e5cffSnorby if_set_tos(int fd, int tos) 527978e5cffSnorby { 528978e5cffSnorby if (setsockopt(fd, IPPROTO_IP, IP_TOS, 529df69c215Sderaadt (int *)&tos, sizeof(tos)) == -1) { 530978e5cffSnorby log_warn("if_set_tos: error setting IP_TOS to 0x%x", tos); 531978e5cffSnorby return (-1); 532978e5cffSnorby } 533978e5cffSnorby 534978e5cffSnorby return (0); 535978e5cffSnorby } 536978e5cffSnorby 537978e5cffSnorby void 538978e5cffSnorby if_set_recvbuf(int fd) 539978e5cffSnorby { 540978e5cffSnorby int bsize; 541978e5cffSnorby 542978e5cffSnorby bsize = 65535; 543978e5cffSnorby while (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bsize, 544978e5cffSnorby sizeof(bsize)) == -1) 545978e5cffSnorby bsize /= 2; 546978e5cffSnorby } 547978e5cffSnorby 548978e5cffSnorby int 549978e5cffSnorby if_join_group(struct iface *iface, struct in_addr *addr) 550978e5cffSnorby { 551978e5cffSnorby struct ip_mreq mreq; 552978e5cffSnorby 553978e5cffSnorby switch (iface->type) { 554978e5cffSnorby case IF_TYPE_POINTOPOINT: 555978e5cffSnorby case IF_TYPE_BROADCAST: 556978e5cffSnorby mreq.imr_multiaddr.s_addr = addr->s_addr; 557978e5cffSnorby mreq.imr_interface.s_addr = iface->addr.s_addr; 558978e5cffSnorby 559978e5cffSnorby if (setsockopt(iface->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, 560df69c215Sderaadt (void *)&mreq, sizeof(mreq)) == -1) { 561978e5cffSnorby log_debug("if_join_group: error IP_ADD_MEMBERSHIP, " 562978e5cffSnorby "interface %s", iface->name); 563978e5cffSnorby return (-1); 564978e5cffSnorby } 565978e5cffSnorby break; 566978e5cffSnorby default: 567978e5cffSnorby fatalx("if_join_group: unknown interface type"); 568978e5cffSnorby } 569978e5cffSnorby 570978e5cffSnorby return (0); 571978e5cffSnorby } 572978e5cffSnorby 573978e5cffSnorby int 574978e5cffSnorby if_leave_group(struct iface *iface, struct in_addr *addr) 575978e5cffSnorby { 576978e5cffSnorby struct ip_mreq mreq; 577978e5cffSnorby 578978e5cffSnorby switch (iface->type) { 579978e5cffSnorby case IF_TYPE_POINTOPOINT: 580978e5cffSnorby case IF_TYPE_BROADCAST: 581978e5cffSnorby mreq.imr_multiaddr.s_addr = addr->s_addr; 582978e5cffSnorby mreq.imr_interface.s_addr = iface->addr.s_addr; 583978e5cffSnorby 584978e5cffSnorby if (setsockopt(iface->fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, 585df69c215Sderaadt (void *)&mreq, sizeof(mreq)) == -1) { 586978e5cffSnorby log_debug("if_leave_group: error IP_DROP_MEMBERSHIP, " 587978e5cffSnorby "interface %s", iface->name); 588978e5cffSnorby return (-1); 589978e5cffSnorby } 590978e5cffSnorby break; 591978e5cffSnorby default: 592978e5cffSnorby fatalx("if_leave_group: unknown interface type"); 593978e5cffSnorby } 594978e5cffSnorby 595978e5cffSnorby return (0); 596978e5cffSnorby } 597978e5cffSnorby 598978e5cffSnorby int 599978e5cffSnorby if_set_mcast(struct iface *iface) 600978e5cffSnorby { 601978e5cffSnorby switch (iface->type) { 602978e5cffSnorby case IF_TYPE_POINTOPOINT: 603978e5cffSnorby case IF_TYPE_BROADCAST: 604978e5cffSnorby if (setsockopt(iface->fd, IPPROTO_IP, IP_MULTICAST_IF, 605978e5cffSnorby (char *)&iface->addr.s_addr, 606df69c215Sderaadt sizeof(iface->addr.s_addr)) == -1) { 607978e5cffSnorby log_debug("if_set_mcast: error setting " 608978e5cffSnorby "IP_MULTICAST_IF, interface %s", iface->name); 609978e5cffSnorby return (-1); 610978e5cffSnorby } 611978e5cffSnorby break; 612978e5cffSnorby default: 613978e5cffSnorby fatalx("if_set_mcast: unknown interface type"); 614978e5cffSnorby } 615978e5cffSnorby 616978e5cffSnorby return (0); 617978e5cffSnorby } 618978e5cffSnorby 619978e5cffSnorby int 620978e5cffSnorby if_set_mcast_loop(int fd) 621978e5cffSnorby { 622978e5cffSnorby u_int8_t loop = 0; 623978e5cffSnorby 624978e5cffSnorby if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, 625df69c215Sderaadt (char *)&loop, sizeof(loop)) == -1) { 626978e5cffSnorby log_warn("if_set_mcast_loop: error setting IP_MULTICAST_LOOP"); 627978e5cffSnorby return (-1); 628978e5cffSnorby } 629978e5cffSnorby 630978e5cffSnorby return (0); 631978e5cffSnorby } 632978e5cffSnorby 633978e5cffSnorby struct ctl_iface * 634978e5cffSnorby if_to_ctl(struct iface *iface) 635978e5cffSnorby { 636978e5cffSnorby static struct ctl_iface ictl; 637978e5cffSnorby struct timeval tv, now, res; 638978e5cffSnorby 639978e5cffSnorby memcpy(ictl.name, iface->name, sizeof(ictl.name)); 640978e5cffSnorby memcpy(&ictl.addr, &iface->addr, sizeof(ictl.addr)); 641978e5cffSnorby memcpy(&ictl.mask, &iface->mask, sizeof(ictl.mask)); 642978e5cffSnorby memcpy(&ictl.querier, &iface->querier, sizeof(ictl.querier)); 643978e5cffSnorby 644978e5cffSnorby ictl.ifindex = iface->ifindex; 645978e5cffSnorby ictl.state = iface->state; 646978e5cffSnorby ictl.mtu = iface->mtu; 6478464310fStodd ictl.nbr_cnt = iface->nbr_cnt; 648d0cc1e6eSnorby ictl.adj_cnt = iface->adj_cnt; 649978e5cffSnorby 650978e5cffSnorby ictl.gen_id = iface->gen_id; 651978e5cffSnorby ictl.group_cnt = iface->group_cnt; 652978e5cffSnorby ictl.probe_interval = iface->probe_interval; 653978e5cffSnorby ictl.query_interval = iface->query_interval; 654978e5cffSnorby ictl.query_resp_interval = iface->query_resp_interval; 655978e5cffSnorby ictl.recv_query_resp_interval = iface->recv_query_resp_interval; 656978e5cffSnorby ictl.group_member_interval = iface->group_member_interval; 657978e5cffSnorby ictl.querier_present_interval = iface->querier_present_interval; 658978e5cffSnorby ictl.startup_query_interval = iface->startup_query_interval; 659978e5cffSnorby ictl.startup_query_cnt = iface->startup_query_cnt; 660978e5cffSnorby ictl.last_member_query_interval = iface->last_member_query_interval; 661978e5cffSnorby ictl.last_member_query_cnt = iface->last_member_query_cnt; 662978e5cffSnorby ictl.last_member_query_time = iface->last_member_query_time; 663978e5cffSnorby ictl.v1_querier_present_tmout = iface->v1_querier_present_tmout; 664978e5cffSnorby ictl.v1_host_present_interval = iface->v1_host_present_interval; 665978e5cffSnorby ictl.dead_interval = iface->dead_interval; 666978e5cffSnorby 667978e5cffSnorby ictl.baudrate = iface->baudrate; 668978e5cffSnorby ictl.flags = iface->flags; 669978e5cffSnorby ictl.metric = iface->metric; 670978e5cffSnorby ictl.type = iface->type; 671978e5cffSnorby ictl.robustness = iface->robustness; 672978e5cffSnorby ictl.linkstate = iface->linkstate; 673978e5cffSnorby ictl.passive = iface->passive; 674978e5cffSnorby ictl.igmp_version = iface->igmp_version; 6759f69273fSstsp ictl.if_type = iface->if_type; 676978e5cffSnorby 677978e5cffSnorby gettimeofday(&now, NULL); 678978e5cffSnorby if (evtimer_pending(&iface->probe_timer, &tv)) { 679978e5cffSnorby timersub(&tv, &now, &res); 680978e5cffSnorby ictl.probe_timer = res.tv_sec; 681978e5cffSnorby } else 682978e5cffSnorby ictl.probe_timer = -1; 683978e5cffSnorby 684978e5cffSnorby if (evtimer_pending(&iface->query_timer, &tv)) { 685978e5cffSnorby timersub(&tv, &now, &res); 686978e5cffSnorby ictl.query_timer = res.tv_sec; 687978e5cffSnorby } else 688978e5cffSnorby ictl.query_timer = -1; 689978e5cffSnorby 690978e5cffSnorby if (evtimer_pending(&iface->querier_present_timer, &tv)) { 691978e5cffSnorby timersub(&tv, &now, &res); 692978e5cffSnorby ictl.querier_present_timer = res.tv_sec; 693978e5cffSnorby } else 694978e5cffSnorby ictl.querier_present_timer = -1; 695978e5cffSnorby 696978e5cffSnorby if (iface->state != IF_STA_DOWN) { 697978e5cffSnorby ictl.uptime = now.tv_sec - iface->uptime; 698978e5cffSnorby } else 699978e5cffSnorby ictl.uptime = 0; 700978e5cffSnorby 701978e5cffSnorby return (&ictl); 702978e5cffSnorby } 703