From patchwork Sun Dec 8 09:25:05 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Pali_Roh=C3=A1r?= X-Patchwork-Id: 3306211 Return-Path: X-Original-To: patchwork-linux-wireless@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id AAC169F37A for ; Sun, 8 Dec 2013 09:34:45 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id A81EF20374 for ; Sun, 8 Dec 2013 09:34:44 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id CDA3E20348 for ; Sun, 8 Dec 2013 09:34:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755255Ab3LHJ2I (ORCPT ); Sun, 8 Dec 2013 04:28:08 -0500 Received: from mail-ee0-f50.google.com ([74.125.83.50]:60377 "EHLO mail-ee0-f50.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754413Ab3LHJ1Z (ORCPT ); Sun, 8 Dec 2013 04:27:25 -0500 Received: by mail-ee0-f50.google.com with SMTP id c41so992629eek.37 for ; Sun, 08 Dec 2013 01:27:23 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-type:content-transfer-encoding; bh=DJMZFP0T6+44PpLRsJihZL4E4HR6dagXF1Sn8DhXv64=; b=MyVlW2ZCFyez3eGVTS/rVKOXLJoCB6CmlIMnEwOnTvPxsezhfkqsaBBzdaMK7sFRoR DbO8i0mxYm0ZCqcKIVK0tUCm0V2+RXo0vW5gFZIgOI+rWLQnSVyUOfexiQFqriyNPu2q oLDtg/cBhRgDKTeuR5FbsbAZ1PYGTIA8io2a0UriU4oVTxH6BD1/Y/VnZj2Dg3Zwt67c U2niKqFiBZ/xar0CONsPuIqNeb9OOQqzZ61UFvlp7+N52gCD4P0w8G3YRrh1aRDtel2t Keho+hpDV47AuMQs+L9E5rrMO2keAC5Cu9BSBlc7mgQfOkJU4cY6odEUxRupKWCAVGit HV3A== X-Received: by 10.14.205.201 with SMTP id j49mr2170105eeo.85.1386494843639; Sun, 08 Dec 2013 01:27:23 -0800 (PST) Received: from Pali-EliteBook.kolej.mff.cuni.cz (pali.kolej.mff.cuni.cz. [78.128.193.202]) by mx.google.com with ESMTPSA id m1sm15397623eeg.0.2013.12.08.01.27.22 for (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Sun, 08 Dec 2013 01:27:22 -0800 (PST) From: =?UTF-8?q?Pali=20Roh=C3=A1r?= To: Luciano Coelho , "John W. Linville" Cc: linux-wireless@vger.kernel.org, netdev@vger.kernel.org, linux-kernel@vger.kernel.org, freemangordon@abv.bg, aaro.koskinen@iki.fi, pavel@ucw.cz, sre@ring0.de, joni.lapilainen@gmail.com, Johannes Berg , Felipe Contreras , David Gnedt , =?UTF-8?q?Pali=20Roh=C3=A1r?= Subject: [PATCH v2 07/16] wl1251: implement multicast address filtering Date: Sun, 8 Dec 2013 10:25:05 +0100 Message-Id: <1386494714-21070-8-git-send-email-pali.rohar@gmail.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1386494714-21070-1-git-send-email-pali.rohar@gmail.com> References: <1382819655-30430-1-git-send-email-pali.rohar@gmail.com> <1386494714-21070-1-git-send-email-pali.rohar@gmail.com> MIME-Version: 1.0 Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, T_DKIM_INVALID, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: David Gnedt Port multicast address filtering from wl1271 driver. It sets up the hardware multicast address filter in configure_filter() with addresses supplied through prepare_multicast(). Signed-off-by: David Gnedt Signed-off-by: Pali Rohár Reviewed-by: Pavel Machek --- drivers/net/wireless/ti/wl1251/acx.c | 9 ++--- drivers/net/wireless/ti/wl1251/acx.h | 9 ++--- drivers/net/wireless/ti/wl1251/init.c | 2 +- drivers/net/wireless/ti/wl1251/main.c | 57 +++++++++++++++++++++++++++++-- drivers/net/wireless/ti/wl1251/wl1251.h | 1 + 5 files changed, 67 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/ti/wl1251/acx.c b/drivers/net/wireless/ti/wl1251/acx.c index 1ec98e9..f772e62 100644 --- a/drivers/net/wireless/ti/wl1251/acx.c +++ b/drivers/net/wireless/ti/wl1251/acx.c @@ -408,7 +408,8 @@ out: return ret; } -int wl1251_acx_group_address_tbl(struct wl1251 *wl) +int wl1251_acx_group_address_tbl(struct wl1251 *wl, bool enable, + void *mc_list, u32 mc_list_len) { struct acx_dot11_grp_addr_tbl *acx; int ret; @@ -422,9 +423,9 @@ int wl1251_acx_group_address_tbl(struct wl1251 *wl) } /* MAC filtering */ - acx->enabled = 0; - acx->num_groups = 0; - memset(acx->mac_table, 0, ADDRESS_GROUP_MAX_LEN); + acx->enabled = enable; + acx->num_groups = mc_list_len; + memcpy(acx->mac_table, mc_list, mc_list_len * ETH_ALEN); ret = wl1251_cmd_configure(wl, DOT11_GROUP_ADDRESS_TBL, acx, sizeof(*acx)); diff --git a/drivers/net/wireless/ti/wl1251/acx.h b/drivers/net/wireless/ti/wl1251/acx.h index bea2e67..820573c 100644 --- a/drivers/net/wireless/ti/wl1251/acx.h +++ b/drivers/net/wireless/ti/wl1251/acx.h @@ -350,8 +350,8 @@ struct acx_slot { } __packed; -#define ADDRESS_GROUP_MAX (8) -#define ADDRESS_GROUP_MAX_LEN (ETH_ALEN * ADDRESS_GROUP_MAX) +#define ACX_MC_ADDRESS_GROUP_MAX (8) +#define ACX_MC_ADDRESS_GROUP_MAX_LEN (ETH_ALEN * ACX_MC_ADDRESS_GROUP_MAX) struct acx_dot11_grp_addr_tbl { struct acx_header header; @@ -359,7 +359,7 @@ struct acx_dot11_grp_addr_tbl { u8 enabled; u8 num_groups; u8 pad[2]; - u8 mac_table[ADDRESS_GROUP_MAX_LEN]; + u8 mac_table[ACX_MC_ADDRESS_GROUP_MAX_LEN]; } __packed; @@ -1464,7 +1464,8 @@ int wl1251_acx_rx_msdu_life_time(struct wl1251 *wl, u32 life_time); int wl1251_acx_rx_config(struct wl1251 *wl, u32 config, u32 filter); int wl1251_acx_pd_threshold(struct wl1251 *wl); int wl1251_acx_slot(struct wl1251 *wl, enum acx_slot_type slot_time); -int wl1251_acx_group_address_tbl(struct wl1251 *wl); +int wl1251_acx_group_address_tbl(struct wl1251 *wl, bool enable, + void *mc_list, u32 mc_list_len); int wl1251_acx_service_period_timeout(struct wl1251 *wl); int wl1251_acx_rts_threshold(struct wl1251 *wl, u16 rts_threshold); int wl1251_acx_beacon_filter_opt(struct wl1251 *wl, bool enable_filter); diff --git a/drivers/net/wireless/ti/wl1251/init.c b/drivers/net/wireless/ti/wl1251/init.c index 92de289..f8a2ea9 100644 --- a/drivers/net/wireless/ti/wl1251/init.c +++ b/drivers/net/wireless/ti/wl1251/init.c @@ -127,7 +127,7 @@ int wl1251_hw_init_phy_config(struct wl1251 *wl) if (ret < 0) return ret; - ret = wl1251_acx_group_address_tbl(wl); + ret = wl1251_acx_group_address_tbl(wl, true, NULL, 0); if (ret < 0) return ret; diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c index 39a6105..ee318c8 100644 --- a/drivers/net/wireless/ti/wl1251/main.c +++ b/drivers/net/wireless/ti/wl1251/main.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "wl1251.h" #include "wl12xx_80211.h" @@ -678,6 +679,44 @@ out: return ret; } +struct wl1251_filter_params { + bool enabled; + int mc_list_length; + u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN]; +}; + +static u64 wl1251_op_prepare_multicast(struct ieee80211_hw *hw, + struct netdev_hw_addr_list *mc_list) +{ + struct wl1251_filter_params *fp; + struct netdev_hw_addr *ha; + struct wl1251 *wl = hw->priv; + + if (unlikely(wl->state == WL1251_STATE_OFF)) + return 0; + + fp = kzalloc(sizeof(*fp), GFP_ATOMIC); + if (!fp) { + wl1251_error("Out of memory setting filters."); + return 0; + } + + /* update multicast filtering parameters */ + fp->mc_list_length = 0; + if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) { + fp->enabled = false; + } else { + fp->enabled = true; + netdev_hw_addr_list_for_each(ha, mc_list) { + memcpy(fp->mc_list[fp->mc_list_length], + ha->addr, ETH_ALEN); + fp->mc_list_length++; + } + } + + return (u64)(unsigned long)fp; +} + #define WL1251_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \ FIF_ALLMULTI | \ FIF_FCSFAIL | \ @@ -688,8 +727,9 @@ out: static void wl1251_op_configure_filter(struct ieee80211_hw *hw, unsigned int changed, - unsigned int *total,u64 multicast) + unsigned int *total, u64 multicast) { + struct wl1251_filter_params *fp = (void *)(unsigned long)multicast; struct wl1251 *wl = hw->priv; int ret; @@ -698,9 +738,11 @@ static void wl1251_op_configure_filter(struct ieee80211_hw *hw, *total &= WL1251_SUPPORTED_FILTERS; changed &= WL1251_SUPPORTED_FILTERS; - if (changed == 0) + if (changed == 0) { /* no filters which we support changed */ + kfree(fp); return; + } mutex_lock(&wl->mutex); @@ -737,6 +779,15 @@ static void wl1251_op_configure_filter(struct ieee80211_hw *hw, if (ret < 0) goto out; + if (*total & FIF_ALLMULTI || *total & FIF_PROMISC_IN_BSS) + ret = wl1251_acx_group_address_tbl(wl, false, NULL, 0); + else if (fp) + ret = wl1251_acx_group_address_tbl(wl, fp->enabled, + fp->mc_list, + fp->mc_list_length); + if (ret < 0) + goto out; + /* send filters to firmware */ wl1251_acx_rx_config(wl, wl->rx_config, wl->rx_filter); @@ -744,6 +795,7 @@ static void wl1251_op_configure_filter(struct ieee80211_hw *hw, out: mutex_unlock(&wl->mutex); + kfree(fp); } /* HW encryption */ @@ -1283,6 +1335,7 @@ static const struct ieee80211_ops wl1251_ops = { .add_interface = wl1251_op_add_interface, .remove_interface = wl1251_op_remove_interface, .config = wl1251_op_config, + .prepare_multicast = wl1251_op_prepare_multicast, .configure_filter = wl1251_op_configure_filter, .tx = wl1251_op_tx, .set_key = wl1251_op_set_key, diff --git a/drivers/net/wireless/ti/wl1251/wl1251.h b/drivers/net/wireless/ti/wl1251/wl1251.h index 45df03a..93c18d2 100644 --- a/drivers/net/wireless/ti/wl1251/wl1251.h +++ b/drivers/net/wireless/ti/wl1251/wl1251.h @@ -93,6 +93,7 @@ enum { } while (0) #define WL1251_DEFAULT_RX_CONFIG (CFG_UNI_FILTER_EN | \ + CFG_MC_FILTER_EN | \ CFG_BSSID_FILTER_EN) #define WL1251_DEFAULT_RX_FILTER (CFG_RX_PRSP_EN | \