104 #if LWIP_IPV4 && LWIP_IGMP 118 static struct igmp_group *igmp_lookup_group(
struct netif *ifp,
const ip4_addr_t *addr);
119 static err_t igmp_remove_group(
struct netif*
netif,
struct igmp_group *group);
120 static void igmp_timeout(
struct netif *
netif,
struct igmp_group *group);
121 static void igmp_start_timer(
struct igmp_group *group, u8_t max_time);
122 static void igmp_delaying_member(
struct igmp_group *group, u8_t maxresp);
123 static err_t igmp_ip_output_if(
struct pbuf *p,
const ip4_addr_t *src,
const ip4_addr_t *dest,
struct netif *
netif);
124 static void igmp_send(
struct netif *
netif,
struct igmp_group *group, u8_t type);
126 static ip4_addr_t allsystems;
127 static ip4_addr_t allrouters;
137 IP4_ADDR(&allsystems, 224, 0, 0, 1);
138 IP4_ADDR(&allrouters, 224, 0, 0, 2);
149 struct igmp_group* group;
153 group = igmp_lookup_group(netif, &allsystems);
156 group->group_state = IGMP_GROUP_IDLE_MEMBER;
160 if (netif->igmp_mac_filter != NULL) {
162 ip4_addr_debug_print_val(
IGMP_DEBUG, allsystems);
179 igmp_stop(
struct netif *netif)
181 struct igmp_group *group = netif_igmp_data(netif);
183 netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_IGMP, NULL);
185 while (group != NULL) {
186 struct igmp_group *next = group->next;
189 if (netif->igmp_mac_filter != NULL) {
191 ip4_addr_debug_print(
IGMP_DEBUG, &group->group_address);
211 igmp_report_groups(
struct netif *netif)
213 struct igmp_group *group = netif_igmp_data(netif);
222 while (group != NULL) {
223 igmp_delaying_member(group, IGMP_JOIN_DELAYING_MEMBER_TMR);
237 igmp_lookfor_group(
struct netif *ifp,
const ip4_addr_t *addr)
239 struct igmp_group *group = netif_igmp_data(ifp);
241 while (group != NULL) {
242 if (ip4_addr_cmp(&(group->group_address), addr)) {
262 static struct igmp_group *
263 igmp_lookup_group(
struct netif *ifp,
const ip4_addr_t *addr)
265 struct igmp_group *group;
266 struct igmp_group *list_head = netif_igmp_data(ifp);
269 group = igmp_lookfor_group(ifp, addr);
276 group = (
struct igmp_group *)
memp_malloc(MEMP_IGMP_GROUP);
278 ip4_addr_set(&(group->group_address), addr);
280 group->group_state = IGMP_GROUP_NON_MEMBER;
281 group->last_reporter_flag = 0;
285 if (list_head == NULL) {
287 LWIP_ASSERT(
"igmp_lookup_group: first group must be allsystems",
288 (ip4_addr_cmp(addr, &allsystems) != 0));
290 netif_set_client_data(ifp, LWIP_NETIF_CLIENT_DATA_INDEX_IGMP, group);
293 LWIP_ASSERT(
"igmp_lookup_group: all except first group must not be allsystems",
294 (ip4_addr_cmp(addr, &allsystems) == 0));
295 group->next = list_head->next;
296 list_head->next = group;
300 LWIP_DEBUGF(
IGMP_DEBUG, (
"igmp_lookup_group: %sallocated a new group with address ", (group?
"":
"impossible to ")));
314 igmp_remove_group(
struct netif* netif,
struct igmp_group *group)
317 struct igmp_group *tmp_group;
320 for (tmp_group = netif_igmp_data(netif); tmp_group != NULL; tmp_group = tmp_group->next) {
321 if (tmp_group->next == group) {
322 tmp_group->next = group->next;
327 if (tmp_group == NULL) {
342 igmp_input(
struct pbuf *p,
struct netif *inp,
const ip4_addr_t *dest)
345 struct igmp_group* group;
346 struct igmp_group* groupref;
348 IGMP_STATS_INC(igmp.recv);
351 if (p->
len < IGMP_MINLEN) {
353 IGMP_STATS_INC(igmp.lenerr);
359 ip4_addr_debug_print(
IGMP_DEBUG, &(ip4_current_header()->src));
361 ip4_addr_debug_print(
IGMP_DEBUG, &(ip4_current_header()->dest));
366 if (inet_chksum(igmp, p->
len)) {
368 IGMP_STATS_INC(igmp.chkerr);
374 group = igmp_lookfor_group(inp, dest);
379 IGMP_STATS_INC(igmp.drop);
385 switch (igmp->igmp_msgtype) {
386 case IGMP_MEMB_QUERY:
388 if ((ip4_addr_cmp(dest, &allsystems)) && ip4_addr_isany(&igmp->igmp_group_address)) {
390 LWIP_DEBUGF(
IGMP_DEBUG, (
"igmp_input: General IGMP_MEMB_QUERY on \"ALL SYSTEMS\" address (224.0.0.1) [igmp_maxresp=%i]\n", (
int)(igmp->igmp_maxresp)));
392 if (igmp->igmp_maxresp == 0) {
393 IGMP_STATS_INC(igmp.rx_v1);
394 LWIP_DEBUGF(
IGMP_DEBUG, (
"igmp_input: got an all hosts query with time== 0 - this is V1 and not implemented - treat as v2\n"));
395 igmp->igmp_maxresp = IGMP_V1_DELAYING_MEMBER_TMR;
397 IGMP_STATS_INC(igmp.rx_general);
400 groupref = netif_igmp_data(inp);
404 if(groupref != NULL) {
405 groupref = groupref->next;
409 igmp_delaying_member(groupref, igmp->igmp_maxresp);
410 groupref = groupref->next;
414 if (!ip4_addr_isany(&igmp->igmp_group_address)) {
416 ip4_addr_debug_print(
IGMP_DEBUG, &igmp->igmp_group_address);
417 if (ip4_addr_cmp(dest, &allsystems)) {
418 ip4_addr_t groupaddr;
419 LWIP_DEBUGF(
IGMP_DEBUG, (
" using \"ALL SYSTEMS\" address (224.0.0.1) [igmp_maxresp=%i]\n", (
int)(igmp->igmp_maxresp)));
421 ip4_addr_copy(groupaddr, igmp->igmp_group_address);
422 group = igmp_lookfor_group(inp, &groupaddr);
424 LWIP_DEBUGF(
IGMP_DEBUG, (
" with the group address as destination [igmp_maxresp=%i]\n", (
int)(igmp->igmp_maxresp)));
428 IGMP_STATS_INC(igmp.rx_group);
429 igmp_delaying_member(group, igmp->igmp_maxresp);
431 IGMP_STATS_INC(igmp.drop);
434 IGMP_STATS_INC(igmp.proterr);
438 case IGMP_V2_MEMB_REPORT:
440 IGMP_STATS_INC(igmp.rx_report);
441 if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) {
444 group->group_state = IGMP_GROUP_IDLE_MEMBER;
445 group->last_reporter_flag = 0;
450 igmp->igmp_msgtype, group->group_state, (
void*)&group, (
void*)inp));
451 IGMP_STATS_INC(igmp.proterr);
468 igmp_joingroup(
const ip4_addr_t *ifaddr,
const ip4_addr_t *groupaddr)
474 LWIP_ERROR(
"igmp_joingroup: attempt to join non-multicast address", ip4_addr_ismulticast(groupaddr),
return ERR_VAL;);
475 LWIP_ERROR(
"igmp_joingroup: attempt to join allsystems address", (!ip4_addr_cmp(groupaddr, &allsystems)),
return ERR_VAL;);
479 while (netif != NULL) {
481 if ((netif->flags &
NETIF_FLAG_IGMP) && ((ip4_addr_isany(ifaddr) || ip4_addr_cmp(netif_ip4_addr(netif), ifaddr)))) {
482 err = igmp_joingroup_netif(netif, groupaddr);
505 igmp_joingroup_netif(
struct netif *netif,
const ip4_addr_t *groupaddr)
507 struct igmp_group *group;
510 LWIP_ERROR(
"igmp_joingroup_netif: attempt to join non-multicast address", ip4_addr_ismulticast(groupaddr),
return ERR_VAL;);
511 LWIP_ERROR(
"igmp_joingroup_netif: attempt to join allsystems address", (!ip4_addr_cmp(groupaddr, &allsystems)),
return ERR_VAL;);
517 group = igmp_lookup_group(netif, groupaddr);
521 if (group->group_state != IGMP_GROUP_NON_MEMBER) {
522 LWIP_DEBUGF(
IGMP_DEBUG, (
"igmp_joingroup_netif: join to group not in state IGMP_GROUP_NON_MEMBER\n"));
530 if ((group->use==0) && (netif->igmp_mac_filter != NULL)) {
537 IGMP_STATS_INC(igmp.tx_join);
538 igmp_send(netif, group, IGMP_V2_MEMB_REPORT);
540 igmp_start_timer(group, IGMP_JOIN_DELAYING_MEMBER_TMR);
543 group->group_state = IGMP_GROUP_DELAYING_MEMBER;
564 igmp_leavegroup(
const ip4_addr_t *ifaddr,
const ip4_addr_t *groupaddr)
570 LWIP_ERROR(
"igmp_leavegroup: attempt to leave non-multicast address", ip4_addr_ismulticast(groupaddr),
return ERR_VAL;);
571 LWIP_ERROR(
"igmp_leavegroup: attempt to leave allsystems address", (!ip4_addr_cmp(groupaddr, &allsystems)),
return ERR_VAL;);
575 while (netif != NULL) {
577 if ((netif->flags &
NETIF_FLAG_IGMP) && ((ip4_addr_isany(ifaddr) || ip4_addr_cmp(netif_ip4_addr(netif), ifaddr)))) {
578 err_t res = igmp_leavegroup_netif(netif, groupaddr);
600 igmp_leavegroup_netif(
struct netif *netif,
const ip4_addr_t *groupaddr)
602 struct igmp_group *group;
605 LWIP_ERROR(
"igmp_leavegroup_netif: attempt to leave non-multicast address", ip4_addr_ismulticast(groupaddr),
return ERR_VAL;);
606 LWIP_ERROR(
"igmp_leavegroup_netif: attempt to leave allsystems address", (!ip4_addr_cmp(groupaddr, &allsystems)),
return ERR_VAL;);
612 group = igmp_lookfor_group(netif, groupaddr);
621 if (group->use <= 1) {
623 igmp_remove_group(netif, group);
626 if (group->last_reporter_flag) {
628 IGMP_STATS_INC(igmp.tx_leave);
629 igmp_send(netif, group, IGMP_LEAVE_GROUP);
633 if (netif->igmp_mac_filter != NULL) {
662 while (netif != NULL) {
663 struct igmp_group *group = netif_igmp_data(netif);
665 while (group != NULL) {
666 if (group->timer > 0) {
668 if (group->timer == 0) {
669 igmp_timeout(netif, group);
685 igmp_timeout(
struct netif *netif,
struct igmp_group *group)
689 if ((group->group_state == IGMP_GROUP_DELAYING_MEMBER) &&
690 (!(ip4_addr_cmp(&(group->group_address), &allsystems)))) {
692 ip4_addr_debug_print(
IGMP_DEBUG, &(group->group_address));
695 group->group_state = IGMP_GROUP_IDLE_MEMBER;
697 IGMP_STATS_INC(igmp.tx_report);
698 igmp_send(netif, group, IGMP_V2_MEMB_REPORT);
710 igmp_start_timer(
struct igmp_group *group, u8_t max_time)
713 group->timer = max_time > 2 ? (LWIP_RAND() % max_time) : 1;
716 group->timer = max_time / 2;
719 if (group->timer == 0) {
731 igmp_delaying_member(
struct igmp_group *group, u8_t maxresp)
733 if ((group->group_state == IGMP_GROUP_IDLE_MEMBER) ||
734 ((group->group_state == IGMP_GROUP_DELAYING_MEMBER) &&
735 ((group->timer == 0) || (maxresp < group->timer)))) {
736 igmp_start_timer(group, maxresp);
737 group->group_state = IGMP_GROUP_DELAYING_MEMBER;
759 igmp_ip_output_if(
struct pbuf *p,
const ip4_addr_t *src,
const ip4_addr_t *dest,
struct netif *netif)
763 ra[0] = PP_HTONS(ROUTER_ALERT);
765 IGMP_STATS_INC(igmp.xmit);
766 return ip4_output_if_opt(p, src, dest, IGMP_TTL, 0, IP_PROTO_IGMP, netif, ra, ROUTER_ALERTLEN);
776 igmp_send(
struct netif *netif,
struct igmp_group *group, u8_t type)
778 struct pbuf* p = NULL;
780 ip4_addr_t src = *IP4_ADDR_ANY4;
781 ip4_addr_t* dest = NULL;
788 LWIP_ASSERT(
"igmp_send: check that first pbuf can hold struct igmp_msg",
790 ip4_addr_copy(src, *netif_ip4_addr(netif));
792 if (type == IGMP_V2_MEMB_REPORT) {
793 dest = &(group->group_address);
794 ip4_addr_copy(igmp->igmp_group_address, group->group_address);
795 group->last_reporter_flag = 1;
797 if (type == IGMP_LEAVE_GROUP) {
799 ip4_addr_copy(igmp->igmp_group_address, group->group_address);
803 if ((type == IGMP_V2_MEMB_REPORT) || (type == IGMP_LEAVE_GROUP)) {
804 igmp->igmp_msgtype = type;
805 igmp->igmp_maxresp = 0;
806 igmp->igmp_checksum = 0;
807 igmp->igmp_checksum = inet_chksum(igmp, IGMP_MINLEN);
809 igmp_ip_output_if(p, &src, dest, netif);
815 IGMP_STATS_INC(igmp.memerr);
struct netif * netif_list
void memp_free(memp_t type, void *mem)
#define LWIP_DEBUGF(debug, message)
struct pbuf * pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
u8_t pbuf_free(struct pbuf *p)
void * memp_malloc(memp_t type)