From e133fae263090f5795b8024a4024b81e06770132 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 22 Aug 2013 08:36:41 +0200 Subject: mac80211: minstrel_ht: don't use control.flags in TX status path Sujith reports that my commit af61a165187bb94b1dc7628ef815c23d0eacf40b ("mac80211: add control port protocol TX control flag") broke ath9k (aggregation). The reason is that I made minstrel_ht use the flag in the TX status path, where it can have been overwritten by the driver. Since we have no more space in info->flags, revert that part of the change for now, until we can reshuffle the flags or so. Reported-by: Sujith Manoharan Signed-off-by: Johannes Berg diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index 9eff382..c397ff5 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c @@ -439,13 +439,12 @@ minstrel_aggr_check(struct ieee80211_sta *pubsta, struct sk_buff *skb) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct sta_info *sta = container_of(pubsta, struct sta_info, sta); - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); u16 tid; if (unlikely(!ieee80211_is_data_qos(hdr->frame_control))) return; - if (unlikely(info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO)) + if (unlikely(skb->protocol == cpu_to_be16(ETH_P_PAE))) return; tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; -- cgit v0.10.2 From 1fb9026000e66ffe032b11ec724c1bc7d068198e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 21 Aug 2013 11:24:01 +0200 Subject: mac80211: move setting WIPHY_FLAG_SUPPORTS_SCHED_SCAN into drivers mac80211 currently sets WIPHY_FLAG_SUPPORTS_SCHED_SCAN based on whether the start_sched_scan operation is supported or not, but that will not be correct for all drivers, we're adding scheduled scan to the iwlmvm driver but it depends on firmware support. Therefore, move setting WIPHY_FLAG_SUPPORTS_SCHED_SCAN into the drivers so that they can control it regardless of implementing the operation. This currently only affects the TI drivers since they're the only ones implementing scheduled scan (in a mac80211 driver.) Acked-by: Luciano Coelho Signed-off-by: Johannes Berg diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index d1b19c3..38995f9 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -5623,7 +5623,8 @@ static int wl1271_init_ieee80211(struct wl1271 *wl) wl->hw->wiphy->max_remain_on_channel_duration = 5000; wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD | - WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; + WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | + WIPHY_FLAG_SUPPORTS_SCHED_SCAN; /* make sure all our channels fit in the scanned_ch bitmask */ BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) + diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 25eb35b..21d5d44 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -892,9 +892,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) if (!local->ops->remain_on_channel) local->hw.wiphy->max_remain_on_channel_duration = 5000; - if (local->ops->sched_scan_start) - local->hw.wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; - /* mac80211 based drivers don't support internal TDLS setup */ if (local->hw.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) local->hw.wiphy->flags |= WIPHY_FLAG_TDLS_EXTERNAL_SETUP; -- cgit v0.10.2 From a4ef66a915b957416a89a48365aea2ec2dc551f6 Mon Sep 17 00:00:00 2001 From: Chun-Yeow Yeoh Date: Thu, 22 Aug 2013 10:28:58 -0700 Subject: mac80211: only respond to probe request with mesh ID Previously, the mesh STA responds to probe request from legacy STA but now it will only respond to legacy STA if the legacy STA does include the specific mesh ID or wildcard mesh ID in the probe request. The iw patch "iw: scan using meshid" can be used either by legacy STA or by mesh STA to do active scanning by inserting the mesh ID in the probe request frame. Signed-off-by: Chun-Yeow Yeoh Acked-by: Thomas Pedersen Acked-by: Javier Cardona Signed-off-by: Johannes Berg diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 885a5f6..707ac61 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -832,6 +832,9 @@ ieee80211_mesh_rx_probe_req(struct ieee80211_sub_if_data *sdata, ieee802_11_parse_elems(pos, len - baselen, false, &elems); + if (!elems.mesh_id) + return; + /* 802.11-2012 10.1.4.3.2 */ if ((!ether_addr_equal(mgmt->da, sdata->vif.addr) && !is_broadcast_ether_addr(mgmt->da)) || -- cgit v0.10.2 From c4c205f3cd17b567b8e20098522416eac2e73960 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Fri, 23 Aug 2013 09:35:38 -0400 Subject: mac80211: assign seqnums for group QoS frames According to 802.11-2012 9.3.2.10, paragraph 4, QoS data frames with a group address in the Address 1 field have sequence numbers allocated from the same counter as non-QoS data and management frames. Without this flag, some drivers may not assign sequence numbers, and in rare cases frames might get dropped. Set the control flag accordingly. Signed-off-by: Bob Copeland Signed-off-by: Johannes Berg diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 098ae85..3456c04 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -781,9 +781,11 @@ ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx) /* * Anything but QoS data that has a sequence number field * (is long enough) gets a sequence number from the global - * counter. + * counter. QoS data frames with a multicast destination + * also use the global counter (802.11-2012 9.3.2.10). */ - if (!ieee80211_is_data_qos(hdr->frame_control)) { + if (!ieee80211_is_data_qos(hdr->frame_control) || + is_multicast_ether_addr(hdr->addr1)) { /* driver should assign sequence number */ info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ; /* for pure STA mode without beacons, we can do it */ -- cgit v0.10.2 From 19504cf5f35fbe85db811fce9f4392a0cbdada2f Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 15 Aug 2013 14:51:28 +0300 Subject: cfg80211: add flags to cfg80211_rx_mgmt() Add flags intended to report various auxiliary information and introduce the NL80211_RXMGMT_FLAG_ANSWERED flag to report that the frame was already answered by the device. Signed-off-by: Vladimir Kondratiev [REPLIED->ANSWERED, reword commit message] Signed-off-by: Johannes Berg diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index 87aefb4..546d5da 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -568,8 +568,8 @@ static int ath6kl_wmi_rx_probe_req_event_rx(struct wmi *wmi, u8 *datap, int len, dlen, freq, vif->probe_req_report); if (vif->probe_req_report || vif->nw_type == AP_NETWORK) - cfg80211_rx_mgmt(&vif->wdev, freq, 0, - ev->data, dlen, GFP_ATOMIC); + cfg80211_rx_mgmt(&vif->wdev, freq, 0, ev->data, dlen, 0, + GFP_ATOMIC); return 0; } @@ -608,8 +608,7 @@ static int ath6kl_wmi_rx_action_event_rx(struct wmi *wmi, u8 *datap, int len, return -EINVAL; } ath6kl_dbg(ATH6KL_DBG_WMI, "rx_action: len=%u freq=%u\n", dlen, freq); - cfg80211_rx_mgmt(&vif->wdev, freq, 0, - ev->data, dlen, GFP_ATOMIC); + cfg80211_rx_mgmt(&vif->wdev, freq, 0, ev->data, dlen, 0, GFP_ATOMIC); return 0; } diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index dc8059a..21c791e 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -339,7 +339,7 @@ static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len) } } else { cfg80211_rx_mgmt(wil->wdev, freq, signal, - (void *)rx_mgmt_frame, d_len, GFP_KERNEL); + (void *)rx_mgmt_frame, d_len, 0, GFP_KERNEL); } } diff --git a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c index 79555f0..d7a9745 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c @@ -1430,7 +1430,7 @@ int brcmf_p2p_notify_action_frame_rx(struct brcmf_if *ifp, IEEE80211_BAND_5GHZ); wdev = &ifp->vif->wdev; - cfg80211_rx_mgmt(wdev, freq, 0, (u8 *)mgmt_frame, mgmt_frame_len, + cfg80211_rx_mgmt(wdev, freq, 0, (u8 *)mgmt_frame, mgmt_frame_len, 0, GFP_ATOMIC); kfree(mgmt_frame); @@ -1895,7 +1895,7 @@ s32 brcmf_p2p_notify_rx_mgmt_p2p_probereq(struct brcmf_if *ifp, IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ); - cfg80211_rx_mgmt(&vif->wdev, freq, 0, mgmt_frame, mgmt_frame_len, + cfg80211_rx_mgmt(&vif->wdev, freq, 0, mgmt_frame, mgmt_frame_len, 0, GFP_ATOMIC); brcmf_dbg(INFO, "mgmt_frame_len (%d) , e->datalen (%d), chanspec (%04x), freq (%d)\n", diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c index e57ac0d..5d9e150 100644 --- a/drivers/net/wireless/mwifiex/util.c +++ b/drivers/net/wireless/mwifiex/util.c @@ -171,8 +171,8 @@ mwifiex_process_mgmt_packet(struct mwifiex_private *priv, rx_pd->rx_pkt_length = cpu_to_le16(pkt_len); cfg80211_rx_mgmt(priv->wdev, priv->roc_cfg.chan.center_freq, - CAL_RSSI(rx_pd->snr, rx_pd->nf), - skb->data, pkt_len, GFP_ATOMIC); + CAL_RSSI(rx_pd->snr, rx_pd->nf), skb->data, pkt_len, + 0, GFP_ATOMIC); return 0; } diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 9ab7a06..d530c54 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -4056,6 +4056,7 @@ void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr, * @sig_dbm: signal strength in mBm, or 0 if unknown * @buf: Management frame (header + body) * @len: length of the frame data + * @flags: flags, as defined in enum nl80211_rxmgmt_flags * @gfp: context flags * * This function is called whenever an Action frame is received for a station @@ -4067,7 +4068,7 @@ void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr, * driver is responsible for rejecting the frame. */ bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_dbm, - const u8 *buf, size_t len, gfp_t gfp); + const u8 *buf, size_t len, u32 flags, gfp_t gfp); /** * cfg80211_mgmt_tx_status - notification of TX status for management frame diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 1f42bc3..fde2c02 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -1493,6 +1493,9 @@ enum nl80211_commands { * @NL80211_ATTR_CSA_C_OFF_PRESP: Offset of the channel switch counter * field in the probe response (%NL80211_ATTR_PROBE_RESP). * + * @NL80211_ATTR_RXMGMT_FLAGS: flags for nl80211_send_mgmt(), u32. + * As specified in the &enum nl80211_rxmgmt_flags. + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -1801,6 +1804,8 @@ enum nl80211_attrs { NL80211_ATTR_CSA_C_OFF_BEACON, NL80211_ATTR_CSA_C_OFF_PRESP, + NL80211_ATTR_RXMGMT_FLAGS, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -3901,4 +3906,15 @@ enum nl80211_crit_proto_id { /* maximum duration for critical protocol measures */ #define NL80211_CRIT_PROTO_MAX_DURATION 5000 /* msec */ +/** + * enum nl80211_rxmgmt_flags - flags for received management frame. + * + * Used by cfg80211_rx_mgmt() + * + * @NL80211_RXMGMT_FLAG_ANSWERED: frame was answered by device/driver. + */ +enum nl80211_rxmgmt_flags { + NL80211_RXMGMT_FLAG_ANSWERED = 1 << 0, +}; + #endif /* __LINUX_NL80211_H */ diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index ffad155..0790105 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2678,8 +2678,7 @@ ieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data *rx) sig = status->signal; if (cfg80211_rx_mgmt(&rx->sdata->wdev, status->freq, sig, - rx->skb->data, rx->skb->len, - GFP_ATOMIC)) { + rx->skb->data, rx->skb->len, 0, GFP_ATOMIC)) { if (rx->sta) rx->sta->rx_packets++; dev_kfree_skb(rx->skb); diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index bfac5e1..8d49c1c 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -621,7 +621,7 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, } bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_mbm, - const u8 *buf, size_t len, gfp_t gfp) + const u8 *buf, size_t len, u32 flags, gfp_t gfp) { struct wiphy *wiphy = wdev->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); @@ -664,7 +664,7 @@ bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_mbm, /* Indicate the received Action frame to user space */ if (nl80211_send_mgmt(rdev, wdev, reg->nlportid, freq, sig_mbm, - buf, len, gfp)) + buf, len, flags, gfp)) continue; result = true; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 334697d..a51269d 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -10446,7 +10446,7 @@ EXPORT_SYMBOL(cfg80211_rx_unexpected_4addr_frame); int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev, u32 nlportid, int freq, int sig_dbm, - const u8 *buf, size_t len, gfp_t gfp) + const u8 *buf, size_t len, u32 flags, gfp_t gfp) { struct net_device *netdev = wdev->netdev; struct sk_buff *msg; @@ -10469,7 +10469,9 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq) || (sig_dbm && nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) || - nla_put(msg, NL80211_ATTR_FRAME, len, buf)) + nla_put(msg, NL80211_ATTR_FRAME, len, buf) || + (flags && + nla_put_u32(msg, NL80211_ATTR_RXMGMT_FLAGS, flags))) goto nla_put_failure; genlmsg_end(msg, hdr); diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index 44341bf..2c0f2b3 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h @@ -66,7 +66,7 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev, int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev, u32 nlpid, int freq, int sig_dbm, - const u8 *buf, size_t len, gfp_t gfp); + const u8 *buf, size_t len, u32 flags, gfp_t gfp); void nl80211_radar_notify(struct cfg80211_registered_device *rdev, -- cgit v0.10.2 From bcdd822007e44b1da1ad5a62f20b75ee7d8da608 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Mon, 26 Aug 2013 15:32:58 +0800 Subject: mac80211_hwsim: fix error return code in init_mac80211_hwsim() Fix to return -ENOMEM in the netdev alloc error handling case instead of 0, as done elsewhere in this function. Signed-off-by: Wei Yongjun Signed-off-by: Johannes Berg diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index a0d2aac..2cd3f54 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -2528,8 +2528,10 @@ static int __init init_mac80211_hwsim(void) } hwsim_mon = alloc_netdev(0, "hwsim%d", hwsim_mon_setup); - if (hwsim_mon == NULL) + if (hwsim_mon == NULL) { + err = -ENOMEM; goto failed; + } rtnl_lock(); -- cgit v0.10.2 From a98655387762394371b88cdfb8215884757978ab Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 26 Aug 2013 09:30:32 +0200 Subject: mac80211: fix change_interface queue assignments Jouni reported that with mac80211_hwsim, multicast TX was causing crashes due to invalid vif->cab_queue assignment. It turns out that this is caused by change_interface() getting invoked and not having the vif->type/vif->p2p assigned correctly before calling the queue check (ieee80211_check_queues). Fix this by passing the 'external' interface type to the function and adjusting it accordingly. While at it, also fix the error path in change_interface, it wasn't correctly resetting to the external type but using the internal one instead. Fortunately this affects on hwsim because all other drivers set the vif->type/vif->p2p variables when changing iftype. This shouldn't be needed, but almost all implementations actually do it for their own internal handling. Reported-by: Jouni Malinen Signed-off-by: Johannes Berg diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 7ca534b..fcecd63 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -308,12 +308,13 @@ static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata, return 0; } -static int ieee80211_check_queues(struct ieee80211_sub_if_data *sdata) +static int ieee80211_check_queues(struct ieee80211_sub_if_data *sdata, + enum nl80211_iftype iftype) { int n_queues = sdata->local->hw.queues; int i; - if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE) { + if (iftype != NL80211_IFTYPE_P2P_DEVICE) { for (i = 0; i < IEEE80211_NUM_ACS; i++) { if (WARN_ON_ONCE(sdata->vif.hw_queue[i] == IEEE80211_INVAL_HW_QUEUE)) @@ -324,8 +325,9 @@ static int ieee80211_check_queues(struct ieee80211_sub_if_data *sdata) } } - if ((sdata->vif.type != NL80211_IFTYPE_AP && - sdata->vif.type != NL80211_IFTYPE_MESH_POINT) || + if ((iftype != NL80211_IFTYPE_AP && + iftype != NL80211_IFTYPE_P2P_GO && + iftype != NL80211_IFTYPE_MESH_POINT) || !(sdata->local->hw.flags & IEEE80211_HW_QUEUE_CONTROL)) { sdata->vif.cab_queue = IEEE80211_INVAL_HW_QUEUE; return 0; @@ -408,7 +410,7 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local) return ret; } - ret = ieee80211_check_queues(sdata); + ret = ieee80211_check_queues(sdata, NL80211_IFTYPE_MONITOR); if (ret) { kfree(sdata); return ret; @@ -592,7 +594,8 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) res = drv_add_interface(local, sdata); if (res) goto err_stop; - res = ieee80211_check_queues(sdata); + res = ieee80211_check_queues(sdata, + ieee80211_vif_type_p2p(&sdata->vif)); if (res) goto err_del_interface; } @@ -1389,14 +1392,14 @@ static int ieee80211_runtime_change_iftype(struct ieee80211_sub_if_data *sdata, ret = drv_change_interface(local, sdata, internal_type, p2p); if (ret) - type = sdata->vif.type; + type = ieee80211_vif_type_p2p(&sdata->vif); /* * Ignore return value here, there's not much we can do since * the driver changed the interface type internally already. * The warnings will hopefully make driver authors fix it :-) */ - ieee80211_check_queues(sdata); + ieee80211_check_queues(sdata, type); ieee80211_setup_sdata(sdata, type); -- cgit v0.10.2