00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080 #include "lwip/opt.h"
00081
00082 #if LWIP_IGMP
00083
00084 #include "lwip/igmp.h"
00085 #include "lwip/debug.h"
00086 #include "lwip/def.h"
00087 #include "lwip/mem.h"
00088 #include "lwip/ip.h"
00089 #include "lwip/inet.h"
00090 #include "lwip/inet_chksum.h"
00091 #include "lwip/netif.h"
00092 #include "lwip/icmp.h"
00093 #include "lwip/udp.h"
00094 #include "lwip/tcp.h"
00095 #include "lwip/stats.h"
00096
00097 #include "string.h"
00098
00099
00100
00101
00102
00103 static struct igmp_group* igmp_group_list;
00104 static struct ip_addr allsystems;
00105 static struct ip_addr allrouters;
00106
00107
00108
00109
00110 void
00111 igmp_init(void)
00112 {
00113 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_init: initializing\n"));
00114
00115 IP4_ADDR(&allsystems, 224, 0, 0, 1);
00116 IP4_ADDR(&allrouters, 224, 0, 0, 2);
00117 }
00118
00119 #ifdef LWIP_DEBUG
00120
00121
00122
00123 void
00124 igmp_dump_group_list()
00125 {
00126 struct igmp_group *group = igmp_group_list;
00127
00128 while (group != NULL) {
00129 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_dump_group_list: [%"U32_F"] ", (u32_t)(group->group_state)));
00130 ip_addr_debug_print(IGMP_DEBUG, &group->group_address);
00131 LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", group->interface));
00132 group = group->next;
00133 }
00134 LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
00135 }
00136 #else
00137 #define igmp_dump_group_list()
00138 #endif
00139
00140
00141
00142
00143
00144
00145 err_t
00146 igmp_start(struct netif *netif)
00147 {
00148 struct igmp_group* group;
00149
00150 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: starting IGMP processing on if %p\n", netif));
00151
00152 group = igmp_lookup_group(netif, &allsystems);
00153
00154 if (group != NULL) {
00155 group->group_state = IGMP_GROUP_IDLE_MEMBER;
00156 group->use++;
00157
00158
00159 if (netif->igmp_mac_filter != NULL) {
00160 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: igmp_mac_filter(ADD "));
00161 ip_addr_debug_print(IGMP_DEBUG, &allsystems);
00162 LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
00163 netif->igmp_mac_filter( netif, &allsystems, IGMP_ADD_MAC_FILTER);
00164 }
00165
00166 return ERR_OK;
00167 }
00168
00169 return ERR_MEM;
00170 }
00171
00172
00173
00174
00175
00176
00177 err_t
00178 igmp_stop(struct netif *netif)
00179 {
00180 struct igmp_group *group = igmp_group_list;
00181 struct igmp_group *prev = NULL;
00182 struct igmp_group *next;
00183
00184
00185 while (group != NULL) {
00186 next = group->next;
00187
00188 if (group->interface == netif) {
00189
00190 if (group == igmp_group_list) {
00191 igmp_group_list = next;
00192 }
00193
00194 if (prev != NULL) {
00195 prev->next = next;
00196 }
00197
00198 if (netif->igmp_mac_filter != NULL) {
00199 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_stop: igmp_mac_filter(DEL "));
00200 ip_addr_debug_print(IGMP_DEBUG, &group->group_address);
00201 LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
00202 netif->igmp_mac_filter(netif, &(group->group_address), IGMP_DEL_MAC_FILTER);
00203 }
00204
00205 memp_free(MEMP_IGMP_GROUP, group);
00206 } else {
00207
00208 prev = group;
00209 }
00210
00211 group = next;
00212 }
00213 return ERR_OK;
00214 }
00215
00216
00217
00218
00219
00220
00221 void
00222 igmp_report_groups( struct netif *netif)
00223 {
00224 struct igmp_group *group = igmp_group_list;
00225
00226 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_report_groups: sending IGMP reports on if %p\n", netif));
00227
00228 while (group != NULL) {
00229 if (group->interface == netif) {
00230 igmp_delaying_member( group, IGMP_JOIN_DELAYING_MEMBER_TMR);
00231 }
00232 group = group->next;
00233 }
00234 }
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244 struct igmp_group *
00245 igmp_lookfor_group(struct netif *ifp, struct ip_addr *addr)
00246 {
00247 struct igmp_group *group = igmp_group_list;
00248
00249 while (group != NULL) {
00250 if ((group->interface == ifp) && (ip_addr_cmp(&(group->group_address), addr))) {
00251 return group;
00252 }
00253 group = group->next;
00254 }
00255
00256
00257
00258
00259 return NULL;
00260 }
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270 struct igmp_group *
00271 igmp_lookup_group(struct netif *ifp, struct ip_addr *addr)
00272 {
00273 struct igmp_group *group = igmp_group_list;
00274
00275
00276 group = igmp_lookfor_group(ifp, addr);
00277 if (group != NULL) {
00278
00279 return group;
00280 }
00281
00282
00283 group = memp_malloc(MEMP_IGMP_GROUP);
00284 if (group != NULL) {
00285 group->interface = ifp;
00286 ip_addr_set(&(group->group_address), addr);
00287 group->timer = 0;
00288 group->group_state = IGMP_GROUP_NON_MEMBER;
00289 group->last_reporter_flag = 0;
00290 group->use = 0;
00291 group->next = igmp_group_list;
00292
00293 igmp_group_list = group;
00294 }
00295
00296 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_lookup_group: %sallocated a new group with address ", (group?"":"impossible to ")));
00297 ip_addr_debug_print(IGMP_DEBUG, addr);
00298 LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", ifp));
00299
00300 return group;
00301 }
00302
00303
00304
00305
00306
00307
00308
00309 err_t
00310 igmp_remove_group(struct igmp_group *group)
00311 {
00312 err_t err = ERR_OK;
00313
00314
00315 if (igmp_group_list == group) {
00316 igmp_group_list = group->next;
00317 } else {
00318
00319 struct igmp_group *tmpGroup;
00320 for (tmpGroup = igmp_group_list; tmpGroup != NULL; tmpGroup = tmpGroup->next) {
00321 if (tmpGroup->next == group) {
00322 tmpGroup->next = group->next;
00323 break;
00324 }
00325 }
00326
00327 if (tmpGroup == NULL)
00328 err = ERR_ARG;
00329 }
00330
00331 memp_free(MEMP_IGMP_GROUP, group);
00332
00333 return err;
00334 }
00335
00336
00337
00338
00339
00340
00341
00342
00343 void
00344 igmp_input(struct pbuf *p, struct netif *inp, struct ip_addr *dest)
00345 {
00346 struct ip_hdr * iphdr;
00347 struct igmp_msg* igmp;
00348 struct igmp_group* group;
00349 struct igmp_group* groupref;
00350
00351
00352 iphdr = p->payload;
00353 if (pbuf_header(p, -(s16_t)(IPH_HL(iphdr) * 4)) || (p->len < IGMP_MINLEN)) {
00354 pbuf_free(p);
00355 IGMP_STATS_INC(igmp.lenerr);
00356 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: length error\n"));
00357 return;
00358 }
00359
00360 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: message from "));
00361 ip_addr_debug_print(IGMP_DEBUG, &(iphdr->src));
00362 LWIP_DEBUGF(IGMP_DEBUG, (" to address "));
00363 ip_addr_debug_print(IGMP_DEBUG, &(iphdr->dest));
00364 LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", inp));
00365
00366
00367 igmp = (struct igmp_msg *)p->payload;
00368 if (inet_chksum(igmp, p->len)) {
00369 pbuf_free(p);
00370 IGMP_STATS_INC(igmp.chkerr);
00371 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: checksum error\n"));
00372 return;
00373 }
00374
00375
00376 group = igmp_lookfor_group(inp, dest);
00377
00378
00379 if (!group) {
00380 pbuf_free(p);
00381 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP frame not for us\n"));
00382 return;
00383 }
00384
00385
00386 switch (igmp->igmp_msgtype) {
00387 case IGMP_MEMB_QUERY: {
00388
00389 if ((ip_addr_cmp(dest, &allsystems)) && (igmp->igmp_group_address.addr == 0)) {
00390
00391 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)));
00392
00393 if (igmp->igmp_maxresp == 0) {
00394 IGMP_STATS_INC(igmp.v1_rxed);
00395 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: got an all hosts query with time== 0 - this is V1 and not implemented - treat as v2\n"));
00396 igmp->igmp_maxresp = IGMP_V1_DELAYING_MEMBER_TMR;
00397 }
00398
00399 IGMP_STATS_INC(igmp.group_query_rxed);
00400 groupref = igmp_group_list;
00401 while (groupref) {
00402
00403 if ((groupref->interface == inp) && (!(ip_addr_cmp(&(groupref->group_address), &allsystems)))) {
00404 igmp_delaying_member( groupref, igmp->igmp_maxresp);
00405 }
00406 groupref = groupref->next;
00407 }
00408 } else {
00409
00410 if (group->group_address.addr != 0) {
00411 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_MEMB_QUERY to a specific group "));
00412 ip_addr_debug_print(IGMP_DEBUG, &group->group_address);
00413 if (ip_addr_cmp (dest, &allsystems)) {
00414 LWIP_DEBUGF(IGMP_DEBUG, (" using \"ALL SYSTEMS\" address (224.0.0.1) [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp)));
00415
00416 group = igmp_lookfor_group(inp, &igmp->igmp_group_address);
00417 } else {
00418 LWIP_DEBUGF(IGMP_DEBUG, (" with the group address as destination [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp)));
00419 }
00420
00421 if (group != NULL) {
00422 IGMP_STATS_INC(igmp.unicast_query);
00423 igmp_delaying_member( group, igmp->igmp_maxresp);
00424 }
00425 }
00426 }
00427 break;
00428 }
00429 case IGMP_V2_MEMB_REPORT: {
00430 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_V2_MEMB_REPORT\n"));
00431
00432 IGMP_STATS_INC(igmp.report_rxed);
00433 if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) {
00434
00435 group->timer = 0;
00436 group->group_state = IGMP_GROUP_IDLE_MEMBER;
00437 group->last_reporter_flag = 0;
00438 }
00439 break;
00440 }
00441 default: {
00442 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: unexpected msg %d in state %d on group %p on if %p\n",
00443 igmp->igmp_msgtype, group->group_state, &group, group->interface));
00444 break;
00445 }
00446 }
00447
00448 pbuf_free(p);
00449 return;
00450 }
00451
00452
00453
00454
00455
00456
00457
00458
00459 err_t
00460 igmp_joingroup(struct ip_addr *ifaddr, struct ip_addr *groupaddr)
00461 {
00462 err_t err = ERR_VAL;
00463 struct igmp_group *group;
00464 struct netif *netif;
00465
00466
00467 LWIP_ERROR("igmp_joingroup: attempt to join non-multicast address", ip_addr_ismulticast(groupaddr), return ERR_VAL;);
00468 LWIP_ERROR("igmp_joingroup: attempt to join allsystems address", (!ip_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;);
00469
00470
00471 netif = netif_list;
00472 while (netif != NULL) {
00473
00474 if ((netif->flags & NETIF_FLAG_IGMP) && ((ip_addr_isany(ifaddr) || ip_addr_cmp(&(netif->ip_addr), ifaddr)))) {
00475
00476 group = igmp_lookup_group(netif, groupaddr);
00477
00478 if (group != NULL) {
00479
00480 if (group->group_state != IGMP_GROUP_NON_MEMBER) {
00481 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: join to group not in state IGMP_GROUP_NON_MEMBER\n"));
00482 } else {
00483
00484 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: join to new group: "));
00485 ip_addr_debug_print(IGMP_DEBUG, groupaddr);
00486 LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
00487
00488
00489 if ((group->use==0) && (netif->igmp_mac_filter != NULL)) {
00490 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: igmp_mac_filter(ADD "));
00491 ip_addr_debug_print(IGMP_DEBUG, groupaddr);
00492 LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
00493 netif->igmp_mac_filter(netif, groupaddr, IGMP_ADD_MAC_FILTER);
00494 }
00495
00496 IGMP_STATS_INC(igmp.join_sent);
00497 igmp_send(group, IGMP_V2_MEMB_REPORT);
00498
00499 igmp_start_timer(group, IGMP_JOIN_DELAYING_MEMBER_TMR);
00500
00501
00502 group->group_state = IGMP_GROUP_DELAYING_MEMBER;
00503 }
00504
00505 group->use++;
00506
00507 err = ERR_OK;
00508 } else {
00509
00510
00511 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: Not enought memory to join to group\n"));
00512 return ERR_MEM;
00513 }
00514 }
00515
00516 netif = netif->next;
00517 }
00518
00519 return err;
00520 }
00521
00522
00523
00524
00525
00526
00527
00528
00529 err_t
00530 igmp_leavegroup(struct ip_addr *ifaddr, struct ip_addr *groupaddr)
00531 {
00532 err_t err = ERR_VAL;
00533 struct igmp_group *group;
00534 struct netif *netif;
00535
00536
00537 LWIP_ERROR("igmp_leavegroup: attempt to leave non-multicast address", ip_addr_ismulticast(groupaddr), return ERR_VAL;);
00538 LWIP_ERROR("igmp_leavegroup: attempt to leave allsystems address", (!ip_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;);
00539
00540
00541 netif = netif_list;
00542 while (netif != NULL) {
00543
00544 if ((netif->flags & NETIF_FLAG_IGMP) && ((ip_addr_isany(ifaddr) || ip_addr_cmp(&(netif->ip_addr), ifaddr)))) {
00545
00546 group = igmp_lookfor_group(netif, groupaddr);
00547
00548 if (group != NULL) {
00549
00550 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: Leaving group: "));
00551 ip_addr_debug_print(IGMP_DEBUG, groupaddr);
00552 LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
00553
00554
00555 if (group->use <= 1) {
00556
00557 if (group->last_reporter_flag) {
00558 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: sending leaving group\n"));
00559 IGMP_STATS_INC(igmp.leave_sent);
00560 igmp_send(group, IGMP_LEAVE_GROUP);
00561 }
00562
00563
00564 if (netif->igmp_mac_filter != NULL) {
00565 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: igmp_mac_filter(DEL "));
00566 ip_addr_debug_print(IGMP_DEBUG, groupaddr);
00567 LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
00568 netif->igmp_mac_filter(netif, groupaddr, IGMP_DEL_MAC_FILTER);
00569 }
00570
00571 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: remove group: "));
00572 ip_addr_debug_print(IGMP_DEBUG, groupaddr);
00573 LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
00574
00575
00576 igmp_remove_group(group);
00577 } else {
00578
00579 group->use--;
00580 }
00581
00582 err = ERR_OK;
00583 } else {
00584
00585 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: not member of group\n"));
00586 }
00587 }
00588
00589 netif = netif->next;
00590 }
00591
00592 return err;
00593 }
00594
00595
00596
00597
00598
00599 void
00600 igmp_tmr(void)
00601 {
00602 struct igmp_group *group = igmp_group_list;
00603
00604 while (group != NULL) {
00605 if (group->timer != 0) {
00606 group->timer -= 1;
00607 if (group->timer == 0) {
00608 igmp_timeout(group);
00609 }
00610 }
00611 group = group->next;
00612 }
00613 }
00614
00615
00616
00617
00618
00619
00620
00621 void
00622 igmp_timeout(struct igmp_group *group)
00623 {
00624
00625 if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) {
00626 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_timeout: report membership for group with address "));
00627 ip_addr_debug_print(IGMP_DEBUG, &(group->group_address));
00628 LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", group->interface));
00629
00630 igmp_send(group, IGMP_V2_MEMB_REPORT);
00631 }
00632 }
00633
00634
00635
00636
00637
00638
00639
00640
00641 void
00642 igmp_start_timer(struct igmp_group *group, u8_t max_time)
00643 {
00644
00645
00646
00647 group->timer = max_time;
00648 }
00649
00650
00651
00652
00653
00654
00655 void
00656 igmp_stop_timer(struct igmp_group *group)
00657 {
00658 group->timer = 0;
00659 }
00660
00661
00662
00663
00664
00665
00666
00667 void
00668 igmp_delaying_member( struct igmp_group *group, u8_t maxresp)
00669 {
00670 if ((group->group_state == IGMP_GROUP_IDLE_MEMBER) ||
00671 ((group->group_state == IGMP_GROUP_DELAYING_MEMBER) && (maxresp > group->timer))) {
00672 igmp_start_timer(group, (maxresp)/2);
00673 group->group_state = IGMP_GROUP_DELAYING_MEMBER;
00674 }
00675 }
00676
00677
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696 err_t
00697 igmp_ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
00698 u8_t ttl, u8_t proto, struct netif *netif)
00699 {
00700
00701 u16_t ra[2];
00702 ra[0] = htons (ROUTER_ALERT);
00703 ra[1] = 0x0000;
00704 return ip_output_if_opt(p, src, dest, ttl, 0, proto, netif, ra, ROUTER_ALERTLEN);
00705 }
00706
00707
00708
00709
00710
00711
00712
00713 void
00714 igmp_send(struct igmp_group *group, u8_t type)
00715 {
00716 struct pbuf* p = NULL;
00717 struct igmp_msg* igmp = NULL;
00718 struct ip_addr src = {0};
00719 struct ip_addr* dest = NULL;
00720
00721
00722 p = pbuf_alloc(PBUF_TRANSPORT, IGMP_MINLEN, PBUF_RAM);
00723
00724 if (p) {
00725 igmp = p->payload;
00726 LWIP_ASSERT("igmp_send: check that first pbuf can hold struct igmp_msg",
00727 (p->len >= sizeof(struct igmp_msg)));
00728 ip_addr_set(&src, &((group->interface)->ip_addr));
00729
00730 if (type == IGMP_V2_MEMB_REPORT) {
00731 dest = &(group->group_address);
00732 IGMP_STATS_INC(igmp.report_sent);
00733 ip_addr_set(&(igmp->igmp_group_address), &(group->group_address));
00734 group->last_reporter_flag = 1;
00735 } else {
00736 if (type == IGMP_LEAVE_GROUP) {
00737 dest = &allrouters;
00738 ip_addr_set(&(igmp->igmp_group_address), &(group->group_address));
00739 }
00740 }
00741
00742 if ((type == IGMP_V2_MEMB_REPORT) || (type == IGMP_LEAVE_GROUP)) {
00743 igmp->igmp_msgtype = type;
00744 igmp->igmp_maxresp = 0;
00745 igmp->igmp_checksum = 0;
00746 igmp->igmp_checksum = inet_chksum( igmp, IGMP_MINLEN);
00747
00748 igmp_ip_output_if(p, &src, dest, IGMP_TTL, IP_PROTO_IGMP, group->interface);
00749 }
00750
00751 pbuf_free(p);
00752 } else {
00753 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_send: not enough memory for igmp_send\n"));
00754 }
00755 }
00756
00757 #endif