From d4616a7fc65d4ebac363cb8edba18bdc424ecb26 Mon Sep 17 00:00:00 2001 From: fbernon Date: Tue, 4 Sep 2007 15:15:20 +0000 Subject: [PATCH] Replace mem_malloc call by memp_malloc, and use a new MEMP_NUM_IGMP_GROUP option (see opt.h to define the value). It will avoid potential fragmentation problems, use a counter to know how many times a group is used on an netif, and free it when all applications leave it. MEMP_NUM_IGMP_GROUP got 8 as default value (and init.c got a sanity check if LWIP_IGMP!=0). --- CHANGELOG | 8 +++ src/core/init.c | 3 + src/core/ipv4/igmp.c | 118 ++++++++++++++++++++++++++--------- src/core/memp.c | 1 + src/include/ipv4/lwip/igmp.h | 31 ++++----- src/include/lwip/memp_std.h | 4 ++ src/include/lwip/opt.h | 10 +++ 7 files changed, 131 insertions(+), 44 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 0b412854..4074c023 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -19,6 +19,14 @@ HISTORY ++ New features: + 2007-09-04 Frédéric Bernon, Bill Florac + * igmp.h, igmp.c, memp_std.h, memp.c, init.c, opt.h: Replace mem_malloc call by + memp_malloc, and use a new MEMP_NUM_IGMP_GROUP option (see opt.h to define the + value). It will avoid potential fragmentation problems, use a counter to know + how many times a group is used on an netif, and free it when all applications + leave it. MEMP_NUM_IGMP_GROUP got 8 as default value (and init.c got a sanity + check if LWIP_IGMP!=0). + 2007-09-03 Frédéric Bernon * igmp.h, igmp.c, sockets.c, api_msg.c: Changes for "#20503 IGMP Improvement". Initialize igmp_mac_filter to NULL in netif_add (this field should be set in diff --git a/src/core/init.c b/src/core/init.c index 7311831b..00ff8e25 100644 --- a/src/core/init.c +++ b/src/core/init.c @@ -84,6 +84,9 @@ #if (LWIP_TCP && (MEMP_NUM_TCP_PCB<=0)) #error "If you want to use TCP, you have to define MEMP_NUM_TCP_PCB>=1 in your lwipopts.h" #endif +#if (LWIP_IGMP && (MEMP_NUM_IGMP_GROUP<=1)) + #error "If you want to use IGMP, you have to define MEMP_NUM_IGMP_GROUP>1 in your lwipopts.h" +#endif #if ((LWIP_SOCKET || LWIP_NETCONN) && (NO_SYS==1)) #error "If you want to use Sequential API, you have to define NO_SYS=0 in your lwipopts.h" #endif diff --git a/src/core/ipv4/igmp.c b/src/core/ipv4/igmp.c index 92c63e6a..d5bc0b7f 100644 --- a/src/core/ipv4/igmp.c +++ b/src/core/ipv4/igmp.c @@ -93,8 +93,7 @@ Steve Reynolds #include "string.h" -/* IGMP support available? */ -#if defined(LWIP_IGMP) && (LWIP_IGMP > 0) +#if LWIP_IGMP /* don't build if not configured for use in lwipopts.h */ /*----------------------------------------------------------------------------- * Globales @@ -133,10 +132,14 @@ igmp_start(struct netif *netif) group = igmp_lookup_group(netif, &allsystems); if (group != NULL) { - group->group_state = IDLE_MEMBER; + group->group_state = IGMP_GROUP_IDLE_MEMBER; + group->use++; /* Allow the igmp messages at the MAC level */ if (netif->igmp_mac_filter != NULL) { + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: igmp_mac_filter(ADD ")); + ip_addr_debug_print(IGMP_DEBUG, &allsystems); + LWIP_DEBUGF(IGMP_DEBUG, (") on if %x\n", (int) netif)); netif->igmp_mac_filter( netif, &allsystems, IGMP_ADD_MAC_FILTER); } @@ -192,16 +195,17 @@ igmp_lookup_group(struct netif *ifp, struct ip_addr *addr) return group; } - /* Group doesn't exist yet, create a new one. */ - group = mem_malloc(sizeof(struct igmp_group)); + /* Group doesn't exist yet, create a new one */ + group = memp_malloc(MEMP_IGMP_GROUP); if (group != NULL) { group->interface = ifp; ip_addr_set(&(group->group_address), addr); group->timer = 0; /* Not running */ - group->group_state = NON_MEMBER; + group->group_state = IGMP_GROUP_NON_MEMBER; group->last_reporter_flag = 0; + group->use = 0; group->next = igmp_group_list; - + igmp_group_list = group; } @@ -212,6 +216,39 @@ igmp_lookup_group(struct netif *ifp, struct ip_addr *addr) return group; } +/** + * Remove a group in the global igmp_group_list + * + * @param group the group to remove from the global igmp_group_list + * @return ERR_OK if group was removed from the list, an err_t otherwise + */ +err_t +igmp_remove_group(struct igmp_group *group) +{ + err_t err = ERR_OK; + + /* Is it the first group? */ + if (igmp_group_list == group) { + igmp_group_list = group->next; + } else { + /* look for group further down the list */ + struct igmp_group *tmpGroup; + for (tmpGroup = igmp_group_list; tmpGroup != NULL; tmpGroup = tmpGroup->next) { + if (tmpGroup->next == group) { + tmpGroup->next = group->next; + break; + } + } + /* Group not found in the global igmp_group_list */ + if (tmpGroup == NULL) + err = ERR_ARG; + } + /* free group */ + memp_free(MEMP_IGMP_GROUP, group); + + return err; +} + /** * Called from ip_input() if a new IGMP packet is received. * @@ -309,10 +346,10 @@ igmp_input(struct pbuf *p, struct netif *inp, struct ip_addr *dest) LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_V2_MEMB_REPORT\n")); IGMP_STATS_INC(igmp.report_rxed); - if (group->group_state == DELAYING_MEMBER) { + if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) { /* This is on a specific group we have already looked up */ group->timer = 0; /* stopped */ - group->group_state = IDLE_MEMBER; + group->group_state = IGMP_GROUP_IDLE_MEMBER; group->last_reporter_flag = 0; } break; @@ -343,6 +380,7 @@ igmp_joingroup(struct ip_addr *ifaddr, struct ip_addr *groupaddr) /* make sure it is multicast address */ LWIP_ERROR("igmp_joingroup: attempt to join non-multicast address", ip_addr_ismulticast(groupaddr), return ERR_VAL;); + LWIP_ERROR("igmp_joingroup: attempt to join allsystems address", (!ip_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;); /* loop through netif's */ netif = netif_list; @@ -354,15 +392,19 @@ igmp_joingroup(struct ip_addr *ifaddr, struct ip_addr *groupaddr) if (group != NULL) { /* This should create a new group, check the state to make sure */ - if (group->group_state != NON_MEMBER) { - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: join to group not in state NON_MEMBER\n")); + if (group->group_state != IGMP_GROUP_NON_MEMBER) { + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: join to group not in state IGMP_GROUP_NON_MEMBER\n")); } else { /* OK - it was new group */ LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: join to new group: ")); ip_addr_debug_print(IGMP_DEBUG, groupaddr); LWIP_DEBUGF(IGMP_DEBUG, ("\n")); - if (netif->igmp_mac_filter != NULL) { + /* If first use of the group, allow the group at the MAC level */ + if ((group->use==0) && (netif->igmp_mac_filter != NULL)) { + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: igmp_mac_filter(ADD ")); + ip_addr_debug_print(IGMP_DEBUG, groupaddr); + LWIP_DEBUGF(IGMP_DEBUG, (") on if %x\n", (int) netif)); netif->igmp_mac_filter(netif, groupaddr, IGMP_ADD_MAC_FILTER); } @@ -372,8 +414,10 @@ igmp_joingroup(struct ip_addr *ifaddr, struct ip_addr *groupaddr) igmp_start_timer(group, IGMP_JOIN_DELAYING_MEMBER_TMR); /* Need to work out where this timer comes from */ - group->group_state = DELAYING_MEMBER; + group->group_state = IGMP_GROUP_DELAYING_MEMBER; } + /* Increment group use */ + group->use++; /* Join on this interface */ err = ERR_OK; } else { @@ -406,6 +450,7 @@ igmp_leavegroup(struct ip_addr *ifaddr, struct ip_addr *groupaddr) /* make sure it is multicast address */ LWIP_ERROR("igmp_leavegroup: attempt to leave non-multicast address", ip_addr_ismulticast(groupaddr), return ERR_VAL;); + LWIP_ERROR("igmp_leavegroup: attempt to leave allsystems address", (!ip_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;); /* loop through netif's */ netif = netif_list; @@ -421,19 +466,32 @@ igmp_leavegroup(struct ip_addr *ifaddr, struct ip_addr *groupaddr) ip_addr_debug_print(IGMP_DEBUG, groupaddr); LWIP_DEBUGF(IGMP_DEBUG, ("\n")); - if (group->last_reporter_flag) { - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: sending leaving group\n")); - IGMP_STATS_INC(igmp.leave_sent); - igmp_send(group, IGMP_LEAVE_GROUP); - } - - /* The block is not deleted since the group still exists and we may rejoin */ - group->last_reporter_flag = 0; - group->group_state = NON_MEMBER; - group->timer = 0; - - if (netif->igmp_mac_filter != NULL) { - netif->igmp_mac_filter(netif, groupaddr, IGMP_DEL_MAC_FILTER); + /* If there is no other use of the group */ + if (group->use <= 1) { + /* If we are the last reporter for this group */ + if (group->last_reporter_flag) { + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: sending leaving group\n")); + IGMP_STATS_INC(igmp.leave_sent); + igmp_send(group, IGMP_LEAVE_GROUP); + } + + /* Disable the group at the MAC level */ + if (netif->igmp_mac_filter != NULL) { + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: igmp_mac_filter(DEL ")); + ip_addr_debug_print(IGMP_DEBUG, groupaddr); + LWIP_DEBUGF(IGMP_DEBUG, (") on if %x\n", (int) netif)); + netif->igmp_mac_filter(netif, groupaddr, IGMP_DEL_MAC_FILTER); + } + + LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: remove group: ")); + ip_addr_debug_print(IGMP_DEBUG, groupaddr); + LWIP_DEBUGF(IGMP_DEBUG, ("\n")); + + /* Free the group */ + igmp_remove_group(group); + } else { + /* Decrement group use */ + group->use--; } /* Leave on this interface */ err = ERR_OK; @@ -478,8 +536,8 @@ igmp_tmr(void) void igmp_timeout(struct igmp_group *group) { - /* If the state is DELAYING_MEMBER then we send a report for this group */ - if (group->group_state == DELAYING_MEMBER) { + /* If the state is IGMP_GROUP_DELAYING_MEMBER then we send a report for this group */ + if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) { LWIP_DEBUGF(IGMP_DEBUG, ("igmp_timeout: report membership for group with address ")); ip_addr_debug_print(IGMP_DEBUG, &(group->group_address)); LWIP_DEBUGF(IGMP_DEBUG, (" on if %x\n", (int) group->interface)); @@ -524,9 +582,9 @@ igmp_stop_timer(struct igmp_group *group) void igmp_delaying_member( struct igmp_group *group, u8_t maxresp) { - if ((group->group_state == IDLE_MEMBER) || ((group->group_state == DELAYING_MEMBER) && (maxresp > group->timer))) { + if ((group->group_state == IGMP_GROUP_IDLE_MEMBER) || ((group->group_state == IGMP_GROUP_DELAYING_MEMBER) && (maxresp > group->timer))) { igmp_start_timer(group, (maxresp)/2); - group->group_state = DELAYING_MEMBER; + group->group_state = IGMP_GROUP_DELAYING_MEMBER; } } diff --git a/src/core/memp.c b/src/core/memp.c index 00cd5a55..05d18dd1 100644 --- a/src/core/memp.c +++ b/src/core/memp.c @@ -44,6 +44,7 @@ #include "lwip/udp.h" #include "lwip/raw.h" #include "lwip/tcp.h" +#include "lwip/igmp.h" #include "lwip/api.h" #include "lwip/api_msg.h" #include "lwip/tcpip.h" diff --git a/src/include/ipv4/lwip/igmp.h b/src/include/ipv4/lwip/igmp.h index 6eb445d6..05c4cbd6 100644 --- a/src/include/ipv4/lwip/igmp.h +++ b/src/include/ipv4/lwip/igmp.h @@ -36,9 +36,9 @@ #define __LWIP_IGMP_H__ #include "lwip/opt.h" +#include "lwip/inet.h" -/* IGMP support available? */ -#if defined(LWIP_IGMP) && (LWIP_IGMP > 0) +#if LWIP_IGMP /* don't build if not configured for use in lwipopts.h */ #ifdef __cplusplus extern "C" { @@ -70,17 +70,17 @@ extern "C" { #define IGMP_ADD_MAC_FILTER 1 /* Group membership states */ -#define NON_MEMBER 0 -#define DELAYING_MEMBER 1 -#define IDLE_MEMBER 2 +#define IGMP_GROUP_NON_MEMBER 0 +#define IGMP_GROUP_DELAYING_MEMBER 1 +#define IGMP_GROUP_IDLE_MEMBER 2 /* * IGMP packet format. */ struct igmp_msg { - u8_t igmp_msgtype; - u8_t igmp_maxresp; - u16_t igmp_checksum; + u8_t igmp_msgtype; + u8_t igmp_maxresp; + u16_t igmp_checksum; struct ip_addr igmp_group_address; }; @@ -98,11 +98,12 @@ struct igmp_msg { struct igmp_group { struct igmp_group *next; - struct netif *interface; - struct ip_addr group_address; - u8_t last_reporter_flag; /* signifies we were the last person to report */ - u8_t group_state; - u16_t timer; + struct netif *interface; + struct ip_addr group_address; + u8_t last_reporter_flag; /* signifies we were the last person to report */ + u8_t group_state; + u16_t timer; + u8_t use; /* counter of simultaneous uses */ }; @@ -115,6 +116,8 @@ struct igmp_group *igmp_lookfor_group(struct netif *ifp, struct ip_addr *addr); struct igmp_group *igmp_lookup_group(struct netif *ifp, struct ip_addr *addr); +err_t igmp_remove_group(struct igmp_group *group); + void igmp_input( struct pbuf *p, struct netif *inp, struct ip_addr *dest); err_t igmp_joingroup( struct ip_addr *ifaddr, struct ip_addr *groupaddr); @@ -125,7 +128,7 @@ void igmp_tmr(void); void igmp_timeout( struct igmp_group *group); -void igmp_start_timer( struct igmp_group *group,u8_t max_time); +void igmp_start_timer( struct igmp_group *group, u8_t max_time); void igmp_stop_timer( struct igmp_group *group); diff --git a/src/include/lwip/memp_std.h b/src/include/lwip/memp_std.h index 1705c0a0..c074103a 100644 --- a/src/include/lwip/memp_std.h +++ b/src/include/lwip/memp_std.h @@ -53,6 +53,10 @@ LWIP_MEMPOOL(TCPIP_MSG_INPKT,MEMP_NUM_TCPIP_MSG_INPKT, sizeof(struct tcpip_msg), LWIP_MEMPOOL(ARP_QUEUE, MEMP_NUM_ARP_QUEUE, sizeof(struct etharp_q_entry), "ARP_QUEUE") #endif /* ARP_QUEUEING */ +#if LWIP_IGMP +LWIP_MEMPOOL(IGMP_GROUP, MEMP_NUM_IGMP_GROUP, sizeof(struct igmp_group), "IGMP_GROUP") +#endif /* LWIP_IGMP */ + #if NO_SYS==0 LWIP_MEMPOOL(SYS_TIMEOUT, MEMP_NUM_SYS_TIMEOUT, sizeof(struct sys_timeo), "SYS_TIMEOUT") #endif /* NO_SYS==0 */ diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h index dd2b5dba..a4121ce0 100644 --- a/src/include/lwip/opt.h +++ b/src/include/lwip/opt.h @@ -221,6 +221,16 @@ #define MEMP_NUM_ARP_QUEUE 30 #endif +/** + * MEMP_NUM_IGMP_GROUP: The number of multicast groups whose network interfaces + * can be members et the same time (one per netif - allsystems group -, plus one + * per netif membership). + * (requires the LWIP_IGMP option) + */ +#ifndef MEMP_NUM_IGMP_GROUP +#define MEMP_NUM_IGMP_GROUP 8 +#endif + /** * MEMP_NUM_SYS_TIMEOUT: the number of simulateously active timeouts. * (requires NO_SYS==0)