Warning, cross-references for /kernel/lwip/core/ipv4/igmp.c need to be fixed.
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080 #include "lwip/opt.h"
0081
0082 #if LWIP_IGMP
0083
0084 #include "lwip/igmp.h"
0085 #include "lwip/debug.h"
0086 #include "lwip/def.h"
0087 #include "lwip/mem.h"
0088 #include "lwip/ip.h"
0089 #include "lwip/inet.h"
0090 #include "lwip/inet_chksum.h"
0091 #include "lwip/netif.h"
0092 #include "lwip/icmp.h"
0093 #include "lwip/udp.h"
0094 #include "lwip/tcp.h"
0095 #include "lwip/stats.h"
0096
0097 #include "string.h"
0098
0099
0100
0101
0102
0103 static struct igmp_group* igmp_group_list;
0104 static struct ip_addr allsystems;
0105 static struct ip_addr allrouters;
0106
0107
0108
0109
0110 void
0111 igmp_init(void)
0112 {
0113 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_init: initializing\n"));
0114
0115 IP4_ADDR(&allsystems, 224, 0, 0, 1);
0116 IP4_ADDR(&allrouters, 224, 0, 0, 2);
0117 }
0118
0119 #ifdef LWIP_DEBUG
0120
0121
0122
0123 void
0124 igmp_dump_group_list()
0125 {
0126 struct igmp_group *group = igmp_group_list;
0127
0128 while (group != NULL) {
0129 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_dump_group_list: [%"U32_F"] ", (u32_t)(group->group_state)));
0130 ip_addr_debug_print(IGMP_DEBUG, &group->group_address);
0131 LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", group->interface));
0132 group = group->next;
0133 }
0134 LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
0135 }
0136 #else
0137 #define igmp_dump_group_list()
0138 #endif
0139
0140
0141
0142
0143
0144
0145 err_t
0146 igmp_start(struct netif *netif)
0147 {
0148 struct igmp_group* group;
0149
0150 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: starting IGMP processing on if %p\n", netif));
0151
0152 group = igmp_lookup_group(netif, &allsystems);
0153
0154 if (group != NULL) {
0155 group->group_state = IGMP_GROUP_IDLE_MEMBER;
0156 group->use++;
0157
0158
0159 if (netif->igmp_mac_filter != NULL) {
0160 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: igmp_mac_filter(ADD "));
0161 ip_addr_debug_print(IGMP_DEBUG, &allsystems);
0162 LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
0163 netif->igmp_mac_filter( netif, &allsystems, IGMP_ADD_MAC_FILTER);
0164 }
0165
0166 return ERR_OK;
0167 }
0168
0169 return ERR_MEM;
0170 }
0171
0172
0173
0174
0175
0176
0177 err_t
0178 igmp_stop(struct netif *netif)
0179 {
0180 struct igmp_group *group = igmp_group_list;
0181 struct igmp_group *prev = NULL;
0182 struct igmp_group *next;
0183
0184
0185 while (group != NULL) {
0186 next = group->next;
0187
0188 if (group->interface == netif) {
0189
0190 if (group == igmp_group_list) {
0191 igmp_group_list = next;
0192 }
0193
0194 if (prev != NULL) {
0195 prev->next = next;
0196 }
0197
0198 if (netif->igmp_mac_filter != NULL) {
0199 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_stop: igmp_mac_filter(DEL "));
0200 ip_addr_debug_print(IGMP_DEBUG, &group->group_address);
0201 LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
0202 netif->igmp_mac_filter(netif, &(group->group_address), IGMP_DEL_MAC_FILTER);
0203 }
0204
0205 memp_free(MEMP_IGMP_GROUP, group);
0206 } else {
0207
0208 prev = group;
0209 }
0210
0211 group = next;
0212 }
0213 return ERR_OK;
0214 }
0215
0216
0217
0218
0219
0220
0221 void
0222 igmp_report_groups( struct netif *netif)
0223 {
0224 struct igmp_group *group = igmp_group_list;
0225
0226 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_report_groups: sending IGMP reports on if %p\n", netif));
0227
0228 while (group != NULL) {
0229 if (group->interface == netif) {
0230 igmp_delaying_member( group, IGMP_JOIN_DELAYING_MEMBER_TMR);
0231 }
0232 group = group->next;
0233 }
0234 }
0235
0236
0237
0238
0239
0240
0241
0242
0243
0244 struct igmp_group *
0245 igmp_lookfor_group(struct netif *ifp, struct ip_addr *addr)
0246 {
0247 struct igmp_group *group = igmp_group_list;
0248
0249 while (group != NULL) {
0250 if ((group->interface == ifp) && (ip_addr_cmp(&(group->group_address), addr))) {
0251 return group;
0252 }
0253 group = group->next;
0254 }
0255
0256
0257
0258
0259 return NULL;
0260 }
0261
0262
0263
0264
0265
0266
0267
0268
0269
0270 struct igmp_group *
0271 igmp_lookup_group(struct netif *ifp, struct ip_addr *addr)
0272 {
0273 struct igmp_group *group = igmp_group_list;
0274
0275
0276 group = igmp_lookfor_group(ifp, addr);
0277 if (group != NULL) {
0278
0279 return group;
0280 }
0281
0282
0283 group = memp_malloc(MEMP_IGMP_GROUP);
0284 if (group != NULL) {
0285 group->interface = ifp;
0286 ip_addr_set(&(group->group_address), addr);
0287 group->timer = 0;
0288 group->group_state = IGMP_GROUP_NON_MEMBER;
0289 group->last_reporter_flag = 0;
0290 group->use = 0;
0291 group->next = igmp_group_list;
0292
0293 igmp_group_list = group;
0294 }
0295
0296 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_lookup_group: %sallocated a new group with address ", (group?"":"impossible to ")));
0297 ip_addr_debug_print(IGMP_DEBUG, addr);
0298 LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", ifp));
0299
0300 return group;
0301 }
0302
0303
0304
0305
0306
0307
0308
0309 err_t
0310 igmp_remove_group(struct igmp_group *group)
0311 {
0312 err_t err = ERR_OK;
0313
0314
0315 if (igmp_group_list == group) {
0316 igmp_group_list = group->next;
0317 } else {
0318
0319 struct igmp_group *tmpGroup;
0320 for (tmpGroup = igmp_group_list; tmpGroup != NULL; tmpGroup = tmpGroup->next) {
0321 if (tmpGroup->next == group) {
0322 tmpGroup->next = group->next;
0323 break;
0324 }
0325 }
0326
0327 if (tmpGroup == NULL)
0328 err = ERR_ARG;
0329 }
0330
0331 memp_free(MEMP_IGMP_GROUP, group);
0332
0333 return err;
0334 }
0335
0336
0337
0338
0339
0340
0341
0342
0343 void
0344 igmp_input(struct pbuf *p, struct netif *inp, struct ip_addr *dest)
0345 {
0346 struct ip_hdr * iphdr;
0347 struct igmp_msg* igmp;
0348 struct igmp_group* group;
0349 struct igmp_group* groupref;
0350
0351
0352 iphdr = p->payload;
0353 if (pbuf_header(p, -(s16_t)(IPH_HL(iphdr) * 4)) || (p->len < IGMP_MINLEN)) {
0354 pbuf_free(p);
0355 IGMP_STATS_INC(igmp.lenerr);
0356 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: length error\n"));
0357 return;
0358 }
0359
0360 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: message from "));
0361 ip_addr_debug_print(IGMP_DEBUG, &(iphdr->src));
0362 LWIP_DEBUGF(IGMP_DEBUG, (" to address "));
0363 ip_addr_debug_print(IGMP_DEBUG, &(iphdr->dest));
0364 LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", inp));
0365
0366
0367 igmp = (struct igmp_msg *)p->payload;
0368 if (inet_chksum(igmp, p->len)) {
0369 pbuf_free(p);
0370 IGMP_STATS_INC(igmp.chkerr);
0371 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: checksum error\n"));
0372 return;
0373 }
0374
0375
0376 group = igmp_lookfor_group(inp, dest);
0377
0378
0379 if (!group) {
0380 pbuf_free(p);
0381 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP frame not for us\n"));
0382 return;
0383 }
0384
0385
0386 switch (igmp->igmp_msgtype) {
0387 case IGMP_MEMB_QUERY: {
0388
0389 if ((ip_addr_cmp(dest, &allsystems)) && (igmp->igmp_group_address.addr == 0)) {
0390
0391 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)));
0392
0393 if (igmp->igmp_maxresp == 0) {
0394 IGMP_STATS_INC(igmp.v1_rxed);
0395 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: got an all hosts query with time== 0 - this is V1 and not implemented - treat as v2\n"));
0396 igmp->igmp_maxresp = IGMP_V1_DELAYING_MEMBER_TMR;
0397 }
0398
0399 IGMP_STATS_INC(igmp.group_query_rxed);
0400 groupref = igmp_group_list;
0401 while (groupref) {
0402
0403 if ((groupref->interface == inp) && (!(ip_addr_cmp(&(groupref->group_address), &allsystems)))) {
0404 igmp_delaying_member( groupref, igmp->igmp_maxresp);
0405 }
0406 groupref = groupref->next;
0407 }
0408 } else {
0409
0410 if (group->group_address.addr != 0) {
0411 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_MEMB_QUERY to a specific group "));
0412 ip_addr_debug_print(IGMP_DEBUG, &group->group_address);
0413 if (ip_addr_cmp (dest, &allsystems)) {
0414 LWIP_DEBUGF(IGMP_DEBUG, (" using \"ALL SYSTEMS\" address (224.0.0.1) [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp)));
0415
0416 group = igmp_lookfor_group(inp, &igmp->igmp_group_address);
0417 } else {
0418 LWIP_DEBUGF(IGMP_DEBUG, (" with the group address as destination [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp)));
0419 }
0420
0421 if (group != NULL) {
0422 IGMP_STATS_INC(igmp.unicast_query);
0423 igmp_delaying_member( group, igmp->igmp_maxresp);
0424 }
0425 }
0426 }
0427 break;
0428 }
0429 case IGMP_V2_MEMB_REPORT: {
0430 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_V2_MEMB_REPORT\n"));
0431
0432 IGMP_STATS_INC(igmp.report_rxed);
0433 if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) {
0434
0435 group->timer = 0;
0436 group->group_state = IGMP_GROUP_IDLE_MEMBER;
0437 group->last_reporter_flag = 0;
0438 }
0439 break;
0440 }
0441 default: {
0442 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: unexpected msg %d in state %d on group %p on if %p\n",
0443 igmp->igmp_msgtype, group->group_state, &group, group->interface));
0444 break;
0445 }
0446 }
0447
0448 pbuf_free(p);
0449 return;
0450 }
0451
0452
0453
0454
0455
0456
0457
0458
0459 err_t
0460 igmp_joingroup(struct ip_addr *ifaddr, struct ip_addr *groupaddr)
0461 {
0462 err_t err = ERR_VAL;
0463 struct igmp_group *group;
0464 struct netif *netif;
0465
0466
0467 LWIP_ERROR("igmp_joingroup: attempt to join non-multicast address", ip_addr_ismulticast(groupaddr), return ERR_VAL;);
0468 LWIP_ERROR("igmp_joingroup: attempt to join allsystems address", (!ip_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;);
0469
0470
0471 netif = netif_list;
0472 while (netif != NULL) {
0473
0474 if ((netif->flags & NETIF_FLAG_IGMP) && ((ip_addr_isany(ifaddr) || ip_addr_cmp(&(netif->ip_addr), ifaddr)))) {
0475
0476 group = igmp_lookup_group(netif, groupaddr);
0477
0478 if (group != NULL) {
0479
0480 if (group->group_state != IGMP_GROUP_NON_MEMBER) {
0481 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: join to group not in state IGMP_GROUP_NON_MEMBER\n"));
0482 } else {
0483
0484 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: join to new group: "));
0485 ip_addr_debug_print(IGMP_DEBUG, groupaddr);
0486 LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
0487
0488
0489 if ((group->use==0) && (netif->igmp_mac_filter != NULL)) {
0490 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: igmp_mac_filter(ADD "));
0491 ip_addr_debug_print(IGMP_DEBUG, groupaddr);
0492 LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
0493 netif->igmp_mac_filter(netif, groupaddr, IGMP_ADD_MAC_FILTER);
0494 }
0495
0496 IGMP_STATS_INC(igmp.join_sent);
0497 igmp_send(group, IGMP_V2_MEMB_REPORT);
0498
0499 igmp_start_timer(group, IGMP_JOIN_DELAYING_MEMBER_TMR);
0500
0501
0502 group->group_state = IGMP_GROUP_DELAYING_MEMBER;
0503 }
0504
0505 group->use++;
0506
0507 err = ERR_OK;
0508 } else {
0509
0510
0511 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: Not enought memory to join to group\n"));
0512 return ERR_MEM;
0513 }
0514 }
0515
0516 netif = netif->next;
0517 }
0518
0519 return err;
0520 }
0521
0522
0523
0524
0525
0526
0527
0528
0529 err_t
0530 igmp_leavegroup(struct ip_addr *ifaddr, struct ip_addr *groupaddr)
0531 {
0532 err_t err = ERR_VAL;
0533 struct igmp_group *group;
0534 struct netif *netif;
0535
0536
0537 LWIP_ERROR("igmp_leavegroup: attempt to leave non-multicast address", ip_addr_ismulticast(groupaddr), return ERR_VAL;);
0538 LWIP_ERROR("igmp_leavegroup: attempt to leave allsystems address", (!ip_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;);
0539
0540
0541 netif = netif_list;
0542 while (netif != NULL) {
0543
0544 if ((netif->flags & NETIF_FLAG_IGMP) && ((ip_addr_isany(ifaddr) || ip_addr_cmp(&(netif->ip_addr), ifaddr)))) {
0545
0546 group = igmp_lookfor_group(netif, groupaddr);
0547
0548 if (group != NULL) {
0549
0550 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: Leaving group: "));
0551 ip_addr_debug_print(IGMP_DEBUG, groupaddr);
0552 LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
0553
0554
0555 if (group->use <= 1) {
0556
0557 if (group->last_reporter_flag) {
0558 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: sending leaving group\n"));
0559 IGMP_STATS_INC(igmp.leave_sent);
0560 igmp_send(group, IGMP_LEAVE_GROUP);
0561 }
0562
0563
0564 if (netif->igmp_mac_filter != NULL) {
0565 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: igmp_mac_filter(DEL "));
0566 ip_addr_debug_print(IGMP_DEBUG, groupaddr);
0567 LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
0568 netif->igmp_mac_filter(netif, groupaddr, IGMP_DEL_MAC_FILTER);
0569 }
0570
0571 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: remove group: "));
0572 ip_addr_debug_print(IGMP_DEBUG, groupaddr);
0573 LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
0574
0575
0576 igmp_remove_group(group);
0577 } else {
0578
0579 group->use--;
0580 }
0581
0582 err = ERR_OK;
0583 } else {
0584
0585 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: not member of group\n"));
0586 }
0587 }
0588
0589 netif = netif->next;
0590 }
0591
0592 return err;
0593 }
0594
0595
0596
0597
0598
0599 void
0600 igmp_tmr(void)
0601 {
0602 struct igmp_group *group = igmp_group_list;
0603
0604 while (group != NULL) {
0605 if (group->timer != 0) {
0606 group->timer -= 1;
0607 if (group->timer == 0) {
0608 igmp_timeout(group);
0609 }
0610 }
0611 group = group->next;
0612 }
0613 }
0614
0615
0616
0617
0618
0619
0620
0621 void
0622 igmp_timeout(struct igmp_group *group)
0623 {
0624
0625 if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) {
0626 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_timeout: report membership for group with address "));
0627 ip_addr_debug_print(IGMP_DEBUG, &(group->group_address));
0628 LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", group->interface));
0629
0630 igmp_send(group, IGMP_V2_MEMB_REPORT);
0631 }
0632 }
0633
0634
0635
0636
0637
0638
0639
0640
0641 void
0642 igmp_start_timer(struct igmp_group *group, u8_t max_time)
0643 {
0644
0645
0646
0647 group->timer = max_time;
0648 }
0649
0650
0651
0652
0653
0654
0655 void
0656 igmp_stop_timer(struct igmp_group *group)
0657 {
0658 group->timer = 0;
0659 }
0660
0661
0662
0663
0664
0665
0666
0667 void
0668 igmp_delaying_member( struct igmp_group *group, u8_t maxresp)
0669 {
0670 if ((group->group_state == IGMP_GROUP_IDLE_MEMBER) ||
0671 ((group->group_state == IGMP_GROUP_DELAYING_MEMBER) && (maxresp > group->timer))) {
0672 igmp_start_timer(group, (maxresp)/2);
0673 group->group_state = IGMP_GROUP_DELAYING_MEMBER;
0674 }
0675 }
0676
0677
0678
0679
0680
0681
0682
0683
0684
0685
0686
0687
0688
0689
0690
0691
0692
0693
0694
0695
0696 err_t
0697 igmp_ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
0698 u8_t ttl, u8_t proto, struct netif *netif)
0699 {
0700
0701 u16_t ra[2];
0702 ra[0] = htons (ROUTER_ALERT);
0703 ra[1] = 0x0000;
0704 return ip_output_if_opt(p, src, dest, ttl, 0, proto, netif, ra, ROUTER_ALERTLEN);
0705 }
0706
0707
0708
0709
0710
0711
0712
0713 void
0714 igmp_send(struct igmp_group *group, u8_t type)
0715 {
0716 struct pbuf* p = NULL;
0717 struct igmp_msg* igmp = NULL;
0718 struct ip_addr src = {0};
0719 struct ip_addr* dest = NULL;
0720
0721
0722 p = pbuf_alloc(PBUF_TRANSPORT, IGMP_MINLEN, PBUF_RAM);
0723
0724 if (p) {
0725 igmp = p->payload;
0726 LWIP_ASSERT("igmp_send: check that first pbuf can hold struct igmp_msg",
0727 (p->len >= sizeof(struct igmp_msg)));
0728 ip_addr_set(&src, &((group->interface)->ip_addr));
0729
0730 if (type == IGMP_V2_MEMB_REPORT) {
0731 dest = &(group->group_address);
0732 IGMP_STATS_INC(igmp.report_sent);
0733 ip_addr_set(&(igmp->igmp_group_address), &(group->group_address));
0734 group->last_reporter_flag = 1;
0735 } else {
0736 if (type == IGMP_LEAVE_GROUP) {
0737 dest = &allrouters;
0738 ip_addr_set(&(igmp->igmp_group_address), &(group->group_address));
0739 }
0740 }
0741
0742 if ((type == IGMP_V2_MEMB_REPORT) || (type == IGMP_LEAVE_GROUP)) {
0743 igmp->igmp_msgtype = type;
0744 igmp->igmp_maxresp = 0;
0745 igmp->igmp_checksum = 0;
0746 igmp->igmp_checksum = inet_chksum( igmp, IGMP_MINLEN);
0747
0748 igmp_ip_output_if(p, &src, dest, IGMP_TTL, IP_PROTO_IGMP, group->interface);
0749 }
0750
0751 pbuf_free(p);
0752 } else {
0753 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_send: not enough memory for igmp_send\n"));
0754 }
0755 }
0756
0757 #endif