This patch is intended to drop the duplicate unicast frame from forwarding or pushing to the upper layer. Reuse most of codes previously used for detect and droping the multicast frame.
Please comment on this. Signed-off-by: Chun-Yeow Yeoh <[email protected]> --- net/mac80211/ieee80211_i.h | 3 +- net/mac80211/iface.c | 2 +- net/mac80211/mesh.c | 70 ++++++++++++++++++++++++++++--------------- net/mac80211/mesh.h | 34 +++++++++++---------- net/mac80211/rx.c | 10 +++++- 5 files changed, 75 insertions(+), 44 deletions(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 95beb18..f33f44f 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -568,7 +568,8 @@ struct ieee80211_if_mesh { unsigned long next_perr; /* Timestamp of last PREQ sent */ unsigned long last_preq; - struct mesh_rmc *rmc; + struct mesh_rfc *rmc; + struct mesh_rfc *ruc; spinlock_t mesh_preq_queue_lock; struct mesh_preq_queue preq_queue; int preq_queue_len; diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 8edaf67..13b64c1 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -947,7 +947,7 @@ static void ieee80211_teardown_sdata(struct ieee80211_sub_if_data *sdata) sdata->fragment_next = 0; if (ieee80211_vif_is_mesh(&sdata->vif)) - mesh_rmc_free(sdata); + mesh_rfc_free(sdata); flushed = sta_info_flush(sdata); WARN_ON(flushed); diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index aead541..d27dd4a 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -14,7 +14,7 @@ #include "mesh.h" static int mesh_allocated; -static struct kmem_cache *rm_cache; +static struct kmem_cache *rm_cache, *ru_cache; bool mesh_action_is_path_sel(struct ieee80211_mgmt *mgmt) { @@ -26,7 +26,9 @@ void ieee80211s_init(void) { mesh_pathtbl_init(); mesh_allocated = 1; - rm_cache = kmem_cache_create("mesh_rmc", sizeof(struct rmc_entry), + rm_cache = kmem_cache_create("mesh_rmc", sizeof(struct rfc_entry), + 0, 0, NULL); + ru_cache = kmem_cache_create("mesh_ruc", sizeof(struct rfc_entry), 0, 0, NULL); } @@ -36,6 +38,7 @@ void ieee80211s_stop(void) return; mesh_pathtbl_unregister(); kmem_cache_destroy(rm_cache); + kmem_cache_destroy(ru_cache); } static void ieee80211_mesh_housekeeping_timer(unsigned long data) @@ -165,41 +168,52 @@ void mesh_sta_cleanup(struct sta_info *sta) ieee80211_mbss_info_change_notify(sdata, changed); } -int mesh_rmc_init(struct ieee80211_sub_if_data *sdata) +int mesh_rfc_init(struct ieee80211_sub_if_data *sdata) { int i; - sdata->u.mesh.rmc = kmalloc(sizeof(struct mesh_rmc), GFP_KERNEL); - if (!sdata->u.mesh.rmc) + sdata->u.mesh.rmc = kmalloc(sizeof(struct mesh_rfc), GFP_KERNEL); + sdata->u.mesh.ruc = kmalloc(sizeof(struct mesh_rfc), GFP_KERNEL); + if (!(sdata->u.mesh.rmc || sdata->u.mesh.ruc)) return -ENOMEM; - sdata->u.mesh.rmc->idx_mask = RMC_BUCKETS - 1; - for (i = 0; i < RMC_BUCKETS; i++) + sdata->u.mesh.rmc->idx_mask = RFC_BUCKETS - 1; + sdata->u.mesh.ruc->idx_mask = RFC_BUCKETS - 1; + for (i = 0; i < RFC_BUCKETS; i++) { INIT_LIST_HEAD(&sdata->u.mesh.rmc->bucket[i]); + INIT_LIST_HEAD(&sdata->u.mesh.ruc->bucket[i]); + } return 0; } -void mesh_rmc_free(struct ieee80211_sub_if_data *sdata) +void mesh_rfc_free(struct ieee80211_sub_if_data *sdata) { - struct mesh_rmc *rmc = sdata->u.mesh.rmc; - struct rmc_entry *p, *n; + struct mesh_rfc *rmc = sdata->u.mesh.rmc, + *ruc = sdata->u.mesh.ruc; + struct rfc_entry *p, *n; int i; - if (!sdata->u.mesh.rmc) + if (!(sdata->u.mesh.rmc || sdata->u.mesh.ruc)) return; - for (i = 0; i < RMC_BUCKETS; i++) { + for (i = 0; i < RFC_BUCKETS; i++) { list_for_each_entry_safe(p, n, &rmc->bucket[i], list) { list_del(&p->list); kmem_cache_free(rm_cache, p); } + list_for_each_entry_safe(p, n, &ruc->bucket[i], list) { + list_del(&p->list); + kmem_cache_free(ru_cache, p); + } } kfree(rmc); + kfree(ruc); sdata->u.mesh.rmc = NULL; + sdata->u.mesh.ruc = NULL; } /** - * mesh_rmc_check - Check frame in recent multicast cache and add if absent. + * mesh_rfc_check - Check frame in recent unicast/multicast cache and add if absent. * * @sdata: interface * @sa: source address @@ -211,37 +225,43 @@ void mesh_rmc_free(struct ieee80211_sub_if_data *sdata) * received this frame lately. If the frame is not in the cache, it is added to * it. */ -int mesh_rmc_check(struct ieee80211_sub_if_data *sdata, - const u8 *sa, struct ieee80211s_hdr *mesh_hdr) +int mesh_rfc_check(struct ieee80211_sub_if_data *sdata, + const u8 *sa, struct ieee80211s_hdr *mesh_hdr, + struct mesh_rfc *rfc, bool unicast) { - struct mesh_rmc *rmc = sdata->u.mesh.rmc; u32 seqnum = 0; int entries = 0; u8 idx; - struct rmc_entry *p, *n; + struct rfc_entry *p, *n; /* Don't care about endianness since only match matters */ memcpy(&seqnum, &mesh_hdr->seqnum, sizeof(mesh_hdr->seqnum)); - idx = le32_to_cpu(mesh_hdr->seqnum) & rmc->idx_mask; - list_for_each_entry_safe(p, n, &rmc->bucket[idx], list) { + idx = le32_to_cpu(mesh_hdr->seqnum) & rfc->idx_mask; + list_for_each_entry_safe(p, n, &rfc->bucket[idx], list) { ++entries; if (time_after(jiffies, p->exp_time) || - entries == RMC_QUEUE_MAX_LEN) { + entries == RFC_QUEUE_MAX_LEN) { list_del(&p->list); - kmem_cache_free(rm_cache, p); + if (!unicast) + kmem_cache_free(rm_cache, p); + else + kmem_cache_free(ru_cache, p); --entries; } else if ((seqnum == p->seqnum) && ether_addr_equal(sa, p->sa)) return -1; } - p = kmem_cache_alloc(rm_cache, GFP_ATOMIC); + if (!unicast) + p = kmem_cache_alloc(rm_cache, GFP_ATOMIC); + else + p = kmem_cache_alloc(ru_cache, GFP_ATOMIC); if (!p) return 0; p->seqnum = seqnum; - p->exp_time = jiffies + RMC_TIMEOUT; + p->exp_time = jiffies + RFC_TIMEOUT; memcpy(p->sa, sa, ETH_ALEN); - list_add(&p->list, &rmc->bucket[idx]); + list_add(&p->list, &rfc->bucket[idx]); return 0; } @@ -1023,7 +1043,7 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata) ifmsh->sn = 0; ifmsh->num_gates = 0; atomic_set(&ifmsh->mpaths, 0); - mesh_rmc_init(sdata); + mesh_rfc_init(sdata); ifmsh->last_preq = jiffies; ifmsh->next_perr = jiffies; /* Allocate all mesh structures when creating the first mesh interface. */ diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 6ffabbe..f9674eb 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -159,32 +159,33 @@ struct mesh_table { struct rcu_head rcu_head; }; -/* Recent multicast cache */ -/* RMC_BUCKETS must be a power of 2, maximum 256 */ -#define RMC_BUCKETS 256 -#define RMC_QUEUE_MAX_LEN 4 -#define RMC_TIMEOUT (3 * HZ) +/* Recent unicast/multicast cache */ +/* RFC_BUCKETS must be a power of 2, maximum 256 */ +#define RFC_BUCKETS 256 +#define RFC_QUEUE_MAX_LEN 4 +#define RFC_TIMEOUT (3 * HZ) /** - * struct rmc_entry - entry in the Recent Multicast Cache + * struct rfc_entry - entry in the Recent Unicast/Multicast Cache * * @seqnum: mesh sequence number of the frame * @exp_time: expiration time of the entry, in jiffies * @sa: source address of the frame * - * The Recent Multicast Cache keeps track of the latest multicast frames that - * have been received by a mesh interface and discards received multicast frames - * that are found in the cache. + * The Recent Unicast/Multicast Cache keeps track of the latest + * unicast/multicast frames that have been received by a mesh interface + * and discards received unicast/multicast frames that are found in + * the cache. */ -struct rmc_entry { +struct rfc_entry { struct list_head list; u32 seqnum; unsigned long exp_time; u8 sa[ETH_ALEN]; }; -struct mesh_rmc { - struct list_head bucket[RMC_BUCKETS]; +struct mesh_rfc { + struct list_head bucket[RFC_BUCKETS]; u32 idx_mask; }; @@ -209,8 +210,9 @@ int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc, int ieee80211_new_mesh_header(struct ieee80211_sub_if_data *sdata, struct ieee80211s_hdr *meshhdr, const char *addr4or5, const char *addr6); -int mesh_rmc_check(struct ieee80211_sub_if_data *sdata, - const u8 *addr, struct ieee80211s_hdr *mesh_hdr); +int mesh_rfc_check(struct ieee80211_sub_if_data *sdata, + const u8 *addr, struct ieee80211s_hdr *mesh_hdr, + struct mesh_rfc *rfc, bool unicast); bool mesh_matches_local(struct ieee80211_sub_if_data *sdata, struct ieee802_11_elems *ie); void mesh_ids_set_default(struct ieee80211_if_mesh *mesh); @@ -228,8 +230,8 @@ int mesh_add_ht_cap_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); int mesh_add_ht_oper_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); -void mesh_rmc_free(struct ieee80211_sub_if_data *sdata); -int mesh_rmc_init(struct ieee80211_sub_if_data *sdata); +void mesh_rfc_free(struct ieee80211_sub_if_data *sdata); +int mesh_rfc_init(struct ieee80211_sub_if_data *sdata); void ieee80211s_init(void); void ieee80211s_update_metric(struct ieee80211_local *local, struct sta_info *sta, struct sk_buff *skb); diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 5b4492a..b8b3e20 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2018,7 +2018,15 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) /* frame is in RMC, don't forward */ if (ieee80211_is_data(hdr->frame_control) && is_multicast_ether_addr(hdr->addr1) && - mesh_rmc_check(rx->sdata, hdr->addr3, mesh_hdr)) + mesh_rfc_check(rx->sdata, hdr->addr3, mesh_hdr, + sdata->u.mesh.rmc, 0)) + return RX_DROP_MONITOR; + + /* duplicate unicast frame, don't forward and proceed */ + if (ieee80211_is_data(hdr->frame_control) && + !is_multicast_ether_addr(hdr->addr1) && + mesh_rfc_check(rx->sdata, hdr->addr4, mesh_hdr, + sdata->u.mesh.ruc, 1)) return RX_DROP_MONITOR; if (!ieee80211_is_data(hdr->frame_control) || -- 1.7.0.4 _______________________________________________ Devel mailing list [email protected] http://lists.open80211s.org/cgi-bin/mailman/listinfo/devel
