* Re: bcmdhd: Strange Power Save messages
From: Gucea Doru @ 2016-10-07 14:33 UTC (permalink / raw)
To: Arend Van Spriel
Cc: Krishna Chaitanya, Arend van Spriel, Andra Paraschiv,
linux-wireless
In-Reply-To: <8d01e83b-800d-bba4-b948-abbdc5188f6b@broadcom.com>
On Thu, Oct 6, 2016 at 10:25 AM, Arend Van Spriel
<arend.vanspriel@broadcom.com> wrote:
> On 6-10-2016 10:07, Gucea Doru wrote:
>> On Wed, Oct 5, 2016 at 11:12 AM, Arend Van Spriel
>> <arend.vanspriel@broadcom.com> wrote:
>>> On 4-10-2016 13:39, Gucea Doru wrote:
>>>> On Sat, Oct 1, 2016 at 2:52 PM, Arend van Spriel
>>>>> <arend.vanspriel@broadcom.com> wrote:
>>>>>>
>>>>>>
>>>>>> On 29-09-16 13:32, Gucea Doru wrote:
>>>>>>> On Tue, Sep 27, 2016 at 12:03 PM, Gucea Doru <gucea.doru@gmail.com> wrote:
>>>>>>>> What is the decision triggering the exit from the PS mode immediately
>>>>>>>> after the ping request? I am asking this because 802.11 PS legacy
>>>>>>>> specifies that the client should wait for a beacon with TIM set in
>>>>>>>> order to wake up: in my case, there is no beacon between the ping
>>>>>>>> request message and the Null frame that announces the exit from the PS
>>>>>>>> mode.
>>>>>>>
>>>>>>>
>>>>>>> Any help would be highly appreciated :)
>>>>>>
>>>>>> Actually though I already sent you are reply, but alas here it is.
>>>>>>
>>>>>> bcmdhd is our aosp driver. I am maintaining the upstream brcm80211
>>>>>> drivers. Regardless your question is more for firmware running on the
>>>>>> device. So like the same behavior would be observed when using brcmfmac
>>>>>> with same firmware.
>>>>>>
>>>>>>> IEEE Std 802.11-2012, section 10.2.1.8 specifies that "when the STA
>>>>>>> detects that the bit corresponding to its AID is 1 i the TIM, the STA
>>>>>>> shall issue a PS Poll". In my capture there are cases when the STA
>>>>>>> exits the PS mode without waiting for a beacon.
>>>>>>
>>>>>> It is a bit tricky, but the standard does not explicitly say the STA
>>>>>> should be in power-save at any other time. So it is difficult to say
>>>>>> what event occurred on the STA side to exit PS mode. Also STA means
>>>>>> P2P-Client as you say. That means that you have multiple interfaces:
>>>>>> regular STA and P2P-Client. So is the STA connected to some other AP or
>>>>>> just not connected. wpa_supplicant will do intermittent scan or initiate
>>>>>> scheduled scan by which firmware will scan at a certain interval. That
>>>>>> is just some things I can come up with and I am sure there are more.
>>>>
>>>> I agree that there may be some events belonging to the regular STA
>>>> interface that could trigger the Null Frame (which includes the exit
>>>> from PS Mode). However, I would expect to see some management frames
>>>> in the air before/after the Null Packet (e.g.: a Probe request in case
>>>> of a scheduled scan). But in my case the trigger for the Null frame
>>>> seems to be the ping request packet, the scenario is the same every
>>>> time: ping request -> Block ACK -> Null Frame (Wireshark trace
>>>> confirms this behavior).
>>>>
>>>> I thought that you had a power save optimization algorithm that keeps
>>>> the card on a few milliseconds just to see if we can have a fast reply
>>>> from the peer. Does this ring a bell? :)
>>>
>>> It does not. That would be implemented in firmware. As said I am working
>>> on brcmfmac/brcmsmac. So bcmdhd and firmware are not my expertise.
>>>
>>
>> Arend, could you please redirect me to a Broadcom firmware maintainer?
>
> Can you please elaborate on your platform, broadcom chipset, and what
> version of bcmdhd you are using.
>
Platform: Nexus 5 running CM13 (Android 6.0.1)
Broadcom chipset: BCM4339 Wi-Fi Chipset
bcmdhd version:Dongle Host Driver, version 1.88.45 (r)
Do you need more information?
Thank you,
Doru
^ permalink raw reply
* [PATCH v4 2/4] mac80211: filter multicast data packets on AP / AP_VLAN
From: Michael Braun @ 2016-10-07 13:12 UTC (permalink / raw)
To: johannes; +Cc: Michael Braun, linux-wireless, projekt-wlan, netdev
In-Reply-To: <1475845944-27680-1-git-send-email-michael-dev@fami-braun.de>
This patch adds filtering for multicast data packets on AP_VLAN interfaces
that have no authorized station connected and changes filtering on AP
interfaces to not count stations assigned to AP_VLAN interfaces.
This saves airtime and avoids waking up other stations currently authorized
in this BSS. When using WPA, the packets dropped could not be decrypted by
any station.
The behaviour when there are no AP_VLAN interfaces is left unchanged.
When there are AP_VLAN interfaces, this patch
1. adds filtering multicast data packets sent on AP_VLAN interfaces that
have no authorized station connected.
No filtering happens on 4addr AP_VLAN interfaces.
2. makes filtering of multicast data packets sent on AP interfaces depend
on the number of authorized stations in this bss not assigned to an
AP_VLAN interface.
Therefore, a new num_mcast_sta counter is added for AP_VLAN interfaces.
The existing one for AP interfaces is altered to not track stations
assigned to an AP_VLAN interface.
The new counter is exposed in debugfs.
Signed-off-by: Michael Braun <michael-dev@fami-braun.de>
--
v4:
- update description
v3:
- reuse existing num_mcast_sta
v2:
- use separate function to inc/dec mcast_sta counters
- do not filter in 4addr mode
- change description
- change filtering on AP interface (do not count AP_VLAN sta)
- use new counters regardless of 4addr or not
- simplify cfg.c:change_station
- remove no-op change in __cleanup_single_sta
---
net/mac80211/cfg.c | 20 ++++++--------------
net/mac80211/debugfs_netdev.c | 11 +++++++++++
net/mac80211/ieee80211_i.h | 33 +++++++++++++++++++++++++++++++++
net/mac80211/rx.c | 5 +++--
net/mac80211/sta_info.c | 10 ++--------
net/mac80211/tx.c | 5 ++---
6 files changed, 57 insertions(+), 27 deletions(-)
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 24133f5..1edb017 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1357,9 +1357,6 @@ static int ieee80211_change_station(struct wiphy *wiphy,
goto out_err;
if (params->vlan && params->vlan != sta->sdata->dev) {
- bool prev_4addr = false;
- bool new_4addr = false;
-
vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
if (params->vlan->ieee80211_ptr->use_4addr) {
@@ -1369,26 +1366,21 @@ static int ieee80211_change_station(struct wiphy *wiphy,
}
rcu_assign_pointer(vlansdata->u.vlan.sta, sta);
- new_4addr = true;
__ieee80211_check_fast_rx_iface(vlansdata);
}
if (sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
- sta->sdata->u.vlan.sta) {
+ sta->sdata->u.vlan.sta)
RCU_INIT_POINTER(sta->sdata->u.vlan.sta, NULL);
- prev_4addr = true;
- }
+
+ if (test_sta_flag(sta, WLAN_STA_AUTHORIZED))
+ ieee80211_vif_dec_num_mcast(sta->sdata);
sta->sdata = vlansdata;
ieee80211_check_fast_xmit(sta);
- if (sta->sta_state == IEEE80211_STA_AUTHORIZED &&
- prev_4addr != new_4addr) {
- if (new_4addr)
- atomic_dec(&sta->sdata->bss->num_mcast_sta);
- else
- atomic_inc(&sta->sdata->bss->num_mcast_sta);
- }
+ if (test_sta_flag(sta, WLAN_STA_AUTHORIZED))
+ ieee80211_vif_inc_num_mcast(sta->sdata);
ieee80211_send_layer2_update(sta);
}
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index a5ba739..ed7bff4 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -477,6 +477,7 @@ IEEE80211_IF_FILE_RW(tdls_wider_bw);
IEEE80211_IF_FILE(num_mcast_sta, u.ap.num_mcast_sta, ATOMIC);
IEEE80211_IF_FILE(num_sta_ps, u.ap.ps.num_sta_ps, ATOMIC);
IEEE80211_IF_FILE(dtim_count, u.ap.ps.dtim_count, DEC);
+IEEE80211_IF_FILE(num_mcast_sta_vlan, u.vlan.num_mcast_sta, ATOMIC);
static ssize_t ieee80211_if_fmt_num_buffered_multicast(
const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
@@ -643,6 +644,13 @@ static void add_ap_files(struct ieee80211_sub_if_data *sdata)
DEBUGFS_ADD_MODE(tkip_mic_test, 0200);
}
+static void add_vlan_files(struct ieee80211_sub_if_data *sdata)
+{
+ /* add num_mcast_sta_vlan using name num_mcast_sta */
+ debugfs_create_file("num_mcast_sta", 0400, sdata->vif.debugfs_dir,
+ sdata, &num_mcast_sta_vlan_ops);
+}
+
static void add_ibss_files(struct ieee80211_sub_if_data *sdata)
{
DEBUGFS_ADD_MODE(tsf, 0600);
@@ -746,6 +754,9 @@ static void add_files(struct ieee80211_sub_if_data *sdata)
case NL80211_IFTYPE_AP:
add_ap_files(sdata);
break;
+ case NL80211_IFTYPE_AP_VLAN:
+ add_vlan_files(sdata);
+ break;
case NL80211_IFTYPE_WDS:
add_wds_files(sdata);
break;
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index f56d342..70c0963 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -305,6 +305,7 @@ struct ieee80211_if_vlan {
/* used for all tx if the VLAN is configured to 4-addr mode */
struct sta_info __rcu *sta;
+ atomic_t num_mcast_sta; /* number of stations receiving multicast */
};
struct mesh_stats {
@@ -1496,6 +1497,38 @@ ieee80211_have_rx_timestamp(struct ieee80211_rx_status *status)
return false;
}
+static inline void
+ieee80211_vif_inc_num_mcast(struct ieee80211_sub_if_data *sdata)
+{
+ if (sdata->vif.type == NL80211_IFTYPE_AP)
+ atomic_inc(&sdata->u.ap.num_mcast_sta);
+ else if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+ atomic_inc(&sdata->u.vlan.num_mcast_sta);
+}
+
+static inline void
+ieee80211_vif_dec_num_mcast(struct ieee80211_sub_if_data *sdata)
+{
+ if (sdata->vif.type == NL80211_IFTYPE_AP)
+ atomic_dec(&sdata->u.ap.num_mcast_sta);
+ else if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+ atomic_dec(&sdata->u.vlan.num_mcast_sta);
+}
+
+/* This function returns the number of multicast stations connected to this
+ * interface. It returns -1 if that number is not tracked, that is for netdevs
+ * not in AP or AP_VLAN mode or when using 4addr.
+ */
+static inline int
+ieee80211_vif_get_num_mcast_if(struct ieee80211_sub_if_data *sdata)
+{
+ if (sdata->vif.type == NL80211_IFTYPE_AP)
+ return atomic_read(&sdata->u.ap.num_mcast_sta);
+ if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN && !sdata->u.vlan.sta)
+ return atomic_read(&sdata->u.vlan.num_mcast_sta);
+ return -1;
+}
+
u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local,
struct ieee80211_rx_status *status,
unsigned int mpdu_len,
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 3d8d889..7e5086a 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -2161,7 +2161,8 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
sdata->vif.type == NL80211_IFTYPE_AP_VLAN) &&
!(sdata->flags & IEEE80211_SDATA_DONT_BRIDGE_PACKETS) &&
(sdata->vif.type != NL80211_IFTYPE_AP_VLAN || !sdata->u.vlan.sta)) {
- if (is_multicast_ether_addr(ehdr->h_dest)) {
+ if (is_multicast_ether_addr(ehdr->h_dest) &&
+ ieee80211_vif_get_num_mcast_if(sdata) != 0) {
/*
* send multicast frames both to higher layers in
* local net stack and back to the wireless medium
@@ -2170,7 +2171,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
if (!xmit_skb)
net_info_ratelimited("%s: failed to clone multicast frame\n",
dev->name);
- } else {
+ } else if (!is_multicast_ether_addr(ehdr->h_dest)) {
dsta = sta_info_get(sdata, skb->data);
if (dsta) {
/*
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 76b737d..216ef65 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -1882,10 +1882,7 @@ int sta_info_move_state(struct sta_info *sta,
if (!sta->sta.support_p2p_ps)
ieee80211_recalc_p2p_go_ps_allowed(sta->sdata);
} else if (sta->sta_state == IEEE80211_STA_AUTHORIZED) {
- if (sta->sdata->vif.type == NL80211_IFTYPE_AP ||
- (sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
- !sta->sdata->u.vlan.sta))
- atomic_dec(&sta->sdata->bss->num_mcast_sta);
+ ieee80211_vif_dec_num_mcast(sta->sdata);
clear_bit(WLAN_STA_AUTHORIZED, &sta->_flags);
ieee80211_clear_fast_xmit(sta);
ieee80211_clear_fast_rx(sta);
@@ -1893,10 +1890,7 @@ int sta_info_move_state(struct sta_info *sta,
break;
case IEEE80211_STA_AUTHORIZED:
if (sta->sta_state == IEEE80211_STA_ASSOC) {
- if (sta->sdata->vif.type == NL80211_IFTYPE_AP ||
- (sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
- !sta->sdata->u.vlan.sta))
- atomic_inc(&sta->sdata->bss->num_mcast_sta);
+ ieee80211_vif_inc_num_mcast(sta->sdata);
set_bit(WLAN_STA_AUTHORIZED, &sta->_flags);
ieee80211_check_fast_xmit(sta);
ieee80211_check_fast_rx(sta);
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 5023966..c3ce86e 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -331,9 +331,8 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx)
I802_DEBUG_INC(tx->local->tx_handlers_drop_not_assoc);
return TX_DROP;
}
- } else if (unlikely(tx->sdata->vif.type == NL80211_IFTYPE_AP &&
- ieee80211_is_data(hdr->frame_control) &&
- !atomic_read(&tx->sdata->u.ap.num_mcast_sta))) {
+ } else if (unlikely(ieee80211_is_data(hdr->frame_control) &&
+ ieee80211_vif_get_num_mcast_if(tx->sdata) == 0)) {
/*
* No associated STAs - no need to send multicast
* frames.
--
2.1.4
^ permalink raw reply related
* [PATCH v4 4/4] mac80211: multicast to unicast conversion
From: Michael Braun @ 2016-10-07 13:12 UTC (permalink / raw)
To: johannes; +Cc: Michael Braun, linux-wireless, projekt-wlan, netdev
In-Reply-To: <1475845944-27680-1-git-send-email-michael-dev@fami-braun.de>
This patch adds support for sending multicast data packets with ARP, IPv4
and IPv6 payload (possible 802.1q tagged) as 802.11 unicast frames to all
stations.
IEEE 802.11 multicast has well known issues, among them:
1. packets are not acked and hence not retransmitted, resulting in
decreased reliablity
2. packets are send at low rate, increasing time required on air
When used with AP_VLAN, there is another disadvantage:
3. all stations in the BSS are woken up, regardsless of their AP_VLAN
assignment.
By doing multicast to unicast conversion, all three issus are solved.
IEEE802.11-2012 proposes directed multicast service (DMS) using A-MSDU
frames and a station initiated control protocol. It has the advantage that
the station can recover the destination multicast mac address, but it is
not backward compatible with non QOS stations and does not enable the
administrator of a BSS to force this mode of operation within a BSS.
Additionally, it would require both the ap and the station to implement
the control protocol, which is optional on both ends. Furthermore, I've
seen a few mobile phone stations locally that indicate qos support but
won't complete DHCP if their broadcasts are encapsulated as A-MSDU. Though
they work fine with this series approach.
This patch therefore does not opt to implement DMS but instead just
replicates the packet and changes the destination address. As this works
fine with ARP, IPv4 and IPv6, it is limited to these protocols and normal
802.11 multicast frames are send out for all other payload protocols.
There is a runtime toggle to enable multicast conversion in a per-bss
fashion.
When there is only a single station assigned to the AP_VLAN interface, no
packet replication will occur. 4addr mode of operation is unchanged.
This change opts for iterating all BSS stations for finding the stations
assigned to this AP/AP_VLAN interface, as there currently is no per
AP_VLAN list to iterate and multicast packets are expected to be few.
If needed, such a list could be added later.
Signed-off-by: Michael Braun <michael-dev@fami-braun.de>
--
v4:
- rename MULTICAST_TO_UNICAST to MULTICAST_TO_UNICAST
v3: fix compile error for trace.h
v2: add nl80211 toggle
rename tx_dnat to change_da
change int to bool unicast
---
net/mac80211/cfg.c | 15 +++++++
net/mac80211/debugfs_netdev.c | 3 ++
net/mac80211/ieee80211_i.h | 1 +
net/mac80211/tx.c | 101 ++++++++++++++++++++++++++++++++++++++++++
4 files changed, 120 insertions(+)
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 1edb017..23f711a 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -2242,6 +2242,20 @@ static int ieee80211_set_wds_peer(struct wiphy *wiphy, struct net_device *dev,
return 0;
}
+static int ieee80211_set_multicast_to_unicast(struct wiphy *wiphy,
+ struct net_device *dev,
+ const bool enabled)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ if (sdata->vif.type != NL80211_IFTYPE_AP)
+ return -1;
+
+ sdata->u.ap.unicast = enabled;
+
+ return 0;
+}
+
static void ieee80211_rfkill_poll(struct wiphy *wiphy)
{
struct ieee80211_local *local = wiphy_priv(wiphy);
@@ -3400,6 +3414,7 @@ const struct cfg80211_ops mac80211_config_ops = {
.set_tx_power = ieee80211_set_tx_power,
.get_tx_power = ieee80211_get_tx_power,
.set_wds_peer = ieee80211_set_wds_peer,
+ .set_multicast_to_unicast = ieee80211_set_multicast_to_unicast,
.rfkill_poll = ieee80211_rfkill_poll,
CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd)
CFG80211_TESTMODE_DUMP(ieee80211_testmode_dump)
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index ed7bff4..a5554cc 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -487,6 +487,8 @@ static ssize_t ieee80211_if_fmt_num_buffered_multicast(
}
IEEE80211_IF_FILE_R(num_buffered_multicast);
+IEEE80211_IF_FILE(multicast_to_unicast, u.ap.unicast, HEX);
+
/* IBSS attributes */
static ssize_t ieee80211_if_fmt_tsf(
const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
@@ -642,6 +644,7 @@ static void add_ap_files(struct ieee80211_sub_if_data *sdata)
DEBUGFS_ADD(dtim_count);
DEBUGFS_ADD(num_buffered_multicast);
DEBUGFS_ADD_MODE(tkip_mic_test, 0200);
+ DEBUGFS_ADD_MODE(multicast_to_unicast, 0600);
}
static void add_vlan_files(struct ieee80211_sub_if_data *sdata)
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 70c0963..b23bc21 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -293,6 +293,7 @@ struct ieee80211_if_ap {
driver_smps_mode; /* smps mode request */
struct work_struct request_smps_work;
+ bool unicast;
};
struct ieee80211_if_wds {
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index c3ce86e..6de9549 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -16,6 +16,7 @@
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/skbuff.h>
+#include <linux/if_vlan.h>
#include <linux/etherdevice.h>
#include <linux/bitmap.h>
#include <linux/rcupdate.h>
@@ -1770,6 +1771,102 @@ bool ieee80211_tx_prepare_skb(struct ieee80211_hw *hw,
}
EXPORT_SYMBOL(ieee80211_tx_prepare_skb);
+/* rewrite destination mac address */
+static int ieee80211_change_da(struct sk_buff *skb, struct sta_info *sta)
+{
+ struct ethhdr *eth;
+ int err;
+
+ err = skb_ensure_writable(skb, ETH_HLEN);
+ if (unlikely(err))
+ return err;
+
+ eth = (void *)skb->data;
+ ether_addr_copy(eth->h_dest, sta->sta.addr);
+
+ return 0;
+}
+
+/* Check if multicast to unicast conversion is needed and do it.
+ * Returns 1 if skb was freed and should not be send out.
+ */
+static int
+ieee80211_tx_multicast_to_unicast(struct ieee80211_sub_if_data *sdata,
+ struct sk_buff *skb, u32 info_flags)
+{
+ struct ieee80211_local *local = sdata->local;
+ const struct ethhdr *eth = (void *)skb->data;
+ const struct vlan_ethhdr *ethvlan = (void *)skb->data;
+ struct sta_info *sta, *prev = NULL;
+ struct sk_buff *cloned_skb;
+ u16 ethertype;
+
+ /* check if this is a multicast frame */
+ if (!is_multicast_ether_addr(eth->h_dest))
+ return 0;
+
+ /* check runtime toggle for this bss */
+ if (!sdata->bss->unicast)
+ return 0;
+
+ /* multicast to unicast conversion only for AP interfaces */
+ switch (sdata->vif.type) {
+ case NL80211_IFTYPE_AP_VLAN:
+ sta = rcu_dereference(sdata->u.vlan.sta);
+ if (sta) /* 4addr */
+ return 0;
+ case NL80211_IFTYPE_AP:
+ break;
+ default:
+ return 0;
+ }
+
+ /* info_flags would not get preserved, used only by TLDS */
+ if (info_flags)
+ return 0;
+
+ /* multicast to unicast conversion only for some payload */
+ ethertype = ntohs(eth->h_proto);
+ if (ethertype == ETH_P_8021Q && skb->len >= VLAN_ETH_HLEN)
+ ethertype = ntohs(ethvlan->h_vlan_encapsulated_proto);
+ switch (ethertype) {
+ case ETH_P_ARP:
+ case ETH_P_IP:
+ case ETH_P_IPV6:
+ break;
+ default:
+ return 0;
+ }
+
+ /* clone packets and update destination mac */
+ list_for_each_entry_rcu(sta, &local->sta_list, list) {
+ if (sdata != sta->sdata)
+ continue;
+ if (unlikely(!ether_addr_equal(eth->h_source, sta->sta.addr)))
+ /* do not send back to source */
+ continue;
+ if (!prev) {
+ prev = sta;
+ continue;
+ }
+ cloned_skb = skb_clone(skb, GFP_ATOMIC);
+ if (unlikely(ieee80211_change_da(cloned_skb, prev))) {
+ dev_kfree_skb(cloned_skb);
+ continue;
+ }
+ __ieee80211_subif_start_xmit(cloned_skb, cloned_skb->dev, 0);
+ prev = sta;
+ }
+
+ if (likely(prev)) {
+ ieee80211_change_da(skb, prev);
+ return 0;
+ }
+
+ /* no STA connected, drop */
+ return 1;
+}
+
/*
* Returns false if the frame couldn't be transmitted but was queued instead.
*/
@@ -3353,6 +3450,10 @@ void __ieee80211_subif_start_xmit(struct sk_buff *skb,
rcu_read_lock();
+ /* AP multicast to unicast conversion */
+ if (ieee80211_tx_multicast_to_unicast(sdata, skb, info_flags))
+ goto out_free;
+
if (ieee80211_lookup_ra_sta(sdata, skb, &sta))
goto out_free;
--
2.1.4
^ permalink raw reply related
* [PATCH v4 3/4] cfg80211: configure multicast to unicast for AP interfaces
From: Michael Braun @ 2016-10-07 13:12 UTC (permalink / raw)
To: johannes; +Cc: Michael Braun, linux-wireless, projekt-wlan, netdev
In-Reply-To: <1475845944-27680-1-git-send-email-michael-dev@fami-braun.de>
This add a userspace toggle to configure multicast to unicast.
Signed-off-by: Michael Braun <michael-dev@fami-braun.de>
---
include/net/cfg80211.h | 6 ++++++
include/uapi/linux/nl80211.h | 10 ++++++++++
net/wireless/nl80211.c | 36 ++++++++++++++++++++++++++++++++++++
net/wireless/rdev-ops.h | 12 ++++++++++++
net/wireless/trace.h | 19 +++++++++++++++++++
5 files changed, 83 insertions(+)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index b550314..6ab8940 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -2460,6 +2460,8 @@ struct cfg80211_qos_map {
*
* @set_wds_peer: set the WDS peer for a WDS interface
*
+ * @set_multicast_to_unicast: configure multicast to unicast conversion for BSS
+ *
* @rfkill_poll: polls the hw rfkill line, use cfg80211 reporting
* functions to adjust rfkill hw state
*
@@ -2722,6 +2724,10 @@ struct cfg80211_ops {
int (*set_wds_peer)(struct wiphy *wiphy, struct net_device *dev,
const u8 *addr);
+ int (*set_multicast_to_unicast)(struct wiphy *wiphy,
+ struct net_device *dev,
+ const bool enabled);
+
void (*rfkill_poll)(struct wiphy *wiphy);
#ifdef CONFIG_NL80211_TESTMODE
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 2206941..1b9e87b 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -599,6 +599,9 @@
*
* @NL80211_CMD_SET_WDS_PEER: Set the MAC address of the peer on a WDS interface.
*
+ * @NL80211_CMD_SET_MULTICAST_TO_UNICAST: Configure if AP interface should
+ * perform multicast to unicast conversion (per-BSS).
+ *
* @NL80211_CMD_JOIN_MESH: Join a mesh. The mesh ID must be given, and initial
* mesh config parameters may be given.
* @NL80211_CMD_LEAVE_MESH: Leave the mesh network -- no special arguments, the
@@ -1026,6 +1029,8 @@ enum nl80211_commands {
NL80211_CMD_ABORT_SCAN,
+ NL80211_CMD_SET_MULTICAST_TO_UNICAST,
+
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
@@ -1867,6 +1872,9 @@ enum nl80211_commands {
* @NL80211_ATTR_MESH_PEER_AID: Association ID for the mesh peer (u16). This is
* used to pull the stored data for mesh peer in power save state.
*
+ * @NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED: Multicast packets should be
+ * send out as unicast to all stations.
+ *
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@@ -2261,6 +2269,8 @@ enum nl80211_attrs {
NL80211_ATTR_MESH_PEER_AID,
+ NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index f02653a..57b5d70 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -409,6 +409,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
.len = VHT_MUMIMO_GROUPS_DATA_LEN
},
[NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR] = { .len = ETH_ALEN },
+ [NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED] = { .type = NLA_U8, },
};
/* policy for the key attributes */
@@ -1538,6 +1539,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
goto nla_put_failure;
}
CMD(set_wds_peer, SET_WDS_PEER);
+ CMD(set_multicast_to_unicast, SET_MULTICAST_TO_UNICAST);
if (rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) {
CMD(tdls_mgmt, TDLS_MGMT);
CMD(tdls_oper, TDLS_OPER);
@@ -2164,6 +2166,32 @@ static int nl80211_set_wds_peer(struct sk_buff *skb, struct genl_info *info)
return rdev_set_wds_peer(rdev, dev, bssid);
}
+static int nl80211_set_multicast_to_unicast(struct sk_buff *skb,
+ struct genl_info *info)
+{
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct net_device *dev = info->user_ptr[1];
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ const struct nlattr *nla;
+ bool enabled;
+
+ if (!info->attrs[NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED])
+ return -EINVAL;
+
+ if (netif_running(dev))
+ return -EBUSY;
+
+ if (!rdev->ops->set_multicast_to_unicast)
+ return -EOPNOTSUPP;
+
+ if (wdev->iftype != NL80211_IFTYPE_AP)
+ return -EOPNOTSUPP;
+
+ nla = info->attrs[NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED];
+ enabled = nla_get_flag(nla);
+ return rdev_set_multicast_to_unicast(rdev, dev, enabled);
+}
+
static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *rdev;
@@ -11574,6 +11602,14 @@ static const struct genl_ops nl80211_ops[] = {
NL80211_FLAG_NEED_RTNL,
},
{
+ .cmd = NL80211_CMD_SET_MULTICAST_TO_UNICAST,
+ .doit = nl80211_set_multicast_to_unicast,
+ .policy = nl80211_policy,
+ .flags = GENL_UNS_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV |
+ NL80211_FLAG_NEED_RTNL,
+ },
+ {
.cmd = NL80211_CMD_JOIN_MESH,
.doit = nl80211_join_mesh,
.policy = nl80211_policy,
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
index 85ff30b..7d93c3d 100644
--- a/net/wireless/rdev-ops.h
+++ b/net/wireless/rdev-ops.h
@@ -562,6 +562,18 @@ static inline int rdev_set_wds_peer(struct cfg80211_registered_device *rdev,
return ret;
}
+static inline int
+rdev_set_multicast_to_unicast(struct cfg80211_registered_device *rdev,
+ struct net_device *dev,
+ const bool enabled)
+{
+ int ret;
+ trace_rdev_set_multicast_to_unicast(&rdev->wiphy, dev, enabled);
+ ret = rdev->ops->set_multicast_to_unicast(&rdev->wiphy, dev, enabled);
+ trace_rdev_return_int(&rdev->wiphy, ret);
+ return ret;
+}
+
static inline void rdev_rfkill_poll(struct cfg80211_registered_device *rdev)
{
trace_rdev_rfkill_poll(&rdev->wiphy);
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index 72b5255..8c9aa57 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -2940,6 +2940,25 @@ DEFINE_EVENT(wiphy_wdev_evt, rdev_abort_scan,
TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev),
TP_ARGS(wiphy, wdev)
);
+
+TRACE_EVENT(rdev_set_multicast_to_unicast,
+ TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+ const bool enabled),
+ TP_ARGS(wiphy, netdev, enabled),
+ TP_STRUCT__entry(
+ WIPHY_ENTRY
+ NETDEV_ENTRY
+ __field(bool, enabled)
+ ),
+ TP_fast_assign(
+ WIPHY_ASSIGN;
+ NETDEV_ASSIGN;
+ __entry->enabled = enabled;
+ ),
+ TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", unicast: %s",
+ WIPHY_PR_ARG, NETDEV_PR_ARG,
+ BOOL_TO_STR(__entry->enabled))
+);
#endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */
#undef TRACE_INCLUDE_PATH
--
2.1.4
^ permalink raw reply related
* [PATCH v4 1/4] mac80211: remove unnecessary num_mcast_sta user
From: Michael Braun @ 2016-10-07 13:12 UTC (permalink / raw)
To: johannes; +Cc: Michael Braun, linux-wireless, projekt-wlan, netdev
Checking for num_mcast_sta in __ieee80211_request_smps_ap() is unnecessary,
as sta list will be empty in this case anyway, so list_for_each_entry(sta,
...) will exit immediately.
Signed-off-by: Michael Braun <michael-dev@fami-braun.de>
---
net/mac80211/cfg.c | 7 -------
1 file changed, 7 deletions(-)
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 543b1d4..24133f5 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -2313,13 +2313,6 @@ int __ieee80211_request_smps_ap(struct ieee80211_sub_if_data *sdata,
smps_mode == IEEE80211_SMPS_AUTOMATIC)
return 0;
- /* If no associated stations, there's no need to do anything */
- if (!atomic_read(&sdata->u.ap.num_mcast_sta)) {
- sdata->smps_mode = smps_mode;
- ieee80211_queue_work(&sdata->local->hw, &sdata->recalc_smps);
- return 0;
- }
-
ht_dbg(sdata,
"SMPS %d requested in AP mode, sending Action frame to %d stations\n",
smps_mode, atomic_read(&sdata->u.ap.num_mcast_sta));
--
2.1.4
^ permalink raw reply related
* Re: [v7, 1/3] Documentation: dt: net: add ath9k wireless device binding
From: Kalle Valo @ 2016-10-07 12:17 UTC (permalink / raw)
To: Martin Blumenstingl
Cc: ath9k-devel, devicetree, linux-wireless, ath9k-devel, mcgrof,
mark.rutland, robh+dt, chunkeey, arend.vanspriel, julian.calaby,
bjorn, linux, nbd, Martin Blumenstingl
In-Reply-To: <20161002214743.2263-2-martin.blumenstingl@googlemail.com>
Martin Blumenstingl <martin.blumenstingl@googlemail.com> wrote:
> Add documentation how devicetree can be used to configure ath9k based
> devices.
>
> Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Looks good to me but missing the ack from DT maintainers, will wait for
that.
3 patches set to Deferred.
9359805 [v7,1/3] Documentation: dt: net: add ath9k wireless device binding
9359801 [v7,2/3] ath9k: add a helper to get the string representation of ath_bus_type
9359803 [v7,3/3] ath9k: parse the device configuration from an OF node
--
https://patchwork.kernel.org/patch/9359805/
Documentation about submitting wireless patches and checking status
from patchwork:
https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
^ permalink raw reply
* Re: [v5] ath9k: Switch to using mac80211 intermediate software queues.
From: Kalle Valo @ 2016-10-07 11:43 UTC (permalink / raw)
To: Toke Høiland-Jørgensen
Cc: make-wifi-fast, linux-wireless, Toke Høiland-Jørgensen,
Tim Shepard, Felix Fietkau
In-Reply-To: <20160902140030.11798-1-toke@toke.dk>
Toke Høiland-Jørgensen wrote:
> This switches ath9k over to using the mac80211 intermediate software
> queueing mechanism for data packets. It removes the queueing inside the
> driver, except for the retry queue, and instead pulls from mac80211 when
> a packet is needed. The retry queue is used to store a packet that was
> pulled but can't be sent immediately.
>
> The old code path in ath_tx_start that would queue packets has been
> removed completely, as has the qlen limit tunables (since there's no
> longer a queue in the driver to limit).
>
> Based on Tim's original patch set, but reworked quite thoroughly.
>
> Cc: Tim Shepard <shep@alum.mit.edu>
> Cc: Felix Fietkau <nbd@nbd.name>
> Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
> Signed-off-by: Felix Fietkau <nbd@nbd.name>
Depends on:
bb42f2d13ffc mac80211: Move reorder-sensitive TX handlers to after TXQ dequeue
Patch set to Awaiting Upstream.
--
https://patchwork.kernel.org/patch/9311037/
Documentation about submitting wireless patches and checking status
from patchwork:
https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
^ permalink raw reply
* Re: [1/2] rtl8xxxu: Fix rtl8723bu driver reload issue
From: Kalle Valo @ 2016-10-07 11:24 UTC (permalink / raw)
To: Jes Sorensen; +Cc: linux-wireless, Larry.Finger, stable, Jes Sorensen
In-Reply-To: <1475278518-18527-2-git-send-email-Jes.Sorensen@redhat.com>
Jes Sorensen <Jes.Sorensen@redhat.com> wrote:
> From: Jes Sorensen <Jes.Sorensen@redhat.com>
>
> The generic disable_rf() function clears bits 22 and 23 in
> REG_RX_WAIT_CCA, however we did not re-enable them again in
> rtl8723b_enable_rf()
>
> This resolves the problem for me with 8723bu devices not working again
> after reloading the driver.
>
> Signed-off-by: Jes Sorensen <Jes.Sorensen@redhat.com>
> Cc: stable@vger.kernel.org # 4.7+
2 patches applied to wireless-drivers.git, thanks.
ab05e5ec81c7 rtl8xxxu: Fix rtl8723bu driver reload issue
29d5e6fbd65b rtl8xxxu: Fix rtl8192eu driver reload issue
--
https://patchwork.kernel.org/patch/9359015/
Documentation about submitting wireless patches and checking status
from patchwork:
https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
^ permalink raw reply
* Re: [1/2] rtl8xxxu: Fix memory leak in handling rxdesc16 packets
From: Kalle Valo @ 2016-10-07 11:22 UTC (permalink / raw)
To: Jes Sorensen; +Cc: linux-wireless, Larry.Finger, stable, Jes Sorensen
In-Reply-To: <1475178055-16924-2-git-send-email-Jes.Sorensen@redhat.com>
Jes Sorensen <Jes.Sorensen@redhat.com> wrote:
> From: Jes Sorensen <Jes.Sorensen@redhat.com>
>
> A device running without RX package aggregation could return more data
> in the USB packet than the actual network packet. In this case we
> could would clone the skb but then determine that that there was no
> packet to handle and exit without freeing the cloned skb first.
>
> This has so far only been observed with 8188eu devices, but could
> affect others.
>
> Signed-off-by: Jes Sorensen <Jes.Sorensen@redhat.com>
> Cc: stable@vger.kernel.org # 4.8+
2 patches applied to wireless-drivers.git, thanks.
1e54134ccad0 rtl8xxxu: Fix memory leak in handling rxdesc16 packets
8a55698f2f29 rtl8xxxu: Fix big-endian problem reporting mactime
--
https://patchwork.kernel.org/patch/9356961/
Documentation about submitting wireless patches and checking status
from patchwork:
https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
^ permalink raw reply
* [PATCH 1/3] cfg80211: let ieee80211_amsdu_to_8023s() take only header-less SKB
From: Johannes Berg @ 2016-10-07 8:09 UTC (permalink / raw)
To: linux-wireless; +Cc: Johannes Berg
From: Johannes Berg <johannes.berg@intel.com>
There's only a single case where has_80211_header is passed as true,
which is in mac80211. Given that there's only simple code that needs
to be done before calling it, export that function from cfg80211
instead and let mac80211 call it itself.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
.../net/wireless/marvell/mwifiex/11n_rxreorder.c | 2 +-
include/net/cfg80211.h | 31 +++++++++++++++-------
net/mac80211/rx.c | 8 +++++-
net/wireless/util.c | 24 ++++-------------
4 files changed, 35 insertions(+), 30 deletions(-)
diff --git a/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c b/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c
index 94480123efa3..e9f462e3730b 100644
--- a/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c
+++ b/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c
@@ -45,7 +45,7 @@ static int mwifiex_11n_dispatch_amsdu_pkt(struct mwifiex_private *priv,
skb_trim(skb, le16_to_cpu(local_rx_pd->rx_pkt_length));
ieee80211_amsdu_to_8023s(skb, &list, priv->curr_addr,
- priv->wdev.iftype, 0, false);
+ priv->wdev.iftype, 0);
while (!skb_queue_empty(&list)) {
struct rx_packet_hdr *rx_hdr;
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index fe78f02a242e..f372eadd1963 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -4040,14 +4040,29 @@ unsigned int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr);
*/
/**
+ * ieee80211_data_to_8023_exthdr - convert an 802.11 data frame to 802.3
+ * @skb: the 802.11 data frame
+ * @ehdr: pointer to a &struct ethhdr that will get the header, instead
+ * of it being pushed into the SKB
+ * @addr: the device MAC address
+ * @iftype: the virtual interface type
+ * Return: 0 on success. Non-zero on error.
+ */
+int ieee80211_data_to_8023_exthdr(struct sk_buff *skb, struct ethhdr *ehdr,
+ const u8 *addr, enum nl80211_iftype iftype);
+
+/**
* ieee80211_data_to_8023 - convert an 802.11 data frame to 802.3
* @skb: the 802.11 data frame
* @addr: the device MAC address
* @iftype: the virtual interface type
* Return: 0 on success. Non-zero on error.
*/
-int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
- enum nl80211_iftype iftype);
+static inline int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
+ enum nl80211_iftype iftype)
+{
+ return ieee80211_data_to_8023_exthdr(skb, NULL, addr, iftype);
+}
/**
* ieee80211_data_from_8023 - convert an 802.3 frame to 802.11
@@ -4065,22 +4080,20 @@ int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr,
/**
* ieee80211_amsdu_to_8023s - decode an IEEE 802.11n A-MSDU frame
*
- * Decode an IEEE 802.11n A-MSDU frame and convert it to a list of
- * 802.3 frames. The @list will be empty if the decode fails. The
- * @skb is consumed after the function returns.
+ * Decode an IEEE 802.11 A-MSDU and convert it to a list of 802.3 frames.
+ * The @list will be empty if the decode fails. The @skb must be fully
+ * header-less before being passed in here; it is freed in this function.
*
- * @skb: The input IEEE 802.11n A-MSDU frame.
+ * @skb: The input A-MSDU frame without any headers.
* @list: The output list of 802.3 frames. It must be allocated and
* initialized by by the caller.
* @addr: The device MAC address.
* @iftype: The device interface type.
* @extra_headroom: The hardware extra headroom for SKBs in the @list.
- * @has_80211_header: Set it true if SKB is with IEEE 802.11 header.
*/
void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
const u8 *addr, enum nl80211_iftype iftype,
- const unsigned int extra_headroom,
- bool has_80211_header);
+ const unsigned int extra_headroom);
/**
* cfg80211_classify8021d - determine the 802.1p/1d tag for a data frame
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 3ac2f1cba317..de2d75fa5c51 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -2298,6 +2298,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
__le16 fc = hdr->frame_control;
struct sk_buff_head frame_list;
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
+ struct ethhdr ethhdr;
if (unlikely(!ieee80211_is_data(fc)))
return RX_CONTINUE;
@@ -2329,9 +2330,14 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
skb->dev = dev;
__skb_queue_head_init(&frame_list);
+ if (ieee80211_data_to_8023_exthdr(skb, ðhdr,
+ rx->sdata->vif.addr,
+ rx->sdata->vif.type))
+ return RX_DROP_UNUSABLE;
+
ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr,
rx->sdata->vif.type,
- rx->local->hw.extra_tx_headroom, true);
+ rx->local->hw.extra_tx_headroom);
while (!skb_queue_empty(&frame_list)) {
rx->skb = __skb_dequeue(&frame_list);
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 8edce22d1b93..e36ede840b88 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -420,8 +420,8 @@ unsigned int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr)
}
EXPORT_SYMBOL(ieee80211_get_mesh_hdrlen);
-static int __ieee80211_data_to_8023(struct sk_buff *skb, struct ethhdr *ehdr,
- const u8 *addr, enum nl80211_iftype iftype)
+int ieee80211_data_to_8023_exthdr(struct sk_buff *skb, struct ethhdr *ehdr,
+ const u8 *addr, enum nl80211_iftype iftype)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
struct {
@@ -525,13 +525,7 @@ static int __ieee80211_data_to_8023(struct sk_buff *skb, struct ethhdr *ehdr,
return 0;
}
-
-int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
- enum nl80211_iftype iftype)
-{
- return __ieee80211_data_to_8023(skb, NULL, addr, iftype);
-}
-EXPORT_SYMBOL(ieee80211_data_to_8023);
+EXPORT_SYMBOL(ieee80211_data_to_8023_exthdr);
int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr,
enum nl80211_iftype iftype,
@@ -745,25 +739,18 @@ __ieee80211_amsdu_copy(struct sk_buff *skb, unsigned int hlen,
void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
const u8 *addr, enum nl80211_iftype iftype,
- const unsigned int extra_headroom,
- bool has_80211_header)
+ const unsigned int extra_headroom)
{
unsigned int hlen = ALIGN(extra_headroom, 4);
struct sk_buff *frame = NULL;
u16 ethertype;
u8 *payload;
- int offset = 0, remaining, err;
+ int offset = 0, remaining;
struct ethhdr eth;
bool reuse_frag = skb->head_frag && !skb_has_frag_list(skb);
bool reuse_skb = false;
bool last = false;
- if (has_80211_header) {
- err = __ieee80211_data_to_8023(skb, ð, addr, iftype);
- if (err)
- goto out;
- }
-
while (!last) {
unsigned int subframe_len;
int len;
@@ -819,7 +806,6 @@ void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
purge:
__skb_queue_purge(list);
- out:
dev_kfree_skb(skb);
}
EXPORT_SYMBOL(ieee80211_amsdu_to_8023s);
--
2.8.1
^ permalink raw reply related
* [PATCH 3/3] mac80211: validate DA/SA during A-MSDU decapsulation
From: Johannes Berg @ 2016-10-07 8:09 UTC (permalink / raw)
To: linux-wireless; +Cc: Johannes Berg
In-Reply-To: <1475827779-29808-1-git-send-email-johannes@sipsolutions.net>
From: Johannes Berg <johannes.berg@intel.com>
As pointed out by Michael Braun, we don't check inner L2 addresses
during A-MSDU decapsulation, leading to the possibility that, for
example, a station associated to an AP sends frames as though they
came from somewhere else.
Fix this problem by letting cfg80211 validate the addresses, as
indicated by passing in the ones that need to be validated.
Reported-by: Michael Braun <michael-dev@fami-braun.de>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
net/mac80211/rx.c | 20 +++++++++++++++++++-
1 file changed, 19 insertions(+), 1 deletion(-)
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index cf53fe1a0aa2..a47bbc973f2d 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -2299,6 +2299,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
struct sk_buff_head frame_list;
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
struct ethhdr ethhdr;
+ const u8 *check_da = ethhdr.h_dest, *check_sa = ethhdr.h_source;
if (unlikely(!ieee80211_is_data(fc)))
return RX_CONTINUE;
@@ -2322,6 +2323,23 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
default:
return RX_DROP_UNUSABLE;
}
+ check_da = NULL;
+ check_sa = NULL;
+ } else switch (rx->sdata->vif.type) {
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_AP_VLAN:
+ check_da = NULL;
+ break;
+ case NL80211_IFTYPE_STATION:
+ if (!rx->sta ||
+ !test_sta_flag(rx->sta, WLAN_STA_TDLS_PEER))
+ check_sa = NULL;
+ break;
+ case NL80211_IFTYPE_MESH_POINT:
+ check_sa = NULL;
+ break;
+ default:
+ break;
}
if (is_multicast_ether_addr(hdr->addr1))
@@ -2338,7 +2356,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr,
rx->sdata->vif.type,
rx->local->hw.extra_tx_headroom,
- NULL, NULL);
+ check_da, check_sa);
while (!skb_queue_empty(&frame_list)) {
rx->skb = __skb_dequeue(&frame_list);
--
2.8.1
^ permalink raw reply related
* [PATCH 2/3] cfg80211: add ability to check DA/SA in A-MSDU decapsulation
From: Johannes Berg @ 2016-10-07 8:09 UTC (permalink / raw)
To: linux-wireless; +Cc: Johannes Berg
In-Reply-To: <1475827779-29808-1-git-send-email-johannes@sipsolutions.net>
From: Johannes Berg <johannes.berg@intel.com>
We should not accept arbitrary DA/SA inside A-MSDUs, it could be used
to circumvent protections, like allowing a station to send frames and
make them seem to come from somewhere else.
Add the necessary infrastructure in cfg80211 to allow such checks, in
further patches we'll start using them.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c | 2 +-
include/net/cfg80211.h | 5 ++++-
net/mac80211/rx.c | 3 ++-
net/wireless/util.c | 14 ++++++++++++--
4 files changed, 19 insertions(+), 5 deletions(-)
diff --git a/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c b/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c
index e9f462e3730b..274dd5a1574a 100644
--- a/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c
+++ b/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c
@@ -45,7 +45,7 @@ static int mwifiex_11n_dispatch_amsdu_pkt(struct mwifiex_private *priv,
skb_trim(skb, le16_to_cpu(local_rx_pd->rx_pkt_length));
ieee80211_amsdu_to_8023s(skb, &list, priv->curr_addr,
- priv->wdev.iftype, 0);
+ priv->wdev.iftype, 0, NULL, NULL);
while (!skb_queue_empty(&list)) {
struct rx_packet_hdr *rx_hdr;
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index f372eadd1963..7df600c463eb 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -4090,10 +4090,13 @@ int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr,
* @addr: The device MAC address.
* @iftype: The device interface type.
* @extra_headroom: The hardware extra headroom for SKBs in the @list.
+ * @check_da: DA to check in the inner ethernet header, or NULL
+ * @check_sa: SA to check in the inner ethernet header, or NULL
*/
void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
const u8 *addr, enum nl80211_iftype iftype,
- const unsigned int extra_headroom);
+ const unsigned int extra_headroom,
+ const u8 *check_da, const u8 *check_sa);
/**
* cfg80211_classify8021d - determine the 802.1p/1d tag for a data frame
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index de2d75fa5c51..cf53fe1a0aa2 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -2337,7 +2337,8 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr,
rx->sdata->vif.type,
- rx->local->hw.extra_tx_headroom);
+ rx->local->hw.extra_tx_headroom,
+ NULL, NULL);
while (!skb_queue_empty(&frame_list)) {
rx->skb = __skb_dequeue(&frame_list);
diff --git a/net/wireless/util.c b/net/wireless/util.c
index e36ede840b88..5ea12afc7706 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -739,7 +739,8 @@ __ieee80211_amsdu_copy(struct sk_buff *skb, unsigned int hlen,
void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
const u8 *addr, enum nl80211_iftype iftype,
- const unsigned int extra_headroom)
+ const unsigned int extra_headroom,
+ const u8 *check_da, const u8 *check_sa)
{
unsigned int hlen = ALIGN(extra_headroom, 4);
struct sk_buff *frame = NULL;
@@ -767,8 +768,17 @@ void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
goto purge;
offset += sizeof(struct ethhdr);
- /* reuse skb for the last subframe */
last = remaining <= subframe_len + padding;
+
+ /* FIXME: should we really accept multicast DA? */
+ if ((check_da && !is_multicast_ether_addr(eth.h_dest) &&
+ !ether_addr_equal(check_da, eth.h_dest)) ||
+ (check_sa && !ether_addr_equal(check_sa, eth.h_source))) {
+ offset += len + padding;
+ continue;
+ }
+
+ /* reuse skb for the last subframe */
if (!skb_is_nonlinear(skb) && !reuse_frag && last) {
skb_pull(skb, offset);
frame = skb;
--
2.8.1
^ permalink raw reply related
* Re: [PATCH v8] cfg80211: Provision to allow the support for different beacon intervals
From: Johannes Berg @ 2016-10-07 7:47 UTC (permalink / raw)
To: Kushwaha, Purushottam, Undekari, Sunil Dutt
Cc: linux-wireless@vger.kernel.org, Malinen, Jouni,
Hullur Subramanyam, Amarnath
In-Reply-To: <6c2abcf3f79b4cf6996b69e1a7aa590d@aphydexm01b.ap.qualcomm.com>
On Fri, 2016-10-07 at 07:42 +0000, Kushwaha, Purushottam wrote:
> >
> > However, it seems pretty easy to solve by passing another bool that
> > indicates "all the same"?
> Yes . Thanks .
> We are planning to get the following changes in 2 commits . Let me
> know your consent .
> 1. cfg80211: Provision to allow the support for different beacon
> intervals. ( Would like to go with this in a separate commit as the
> current infrastructure also does not support the validation of
> radar_detect / num_different_channel ) .
> 2. cfg80211 : Check radar_detect and num_different_channels with
> beacon interface combinations.
>
Seems fine, no driver will be able to advertise the different BIs
inbetween the two patches anyway.
I think we might want to add another patch before or inbetween, that
converts the far-too-long argument list of the combination
iter/validation functions to a structure?
johannes
^ permalink raw reply
* RE: [PATCH v8] cfg80211: Provision to allow the support for different beacon intervals
From: Kushwaha, Purushottam @ 2016-10-07 7:42 UTC (permalink / raw)
To: Johannes Berg, Undekari, Sunil Dutt
Cc: linux-wireless@vger.kernel.org, Malinen, Jouni,
Hullur Subramanyam, Amarnath
In-Reply-To: <1475061661.4139.40.camel@sipsolutions.net>
PiBIb3dldmVyLCBpdCBzZWVtcyBwcmV0dHkgZWFzeSB0byBzb2x2ZSBieSBwYXNzaW5nIGFub3Ro
ZXIgYm9vbCB0aGF0IGluZGljYXRlcyAiYWxsIHRoZSBzYW1lIj8NClllcyAuIFRoYW5rcyAuIA0K
V2UgYXJlIHBsYW5uaW5nIHRvIGdldCB0aGUgZm9sbG93aW5nIGNoYW5nZXMgaW4gMiBjb21taXRz
IC4gTGV0IG1lIGtub3cgeW91ciBjb25zZW50IC4gDQoxLiBjZmc4MDIxMTogUHJvdmlzaW9uIHRv
IGFsbG93IHRoZSBzdXBwb3J0IGZvciBkaWZmZXJlbnQgYmVhY29uIGludGVydmFscy4gKCBXb3Vs
ZCBsaWtlIHRvIGdvIHdpdGggdGhpcyBpbiBhIHNlcGFyYXRlIGNvbW1pdCBhcyB0aGUgY3VycmVu
dCBpbmZyYXN0cnVjdHVyZSBhbHNvIGRvZXMgbm90IHN1cHBvcnQgdGhlIHZhbGlkYXRpb24gb2Yg
cmFkYXJfZGV0ZWN0IC8gbnVtX2RpZmZlcmVudF9jaGFubmVsICkgLiANCjIuIGNmZzgwMjExIDog
Q2hlY2sgcmFkYXJfZGV0ZWN0IGFuZCBudW1fZGlmZmVyZW50X2NoYW5uZWxzIHdpdGggYmVhY29u
IGludGVyZmFjZSBjb21iaW5hdGlvbnMuDQoNClJlZ2FyZHMsDQpQdXJ1c2hvdHRhbQ0KDQoNCi0t
LS0tT3JpZ2luYWwgTWVzc2FnZS0tLS0tDQpGcm9tOiBKb2hhbm5lcyBCZXJnIFttYWlsdG86am9o
YW5uZXNAc2lwc29sdXRpb25zLm5ldF0gDQpTZW50OiBXZWRuZXNkYXksIFNlcHRlbWJlciAyOCwg
MjAxNiA0OjUxIFBNDQpUbzogVW5kZWthcmksIFN1bmlsIER1dHQgPHVzZHV0dEBxdGkucXVhbGNv
bW0uY29tPjsgS3VzaHdhaGEsIFB1cnVzaG90dGFtIDxwa3VzaHdhaEBxdGkucXVhbGNvbW0uY29t
Pg0KQ2M6IGxpbnV4LXdpcmVsZXNzQHZnZXIua2VybmVsLm9yZzsgTWFsaW5lbiwgSm91bmkgPGpv
dW5pQHFjYS5xdWFsY29tbS5jb20+OyBIdWxsdXIgU3VicmFtYW55YW0sIEFtYXJuYXRoIDxhbWFy
bmF0aEBxY2EucXVhbGNvbW0uY29tPg0KU3ViamVjdDogUmU6IFtQQVRDSCB2OF0gY2ZnODAyMTE6
IFByb3Zpc2lvbiB0byBhbGxvdyB0aGUgc3VwcG9ydCBmb3IgZGlmZmVyZW50IGJlYWNvbiBpbnRl
cnZhbHMNCg0KSGksDQoNCj4gSW4gUEFUQ0ggdjggLCBjZmc4MDIxMV92YWxpZGF0ZV9iZWFjb25f
aW50IC0+IA0KPiBjZmc4MDIxMV9pdGVyX2NvbWJpbmF0aW9ucyBjYXJyaWVzIHRoZSBhcmd1bWVu
dCBpZnR5cGVfbnVtICwgd2hpY2ggDQo+IGFsc28gY29uc2lkZXJzIHRoZSAibmV3IGludGVyZmFj
ZSIgdGhhdCBpcyBnZXR0aW5nIGFkZGVkLg0KDQpBaCwgcmlnaHQsIEkgcmVtZW1iZXIgbm93LCBz
b3JyeS4NCg0KPiBUaHVzICwgaW4gdGhlIGV4YW1wbGUgeW91IGhhdmUgcXVvdGVkIGFib3ZlICwg
dGhlIGlmdHlwZV9udW0gc2hhbGwgDQo+IHJlcHJlc2VudCAyICggQVAgKyBBUCApICwgYW5kIHRo
dXMgdGhlIG1pbl9nY2Qgb2J0YWluZWQgb3V0IG9mIA0KPiBjZmc4MDIxMV9pdGVyX2NvbWJpbmF0
aW9ucyAoY2ZnODAyMTFfZ2V0X2JlYWNvbl9pbnRfbWluX2djZCkgc2hhbGwgYmUNCj4gNTAgZm9y
IHRoZSBleGFtcGxlIDEgYW5kIDIwMCBmb3IgdGhlIGV4YW1wbGUgMiAuIFRodXMgLCBjb25zaWRl
cmluZyANCj4gdGhlIHR3byBleGFtcGxlcyBtZW50aW9uZWQgYWJvdmUgLCB0aGUgc2Vjb25kIEFQ
IHNob3VsZCBzdWNjZWVkIGZvciANCj4gImV4YW1wbGUgMSIgdnMgZmFpbHVyZSBmb3IgImV4YW1w
bGUgMiIgd2l0aCBwYXRjaA0KPiBWOCAsIGlzbid0ID8NCg0KWWVhaCwgSSB0cmllZCB0byBzaW1w
bGlmeSBhbmQgZGlkIHNvIHRvbyBtdWNoLiBJIGJlbGlldmUgeW91IGFyZSwgZm9yIHRoaXMgcHVy
cG9zZSwgaWdub3JpbmcgZm9yIGV4YW1wbGUgcmFkYXIgZGV0ZWN0aW9uLg0KDQpTaW5jZSB5b3Un
cmUgcGFzc2luZyAwIGZvciBudW1fZGlmZmVyZW50X2NoYW5uZWxzIGFuZCByYWRhcl9kZXRlY3Qs
IHlvdSBtaWdodCBmaW5kIGEgY29tYmluYXRpb24gaXNuJ3QgYWN0dWFsbHkgY3VycmVudGx5IHVz
YWJsZSwgYnV0IHRoYXQgYWxsb3dzIHRoZSBuZXcgYmVhY29uIGludGVydmFsIGNvbmZpZ3VyYXRp
b24uDQoNClNvIEkgdGhpbmsgb3ZlcmFsbCB0aGlzIHdpbGwgb25seSB3b3JrIHJpZ2h0IGlmIGl0
J3MgZG9uZSB3aXRoIGFsbCBuZWNlc3NhcnkgaW5mb3JtYXRpb24sIG5vPw0KDQpUcnlpbmcgdG8g
Y29uc3RydWN0IGFub3RoZXIgZXhhbXBsZSAuLi4gbGV0J3Mgc2F5IHBlcm1pdHRlZCBjb21iaW5h
dGlvbnMgYXJlDQoNCsKgKiBnbyA9IDMsIGNoYW5uZWxzID0gMSwgbWluX2Jjbl9nY2QgPSA1MA0K
wqAqIGdvID0gMywgY2hhbm5lbHMgPSAyLCBtaW5fYmNuX2djZCA9IDEwMA0KDQood2hpY2ggaXNu
J3QgYWN0dWFsbHkgYWxsIHRoYXQgZmFyLWZldGNoZWQsIHNpbmNlIGNoYW5uZWwgaG9wcGluZyB0
YWtlcw0KdGltZSkNCg0KRm9yIHNpbXBsaWZpY2F0aW9uLCBzYXkgeW91IGFscmVhZHkgaGF2ZSB0
d28gR09zIGFjdGl2ZSBvbiBkaWZmZXJlbnQgY2hhbm5lbHMgKHdpdGggQkkgMTAwKSwgYW5kIHdh
bnQgdG8gYWRkIGFub3RoZXIgb25lIC0gd2l0aCBiZWFjb24gaW50ZXJ2YWwgNTAgLSB0aGlzIGlz
bid0IHBvc3NpYmxlLCBidXQgSSBkb24ndCB0aGluayB5b3VyIGNvZGUgd291bGQgZGV0ZWN0IGl0
Pw0KDQpPciwgcGVyaGFwcyBJJ20gcmVhZGluZyB0aGlzIHdyb25nLCBpZiB5b3VyIGNvZGUgKmRv
ZXMqIGRldGVjdCBpdCB0aGVuIGNoYW5naW5nIHRoZSBzY2VuYXJpbyBhIGJpdCB0byBoYXZlIGp1
c3QgYSBzaW5nbGUgY2hhbm5lbCwgeW91ciBjb2RlIHdvdWxkIHByZXZlbnQgaXQgZXZlbiB0aG91
Z2ggaXQncyBhbGxvd2VkPw0KDQoNCj4gVGhlIGN1cnJlbnQgYmVoYXZpb3Igb2YgdGhlIGtlcm5l
bCBpcyB0byBub3QgYWxsb3cgdGhlIGNvbmZpZ3VyYXRpb24gDQo+IG9mIGRpZmZlcmVudCBiZWFj
b24gaW50ZXJ2YWxzIGFuZCBvdXIgZXhwZWN0YXRpb24gaXMgdGhhdCB0aGlzIG5ldyANCj4gcGF0
Y2ggc2hvdWxkIGJlIGJhY2t3YXJkIGNvbXBhdGlibGUgd2l0aCB0aGUgZXhpc3RpbmcgYmVoYXZp
b3IuDQoNCkNvcnJlY3QsIGFuZCBJIGFncmVlLCB3ZSBzaG91bGRuJ3QgYnJlYWsgdGhhdC4NCg0K
PiBOb3cgLCBpZiB3ZSBnbyB3aXRoIHRoaXMgYXBwcm9hY2ggb2YgImludHJvZHVjaW5nIGEgbmV3
IGFyZ3VtZW50IHRvIA0KPiBjZmc4MDIxMV9pdGVyX2NvbWJpbmF0aW9ucyB3aGljaCBzaGFsbCBi
ZSB0aGUgR0NEIG9mIGFsbCB0aGUgZXhpc3RpbmcgDQo+IGNvbWJpbmF0aW9ucyB0byBjaGVjayBh
Z2FpbnN0IHRoZSByZXNwZWN0aXZlIA0KPiAiZGlmZl9iZWFjb25faW50X2djZF9taW4iIiAswqDC
oGNvbnNpZGVyIHRoZSBjYXNlICggc2FtZSBvbmUgd2hpY2ggaXMgDQo+IG1lbnRpb25lZCBhYm92
ZSApIHRoYXQgd2UgaGF2ZSBhIHNpbmdsZSBBUCBpbnRlcmZhY2UgKCBiZWFjb24gaW50ZXJ2YWwg
DQo+ID0gMzAwICkgLCBhbmQgYSBuZXcgQVAgaXMgZ2V0dGluZyBhZGRlZCAoIGJlYWNvbiBpbnRl
cnZhbCA9DQo+IDE1MCApLMKgwqB3aXRoIHRoZSBmb2xsb3dpbmcgYWxsb3dlZCBjb21iaW5hdGlv
bnM6DQo+IA0KPiAxKSAqIGFwID0gMg0KPiDCoMKgwqDCoMKgwqDCoMKgZGlmZl9iZWFjb25faW50
X2djZF9taW4gPSAwICggcmF0aGVyIG5vdCBzcGVjaWZpZWQgKQ0KPiAyKcKgwqAqIGFwID0gMg0K
PiDCoMKgwqDCoMKgwqBkaWZmX2JlYWNvbl9pbnRfZ2NkX21pbiA9IDEwMA0KPiANCj4gVGhlIEdD
RCBjYWxjdWxhdGVkIGlzIDE1MCAuIGNmZzgwMjExX2l0ZXJfY29tYmluYXRpb25zIHNoYWxsIHJl
dHVybiANCj4gc3VjY2VzcyBmb3IgYm90aCB0aGUgc2NlbmFyaW9zICggMSBhbmQgMiApIChUaGUg
aW50ZW50aW9uIGhlcmUgaXMgdG8gDQo+IGNvbXBhcmUgd2l0aCBvbmx5IHRoZSBub256ZXJvICIg
ZGlmZl9iZWFjb25faW50X2djZF9taW4iICkNCj4gDQo+IFRoaXMgc3VjY2VzcyBmcm9tICJjZmc4
MDIxMV9pdGVyX2NvbWJpbmF0aW9ucyIgZG9lcyBub3QgcmVwcmVzZW50IGlmIA0KPiB0aGUgR0NE
IHBhc3NlZCBpcyBjb21wYXJlZCBhZ2FpbnN0IGEgMCAvIG5vbiB6ZXJvIA0KPiAiZGlmZl9iZWFj
b25faW50X2djZF9taW4iICwgaXNuJ3QgPw0KPiANCj4gVGh1cyAsIHdlIGFyZSB0cnlpbmcgdG8g
c29sdmUgdGhpcyBwcm9ibGVtICwgYnkgZ2V0dGluZyB0aGUgDQo+ICJkaWZmX2JlYWNvbl9pbnRf
Z2NkX21pbiIgZm9yIHRoZSByZXNwZWN0aXZlIGludGVyZmFjZSBjb21iaW5hdGlvbiAsIA0KPiBi
ZWZvcmUgY29tcGFyaW5nIGl0IHdpdGggdGhlIGNhbGN1bGF0ZWQgR0NELg0KDQpPaC4gSSB0aGlu
ayBJIGZpbmFsbHkgdW5kZXJzdGFuZCB5b3VyIGNvbmNlcm4gLSBnb29kIHBvaW50IQ0KDQpMZXQg
bWUgc2VlIGlmIEkgdW5kZXJzdGFuZCBjb3JyZWN0bHkgLSB5b3UncmUgc2F5aW5nIHRoYXQgaWYg
SSBmaXJzdCBjYWxjdWxhdGXCoA0KDQrCoCBnID0gR0NEKGFsbCBCSXMsIGluY2x1ZGluZyB0aGUg
bmV3IG9uZSkNCg0KYW5kIHRoZW4gZG8NCg0KwqAgY2ZnODAyMTFfaXRlcl9jb21iaW5hdGlvbnMo
Li4uIGV4aXN0aW5nIHZhcmlhYmxlcyAuLi4sIGcpDQoNCnRoZW4gSSBjYW5ub3QgYWNjdXJhdGVs
eSBkZXRlcm1pbmUgd2hldGhlciBvciBub3QgSSBjYW4gdXNlIGEgY29tYmluYXRpb24gdGhhdCBk
b2Vzbid0IHNwZWNpZnkgYSBtaW5fYmVhY29uX2ludGVydmFsX2djZCwgeW91IGNhbid0IGtub3cg
aWYgdGhlICJhbGwgQklzIiB3ZXJlIHRoZSBzYW1lLCBvciBub3QuDQoNClRoYXQncyBhY3R1YWxs
eSBhIHZlcnkgZ29vZCBwb2ludC4NCg0KSG93ZXZlciwgaXQgc2VlbXMgcHJldHR5IGVhc3kgdG8g
c29sdmUgYnkgcGFzc2luZyBhbm90aGVyIGJvb2wgdGhhdCBpbmRpY2F0ZXMgImFsbCB0aGUgc2Ft
ZSI/DQoNCmpvaGFubmVzDQo=
^ permalink raw reply
* Re: [PATCH] wl18xx: Handle kfree() in better way when kzalloc fails
From: souptick joarder @ 2016-10-07 7:29 UTC (permalink / raw)
To: Johannes Berg
Cc: Souptick Joarder, linux-wireless, Julian Calaby, Kalle Valo,
Rameshwar Sahu
In-Reply-To: <1475823963.2015.24.camel@sipsolutions.net>
On Fri, Oct 7, 2016 at 12:36 PM, Johannes Berg
<johannes@sipsolutions.net> wrote:
>
> On Fri, 2016-10-07 at 12:19 +0530, Souptick Joarder wrote:
> > This patch is added to handle kfree and return error in a better way
>
> What's "better" about this?
>
> kfree(NULL) is perfectly valid, adding another label makes the code
> harder to read,
I agree with you.
when kzalloc(sizeof(*cmd), GFP_KERNEL) fails, try to avoid extra
kfree(cmd_channel) function call,
cause anyway it will call kfree with NULL.
I thought from that point of view.
>
> > - struct wl18xx_cmd_scan_params *cmd;
> > + struct wl18xx_cmd_scan_params *cmd = NULL;
>
> that new initialization is actually *completely* pointless since it's
> overwritten immediately here:
>
> > struct wlcore_scan_channels *cmd_channels = NULL;
> > int ret;
> >
> > cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
> > if (!cmd) {
> > - ret = -ENOMEM;
> > - goto out;
> > + return -ENOMEM;
> > }
> >
> ...
>
> what gives?
>
> johannes
Ok, I will drop this patch.
-Souptick
^ permalink raw reply
* Re: [PATCH] wl18xx: Handle kfree() in better way when kzalloc fails
From: Johannes Berg @ 2016-10-07 7:06 UTC (permalink / raw)
To: Souptick Joarder, linux-wireless, Julian Calaby, Kalle Valo
Cc: Rameshwar Sahu
In-Reply-To: <20161007064923.GA3404@symbol-HP-ZBook-15>
On Fri, 2016-10-07 at 12:19 +0530, Souptick Joarder wrote:
> This patch is added to handle kfree and return error in a better way
What's "better" about this?
kfree(NULL) is perfectly valid, adding another label makes the code
harder to read,
> - struct wl18xx_cmd_scan_params *cmd;
> + struct wl18xx_cmd_scan_params *cmd = NULL;
that new initialization is actually *completely* pointless since it's
overwritten immediately here:
> struct wlcore_scan_channels *cmd_channels = NULL;
> int ret;
>
> cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
> if (!cmd) {
> - ret = -ENOMEM;
> - goto out;
> + return -ENOMEM;
> }
>
...
what gives?
johannes
^ permalink raw reply
* [PATCH] wl18xx: Handle kfree() in better way when kzalloc fails
From: Souptick Joarder @ 2016-10-07 6:49 UTC (permalink / raw)
To: linux-wireless, Julian Calaby, Kalle Valo; +Cc: Rameshwar Sahu
This patch is added to handle kfree and return error in a better way
if kzalloc fails in wl18xx_scan_send() and wl18xx_scan_sched_scan_config().
Signed-off-by: Souptick joarder <jrdr.linux@gmail.com>
---
drivers/net/wireless/ti/wl18xx/scan.c | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/drivers/net/wireless/ti/wl18xx/scan.c b/drivers/net/wireless/ti/wl18xx/scan.c
index 4e522154..aed22e1 100644
--- a/drivers/net/wireless/ti/wl18xx/scan.c
+++ b/drivers/net/wireless/ti/wl18xx/scan.c
@@ -41,14 +41,13 @@ static void wl18xx_adjust_channels(struct wl18xx_cmd_scan_params *cmd,
static int wl18xx_scan_send(struct wl1271 *wl, struct wl12xx_vif *wlvif,
struct cfg80211_scan_request *req)
{
- struct wl18xx_cmd_scan_params *cmd;
+ struct wl18xx_cmd_scan_params *cmd = NULL;
struct wlcore_scan_channels *cmd_channels = NULL;
int ret;
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) {
- ret = -ENOMEM;
- goto out;
+ return -ENOMEM;
}
/* scan on the dev role if the regular one is not started */
@@ -59,7 +58,7 @@ static int wl18xx_scan_send(struct wl1271 *wl, struct wl12xx_vif *wlvif,
if (WARN_ON(cmd->role_id == WL12XX_INVALID_ROLE_ID)) {
ret = -EINVAL;
- goto out;
+ goto err_cmd_free;
}
cmd->scan_type = SCAN_TYPE_SEARCH;
@@ -84,7 +83,7 @@ static int wl18xx_scan_send(struct wl1271 *wl, struct wl12xx_vif *wlvif,
cmd_channels = kzalloc(sizeof(*cmd_channels), GFP_KERNEL);
if (!cmd_channels) {
ret = -ENOMEM;
- goto out;
+ goto err_cmd_free;
}
wlcore_set_scan_chan_params(wl, cmd_channels, req->channels,
@@ -153,6 +152,7 @@ static int wl18xx_scan_send(struct wl1271 *wl, struct wl12xx_vif *wlvif,
out:
kfree(cmd_channels);
+err_cmd_free:
kfree(cmd);
return ret;
}
@@ -171,7 +171,7 @@ int wl18xx_scan_sched_scan_config(struct wl1271 *wl,
struct cfg80211_sched_scan_request *req,
struct ieee80211_scan_ies *ies)
{
- struct wl18xx_cmd_scan_params *cmd;
+ struct wl18xx_cmd_scan_params *cmd = NULL;
struct wlcore_scan_channels *cmd_channels = NULL;
struct conf_sched_scan_settings *c = &wl->conf.sched_scan;
int ret;
@@ -185,15 +185,14 @@ int wl18xx_scan_sched_scan_config(struct wl1271 *wl,
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) {
- ret = -ENOMEM;
- goto out;
+ return -ENOMEM;
}
cmd->role_id = wlvif->role_id;
if (WARN_ON(cmd->role_id == WL12XX_INVALID_ROLE_ID)) {
ret = -EINVAL;
- goto out;
+ goto err_cmd_free;
}
cmd->scan_type = SCAN_TYPE_PERIODIC;
@@ -218,7 +217,7 @@ int wl18xx_scan_sched_scan_config(struct wl1271 *wl,
cmd_channels = kzalloc(sizeof(*cmd_channels), GFP_KERNEL);
if (!cmd_channels) {
ret = -ENOMEM;
- goto out;
+ goto err_cmd_free;
}
/* configure channels */
@@ -296,6 +295,7 @@ int wl18xx_scan_sched_scan_config(struct wl1271 *wl,
out:
kfree(cmd_channels);
+err_cmd_free:
kfree(cmd);
return ret;
}
--
1.9.1
^ permalink raw reply related
* Re: [PATCH] [wl18xx] Fix memory leakage if kzalloc fails
From: Kalle Valo @ 2016-10-07 4:50 UTC (permalink / raw)
To: Souptick Joarder; +Cc: Julian Calaby, linux-wireless, Rameshwar Sahu
In-Reply-To: <CAFqt6zYpMJKrX51--eHXKSEcgb+KVJ7ULjoL==DNKyOeOB5_4Q@mail.gmail.com>
Souptick Joarder <jrdr.linux@gmail.com> writes:
> Hi Julian,
>
>
> On Thu, Oct 6, 2016 at 3:05 PM, Julian Calaby <julian.calaby@gmail.com> wrote:
>> Hi,
>>
>> On Wed, Oct 5, 2016 at 10:50 PM, Souptick Joarder <jrdr.linux@gmail.com> wrote:
>>> This patch is added to properly handle memory leak if kzalloc fails
>>> in wl18xx_scan_send() and wl18xx_scan_sched_scan_config()
>>
>> What memory leak?
>
> My Apologies here. I was addressing here about freeing the invalid memories.
> But I put wrong description. I will resend this patch with proper
> descriptions and addressing your comments.
Also the prefix in the title should be "wl18xx: ", not "[wl18xx]". See:
https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches#subject_name
--
Kalle Valo
^ permalink raw reply
* Non-fatal errors when disabling WiFi - Intel 7260
From: Gabriele Mazzotta @ 2016-10-07 0:16 UTC (permalink / raw)
To: johannes.berg; +Cc: emmanuel.grumbach, luciano.coelho, linux-wireless
Hi,
since commit b7a08b284dcf ("iwlwifi: pcie: extend device reset delay")
I get the following errors when I disable the WiFi:
[ 66.702845] iwlwifi 0000:02:00.0: RF_KILL bit toggled to disable radio.
[ 66.737893] iwlwifi 0000:02:00.0: Failed to wake NIC for hcmd
[ 66.737927] iwlwifi 0000:02:00.0: Error sending TXPATH_FLUSH: enqueue_hcmd failed: -5
[ 66.737933] iwlwifi 0000:02:00.0: Failed to send flush command (-5)
[ 66.772678] iwlwifi 0000:02:00.0: Failed to wake NIC for hcmd
[ 66.772698] iwlwifi 0000:02:00.0: Error sending REMOVE_STA: enqueue_hcmd failed: -5
[ 66.772699] iwlwifi 0000:02:00.0: Failed to remove station. Id=2
[ 66.772701] iwlwifi 0000:02:00.0: Failed sending remove station
[ 66.807518] iwlwifi 0000:02:00.0: Failed to wake NIC for hcmd
[ 66.807531] iwlwifi 0000:02:00.0: Error sending BINDING_CONTEXT_CMD: enqueue_hcmd failed: -5
[ 66.807533] iwlwifi 0000:02:00.0: Failed to send binding (action:3): -5
[ 66.842413] iwlwifi 0000:02:00.0: Failed to wake NIC for hcmd
[ 66.842430] iwlwifi 0000:02:00.0: Error sending MAC_PM_POWER_TABLE: enqueue_hcmd failed: -5
[ 66.877120] iwlwifi 0000:02:00.0: Failed to wake NIC for hcmd
[ 66.877150] iwlwifi 0000:02:00.0: Error sending MAC_CONTEXT_CMD: enqueue_hcmd failed: -5
[ 66.877153] iwlwifi 0000:02:00.0: Failed to remove MAC context: -5
[ 66.911995] iwlwifi 0000:02:00.0: Failed to wake NIC for hcmd
[ 66.912015] iwlwifi 0000:02:00.0: Error sending SCD_QUEUE_CFG: enqueue_hcmd failed: -5
[ 66.912019] iwlwifi 0000:02:00.0: Failed to disable queue 8 (ret=-5)
[ 66.947134] iwlwifi 0000:02:00.0: Failed to wake NIC for hcmd
[ 66.947163] iwlwifi 0000:02:00.0: Error sending TXPATH_FLUSH: enqueue_hcmd failed: -5
[ 66.947165] iwlwifi 0000:02:00.0: Failed to send flush command (-5)
Other than these, there seems to be no noticeable issue, I can
re-enable the WiFi and use it normally.
Reverting the commit on top of 4.8 get rids of the errors.
My laptop has an Intel Corporation Wireless 7260 (rev 6b),
the firmware currently used is 17.352738.0.
Regards,
Gabriele
^ permalink raw reply
* Re: [PATCH] ath10k: cache calibration data when the core is stopped.
From: Marty Faltesek @ 2016-10-06 20:29 UTC (permalink / raw)
To: Valo, Kalle; +Cc: ath10k@lists.infradead.org, linux-wireless@vger.kernel.org
In-Reply-To: <87r37ukjr5.fsf@kamboji.qca.qualcomm.com>
OK the v2 patch is not based on 9340953. If you queue this in 4.10 as
planned then just let me know and
I'll rev v3 based on top of 9340953.
On Thu, Oct 6, 2016 at 3:40 AM, Valo, Kalle <kvalo@qca.qualcomm.com> wrote:
> Marty Faltesek <mfaltesek@google.com> writes:
>
>> On Mon, Oct 3, 2016 at 3:46 AM, Valo, Kalle <kvalo@qca.qualcomm.com> wrote:
>>> Marty Faltesek <mfaltesek@google.com> writes:
>>>
>>>> Caching calibration data allows it to be accessed when the
>>>> device is not active.
>>>>
>>>> Signed-off-by: Marty Faltesek <mfaltesek@google.com>
>>>
>>> No comma in the title, please.
>>>
>>> What tree did you use as the baseline? This doesn't seem to apply to
>>> ath.git:
>>
>> We use backports 20160122 which has not been updated since earlier this year.
>> I can forward port it to your tree, and make sure
>> it builds but won't be able to test it. Will that be OK?
>
> Sure, I can test it.
>
>>> Also please note that this patch (which I'm queuing to 4.9) touches the
>>> same area:
>>>
>>> ath10k: fix debug cal data file
>>>
>>> https://patchwork.kernel.org/patch/9340953/
>>
>> I've modified this too, and this won't be necessary, so can you drop
>> it? If not, let me know and I'll pull it in and make sure I'm based
>> off it too.
>
> Actually I was first planning to push 9340953 to 4.9 and take your patch
> to 4.10. But your patch is a cleaner approach to this and maybe I should
> push that to 4.9 instead? Need to think a bit more.
>
> --
> Kalle Valo
^ permalink raw reply
* Re: [PATCH] [wl18xx] Fix memory leakage if kzalloc fails
From: Souptick Joarder @ 2016-10-06 18:51 UTC (permalink / raw)
To: Julian Calaby; +Cc: linux-wireless, Rameshwar Sahu
In-Reply-To: <CAGRGNgWCxLUz0=EUgtNQ5pLo2wCEpsMeNQHYCpKfh12irp6NDg@mail.gmail.com>
Hi Julian,
On Thu, Oct 6, 2016 at 3:05 PM, Julian Calaby <julian.calaby@gmail.com> wrote:
> Hi,
>
> On Wed, Oct 5, 2016 at 10:50 PM, Souptick Joarder <jrdr.linux@gmail.com> wrote:
>> This patch is added to properly handle memory leak if kzalloc fails
>> in wl18xx_scan_send() and wl18xx_scan_sched_scan_config()
>
> What memory leak?
My Apologies here. I was addressing here about freeing the invalid memories.
But I put wrong description. I will resend this patch with proper
descriptions and addressing your comments.
>
>> Signed-off-by: Souptick Joarder <jrdr.linux@gmail.com>
>> Signed-off-by: Rameshwar Sahu <sahu.rameshwar73@gmail.com>
>
> Why two signed-off-bys?
We both were involved in addressing this.
>
>> ---
>> drivers/net/wireless/ti/wl18xx/scan.c | 20 ++++++++++----------
>> 1 file changed, 10 insertions(+), 10 deletions(-)
>>
>> diff --git a/drivers/net/wireless/ti/wl18xx/scan.c b/drivers/net/wireless/ti/wl18xx/scan.c
>> index 4e522154..aed22e1 100644
>> --- a/drivers/net/wireless/ti/wl18xx/scan.c
>> +++ b/drivers/net/wireless/ti/wl18xx/scan.c
>> @@ -41,14 +41,13 @@ static void wl18xx_adjust_channels(struct wl18xx_cmd_scan_params *cmd,
>> static int wl18xx_scan_send(struct wl1271 *wl, struct wl12xx_vif *wlvif,
>> struct cfg80211_scan_request *req)
>> {
>> - struct wl18xx_cmd_scan_params *cmd;
>> + struct wl18xx_cmd_scan_params *cmd = NULL;
>> struct wlcore_scan_channels *cmd_channels = NULL;
>> int ret;
>>
>> cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
>> if (!cmd) {
>> - ret = -ENOMEM;
>> - goto out;
>> + return -ENOMEM;
>> }
>>
>> /* scan on the dev role if the regular one is not started */
>> @@ -59,7 +58,7 @@ static int wl18xx_scan_send(struct wl1271 *wl, struct wl12xx_vif *wlvif,
>>
>> if (WARN_ON(cmd->role_id == WL12XX_INVALID_ROLE_ID)) {
>> ret = -EINVAL;
>> - goto out;
>> + goto err_cmd_free;
>> }
>>
>> cmd->scan_type = SCAN_TYPE_SEARCH;
>> @@ -84,7 +83,7 @@ static int wl18xx_scan_send(struct wl1271 *wl, struct wl12xx_vif *wlvif,
>> cmd_channels = kzalloc(sizeof(*cmd_channels), GFP_KERNEL);
>> if (!cmd_channels) {
>> ret = -ENOMEM;
>> - goto out;
>> + goto err_cmd_free;
>> }
>>
>> wlcore_set_scan_chan_params(wl, cmd_channels, req->channels,
>> @@ -153,6 +152,7 @@ static int wl18xx_scan_send(struct wl1271 *wl, struct wl12xx_vif *wlvif,
>>
>> out:
>> kfree(cmd_channels);
>> +err_cmd_free:
>
> kfree(NULL) is valid,
I agree with you. As *cmd not initialized with NULL, so it can hold a
garbage address.
In case of memory allocation failure, kernel may enter in abnormal
behavior while freeing this memory.
so therefore the out: and err_cmd_free: labels
> are equivalent from a memory freeing perspective, so where exactly are
> we leaking memory in this function?
I want to avoid kfree(cmd_channels) calls when we have not allocated the memory.
>
>> kfree(cmd);
>> return ret;
>> }
>> @@ -171,7 +171,7 @@ int wl18xx_scan_sched_scan_config(struct wl1271 *wl,
>> struct cfg80211_sched_scan_request *req,
>> struct ieee80211_scan_ies *ies)
>> {
>> - struct wl18xx_cmd_scan_params *cmd;
>> + struct wl18xx_cmd_scan_params *cmd = NULL;
>> struct wlcore_scan_channels *cmd_channels = NULL;
>> struct conf_sched_scan_settings *c = &wl->conf.sched_scan;
>> int ret;
>> @@ -185,15 +185,14 @@ int wl18xx_scan_sched_scan_config(struct wl1271 *wl,
>>
>> cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
>> if (!cmd) {
>> - ret = -ENOMEM;
>> - goto out;
>> + return -ENOMEM;
>> }
>>
>> cmd->role_id = wlvif->role_id;
>>
>> if (WARN_ON(cmd->role_id == WL12XX_INVALID_ROLE_ID)) {
>> ret = -EINVAL;
>> - goto out;
>> + goto err_cmd_free;
>> }
>>
>> cmd->scan_type = SCAN_TYPE_PERIODIC;
>> @@ -218,7 +217,7 @@ int wl18xx_scan_sched_scan_config(struct wl1271 *wl,
>> cmd_channels = kzalloc(sizeof(*cmd_channels), GFP_KERNEL);
>> if (!cmd_channels) {
>> ret = -ENOMEM;
>> - goto out;
>> + goto err_cmd_free;
>> }
>>
>> /* configure channels */
>> @@ -296,6 +295,7 @@ int wl18xx_scan_sched_scan_config(struct wl1271 *wl,
>>
>> out:
>> kfree(cmd_channels);
>> +err_cmd_free:
>
> Same question here.
Please refer above comment for the same.
>
>> kfree(cmd);
>> return ret;
>> }
>> --
>> 1.9.1
>>
>
>
>
> --
> Julian Calaby
>
> Email: julian.calaby@gmail.com
> Profile: http://www.google.com/profiles/julian.calaby/
^ permalink raw reply
* [PATCH v4 3/3] mwifiex: check hw_status in suspend and resume handlers
From: Amitkumar Karwar @ 2016-10-06 18:06 UTC (permalink / raw)
To: linux-wireless
Cc: Cathy Luo, Nishant Sarmukadam, rajatja, briannorris,
Amitkumar Karwar
In-Reply-To: <1475777186-20486-1-git-send-email-akarwar@marvell.com>
We have observed a kernel crash when system immediately suspends
after booting. There is a race between suspend and driver initialization
paths. This patch adds hw_status checks in suspend/resume to fix this issue
and other corner cases.
Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
---
v2: Return failure in suspend/resume handler in this scenario.
v3: Handle "hw_status" not READY cases carefully. Return 0 if
init or shutdown is in progress. Return -EBUSY if firmware download
failed or command timeout ocurred(non-recoverable). (Brian Norris)
v4: In resume, we need not return failure.
---
drivers/net/wireless/marvell/mwifiex/pcie.c | 19 +++++++++++++++----
1 file changed, 15 insertions(+), 4 deletions(-)
diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c
index 1e27dbf..e7c6980 100644
--- a/drivers/net/wireless/marvell/mwifiex/pcie.c
+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c
@@ -121,13 +121,22 @@ static int mwifiex_pcie_suspend(struct device *dev)
struct pci_dev *pdev = to_pci_dev(dev);
card = pci_get_drvdata(pdev);
- if (!card || !card->adapter) {
- pr_err("Card or adapter structure is not valid\n");
+ if (!card || !card->adapter ||
+ card->adapter->hw_status == MWIFIEX_HW_STATUS_RESET ||
+ card->adapter->hw_status == MWIFIEX_HW_STATUS_NOT_READY) {
+ pr_err("Card or adapter structure is not valid or hw_status shows failure\n");
return 0;
}
adapter = card->adapter;
+ if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING ||
+ adapter->hw_status == MWIFIEX_HW_STATUS_INIT_DONE ||
+ adapter->hw_status == MWIFIEX_HW_STATUS_CLOSING) {
+ pr_err("We are in the middle of initialzaion or closing\n");
+ return -EBUSY;
+ }
+
/* Enable the Host Sleep */
if (!mwifiex_enable_hs(adapter)) {
mwifiex_dbg(adapter, ERROR,
@@ -160,8 +169,10 @@ static int mwifiex_pcie_resume(struct device *dev)
struct pci_dev *pdev = to_pci_dev(dev);
card = pci_get_drvdata(pdev);
- if (!card || !card->adapter) {
- pr_err("Card or adapter structure is not valid\n");
+
+ if (!card || !card->adapter ||
+ card->adapter->hw_status != MWIFIEX_HW_STATUS_READY) {
+ pr_err("Card or adapter structure is not valid or hw_status is not ready\n");
return 0;
}
--
1.9.1
^ permalink raw reply related
* [PATCH v4 2/3] mwifiex: remove redundant pdev check in suspend/resume handlers
From: Amitkumar Karwar @ 2016-10-06 18:06 UTC (permalink / raw)
To: linux-wireless
Cc: Cathy Luo, Nishant Sarmukadam, rajatja, briannorris,
Amitkumar Karwar
In-Reply-To: <1475777186-20486-1-git-send-email-akarwar@marvell.com>
to_pci_dev() would just do struct offset arithmetic on struct
device to get 'pdev' pointer. We never get NULL pdev pointer
Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
---
New patch introduced in v3 as per inputs from Brian Norris.
v4: Same as v3
---
drivers/net/wireless/marvell/mwifiex/pcie.c | 22 ++++++----------------
1 file changed, 6 insertions(+), 16 deletions(-)
diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c
index ba9e068..1e27dbf 100644
--- a/drivers/net/wireless/marvell/mwifiex/pcie.c
+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c
@@ -120,14 +120,9 @@ static int mwifiex_pcie_suspend(struct device *dev)
struct pcie_service_card *card;
struct pci_dev *pdev = to_pci_dev(dev);
- if (pdev) {
- card = pci_get_drvdata(pdev);
- if (!card || !card->adapter) {
- pr_err("Card or adapter structure is not valid\n");
- return 0;
- }
- } else {
- pr_err("PCIE device is not specified\n");
+ card = pci_get_drvdata(pdev);
+ if (!card || !card->adapter) {
+ pr_err("Card or adapter structure is not valid\n");
return 0;
}
@@ -164,14 +159,9 @@ static int mwifiex_pcie_resume(struct device *dev)
struct pcie_service_card *card;
struct pci_dev *pdev = to_pci_dev(dev);
- if (pdev) {
- card = pci_get_drvdata(pdev);
- if (!card || !card->adapter) {
- pr_err("Card or adapter structure is not valid\n");
- return 0;
- }
- } else {
- pr_err("PCIE device is not specified\n");
+ card = pci_get_drvdata(pdev);
+ if (!card || !card->adapter) {
+ pr_err("Card or adapter structure is not valid\n");
return 0;
}
--
1.9.1
^ permalink raw reply related
* [PATCH v4 1/3] mwifiex: reset card->adapter during device unregister
From: Amitkumar Karwar @ 2016-10-06 18:06 UTC (permalink / raw)
To: linux-wireless
Cc: Cathy Luo, Nishant Sarmukadam, rajatja, briannorris, Xinming Hu,
Amitkumar Karwar
From: Xinming Hu <huxm@marvell.com>
card->adapter gets initialized during device registration.
As it's not cleared, we may end up accessing invalid memory
in some corner cases. This patch fixes the problem.
Signed-off-by: Xinming Hu <huxm@marvell.com>
Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
---
v4: Same as v1, v2, v3
---
drivers/net/wireless/marvell/mwifiex/pcie.c | 1 +
drivers/net/wireless/marvell/mwifiex/sdio.c | 1 +
2 files changed, 2 insertions(+)
diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c
index f1eeb73..ba9e068 100644
--- a/drivers/net/wireless/marvell/mwifiex/pcie.c
+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c
@@ -3042,6 +3042,7 @@ static void mwifiex_unregister_dev(struct mwifiex_adapter *adapter)
pci_disable_msi(pdev);
}
}
+ card->adapter = NULL;
}
/* This function initializes the PCI-E host memory space, WCB rings, etc.
diff --git a/drivers/net/wireless/marvell/mwifiex/sdio.c b/drivers/net/wireless/marvell/mwifiex/sdio.c
index 8718950..4cad1c2 100644
--- a/drivers/net/wireless/marvell/mwifiex/sdio.c
+++ b/drivers/net/wireless/marvell/mwifiex/sdio.c
@@ -2066,6 +2066,7 @@ mwifiex_unregister_dev(struct mwifiex_adapter *adapter)
struct sdio_mmc_card *card = adapter->card;
if (adapter->card) {
+ card->adapter = NULL;
sdio_claim_host(card->func);
sdio_disable_func(card->func);
sdio_release_host(card->func);
--
1.9.1
^ permalink raw reply related
* [PATCH v3 3/3] mwifiex: check hw_status in suspend and resume handlers
From: Amitkumar Karwar @ 2016-10-06 17:30 UTC (permalink / raw)
To: linux-wireless
Cc: Cathy Luo, Nishant Sarmukadam, rajatja, briannorris,
Amitkumar Karwar
In-Reply-To: <1475775028-20306-1-git-send-email-akarwar@marvell.com>
We have observed a kernel crash when system immediately suspends
after booting. There is a race between suspend and driver initialization
paths. This patch adds hw_status checks in suspend/resume to fix this issue
and other corner cases.
Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
---
v2: Return failure in suspend/resume handler in this scenario.
v3: Handle "hw_status" not READY cases carefully. Return 0 if
init or shutdown is in progress. Return -EBUSY if firmware download
failed or command timeout ocurred(non-recoverable). (Brian Norris)
---
drivers/net/wireless/marvell/mwifiex/pcie.c | 27 +++++++++++++++++++++++----
1 file changed, 23 insertions(+), 4 deletions(-)
diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c
index 1e27dbf..cc18e4d 100644
--- a/drivers/net/wireless/marvell/mwifiex/pcie.c
+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c
@@ -121,13 +121,22 @@ static int mwifiex_pcie_suspend(struct device *dev)
struct pci_dev *pdev = to_pci_dev(dev);
card = pci_get_drvdata(pdev);
- if (!card || !card->adapter) {
- pr_err("Card or adapter structure is not valid\n");
+ if (!card || !card->adapter ||
+ card->adapter->hw_status == MWIFIEX_HW_STATUS_RESET ||
+ card->adapter->hw_status == MWIFIEX_HW_STATUS_NOT_READY) {
+ pr_err("Card or adapter structure is not valid or hw_status not ready\n");
return 0;
}
adapter = card->adapter;
+ if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING ||
+ adapter->hw_status == MWIFIEX_HW_STATUS_INIT_DONE ||
+ adapter->hw_status == MWIFIEX_HW_STATUS_CLOSING) {
+ pr_err("We are in the middle of initialzaion or closing\n");
+ return -EBUSY;
+ }
+
/* Enable the Host Sleep */
if (!mwifiex_enable_hs(adapter)) {
mwifiex_dbg(adapter, ERROR,
@@ -160,13 +169,23 @@ static int mwifiex_pcie_resume(struct device *dev)
struct pci_dev *pdev = to_pci_dev(dev);
card = pci_get_drvdata(pdev);
- if (!card || !card->adapter) {
- pr_err("Card or adapter structure is not valid\n");
+
+ if (!card || !card->adapter ||
+ card->adapter->hw_status == MWIFIEX_HW_STATUS_RESET ||
+ card->adapter->hw_status == MWIFIEX_HW_STATUS_NOT_READY) {
+ pr_err("Card or adapter structure is not valid or hw_status not ready\n");
return 0;
}
adapter = card->adapter;
+ if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING ||
+ adapter->hw_status == MWIFIEX_HW_STATUS_INIT_DONE ||
+ adapter->hw_status == MWIFIEX_HW_STATUS_CLOSING) {
+ pr_err("We are in the middle of initialzaion or closing\n");
+ return -EBUSY;
+ }
+
if (!adapter->is_suspended) {
mwifiex_dbg(adapter, WARN,
"Device already resumed\n");
--
1.9.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox