1*14d72cd0Spyr /* $OpenBSD: group.c,v 1.3 2009/06/06 07:52:04 pyr Exp $ */ 2978e5cffSnorby 3978e5cffSnorby /* 4978e5cffSnorby * Copyright (c) 2006 Esben Norby <norby@openbsd.org> 5978e5cffSnorby * 6978e5cffSnorby * Permission to use, copy, modify, and distribute this software for any 7978e5cffSnorby * purpose with or without fee is hereby granted, provided that the above 8978e5cffSnorby * copyright notice and this permission notice appear in all copies. 9978e5cffSnorby * 10978e5cffSnorby * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11978e5cffSnorby * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12978e5cffSnorby * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13978e5cffSnorby * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14978e5cffSnorby * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15978e5cffSnorby * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16978e5cffSnorby * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17978e5cffSnorby */ 18978e5cffSnorby 19978e5cffSnorby #include <sys/types.h> 20978e5cffSnorby #include <sys/socket.h> 21978e5cffSnorby #include <netinet/in.h> 22978e5cffSnorby #include <arpa/inet.h> 23978e5cffSnorby #include <sys/time.h> 24978e5cffSnorby #include <sys/socket.h> 25978e5cffSnorby #include <stdlib.h> 26978e5cffSnorby #include <string.h> 27978e5cffSnorby #include <event.h> 28978e5cffSnorby 29978e5cffSnorby #include "igmp.h" 30978e5cffSnorby #include "dvmrpd.h" 31978e5cffSnorby #include "dvmrp.h" 32978e5cffSnorby #include "dvmrpe.h" 33978e5cffSnorby #include "log.h" 34978e5cffSnorby #include "control.h" 35978e5cffSnorby 36978e5cffSnorby void dead_timer(int, short, void *); 37978e5cffSnorby int start_dead_timer(struct group *); 38978e5cffSnorby int start_dead_timer_all(struct group *); 39978e5cffSnorby int stop_dead_timer(struct group *); 40978e5cffSnorby 41978e5cffSnorby void v1_host_timer(int, short, void *); 42978e5cffSnorby int start_v1_host_timer(struct group *); 43978e5cffSnorby int stop_v1_host_timer(struct group *); 44978e5cffSnorby 45978e5cffSnorby void retrans_timer(int, short, void *); 46978e5cffSnorby int start_retrans_timer(struct group *); 47978e5cffSnorby int stop_retrans_timer(struct group *); 48978e5cffSnorby 49978e5cffSnorby extern struct dvmrpd_conf *deconf; 50978e5cffSnorby 51978e5cffSnorby #define MAX_ACTIONS 4 52978e5cffSnorby 53978e5cffSnorby struct { 54978e5cffSnorby int state; 55978e5cffSnorby enum group_event event; 56978e5cffSnorby enum group_action action[MAX_ACTIONS]; 57978e5cffSnorby int new_state; 58978e5cffSnorby } grp_fsm[] = { 59978e5cffSnorby /* current state event that happened action(s) to take resulting state */ 60978e5cffSnorby /* querier fsm */ 6163b350beSmichele {GRP_STA_NO_MEMB_PRSNT, GRP_EVT_V2_REPORT_RCVD, {GRP_ACT_ADD_GROUP, 62978e5cffSnorby GRP_ACT_START_TMR, 63978e5cffSnorby GRP_ACT_END}, GRP_STA_MEMB_PRSNT}, 6463b350beSmichele {GRP_STA_NO_MEMB_PRSNT, GRP_EVT_V1_REPORT_RCVD, {GRP_ACT_ADD_GROUP, 65978e5cffSnorby GRP_ACT_START_TMR, 66978e5cffSnorby GRP_ACT_START_V1_HOST_TMR, 67978e5cffSnorby GRP_ACT_END}, GRP_STA_MEMB_PRSNT}, 68978e5cffSnorby 6963b350beSmichele {GRP_STA_MEMB_PRSNT, GRP_EVT_TMR_EXPIRED, {GRP_ACT_DEL_GROUP, 70978e5cffSnorby GRP_ACT_END}, GRP_STA_NO_MEMB_PRSNT}, 71978e5cffSnorby {GRP_STA_MEMB_PRSNT, GRP_EVT_V2_REPORT_RCVD, {GRP_ACT_START_TMR, 72978e5cffSnorby GRP_ACT_END}, 0}, 73978e5cffSnorby {GRP_STA_MEMB_PRSNT, GRP_EVT_V1_REPORT_RCVD, {GRP_ACT_START_TMR, 74978e5cffSnorby GRP_ACT_START_V1_HOST_TMR, 75978e5cffSnorby GRP_ACT_END}, GRP_STA_V1_MEMB_PRSNT}, 76978e5cffSnorby {GRP_STA_MEMB_PRSNT, GRP_EVT_LEAVE_RCVD, {GRP_ACT_START_TMR_ALL, 77978e5cffSnorby GRP_ACT_START_RETRANS_TMR, 78978e5cffSnorby GRP_ACT_SEND_GRP_QUERY, 79978e5cffSnorby GRP_ACT_END}, GRP_STA_CHECK_MEMB}, 80978e5cffSnorby 81978e5cffSnorby {GRP_STA_CHECK_MEMB, GRP_EVT_V2_REPORT_RCVD, {GRP_ACT_START_TMR, 82978e5cffSnorby GRP_ACT_END}, GRP_STA_MEMB_PRSNT}, 8363b350beSmichele {GRP_STA_CHECK_MEMB, GRP_EVT_TMR_EXPIRED, {GRP_ACT_DEL_GROUP, 84978e5cffSnorby GRP_ACT_CLR_RETRANS_TMR, 85978e5cffSnorby GRP_ACT_END}, GRP_STA_NO_MEMB_PRSNT}, 86978e5cffSnorby {GRP_STA_CHECK_MEMB, GRP_EVT_RETRANS_TMR_EXP,{GRP_ACT_SEND_GRP_QUERY, 87978e5cffSnorby GRP_ACT_START_RETRANS_TMR, 88978e5cffSnorby GRP_ACT_END}, 0}, 89978e5cffSnorby {GRP_STA_CHECK_MEMB, GRP_EVT_V1_REPORT_RCVD, {GRP_ACT_START_TMR, 90978e5cffSnorby GRP_ACT_START_V1_HOST_TMR, 91978e5cffSnorby GRP_ACT_END}, GRP_STA_V1_MEMB_PRSNT}, 92978e5cffSnorby 93978e5cffSnorby {GRP_STA_V1_MEMB_PRSNT, GRP_EVT_V1_HOST_TMR_EXP,{GRP_ACT_NOTHING, 94978e5cffSnorby GRP_ACT_END}, GRP_STA_MEMB_PRSNT}, 95978e5cffSnorby {GRP_STA_V1_MEMB_PRSNT, GRP_EVT_V1_REPORT_RCVD, {GRP_ACT_START_TMR, 96978e5cffSnorby GRP_ACT_START_V1_HOST_TMR, 97978e5cffSnorby GRP_ACT_END}, 0}, 98978e5cffSnorby {GRP_STA_V1_MEMB_PRSNT, GRP_EVT_V2_REPORT_RCVD, {GRP_ACT_START_TMR, 99978e5cffSnorby GRP_ACT_END}, 0}, 10063b350beSmichele {GRP_STA_V1_MEMB_PRSNT, GRP_EVT_TMR_EXPIRED, {GRP_ACT_DEL_GROUP, 101978e5cffSnorby GRP_ACT_END}, GRP_STA_NO_MEMB_PRSNT}, 102978e5cffSnorby 103978e5cffSnorby /* non querier fsm */ 10463b350beSmichele {GRP_STA_NO_MEMB_PRSNT, GRP_EVT_REPORT_RCVD, {GRP_ACT_ADD_GROUP, 105978e5cffSnorby GRP_ACT_START_TMR, 106978e5cffSnorby GRP_ACT_END}, GRP_STA_MEMB_PRSNT}, 107978e5cffSnorby {GRP_STA_MEMB_PRSNT, GRP_EVT_REPORT_RCVD, {GRP_ACT_START_TMR, 108978e5cffSnorby GRP_ACT_END}, 0}, 109978e5cffSnorby {GRP_STA_MEMB_PRSNT, GRP_EVT_QUERY_RCVD, {GRP_ACT_START_TMR_ALL, 110978e5cffSnorby GRP_ACT_END}, GRP_STA_CHECK_MEMB}, 111978e5cffSnorby 112978e5cffSnorby {GRP_STA_CHECK_MEMB, GRP_EVT_REPORT_RCVD, {GRP_ACT_START_TMR, 113978e5cffSnorby GRP_ACT_END}, GRP_STA_MEMB_PRSNT}, 114978e5cffSnorby {-1, GRP_EVT_NOTHING, {GRP_ACT_NOTHING, 115978e5cffSnorby GRP_ACT_END}, 0}, 116978e5cffSnorby }; 117978e5cffSnorby 118978e5cffSnorby const char * const group_action_names[] = { 119978e5cffSnorby "END MARKER", 120978e5cffSnorby "START TIMER", 121978e5cffSnorby "START ALL TIMER", 122978e5cffSnorby "START RETRANSMISSION TIMER", 123978e5cffSnorby "START V1 HOST TIMER", 124978e5cffSnorby "SEND GROUP QUERY", 12563b350beSmichele "ADD GROUP", 12663b350beSmichele "DEL GROUP", 127978e5cffSnorby "CLEAR RETRANSMISSION TIMER", 128978e5cffSnorby "NOTHING" 129978e5cffSnorby }; 130978e5cffSnorby 131978e5cffSnorby static const char * const group_event_names[] = { 132978e5cffSnorby "V2 REPORT RCVD", 133978e5cffSnorby "V1 REPORT RCVD", 134978e5cffSnorby "LEAVE RCVD", 135978e5cffSnorby "TIMER EXPIRED", 136978e5cffSnorby "RETRANS TIMER EXPIRED", 137978e5cffSnorby "V1 HOST TIMER EXPIRED", 138978e5cffSnorby "REPORT RCVD", 139978e5cffSnorby "QUERY RCVD", 140978e5cffSnorby "NOTHING" 141978e5cffSnorby }; 142978e5cffSnorby 143978e5cffSnorby int 144978e5cffSnorby group_fsm(struct group *group, enum group_event event) 145978e5cffSnorby { 146978e5cffSnorby struct mfc mfc; 147978e5cffSnorby int old_state; 148978e5cffSnorby int new_state = 0; 149978e5cffSnorby int i, j, ret = 0; 150978e5cffSnorby 151978e5cffSnorby old_state = group->state; 152978e5cffSnorby 153978e5cffSnorby for (i = 0; grp_fsm[i].state != -1; i++) 154978e5cffSnorby if ((grp_fsm[i].state & old_state) && 155978e5cffSnorby (grp_fsm[i].event == event)) { 156978e5cffSnorby new_state = grp_fsm[i].new_state; 157978e5cffSnorby break; 158978e5cffSnorby } 159978e5cffSnorby 160978e5cffSnorby if (grp_fsm[i].state == -1) { 161978e5cffSnorby /* XXX event outside of the defined fsm, ignore it. */ 162978e5cffSnorby log_debug("group_fsm: group %s, event '%s' not expected in " 163978e5cffSnorby "state '%s'", inet_ntoa(group->addr), 164978e5cffSnorby group_event_name(event), group_state_name(old_state)); 165978e5cffSnorby return (0); 166978e5cffSnorby } 167978e5cffSnorby 168978e5cffSnorby for (j = 0; grp_fsm[i].action[j] != GRP_ACT_END; j++) { 169978e5cffSnorby switch (grp_fsm[i].action[j]) { 170978e5cffSnorby case GRP_ACT_START_TMR: 171978e5cffSnorby ret = start_dead_timer(group); 172978e5cffSnorby break; 173978e5cffSnorby case GRP_ACT_START_TMR_ALL: 174978e5cffSnorby ret = start_dead_timer_all(group); 175978e5cffSnorby break; 176978e5cffSnorby case GRP_ACT_START_RETRANS_TMR: 177978e5cffSnorby ret = start_retrans_timer(group); 178978e5cffSnorby break; 179978e5cffSnorby case GRP_ACT_START_V1_HOST_TMR: 180978e5cffSnorby ret = start_v1_host_timer(group); 181978e5cffSnorby break; 182978e5cffSnorby case GRP_ACT_SEND_GRP_QUERY: 183978e5cffSnorby ret = send_igmp_query(group->iface, group); 184978e5cffSnorby break; 18563b350beSmichele case GRP_ACT_ADD_GROUP: 186978e5cffSnorby mfc.origin.s_addr = 0; 187978e5cffSnorby mfc.group = group->addr; 18863b350beSmichele mfc.ifindex = group->iface->ifindex; 18963b350beSmichele dvmrpe_imsg_compose_rde(IMSG_GROUP_ADD, 0, 0, &mfc, 190978e5cffSnorby sizeof(mfc)); 191978e5cffSnorby break; 19263b350beSmichele case GRP_ACT_DEL_GROUP: 193978e5cffSnorby mfc.origin.s_addr = 0; 194978e5cffSnorby mfc.group = group->addr; 19563b350beSmichele mfc.ifindex = group->iface->ifindex; 19663b350beSmichele dvmrpe_imsg_compose_rde(IMSG_GROUP_DEL, 0, 0, &mfc, 197978e5cffSnorby sizeof(mfc)); 198978e5cffSnorby break; 199978e5cffSnorby case GRP_ACT_CLR_RETRANS_TMR: 200978e5cffSnorby ret = stop_retrans_timer(group); 201978e5cffSnorby break; 202978e5cffSnorby case GRP_ACT_NOTHING: 203978e5cffSnorby case GRP_ACT_END: 204978e5cffSnorby /* do nothing */ 205978e5cffSnorby break; 206978e5cffSnorby } 207978e5cffSnorby 208978e5cffSnorby if (ret) { 209978e5cffSnorby log_debug("group_fsm: error changing state for " 210978e5cffSnorby "group %s, event '%s', state '%s'", 211978e5cffSnorby inet_ntoa(group->addr), group_event_name(event), 212978e5cffSnorby group_state_name(old_state)); 213978e5cffSnorby return (-1); 214978e5cffSnorby } 215978e5cffSnorby } 216978e5cffSnorby 217978e5cffSnorby if (new_state != 0) 218978e5cffSnorby group->state = new_state; 219978e5cffSnorby 220978e5cffSnorby for (j = 0; grp_fsm[i].action[j] != GRP_ACT_END; j++) 221978e5cffSnorby log_debug("group_fsm: event '%s' resulted in action '%s' and " 222978e5cffSnorby "changing state for group %s from '%s' to '%s'", 223978e5cffSnorby group_event_name(event), 224978e5cffSnorby group_action_name(grp_fsm[i].action[j]), 225978e5cffSnorby inet_ntoa(group->addr), group_state_name(old_state), 226978e5cffSnorby group_state_name(group->state)); 227978e5cffSnorby 228978e5cffSnorby return (ret); 229978e5cffSnorby } 230978e5cffSnorby 231978e5cffSnorby /* timers */ 232978e5cffSnorby void 233978e5cffSnorby dead_timer(int fd, short event, void *arg) 234978e5cffSnorby { 235978e5cffSnorby struct group *group = arg; 236978e5cffSnorby 237978e5cffSnorby log_debug("dead_timer: %s", inet_ntoa(group->addr)); 238978e5cffSnorby 239978e5cffSnorby group_fsm(group, GRP_EVT_TMR_EXPIRED); 240978e5cffSnorby } 241978e5cffSnorby 242978e5cffSnorby int 243978e5cffSnorby start_dead_timer(struct group *group) 244978e5cffSnorby { 245978e5cffSnorby struct timeval tv; 246978e5cffSnorby 247978e5cffSnorby log_debug("start_dead_timer: %s", inet_ntoa(group->addr)); 248978e5cffSnorby 249978e5cffSnorby /* Group Membership Interval */ 250978e5cffSnorby timerclear(&tv); 251978e5cffSnorby tv.tv_sec = group->iface->robustness * group->iface->query_interval + 252978e5cffSnorby (group->iface->query_resp_interval / 2); 253978e5cffSnorby 254978e5cffSnorby return (evtimer_add(&group->dead_timer, &tv)); 255978e5cffSnorby } 256978e5cffSnorby 257978e5cffSnorby int 258978e5cffSnorby start_dead_timer_all(struct group *group) 259978e5cffSnorby { 260978e5cffSnorby struct timeval tv; 261978e5cffSnorby 262978e5cffSnorby log_debug("start_dead_timer_all: %s", inet_ntoa(group->addr)); 263978e5cffSnorby 264978e5cffSnorby timerclear(&tv); 265978e5cffSnorby if (group->iface->state == IF_STA_QUERIER) { 266978e5cffSnorby /* querier */ 267978e5cffSnorby tv.tv_sec = group->iface->last_member_query_interval * 268978e5cffSnorby group->iface->last_member_query_cnt; 269978e5cffSnorby } else { 270978e5cffSnorby /* non querier */ 271978e5cffSnorby /* XXX max response time received in packet */ 272978e5cffSnorby tv.tv_sec = group->iface->recv_query_resp_interval * 273978e5cffSnorby group->iface->last_member_query_cnt; 274978e5cffSnorby } 275978e5cffSnorby 276978e5cffSnorby return (evtimer_add(&group->dead_timer, &tv)); 277978e5cffSnorby } 278978e5cffSnorby 279978e5cffSnorby int 280978e5cffSnorby stop_dead_timer(struct group *group) 281978e5cffSnorby { 282978e5cffSnorby log_debug("stop_dead_timer: %s", inet_ntoa(group->addr)); 283978e5cffSnorby 284978e5cffSnorby return (evtimer_del(&group->dead_timer)); 285978e5cffSnorby } 286978e5cffSnorby 287978e5cffSnorby void 288978e5cffSnorby v1_host_timer(int fd, short event, void *arg) 289978e5cffSnorby { 290978e5cffSnorby struct group *group = arg; 291978e5cffSnorby 292978e5cffSnorby log_debug("v1_host_timer: %s", inet_ntoa(group->addr)); 293978e5cffSnorby 294978e5cffSnorby group_fsm(group, GRP_EVT_V1_HOST_TMR_EXP); 295978e5cffSnorby } 296978e5cffSnorby 297978e5cffSnorby int 298978e5cffSnorby start_v1_host_timer(struct group *group) 299978e5cffSnorby { 300978e5cffSnorby struct timeval tv; 301978e5cffSnorby 302978e5cffSnorby log_debug("start_v1_host_timer: %s", inet_ntoa(group->addr)); 303978e5cffSnorby 304978e5cffSnorby /* Group Membership Interval */ 305978e5cffSnorby timerclear(&tv); 306978e5cffSnorby tv.tv_sec = group->iface->robustness * group->iface->query_interval + 307978e5cffSnorby (group->iface->query_resp_interval / 2); 308978e5cffSnorby 309978e5cffSnorby return (evtimer_add(&group->v1_host_timer, &tv)); 310978e5cffSnorby } 311978e5cffSnorby 312978e5cffSnorby int 313978e5cffSnorby stop_v1_host_timer(struct group *group) 314978e5cffSnorby { 315978e5cffSnorby log_debug("stop_v1_host_timer: %s", inet_ntoa(group->addr)); 316978e5cffSnorby 317978e5cffSnorby return (evtimer_del(&group->v1_host_timer)); 318978e5cffSnorby } 319978e5cffSnorby 320978e5cffSnorby void 321978e5cffSnorby retrans_timer(int fd, short event, void *arg) 322978e5cffSnorby { 323978e5cffSnorby struct group *group = arg; 324978e5cffSnorby struct timeval tv; 325978e5cffSnorby 326978e5cffSnorby log_debug("retrans_timer: %s", inet_ntoa(group->addr)); 327978e5cffSnorby 328978e5cffSnorby send_igmp_query(group->iface, group); 329978e5cffSnorby 330978e5cffSnorby /* reschedule retrans_timer */ 331978e5cffSnorby if (group->state == GRP_STA_CHECK_MEMB) { 332978e5cffSnorby timerclear(&tv); 333978e5cffSnorby tv.tv_sec = group->iface->last_member_query_interval; 334978e5cffSnorby evtimer_add(&group->retrans_timer, &tv); 335978e5cffSnorby } 336978e5cffSnorby } 337978e5cffSnorby 338978e5cffSnorby int 339978e5cffSnorby start_retrans_timer(struct group *group) 340978e5cffSnorby { 341978e5cffSnorby struct timeval tv; 342978e5cffSnorby 343978e5cffSnorby log_debug("start_retrans_timer: %s", inet_ntoa(group->addr)); 344978e5cffSnorby 345978e5cffSnorby timerclear(&tv); 346978e5cffSnorby tv.tv_sec = group->iface->last_member_query_interval; 347978e5cffSnorby 348978e5cffSnorby return (evtimer_add(&group->retrans_timer, &tv)); 349978e5cffSnorby } 350978e5cffSnorby 351978e5cffSnorby int 352978e5cffSnorby stop_retrans_timer(struct group *group) 353978e5cffSnorby { 354978e5cffSnorby log_debug("stop_retrans_timer: %s", inet_ntoa(group->addr)); 355978e5cffSnorby 356978e5cffSnorby return (evtimer_del(&group->retrans_timer)); 357978e5cffSnorby } 358978e5cffSnorby 359978e5cffSnorby /* group list */ 360978e5cffSnorby struct group * 361978e5cffSnorby group_list_add(struct iface *iface, u_int32_t group) 362978e5cffSnorby { 363978e5cffSnorby struct group *ge; 364978e5cffSnorby struct timeval now; 365978e5cffSnorby 366978e5cffSnorby /* validate group id */ 367978e5cffSnorby if (!IN_MULTICAST(htonl(group))) 368978e5cffSnorby fatalx("group_list_add: invalid group"); 369978e5cffSnorby 370978e5cffSnorby if ((ge = group_list_find(iface, group)) != NULL) { 371978e5cffSnorby return (ge); 372978e5cffSnorby } 373978e5cffSnorby 374978e5cffSnorby if ((ge = calloc(1, sizeof(*ge))) == NULL) 375978e5cffSnorby fatal("group_list_add"); 376978e5cffSnorby 377978e5cffSnorby ge->addr.s_addr = group; 378978e5cffSnorby ge->state = GRP_STA_NO_MEMB_PRSNT; 379978e5cffSnorby evtimer_set(&ge->dead_timer, dead_timer, ge); 380978e5cffSnorby evtimer_set(&ge->v1_host_timer, v1_host_timer, ge); 381978e5cffSnorby evtimer_set(&ge->retrans_timer, retrans_timer, ge); 382978e5cffSnorby 383978e5cffSnorby gettimeofday(&now, NULL); 384978e5cffSnorby ge->uptime = now.tv_sec; 385978e5cffSnorby 386978e5cffSnorby TAILQ_INSERT_TAIL(&iface->group_list, ge, entry); 387978e5cffSnorby iface->group_cnt++; 388978e5cffSnorby 389978e5cffSnorby ge->iface = iface; 390978e5cffSnorby 391978e5cffSnorby log_debug("group_list_add: interface %s, group %s", iface->name, 392978e5cffSnorby inet_ntoa(ge->addr)); 393978e5cffSnorby 394978e5cffSnorby return (ge); 395978e5cffSnorby } 396978e5cffSnorby 397978e5cffSnorby void 398978e5cffSnorby group_list_remove(struct iface *iface, struct group *group) 399978e5cffSnorby { 400978e5cffSnorby log_debug("group_list_remove: interface %s, group %s", iface->name, 401978e5cffSnorby inet_ntoa(group->addr)); 402978e5cffSnorby 403978e5cffSnorby /* stop timers */ 404978e5cffSnorby stop_dead_timer(group); 405978e5cffSnorby start_v1_host_timer(group); 406978e5cffSnorby stop_retrans_timer(group); 407978e5cffSnorby 408978e5cffSnorby TAILQ_REMOVE(&iface->group_list, group, entry); 409978e5cffSnorby free(group); 410978e5cffSnorby iface->group_cnt--; 411978e5cffSnorby } 412978e5cffSnorby 413978e5cffSnorby struct group * 414978e5cffSnorby group_list_find(struct iface *iface, u_int32_t group) 415978e5cffSnorby { 416978e5cffSnorby struct group *ge = NULL; 417978e5cffSnorby 418978e5cffSnorby /* validate group id */ 419978e5cffSnorby if (!IN_MULTICAST(htonl(group))) 420978e5cffSnorby fatalx("group_list_find: invalid group"); 421978e5cffSnorby 422978e5cffSnorby TAILQ_FOREACH(ge, &iface->group_list, entry) { 423978e5cffSnorby if (ge->addr.s_addr == group) 424978e5cffSnorby return (ge); 425978e5cffSnorby } 426978e5cffSnorby 427978e5cffSnorby return (ge); 428978e5cffSnorby } 429978e5cffSnorby 430978e5cffSnorby void 431978e5cffSnorby group_list_clr(struct iface *iface) 432978e5cffSnorby { 433978e5cffSnorby struct group *ge; 434978e5cffSnorby 435978e5cffSnorby while ((ge = TAILQ_FIRST(&iface->group_list)) != NULL) { 436978e5cffSnorby TAILQ_REMOVE(&iface->group_list, ge, entry); 437978e5cffSnorby free(ge); 438978e5cffSnorby } 439978e5cffSnorby iface->group_cnt = 0; 440978e5cffSnorby } 441978e5cffSnorby 442978e5cffSnorby int 443978e5cffSnorby group_list_empty(struct iface *iface) 444978e5cffSnorby { 445978e5cffSnorby return (TAILQ_EMPTY(&iface->group_list)); 446978e5cffSnorby } 447978e5cffSnorby 448978e5cffSnorby void 449978e5cffSnorby group_list_dump(struct iface *iface, struct ctl_conn *c) 450978e5cffSnorby { 451978e5cffSnorby struct group *ge; 452978e5cffSnorby struct ctl_group *gctl; 453978e5cffSnorby 454978e5cffSnorby TAILQ_FOREACH(ge, &iface->group_list, entry) { 455978e5cffSnorby gctl = group_to_ctl(ge); 456*14d72cd0Spyr imsg_compose_event(&c->iev, IMSG_CTL_SHOW_IGMP, 0, 0, 457*14d72cd0Spyr -1, gctl, sizeof(struct ctl_group)); 458978e5cffSnorby } 459978e5cffSnorby } 460978e5cffSnorby 461978e5cffSnorby /* names */ 462978e5cffSnorby const char * 463978e5cffSnorby group_event_name(int event) 464978e5cffSnorby { 465978e5cffSnorby return (group_event_names[event]); 466978e5cffSnorby } 467978e5cffSnorby 468978e5cffSnorby const char * 469978e5cffSnorby group_action_name(int action) 470978e5cffSnorby { 471978e5cffSnorby return (group_action_names[action]); 472978e5cffSnorby } 473978e5cffSnorby 474978e5cffSnorby struct ctl_group * 475978e5cffSnorby group_to_ctl(struct group *group) 476978e5cffSnorby { 477978e5cffSnorby static struct ctl_group gctl; 478978e5cffSnorby struct timeval tv, now, res; 479978e5cffSnorby 480978e5cffSnorby memcpy(&gctl.addr, &group->addr, sizeof(gctl.addr)); 481978e5cffSnorby 482978e5cffSnorby gctl.state = group->state; 483978e5cffSnorby 484978e5cffSnorby gettimeofday(&now, NULL); 485978e5cffSnorby if (evtimer_pending(&group->dead_timer, &tv)) { 486978e5cffSnorby timersub(&tv, &now, &res); 487978e5cffSnorby gctl.dead_timer = res.tv_sec; 488978e5cffSnorby } else 489978e5cffSnorby gctl.dead_timer = 0; 490978e5cffSnorby 491978e5cffSnorby if (group->state != GRP_STA_NO_MEMB_PRSNT) { 492978e5cffSnorby gctl.uptime = now.tv_sec - group->uptime; 493978e5cffSnorby } else 494978e5cffSnorby gctl.uptime = 0; 495978e5cffSnorby 496978e5cffSnorby return (&gctl); 497978e5cffSnorby } 498