Some quick code to use UDP-only (no TCP) with mBed. Echos received packets and sends packets when a button is pressed
igmp.c
00001 /** 00002 * @file 00003 * IGMP - Internet Group Management Protocol 00004 * 00005 */ 00006 00007 /* 00008 * Copyright (c) 2002 CITEL Technologies Ltd. 00009 * All rights reserved. 00010 * 00011 * Redistribution and use in source and binary forms, with or without 00012 * modification, are permitted provided that the following conditions 00013 * are met: 00014 * 1. Redistributions of source code must retain the above copyright 00015 * notice, this list of conditions and the following disclaimer. 00016 * 2. Redistributions in binary form must reproduce the above copyright 00017 * notice, this list of conditions and the following disclaimer in the 00018 * documentation and/or other materials provided with the distribution. 00019 * 3. Neither the name of CITEL Technologies Ltd nor the names of its contributors 00020 * may be used to endorse or promote products derived from this software 00021 * without specific prior written permission. 00022 * 00023 * THIS SOFTWARE IS PROVIDED BY CITEL TECHNOLOGIES AND CONTRIBUTORS ``AS IS'' 00024 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00025 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00026 * ARE DISCLAIMED. IN NO EVENT SHALL CITEL TECHNOLOGIES OR CONTRIBUTORS BE LIABLE 00027 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 00028 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 00029 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 00030 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00031 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 00032 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 00033 * SUCH DAMAGE. 00034 * 00035 * This file is a contribution to the lwIP TCP/IP stack. 00036 * The Swedish Institute of Computer Science and Adam Dunkels 00037 * are specifically granted permission to redistribute this 00038 * source code. 00039 */ 00040 00041 /*------------------------------------------------------------- 00042 Note 1) 00043 Although the rfc requires V1 AND V2 capability 00044 we will only support v2 since now V1 is very old (August 1989) 00045 V1 can be added if required 00046 00047 a debug print and statistic have been implemented to 00048 show this up. 00049 ------------------------------------------------------------- 00050 ------------------------------------------------------------- 00051 Note 2) 00052 A query for a specific group address (as opposed to ALLHOSTS) 00053 has now been implemented as I am unsure if it is required 00054 00055 a debug print and statistic have been implemented to 00056 show this up. 00057 ------------------------------------------------------------- 00058 ------------------------------------------------------------- 00059 Note 3) 00060 The router alert rfc 2113 is implemented in outgoing packets 00061 but not checked rigorously incoming 00062 ------------------------------------------------------------- 00063 Steve Reynolds 00064 ------------------------------------------------------------*/ 00065 00066 /*----------------------------------------------------------------------------- 00067 * RFC 988 - Host extensions for IP multicasting - V0 00068 * RFC 1054 - Host extensions for IP multicasting - 00069 * RFC 1112 - Host extensions for IP multicasting - V1 00070 * RFC 2236 - Internet Group Management Protocol, Version 2 - V2 <- this code is based on this RFC (it's the "de facto" standard) 00071 * RFC 3376 - Internet Group Management Protocol, Version 3 - V3 00072 * RFC 4604 - Using Internet Group Management Protocol Version 3... - V3+ 00073 * RFC 2113 - IP Router Alert Option - 00074 *----------------------------------------------------------------------------*/ 00075 00076 /*----------------------------------------------------------------------------- 00077 * Includes 00078 *----------------------------------------------------------------------------*/ 00079 00080 #include "lwip/opt.h" 00081 00082 #if LWIP_IGMP /* don't build if not configured for use in lwipopts.h */ 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 * Globales 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 * Initialize the IGMP module 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 * Dump global IGMP groups list 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 /* LWIP_DEBUG */ 00139 00140 /** 00141 * Start IGMP processing on interface 00142 * 00143 * @param netif network interface on which start IGMP processing 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 /* Allow the igmp messages at the MAC level */ 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 * Stop IGMP processing on interface 00174 * 00175 * @param netif network interface on which stop IGMP processing 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 /* look for groups joined on this interface further down the list */ 00185 while (group != NULL) { 00186 next = group->next; 00187 /* is it a group joined on this interface? */ 00188 if (group->interface == netif) { 00189 /* is it the first group of the list? */ 00190 if (group == igmp_group_list) { 00191 igmp_group_list = next; 00192 } 00193 /* is there a "previous" group defined? */ 00194 if (prev != NULL) { 00195 prev->next = next; 00196 } 00197 /* disable the group at the MAC level */ 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 /* free group */ 00205 memp_free(MEMP_IGMP_GROUP, group); 00206 } else { 00207 /* change the "previous" */ 00208 prev = group; 00209 } 00210 /* move to "next" */ 00211 group = next; 00212 } 00213 return ERR_OK; 00214 } 00215 00216 /** 00217 * Report IGMP memberships for this interface 00218 * 00219 * @param netif network interface on which report IGMP memberships 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 * Search for a group in the global igmp_group_list 00238 * 00239 * @param ifp the network interface for which to look 00240 * @param addr the group ip address to search for 00241 * @return a struct igmp_group* if the group has been found, 00242 * NULL if the group wasn't found. 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 /* to be clearer, we return NULL here instead of 00257 * 'group' (which is also NULL at this point). 00258 */ 00259 return NULL; 00260 } 00261 00262 /** 00263 * Search for a specific igmp group and create a new one if not found- 00264 * 00265 * @param ifp the network interface for which to look 00266 * @param addr the group ip address to search 00267 * @return a struct igmp_group*, 00268 * NULL on memory error. 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 /* Search if the group already exists */ 00276 group = igmp_lookfor_group(ifp, addr); 00277 if (group != NULL) { 00278 /* Group already exists. */ 00279 return group; 00280 } 00281 00282 /* Group doesn't exist yet, create a new one */ 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; /* Not running */ 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 * Remove a group in the global igmp_group_list 00305 * 00306 * @param group the group to remove from the global igmp_group_list 00307 * @return ERR_OK if group was removed from the list, an err_t otherwise 00308 */ 00309 err_t 00310 igmp_remove_group(struct igmp_group *group) 00311 { 00312 err_t err = ERR_OK; 00313 00314 /* Is it the first group? */ 00315 if (igmp_group_list == group) { 00316 igmp_group_list = group->next; 00317 } else { 00318 /* look for group further down the list */ 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 /* Group not found in the global igmp_group_list */ 00327 if (tmpGroup == NULL) 00328 err = ERR_ARG; 00329 } 00330 /* free group */ 00331 memp_free(MEMP_IGMP_GROUP, group); 00332 00333 return err; 00334 } 00335 00336 /** 00337 * Called from ip_input() if a new IGMP packet is received. 00338 * 00339 * @param p received igmp packet, p->payload pointing to the ip header 00340 * @param inp network interface on which the packet was received 00341 * @param dest destination ip address of the igmp packet 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 /* Note that the length CAN be greater than 8 but only 8 are used - All are included in the checksum */ 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 /* Now calculate and check the checksum */ 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 /* Packet is ok so find an existing group */ 00376 group = igmp_lookfor_group(inp, dest); /* use the incoming IP address! */ 00377 00378 /* If group can be found or create... */ 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 /* NOW ACT ON THE INCOMING MESSAGE TYPE... */ 00386 switch (igmp->igmp_msgtype) { 00387 case IGMP_MEMB_QUERY: { 00388 /* IGMP_MEMB_QUERY to the "all systems" address ? */ 00389 if ((ip_addr_cmp(dest, &allsystems)) && (igmp->igmp_group_address.addr == 0)) { 00390 /* THIS IS THE GENERAL QUERY */ 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 /* Do not send messages on the all systems group address! */ 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 /* IGMP_MEMB_QUERY to a specific group ? */ 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 /* we first need to re-lookfor the group since we used dest last time */ 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 /* This is on a specific group we have already looked up */ 00435 group->timer = 0; /* stopped */ 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 * Join a group on one network interface. 00454 * 00455 * @param ifaddr ip address of the network interface which should join a new group 00456 * @param groupaddr the ip address of the group which to join 00457 * @return ERR_OK if group was joined on the netif(s), an err_t otherwise 00458 */ 00459 err_t 00460 igmp_joingroup(struct ip_addr *ifaddr, struct ip_addr *groupaddr) 00461 { 00462 err_t err = ERR_VAL; /* no matching interface */ 00463 struct igmp_group *group; 00464 struct netif *netif; 00465 00466 /* make sure it is multicast address */ 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 /* loop through netif's */ 00471 netif = netif_list; 00472 while (netif != NULL) { 00473 /* Should we join this interface ? */ 00474 if ((netif->flags & NETIF_FLAG_IGMP) && ((ip_addr_isany(ifaddr) || ip_addr_cmp(&(netif->ip_addr), ifaddr)))) { 00475 /* find group or create a new one if not found */ 00476 group = igmp_lookup_group(netif, groupaddr); 00477 00478 if (group != NULL) { 00479 /* This should create a new group, check the state to make sure */ 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 /* OK - it was new group */ 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 /* If first use of the group, allow the group at the MAC level */ 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 /* Need to work out where this timer comes from */ 00502 group->group_state = IGMP_GROUP_DELAYING_MEMBER; 00503 } 00504 /* Increment group use */ 00505 group->use++; 00506 /* Join on this interface */ 00507 err = ERR_OK; 00508 } else { 00509 /* Return an error even if some network interfaces are joined */ 00510 /** @todo undo any other netif already joined */ 00511 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: Not enought memory to join to group\n")); 00512 return ERR_MEM; 00513 } 00514 } 00515 /* proceed to next network interface */ 00516 netif = netif->next; 00517 } 00518 00519 return err; 00520 } 00521 00522 /** 00523 * Leave a group on one network interface. 00524 * 00525 * @param ifaddr ip address of the network interface which should leave a group 00526 * @param groupaddr the ip address of the group which to leave 00527 * @return ERR_OK if group was left on the netif(s), an err_t otherwise 00528 */ 00529 err_t 00530 igmp_leavegroup(struct ip_addr *ifaddr, struct ip_addr *groupaddr) 00531 { 00532 err_t err = ERR_VAL; /* no matching interface */ 00533 struct igmp_group *group; 00534 struct netif *netif; 00535 00536 /* make sure it is multicast address */ 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 /* loop through netif's */ 00541 netif = netif_list; 00542 while (netif != NULL) { 00543 /* Should we leave this interface ? */ 00544 if ((netif->flags & NETIF_FLAG_IGMP) && ((ip_addr_isany(ifaddr) || ip_addr_cmp(&(netif->ip_addr), ifaddr)))) { 00545 /* find group */ 00546 group = igmp_lookfor_group(netif, groupaddr); 00547 00548 if (group != NULL) { 00549 /* Only send a leave if the flag is set according to the state diagram */ 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 /* If there is no other use of the group */ 00555 if (group->use <= 1) { 00556 /* If we are the last reporter for this group */ 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 /* Disable the group at the MAC level */ 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 /* Free the group */ 00576 igmp_remove_group(group); 00577 } else { 00578 /* Decrement group use */ 00579 group->use--; 00580 } 00581 /* Leave on this interface */ 00582 err = ERR_OK; 00583 } else { 00584 /* It's not a fatal error on "leavegroup" */ 00585 LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: not member of group\n")); 00586 } 00587 } 00588 /* proceed to next network interface */ 00589 netif = netif->next; 00590 } 00591 00592 return err; 00593 } 00594 00595 /** 00596 * The igmp timer function (both for NO_SYS=1 and =0) 00597 * Should be called every IGMP_TMR_INTERVAL milliseconds (100 ms is default). 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 * Called if a timeout for one group is reached. 00617 * Sends a report for this group. 00618 * 00619 * @param group an igmp_group for which a timeout is reached 00620 */ 00621 void 00622 igmp_timeout(struct igmp_group *group) 00623 { 00624 /* If the state is IGMP_GROUP_DELAYING_MEMBER then we send a report for this group */ 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 * Start a timer for an igmp group 00636 * 00637 * @param group the igmp_group for which to start a timer 00638 * @param max_time the time in multiples of IGMP_TMR_INTERVAL (decrease with 00639 * every call to igmp_tmr()) 00640 */ 00641 void 00642 igmp_start_timer(struct igmp_group *group, u8_t max_time) 00643 { 00644 /** 00645 * @todo Important !! this should be random 0 -> max_time. Find out how to do this 00646 */ 00647 group->timer = max_time; 00648 } 00649 00650 /** 00651 * Stop a timer for an igmp_group 00652 * 00653 * @param group the igmp_group for which to stop the timer 00654 */ 00655 void 00656 igmp_stop_timer(struct igmp_group *group) 00657 { 00658 group->timer = 0; 00659 } 00660 00661 /** 00662 * Delaying membership report for a group if necessary 00663 * 00664 * @param group the igmp_group for which "delaying" membership report 00665 * @param maxresp query delay 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 * Sends an IP packet on a network interface. This function constructs the IP header 00680 * and calculates the IP header checksum. If the source IP address is NULL, 00681 * the IP address of the outgoing network interface is filled in as source address. 00682 * 00683 * @param p the packet to send (p->payload points to the data, e.g. next 00684 protocol header; if dest == IP_HDRINCL, p already includes an IP 00685 header and p->payload points to that IP header) 00686 * @param src the source IP address to send from (if src == IP_ADDR_ANY, the 00687 * IP address of the netif used to send is used as source address) 00688 * @param dest the destination IP address to send the packet to 00689 * @param ttl the TTL value to be set in the IP header 00690 * @param proto the PROTOCOL to be set in the IP header 00691 * @param netif the netif on which to send this packet 00692 * @return ERR_OK if the packet was sent OK 00693 * ERR_BUF if p doesn't have enough space for IP/LINK headers 00694 * returns errors returned by netif->output 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 /* This is the "router alert" option */ 00701 u16_t ra[2]; 00702 ra[0] = htons (ROUTER_ALERT); 00703 ra[1] = 0x0000; /* Router shall examine packet */ 00704 return ip_output_if_opt(p, src, dest, ttl, 0, proto, netif, ra, ROUTER_ALERTLEN); 00705 } 00706 00707 /** 00708 * Send an igmp packet to a specific group. 00709 * 00710 * @param group the group to which to send the packet 00711 * @param type the type of igmp packet to send 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 /* IP header + "router alert" option + IGMP header */ 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; /* Remember we were the last to report */ 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 /* LWIP_IGMP */
Generated on Tue Jul 12 2022 19:17:23 by 1.7.2