diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-07-24 10:01:50 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-07-24 10:01:50 -0700 |
commit | 3c4cfadef6a1665d9cd02a543782d03d3e6740c6 (patch) | |
tree | 3df72faaacd494d5ac8c9668df4f529b1b5e4457 /net/mac80211 | |
parent | e017507f37d5cb8b541df165a824958bc333bec3 (diff) | |
parent | 320f5ea0cedc08ef65d67e056bcb9d181386ef2c (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next
Pull networking changes from David S Miller:
1) Remove the ipv4 routing cache. Now lookups go directly into the FIB
trie and use prebuilt routes cached there.
No more garbage collection, no more rDOS attacks on the routing
cache. Instead we now get predictable and consistent performance,
no matter what the pattern of traffic we service.
This has been almost 2 years in the making. Special thanks to
Julian Anastasov, Eric Dumazet, Steffen Klassert, and others who
have helped along the way.
I'm sure that with a change of this magnitude there will be some
kind of fallout, but such things ought the be simple to fix at this
point. Luckily I'm not European so I'll be around all of August to
fix things :-)
The major stages of this work here are each fronted by a forced
merge commit whose commit message contains a top-level description
of the motivations and implementation issues.
2) Pre-demux of established ipv4 TCP sockets, saves a route demux on
input.
3) TCP SYN/ACK performance tweaks from Eric Dumazet.
4) Add namespace support for netfilter L4 conntrack helpers, from Gao
Feng.
5) Add config mechanism for Energy Efficient Ethernet to ethtool, from
Yuval Mintz.
6) Remove quadratic behavior from /proc/net/unix, from Eric Dumazet.
7) Support for connection tracker helpers in userspace, from Pablo
Neira Ayuso.
8) Allow userspace driven TX load balancing functions in TEAM driver,
from Jiri Pirko.
9) Kill off NLMSG_PUT and RTA_PUT macros, more gross stuff with
embedded gotos.
10) TCP Small Queues, essentially minimize the amount of TCP data queued
up in the packet scheduler layer. Whereas the existing BQL (Byte
Queue Limits) limits the pkt_sched --> netdevice queuing levels,
this controls the TCP --> pkt_sched queueing levels.
From Eric Dumazet.
11) Reduce the number of get_page/put_page ops done on SKB fragments,
from Alexander Duyck.
12) Implement protection against blind resets in TCP (RFC 5961), from
Eric Dumazet.
13) Support the client side of TCP Fast Open, basically the ability to
send data in the SYN exchange, from Yuchung Cheng.
Basically, the sender queues up data with a sendmsg() call using
MSG_FASTOPEN, then they do the connect() which emits the queued up
fastopen data.
14) Avoid all the problems we get into in TCP when timers or PMTU events
hit a locked socket. The TCP Small Queues changes added a
tcp_release_cb() that allows us to queue work up to the
release_sock() caller, and that's what we use here too. From Eric
Dumazet.
15) Zero copy on TX support for TUN driver, from Michael S. Tsirkin.
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next: (1870 commits)
genetlink: define lockdep_genl_is_held() when CONFIG_LOCKDEP
r8169: revert "add byte queue limit support".
ipv4: Change rt->rt_iif encoding.
net: Make skb->skb_iif always track skb->dev
ipv4: Prepare for change of rt->rt_iif encoding.
ipv4: Remove all RTCF_DIRECTSRC handliing.
ipv4: Really ignore ICMP address requests/replies.
decnet: Don't set RTCF_DIRECTSRC.
net/ipv4/ip_vti.c: Fix __rcu warnings detected by sparse.
ipv4: Remove redundant assignment
rds: set correct msg_namelen
openvswitch: potential NULL deref in sample()
tcp: dont drop MTU reduction indications
bnx2x: Add new 57840 device IDs
tcp: avoid oops in tcp_metrics and reset tcpm_stamp
niu: Change niu_rbr_fill() to use unlikely() to check niu_rbr_add_page() return value
niu: Fix to check for dma mapping errors.
net: Fix references to out-of-scope variables in put_cmsg_compat()
net: ethernet: davinci_emac: add pm_runtime support
net: ethernet: davinci_emac: Remove unnecessary #include
...
Diffstat (limited to 'net/mac80211')
40 files changed, 2154 insertions, 2003 deletions
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index 8d249d70598..63af25458fd 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig @@ -107,6 +107,19 @@ config MAC80211_DEBUGFS Say N unless you know you need this. +config MAC80211_MESSAGE_TRACING + bool "Trace all mac80211 debug messages" + depends on MAC80211 + ---help--- + Select this option to have mac80211 register the + mac80211_msg trace subsystem with tracepoints to + collect all debugging messages, independent of + printing them into the kernel log. + + The overhead in this option is that all the messages + need to be present in the binary and formatted at + runtime for tracing. + menuconfig MAC80211_DEBUG_MENU bool "Select mac80211 debugging features" depends on MAC80211 @@ -140,26 +153,35 @@ config MAC80211_VERBOSE_DEBUG Do not select this option. -config MAC80211_HT_DEBUG - bool "Verbose HT debugging" +config MAC80211_MLME_DEBUG + bool "Verbose managed MLME output" depends on MAC80211_DEBUG_MENU ---help--- - This option enables 802.11n High Throughput features - debug tracing output. - - It should not be selected on production systems as some + Selecting this option causes mac80211 to print out + debugging messages for the managed-mode MLME. It + should not be selected on production systems as some of the messages are remotely triggerable. Do not select this option. -config MAC80211_TKIP_DEBUG - bool "Verbose TKIP debugging" +config MAC80211_STA_DEBUG + bool "Verbose station debugging" depends on MAC80211_DEBUG_MENU ---help--- Selecting this option causes mac80211 to print out - very verbose TKIP debugging messages. It should not - be selected on production systems as those messages - are remotely triggerable. + debugging messages for station addition/removal. + + Do not select this option. + +config MAC80211_HT_DEBUG + bool "Verbose HT debugging" + depends on MAC80211_DEBUG_MENU + ---help--- + This option enables 802.11n High Throughput features + debug tracing output. + + It should not be selected on production systems as some + of the messages are remotely triggerable. Do not select this option. @@ -174,7 +196,7 @@ config MAC80211_IBSS_DEBUG Do not select this option. -config MAC80211_VERBOSE_PS_DEBUG +config MAC80211_PS_DEBUG bool "Verbose powersave mode debugging" depends on MAC80211_DEBUG_MENU ---help--- @@ -186,7 +208,7 @@ config MAC80211_VERBOSE_PS_DEBUG Do not select this option. -config MAC80211_VERBOSE_MPL_DEBUG +config MAC80211_MPL_DEBUG bool "Verbose mesh peer link debugging" depends on MAC80211_DEBUG_MENU depends on MAC80211_MESH @@ -199,7 +221,7 @@ config MAC80211_VERBOSE_MPL_DEBUG Do not select this option. -config MAC80211_VERBOSE_MPATH_DEBUG +config MAC80211_MPATH_DEBUG bool "Verbose mesh path debugging" depends on MAC80211_DEBUG_MENU depends on MAC80211_MESH @@ -212,7 +234,7 @@ config MAC80211_VERBOSE_MPATH_DEBUG Do not select this option. -config MAC80211_VERBOSE_MHWMP_DEBUG +config MAC80211_MHWMP_DEBUG bool "Verbose mesh HWMP routing debugging" depends on MAC80211_DEBUG_MENU depends on MAC80211_MESH @@ -225,7 +247,7 @@ config MAC80211_VERBOSE_MHWMP_DEBUG Do not select this option. -config MAC80211_VERBOSE_MESH_SYNC_DEBUG +config MAC80211_MESH_SYNC_DEBUG bool "Verbose mesh mesh synchronization debugging" depends on MAC80211_DEBUG_MENU depends on MAC80211_MESH @@ -236,7 +258,7 @@ config MAC80211_VERBOSE_MESH_SYNC_DEBUG Do not select this option. -config MAC80211_VERBOSE_TDLS_DEBUG +config MAC80211_TDLS_DEBUG bool "Verbose TDLS debugging" depends on MAC80211_DEBUG_MENU ---help--- diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index 3e9d931bba3..a7dd110faaf 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile @@ -9,7 +9,6 @@ mac80211-y := \ scan.o offchannel.o \ ht.o agg-tx.o agg-rx.o \ ibss.o \ - work.o \ iface.o \ rate.o \ michael.o \ @@ -25,7 +24,7 @@ mac80211-y := \ wme.o \ event.o \ chan.o \ - driver-trace.o mlme.o + trace.o mlme.o mac80211-$(CONFIG_MAC80211_LEDS) += led.o mac80211-$(CONFIG_MAC80211_DEBUGFS) += \ @@ -43,7 +42,7 @@ mac80211-$(CONFIG_MAC80211_MESH) += \ mac80211-$(CONFIG_PM) += pm.o -CFLAGS_driver-trace.o := -I$(src) +CFLAGS_trace.o := -I$(src) # objects for PID algorithm rc80211_pid-y := rc80211_pid_algo.o @@ -59,4 +58,4 @@ mac80211-$(CONFIG_MAC80211_RC_PID) += $(rc80211_pid-y) mac80211-$(CONFIG_MAC80211_RC_MINSTREL) += $(rc80211_minstrel-y) mac80211-$(CONFIG_MAC80211_RC_MINSTREL_HT) += $(rc80211_minstrel_ht-y) -ccflags-y += -D__CHECK_ENDIAN__ +ccflags-y += -D__CHECK_ENDIAN__ -DDEBUG diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index c649188314c..186d9919b04 100644 --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c @@ -74,18 +74,17 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, RCU_INIT_POINTER(sta->ampdu_mlme.tid_rx[tid], NULL); -#ifdef CONFIG_MAC80211_HT_DEBUG - printk(KERN_DEBUG + ht_dbg(sta->sdata, "Rx BA session stop requested for %pM tid %u %s reason: %d\n", sta->sta.addr, tid, initiator == WLAN_BACK_RECIPIENT ? "recipient" : "inititator", (int)reason); -#endif /* CONFIG_MAC80211_HT_DEBUG */ if (drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_STOP, &sta->sta, tid, NULL, 0)) - printk(KERN_DEBUG "HW problem - can not stop rx " - "aggregation for tid %d\n", tid); + sdata_info(sta->sdata, + "HW problem - can not stop rx aggregation for tid %d\n", + tid); /* check if this is a self generated aggregation halt */ if (initiator == WLAN_BACK_RECIPIENT && tx) @@ -160,9 +159,8 @@ static void sta_rx_agg_session_timer_expired(unsigned long data) } rcu_read_unlock(); -#ifdef CONFIG_MAC80211_HT_DEBUG - printk(KERN_DEBUG "rx session timer expired on tid %d\n", (u16)*ptid); -#endif + ht_dbg(sta->sdata, "rx session timer expired on tid %d\n", (u16)*ptid); + set_bit(*ptid, sta->ampdu_mlme.tid_rx_timer_expired); ieee80211_queue_work(&sta->local->hw, &sta->ampdu_mlme.work); } @@ -249,10 +247,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, status = WLAN_STATUS_REQUEST_DECLINED; if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) { -#ifdef CONFIG_MAC80211_HT_DEBUG - printk(KERN_DEBUG "Suspend in progress. " - "Denying ADDBA request\n"); -#endif + ht_dbg(sta->sdata, "Suspend in progress - Denying ADDBA request\n"); goto end_no_lock; } @@ -264,10 +259,9 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, (!(sta->sta.ht_cap.cap & IEEE80211_HT_CAP_DELAY_BA))) || (buf_size > IEEE80211_MAX_AMPDU_BUF)) { status = WLAN_STATUS_INVALID_QOS_PARAM; -#ifdef CONFIG_MAC80211_HT_DEBUG - net_dbg_ratelimited("AddBA Req with bad params from %pM on tid %u. policy %d, buffer size %d\n", - mgmt->sa, tid, ba_policy, buf_size); -#endif /* CONFIG_MAC80211_HT_DEBUG */ + ht_dbg_ratelimited(sta->sdata, + "AddBA Req with bad params from %pM on tid %u. policy %d, buffer size %d\n", + mgmt->sa, tid, ba_policy, buf_size); goto end_no_lock; } /* determine default buffer size */ @@ -282,10 +276,9 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, mutex_lock(&sta->ampdu_mlme.mtx); if (sta->ampdu_mlme.tid_rx[tid]) { -#ifdef CONFIG_MAC80211_HT_DEBUG - net_dbg_ratelimited("unexpected AddBA Req from %pM on tid %u\n", - mgmt->sa, tid); -#endif /* CONFIG_MAC80211_HT_DEBUG */ + ht_dbg_ratelimited(sta->sdata, + "unexpected AddBA Req from %pM on tid %u\n", + mgmt->sa, tid); /* delete existing Rx BA session on the same tid */ ___ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_RECIPIENT, @@ -324,10 +317,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, ret = drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_START, &sta->sta, tid, &start_seq_num, 0); -#ifdef CONFIG_MAC80211_HT_DEBUG - printk(KERN_DEBUG "Rx A-MPDU request on tid %d result %d\n", tid, ret); -#endif /* CONFIG_MAC80211_HT_DEBUG */ - + ht_dbg(sta->sdata, "Rx A-MPDU request on tid %d result %d\n", tid, ret); if (ret) { kfree(tid_agg_rx->reorder_buf); kfree(tid_agg_rx->reorder_time); diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 7cf07158805..d0deb3edae2 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -135,7 +135,8 @@ void ieee80211_send_bar(struct ieee80211_vif *vif, u8 *ra, u16 tid, u16 ssn) bar->control = cpu_to_le16(bar_control); bar->start_seq_num = cpu_to_le16(ssn); - IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; + IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT | + IEEE80211_TX_CTL_REQ_TX_STATUS; ieee80211_tx_skb_tid(sdata, skb, tid); } EXPORT_SYMBOL(ieee80211_send_bar); @@ -184,10 +185,8 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, spin_unlock_bh(&sta->lock); -#ifdef CONFIG_MAC80211_HT_DEBUG - printk(KERN_DEBUG "Tx BA session stop requested for %pM tid %u\n", + ht_dbg(sta->sdata, "Tx BA session stop requested for %pM tid %u\n", sta->sta.addr, tid); -#endif /* CONFIG_MAC80211_HT_DEBUG */ del_timer_sync(&tid_tx->addba_resp_timer); del_timer_sync(&tid_tx->session_timer); @@ -253,17 +252,13 @@ static void sta_addba_resp_timer_expired(unsigned long data) if (!tid_tx || test_bit(HT_AGG_STATE_RESPONSE_RECEIVED, &tid_tx->state)) { rcu_read_unlock(); -#ifdef CONFIG_MAC80211_HT_DEBUG - printk(KERN_DEBUG "timer expired on tid %d but we are not " - "(or no longer) expecting addBA response there\n", - tid); -#endif + ht_dbg(sta->sdata, + "timer expired on tid %d but we are not (or no longer) expecting addBA response there\n", + tid); return; } -#ifdef CONFIG_MAC80211_HT_DEBUG - printk(KERN_DEBUG "addBA response timer expired on tid %d\n", tid); -#endif + ht_dbg(sta->sdata, "addBA response timer expired on tid %d\n", tid); ieee80211_stop_tx_ba_session(&sta->sta, tid); rcu_read_unlock(); @@ -323,8 +318,9 @@ ieee80211_agg_splice_packets(struct ieee80211_sub_if_data *sdata, ieee80211_stop_queue_agg(sdata, tid); - if (WARN(!tid_tx, "TID %d gone but expected when splicing aggregates" - " from the pending queue\n", tid)) + if (WARN(!tid_tx, + "TID %d gone but expected when splicing aggregates from the pending queue\n", + tid)) return; if (!skb_queue_empty(&tid_tx->pending)) { @@ -372,10 +368,8 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) ret = drv_ampdu_action(local, sdata, IEEE80211_AMPDU_TX_START, &sta->sta, tid, &start_seq_num, 0); if (ret) { -#ifdef CONFIG_MAC80211_HT_DEBUG - printk(KERN_DEBUG "BA request denied - HW unavailable for" - " tid %d\n", tid); -#endif + ht_dbg(sdata, + "BA request denied - HW unavailable for tid %d\n", tid); spin_lock_bh(&sta->lock); ieee80211_agg_splice_packets(sdata, tid_tx, tid); ieee80211_assign_tid_tx(sta, tid, NULL); @@ -388,9 +382,7 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) /* activate the timer for the recipient's addBA response */ mod_timer(&tid_tx->addba_resp_timer, jiffies + ADDBA_RESP_INTERVAL); -#ifdef CONFIG_MAC80211_HT_DEBUG - printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid); -#endif + ht_dbg(sdata, "activated addBA response timer on tid %d\n", tid); spin_lock_bh(&sta->lock); sta->ampdu_mlme.last_addba_req_time[tid] = jiffies; @@ -437,9 +429,7 @@ static void sta_tx_agg_session_timer_expired(unsigned long data) rcu_read_unlock(); -#ifdef CONFIG_MAC80211_HT_DEBUG - printk(KERN_DEBUG "tx session timer expired on tid %d\n", (u16)*ptid); -#endif + ht_dbg(sta->sdata, "tx session timer expired on tid %d\n", (u16)*ptid); ieee80211_stop_tx_ba_session(&sta->sta, *ptid); } @@ -463,10 +453,8 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid, (local->hw.flags & IEEE80211_HW_TX_AMPDU_SETUP_IN_HW)) return -EINVAL; -#ifdef CONFIG_MAC80211_HT_DEBUG - printk(KERN_DEBUG "Open BA session requested for %pM tid %u\n", + ht_dbg(sdata, "Open BA session requested for %pM tid %u\n", pubsta->addr, tid); -#endif /* CONFIG_MAC80211_HT_DEBUG */ if (sdata->vif.type != NL80211_IFTYPE_STATION && sdata->vif.type != NL80211_IFTYPE_MESH_POINT && @@ -476,10 +464,8 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid, return -EINVAL; if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) { -#ifdef CONFIG_MAC80211_HT_DEBUG - printk(KERN_DEBUG "BA sessions blocked. " - "Denying BA session request\n"); -#endif + ht_dbg(sdata, + "BA sessions blocked - Denying BA session request\n"); return -EINVAL; } @@ -497,10 +483,9 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid, */ if (sta->sdata->vif.type == NL80211_IFTYPE_ADHOC && !sta->sta.ht_cap.ht_supported) { -#ifdef CONFIG_MAC80211_HT_DEBUG - printk(KERN_DEBUG "BA request denied - IBSS STA %pM" - "does not advertise HT support\n", pubsta->addr); -#endif /* CONFIG_MAC80211_HT_DEBUG */ + ht_dbg(sdata, + "BA request denied - IBSS STA %pM does not advertise HT support\n", + pubsta->addr); return -EINVAL; } @@ -520,12 +505,9 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid, if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_BURST_RETRIES && time_before(jiffies, sta->ampdu_mlme.last_addba_req_time[tid] + HT_AGG_RETRIES_PERIOD)) { -#ifdef CONFIG_MAC80211_HT_DEBUG - printk(KERN_DEBUG "BA request denied - " - "waiting a grace period after %d failed requests " - "on tid %u\n", + ht_dbg(sdata, + "BA request denied - waiting a grace period after %d failed requests on tid %u\n", sta->ampdu_mlme.addba_req_num[tid], tid); -#endif /* CONFIG_MAC80211_HT_DEBUG */ ret = -EBUSY; goto err_unlock_sta; } @@ -533,10 +515,9 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid, tid_tx = rcu_dereference_protected_tid_tx(sta, tid); /* check if the TID is not in aggregation flow already */ if (tid_tx || sta->ampdu_mlme.tid_start_tx[tid]) { -#ifdef CONFIG_MAC80211_HT_DEBUG - printk(KERN_DEBUG "BA request denied - session is not " - "idle on tid %u\n", tid); -#endif /* CONFIG_MAC80211_HT_DEBUG */ + ht_dbg(sdata, + "BA request denied - session is not idle on tid %u\n", + tid); ret = -EAGAIN; goto err_unlock_sta; } @@ -591,9 +572,7 @@ static void ieee80211_agg_tx_operational(struct ieee80211_local *local, tid_tx = rcu_dereference_protected_tid_tx(sta, tid); -#ifdef CONFIG_MAC80211_HT_DEBUG - printk(KERN_DEBUG "Aggregation is on for tid %d\n", tid); -#endif + ht_dbg(sta->sdata, "Aggregation is on for tid %d\n", tid); drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_TX_OPERATIONAL, @@ -627,10 +606,8 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid) trace_api_start_tx_ba_cb(sdata, ra, tid); if (tid >= STA_TID_NUM) { -#ifdef CONFIG_MAC80211_HT_DEBUG - printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n", - tid, STA_TID_NUM); -#endif + ht_dbg(sdata, "Bad TID value: tid = %d (>= %d)\n", + tid, STA_TID_NUM); return; } @@ -638,9 +615,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid) sta = sta_info_get_bss(sdata, ra); if (!sta) { mutex_unlock(&local->sta_mtx); -#ifdef CONFIG_MAC80211_HT_DEBUG - printk(KERN_DEBUG "Could not find station: %pM\n", ra); -#endif + ht_dbg(sdata, "Could not find station: %pM\n", ra); return; } @@ -648,9 +623,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid) tid_tx = rcu_dereference_protected_tid_tx(sta, tid); if (WARN_ON(!tid_tx)) { -#ifdef CONFIG_MAC80211_HT_DEBUG - printk(KERN_DEBUG "addBA was not requested!\n"); -#endif + ht_dbg(sdata, "addBA was not requested!\n"); goto unlock; } @@ -750,25 +723,18 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid) trace_api_stop_tx_ba_cb(sdata, ra, tid); if (tid >= STA_TID_NUM) { -#ifdef CONFIG_MAC80211_HT_DEBUG - printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n", - tid, STA_TID_NUM); -#endif + ht_dbg(sdata, "Bad TID value: tid = %d (>= %d)\n", + tid, STA_TID_NUM); return; } -#ifdef CONFIG_MAC80211_HT_DEBUG - printk(KERN_DEBUG "Stopping Tx BA session for %pM tid %d\n", - ra, tid); -#endif /* CONFIG_MAC80211_HT_DEBUG */ + ht_dbg(sdata, "Stopping Tx BA session for %pM tid %d\n", ra, tid); mutex_lock(&local->sta_mtx); sta = sta_info_get_bss(sdata, ra); if (!sta) { -#ifdef CONFIG_MAC80211_HT_DEBUG - printk(KERN_DEBUG "Could not find station: %pM\n", ra); -#endif + ht_dbg(sdata, "Could not find station: %pM\n", ra); goto unlock; } @@ -777,9 +743,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid) tid_tx = rcu_dereference_protected_tid_tx(sta, tid); if (!tid_tx || !test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) { -#ifdef CONFIG_MAC80211_HT_DEBUG - printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n"); -#endif + ht_dbg(sdata, "unexpected callback to A-MPDU stop\n"); goto unlock_sta; } @@ -855,17 +819,13 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local, goto out; if (mgmt->u.action.u.addba_resp.dialog_token != tid_tx->dialog_token) { -#ifdef CONFIG_MAC80211_HT_DEBUG - printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid); -#endif + ht_dbg(sta->sdata, "wrong addBA response token, tid %d\n", tid); goto out; } del_timer_sync(&tid_tx->addba_resp_timer); -#ifdef CONFIG_MAC80211_HT_DEBUG - printk(KERN_DEBUG "switched off addBA timer for tid %d\n", tid); -#endif + ht_dbg(sta->sdata, "switched off addBA timer for tid %d\n", tid); /* * addba_resp_timer may have fired before we got here, and @@ -874,11 +834,9 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local, */ if (test_bit(HT_AGG_STATE_WANT_STOP, &tid_tx->state) || test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) { -#ifdef CONFIG_MAC80211_HT_DEBUG - printk(KERN_DEBUG + ht_dbg(sta->sdata, "got addBA resp for tid %d but we already gave up\n", tid); -#endif goto out; } diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 7d5108a867a..d41974aacf5 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -20,31 +20,31 @@ #include "rate.h" #include "mesh.h" -static struct net_device *ieee80211_add_iface(struct wiphy *wiphy, char *name, - enum nl80211_iftype type, - u32 *flags, - struct vif_params *params) +static struct wireless_dev *ieee80211_add_iface(struct wiphy *wiphy, char *name, + enum nl80211_iftype type, + u32 *flags, + struct vif_params *params) { struct ieee80211_local *local = wiphy_priv(wiphy); - struct net_device *dev; + struct wireless_dev *wdev; struct ieee80211_sub_if_data *sdata; int err; - err = ieee80211_if_add(local, name, &dev, type, params); + err = ieee80211_if_add(local, name, &wdev, type, params); if (err) return ERR_PTR(err); if (type == NL80211_IFTYPE_MONITOR && flags) { - sdata = IEEE80211_DEV_TO_SUB_IF(dev); + sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); sdata->u.mntr_flags = *flags; } - return dev; + return wdev; } -static int ieee80211_del_iface(struct wiphy *wiphy, struct net_device *dev) +static int ieee80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev) { - ieee80211_if_remove(IEEE80211_DEV_TO_SUB_IF(dev)); + ieee80211_if_remove(IEEE80211_WDEV_TO_SUB_IF(wdev)); return 0; } @@ -353,6 +353,7 @@ void sta_set_rate_info_tx(struct sta_info *sta, static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) { struct ieee80211_sub_if_data *sdata = sta->sdata; + struct ieee80211_local *local = sdata->local; struct timespec uptime; sinfo->generation = sdata->local->sta_generation; @@ -388,7 +389,9 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) if ((sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) || (sta->local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)) { sinfo->filled |= STATION_INFO_SIGNAL | STATION_INFO_SIGNAL_AVG; - sinfo->signal = (s8)sta->last_signal; + if (!local->ops->get_rssi || + drv_get_rssi(local, sdata, &sta->sta, &sinfo->signal)) + sinfo->signal = (s8)sta->last_signal; sinfo->signal_avg = (s8) -ewma_read(&sta->avg_signal); } @@ -517,7 +520,7 @@ static void ieee80211_get_et_stats(struct wiphy *wiphy, * network device. */ - rcu_read_lock(); + mutex_lock(&local->sta_mtx); if (sdata->vif.type == NL80211_IFTYPE_STATION) { sta = sta_info_get_bss(sdata, sdata->u.mgd.bssid); @@ -546,7 +549,7 @@ static void ieee80211_get_et_stats(struct wiphy *wiphy, data[i] = (u8)sinfo.signal_avg; i++; } else { - list_for_each_entry_rcu(sta, &local->sta_list, list) { + list_for_each_entry(sta, &local->sta_list, list) { /* Make sure this station belongs to the proper dev */ if (sta->sdata->dev != dev) continue; @@ -603,7 +606,7 @@ do_survey: else data[i++] = -1LL; - rcu_read_unlock(); + mutex_unlock(&local->sta_mtx); if (WARN_ON(i != STA_STATS_LEN)) return; @@ -629,10 +632,11 @@ static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev, int idx, u8 *mac, struct station_info *sinfo) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_local *local = sdata->local; struct sta_info *sta; int ret = -ENOENT; - rcu_read_lock(); + mutex_lock(&local->sta_mtx); sta = sta_info_get_by_idx(sdata, idx); if (sta) { @@ -641,7 +645,7 @@ static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev, sta_set_sinfo(sta, sinfo); } - rcu_read_unlock(); + mutex_unlock(&local->sta_mtx); return ret; } @@ -658,10 +662,11 @@ static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev, u8 *mac, struct station_info *sinfo) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_local *local = sdata->local; struct sta_info *sta; int ret = -ENOENT; - rcu_read_lock(); + mutex_lock(&local->sta_mtx); sta = sta_info_get_bss(sdata, mac); if (sta) { @@ -669,11 +674,54 @@ static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev, sta_set_sinfo(sta, sinfo); } - rcu_read_unlock(); + mutex_unlock(&local->sta_mtx); return ret; } +static int ieee80211_set_channel(struct wiphy *wiphy, + struct net_device *netdev, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type) +{ + struct ieee80211_local *local = wiphy_priv(wiphy); + struct ieee80211_sub_if_data *sdata = NULL; + + if (netdev) + sdata = IEEE80211_DEV_TO_SUB_IF(netdev); + + switch (ieee80211_get_channel_mode(local, NULL)) { + case CHAN_MODE_HOPPING: + return -EBUSY; + case CHAN_MODE_FIXED: + if (local->oper_channel != chan || + (!sdata && local->_oper_channel_type != channel_type)) + return -EBUSY; + if (!sdata && local->_oper_channel_type == channel_type) + return 0; + break; + case CHAN_MODE_UNDEFINED: + break; + } + + if (!ieee80211_set_channel_type(local, sdata, channel_type)) + return -EBUSY; + + local->oper_channel = chan; + + /* auto-detects changes */ + ieee80211_hw_config(local, 0); + + return 0; +} + +static int ieee80211_set_monitor_channel(struct wiphy *wiphy, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type) +{ + return ieee80211_set_channel(wiphy, NULL, chan, channel_type); +} + static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata, const u8 *resp, size_t resp_len) { @@ -788,6 +836,11 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, if (old) return -EALREADY; + err = ieee80211_set_channel(wiphy, dev, params->channel, + params->channel_type); + if (err) + return err; + /* * Apply control port protocol, this allows us to * not encrypt dynamic WEP control frames. @@ -864,6 +917,7 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) kfree_rcu(old, rcu_head); + sta_info_flush(sdata->local, sdata); ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); return 0; @@ -1482,7 +1536,7 @@ static int ieee80211_update_mesh_config(struct wiphy *wiphy, if (_chg_mesh_attr(NL80211_MESHCONF_TTL, mask)) conf->dot11MeshTTL = nconf->dot11MeshTTL; if (_chg_mesh_attr(NL80211_MESHCONF_ELEMENT_TTL, mask)) - conf->dot11MeshTTL = nconf->element_ttl; + conf->element_ttl = nconf->element_ttl; if (_chg_mesh_attr(NL80211_MESHCONF_AUTO_OPEN_PLINKS, mask)) conf->auto_open_plinks = nconf->auto_open_plinks; if (_chg_mesh_attr(NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR, mask)) @@ -1517,17 +1571,16 @@ static int ieee80211_update_mesh_config(struct wiphy *wiphy, * announcements, so require this ifmsh to also be a root node * */ if (nconf->dot11MeshGateAnnouncementProtocol && - !conf->dot11MeshHWMPRootMode) { - conf->dot11MeshHWMPRootMode = 1; + !(conf->dot11MeshHWMPRootMode > IEEE80211_ROOTMODE_ROOT)) { + conf->dot11MeshHWMPRootMode = IEEE80211_PROACTIVE_RANN; ieee80211_mesh_root_setup(ifmsh); } conf->dot11MeshGateAnnouncementProtocol = nconf->dot11MeshGateAnnouncementProtocol; } - if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_RANN_INTERVAL, mask)) { + if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_RANN_INTERVAL, mask)) conf->dot11MeshHWMPRannInterval = nconf->dot11MeshHWMPRannInterval; - } if (_chg_mesh_attr(NL80211_MESHCONF_FORWARDING, mask)) conf->dot11MeshForwarding = nconf->dot11MeshForwarding; if (_chg_mesh_attr(NL80211_MESHCONF_RSSI_THRESHOLD, mask)) { @@ -1543,6 +1596,15 @@ static int ieee80211_update_mesh_config(struct wiphy *wiphy, sdata->vif.bss_conf.ht_operation_mode = nconf->ht_opmode; ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_HT); } + if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT, mask)) + conf->dot11MeshHWMPactivePathToRootTimeout = + nconf->dot11MeshHWMPactivePathToRootTimeout; + if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_ROOT_INTERVAL, mask)) + conf->dot11MeshHWMProotInterval = + nconf->dot11MeshHWMProotInterval; + if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL, mask)) + conf->dot11MeshHWMPconfirmationInterval = + nconf->dot11MeshHWMPconfirmationInterval; return 0; } @@ -1558,6 +1620,12 @@ static int ieee80211_join_mesh(struct wiphy *wiphy, struct net_device *dev, err = copy_mesh_setup(ifmsh, setup); if (err) return err; + + err = ieee80211_set_channel(wiphy, dev, setup->channel, + setup->channel_type); + if (err) + return err; + ieee80211_start_mesh(sdata); return 0; @@ -1674,54 +1742,7 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy, return -EINVAL; } - return 0; -} - -static int ieee80211_set_channel(struct wiphy *wiphy, - struct net_device *netdev, - struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type) -{ - struct ieee80211_local *local = wiphy_priv(wiphy); - struct ieee80211_sub_if_data *sdata = NULL; - struct ieee80211_channel *old_oper; - enum nl80211_channel_type old_oper_type; - enum nl80211_channel_type old_vif_oper_type= NL80211_CHAN_NO_HT; - - if (netdev) - sdata = IEEE80211_DEV_TO_SUB_IF(netdev); - - switch (ieee80211_get_channel_mode(local, NULL)) { - case CHAN_MODE_HOPPING: - return -EBUSY; - case CHAN_MODE_FIXED: - if (local->oper_channel != chan) - return -EBUSY; - if (!sdata && local->_oper_channel_type == channel_type) - return 0; - break; - case CHAN_MODE_UNDEFINED: - break; - } - - if (sdata) - old_vif_oper_type = sdata->vif.bss_conf.channel_type; - old_oper_type = local->_oper_channel_type; - - if (!ieee80211_set_channel_type(local, sdata, channel_type)) - return -EBUSY; - - old_oper = local->oper_channel; - local->oper_channel = chan; - - /* Update driver if changes were actually made. */ - if ((old_oper != local->oper_channel) || - (old_oper_type != local->_oper_channel_type)) - ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); - - if (sdata && sdata->vif.type != NL80211_IFTYPE_MONITOR && - old_vif_oper_type != sdata->vif.bss_conf.channel_type) - ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_HT); + ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_QOS); return 0; } @@ -1743,10 +1764,11 @@ static int ieee80211_resume(struct wiphy *wiphy) #endif static int ieee80211_scan(struct wiphy *wiphy, - struct net_device *dev, struct cfg80211_scan_request *req) { - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_sub_if_data *sdata; + + sdata = IEEE80211_WDEV_TO_SUB_IF(req->wdev); switch (ieee80211_vif_type_p2p(&sdata->vif)) { case NL80211_IFTYPE_STATION: @@ -2111,143 +2133,291 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy, return 0; } -static int ieee80211_remain_on_channel_hw(struct ieee80211_local *local, - struct net_device *dev, - struct ieee80211_channel *chan, - enum nl80211_channel_type chantype, - unsigned int duration, u64 *cookie) +static int ieee80211_start_roc_work(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + struct ieee80211_channel *channel, + enum nl80211_channel_type channel_type, + unsigned int duration, u64 *cookie, + struct sk_buff *txskb) { + struct ieee80211_roc_work *roc, *tmp; + bool queued = false; int ret; - u32 random_cookie; lockdep_assert_held(&local->mtx); - if (local->hw_roc_cookie) - return -EBUSY; - /* must be nonzero */ - random_cookie = random32() | 1; - - *cookie = random_cookie; - local->hw_roc_dev = dev; - local->hw_roc_cookie = random_cookie; - local->hw_roc_channel = chan; - local->hw_roc_channel_type = chantype; - local->hw_roc_duration = duration; - ret = drv_remain_on_channel(local, chan, chantype, duration); + roc = kzalloc(sizeof(*roc), GFP_KERNEL); + if (!roc) + return -ENOMEM; + + roc->chan = channel; + roc->chan_type = channel_type; + roc->duration = duration; + roc->req_duration = duration; + roc->frame = txskb; + roc->mgmt_tx_cookie = (unsigned long)txskb; + roc->sdata = sdata; + INIT_DELAYED_WORK(&roc->work, ieee80211_sw_roc_work); + INIT_LIST_HEAD(&roc->dependents); + + /* if there's one pending or we're scanning, queue this one */ + if (!list_empty(&local->roc_list) || local->scanning) + goto out_check_combine; + + /* if not HW assist, just queue & schedule work */ + if (!local->ops->remain_on_channel) { + ieee80211_queue_delayed_work(&local->hw, &roc->work, 0); + goto out_queue; + } + + /* otherwise actually kick it off here (for error handling) */ + + /* + * If the duration is zero, then the driver + * wouldn't actually do anything. Set it to + * 10 for now. + * + * TODO: cancel the off-channel operation + * when we get the SKB's TX status and + * the wait time was zero before. + */ + if (!duration) + duration = 10; + + ret = drv_remain_on_channel(local, channel, channel_type, duration); if (ret) { - local->hw_roc_channel = NULL; - local->hw_roc_cookie = 0; + kfree(roc); + return ret; } - return ret; + roc->started = true; + goto out_queue; + + out_check_combine: + list_for_each_entry(tmp, &local->roc_list, list) { + if (tmp->chan != channel || tmp->chan_type != channel_type) + continue; + + /* + * Extend this ROC if possible: + * + * If it hasn't started yet, just increase the duration + * and add the new one to the list of dependents. + */ + if (!tmp->started) { + list_add_tail(&roc->list, &tmp->dependents); + tmp->duration = max(tmp->duration, roc->duration); + queued = true; + break; + } + + /* If it has already started, it's more difficult ... */ + if (local->ops->remain_on_channel) { + unsigned long j = jiffies; + + /* + * In the offloaded ROC case, if it hasn't begun, add + * this new one to the dependent list to be handled + * when the the master one begins. If it has begun, + * check that there's still a minimum time left and + * if so, start this one, transmitting the frame, but + * add it to the list directly after this one with a + * a reduced time so we'll ask the driver to execute + * it right after finishing the previous one, in the + * hope that it'll also be executed right afterwards, + * effectively extending the old one. + * If there's no minimum time left, just add it to the + * normal list. + */ + if (!tmp->hw_begun) { + list_add_tail(&roc->list, &tmp->dependents); + queued = true; + break; + } + + if (time_before(j + IEEE80211_ROC_MIN_LEFT, + tmp->hw_start_time + + msecs_to_jiffies(tmp->duration))) { + int new_dur; + + ieee80211_handle_roc_started(roc); + + new_dur = roc->duration - + jiffies_to_msecs(tmp->hw_start_time + + msecs_to_jiffies( + tmp->duration) - + j); + + if (new_dur > 0) { + /* add right after tmp */ + list_add(&roc->list, &tmp->list); + } else { + list_add_tail(&roc->list, + &tmp->dependents); + } + queued = true; + } + } else if (del_timer_sync(&tmp->work.timer)) { + unsigned long new_end; + + /* + * In the software ROC case, cancel the timer, if + * that fails then the finish work is already + * queued/pending and thus we queue the new ROC + * normally, if that succeeds then we can extend + * the timer duration and TX the frame (if any.) + */ + + list_add_tail(&roc->list, &tmp->dependents); + queued = true; + + new_end = jiffies + msecs_to_jiffies(roc->duration); + + /* ok, it was started & we canceled timer */ + if (time_after(new_end, tmp->work.timer.expires)) + mod_timer(&tmp->work.timer, new_end); + else + add_timer(&tmp->work.timer); + + ieee80211_handle_roc_started(roc); + } + break; + } + + out_queue: + if (!queued) + list_add_tail(&roc->list, &local->roc_list); + + /* + * cookie is either the roc (for normal roc) + * or the SKB (for mgmt TX) + */ + if (txskb) + *cookie = (unsigned long)txskb; + else + *cookie = (unsigned long)roc; + + return 0; } static int ieee80211_remain_on_channel(struct wiphy *wiphy, - struct net_device *dev, + struct wireless_dev *wdev, struct ieee80211_channel *chan, enum nl80211_channel_type channel_type, unsigned int duration, u64 *cookie) { - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); struct ieee80211_local *local = sdata->local; + int ret; - if (local->ops->remain_on_channel) { - int ret; - - mutex_lock(&local->mtx); - ret = ieee80211_remain_on_channel_hw(local, dev, - chan, channel_type, - duration, cookie); - local->hw_roc_for_tx = false; - mutex_unlock(&local->mtx); - - return ret; - } + mutex_lock(&local->mtx); + ret = ieee80211_start_roc_work(local, sdata, chan, channel_type, + duration, cookie, NULL); + mutex_unlock(&local->mtx); - return ieee80211_wk_remain_on_channel(sdata, chan, channel_type, - duration, cookie); + return ret; } -static int ieee80211_cancel_remain_on_channel_hw(struct ieee80211_local *local, - u64 cookie) +static int ieee80211_cancel_roc(struct ieee80211_local *local, + u64 cookie, bool mgmt_tx) { + struct ieee80211_roc_work *roc, *tmp, *found = NULL; int ret; - lockdep_assert_held(&local->mtx); + mutex_lock(&local->mtx); + list_for_each_entry_safe(roc, tmp, &local->roc_list, list) { + struct ieee80211_roc_work *dep, *tmp2; - if (local->hw_roc_cookie != cookie) - return -ENOENT; + list_for_each_entry_safe(dep, tmp2, &roc->dependents, list) { + if (!mgmt_tx && (unsigned long)dep != cookie) + continue; + else if (mgmt_tx && dep->mgmt_tx_cookie != cookie) + continue; + /* found dependent item -- just remove it */ + list_del(&dep->list); + mutex_unlock(&local->mtx); - ret = drv_cancel_remain_on_channel(local); - if (ret) - return ret; + ieee80211_roc_notify_destroy(dep); + return 0; + } - local->hw_roc_cookie = 0; - local->hw_roc_channel = NULL; + if (!mgmt_tx && (unsigned long)roc != cookie) + continue; + else if (mgmt_tx && roc->mgmt_tx_cookie != cookie) + continue; + + found = roc; + break; + } - ieee80211_recalc_idle(local); + if (!found) { + mutex_unlock(&local->mtx); + return -ENOENT; + } - return 0; -} + /* + * We found the item to cancel, so do that. Note that it + * may have dependents, which we also cancel (and send + * the expired signal for.) Not doing so would be quite + * tricky here, but we may need to fix it later. + */ -static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy, - struct net_device *dev, - u64 cookie) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct ieee80211_local *local = sdata->local; + if (local->ops->remain_on_channel) { + if (found->started) { + ret = drv_cancel_remain_on_channel(local); + if (WARN_ON_ONCE(ret)) { + mutex_unlock(&local->mtx); + return ret; + } + } - if (local->ops->cancel_remain_on_channel) { - int ret; + list_del(&found->list); - mutex_lock(&local->mtx); - ret = ieee80211_cancel_remain_on_channel_hw(local, cookie); + if (found->started) + ieee80211_start_next_roc(local); mutex_unlock(&local->mtx); - return ret; + ieee80211_roc_notify_destroy(found); + } else { + /* work may be pending so use it all the time */ + found->abort = true; + ieee80211_queue_delayed_work(&local->hw, &found->work, 0); + + mutex_unlock(&local->mtx); + + /* work will clean up etc */ + flush_delayed_work(&found->work); } - return ieee80211_wk_cancel_remain_on_channel(sdata, cookie); + return 0; } -static enum work_done_result -ieee80211_offchan_tx_done(struct ieee80211_work *wk, struct sk_buff *skb) +static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + u64 cookie) { - /* - * Use the data embedded in the work struct for reporting - * here so if the driver mangled the SKB before dropping - * it (which is the only way we really should get here) - * then we don't report mangled data. - * - * If there was no wait time, then by the time we get here - * the driver will likely not have reported the status yet, - * so in that case userspace will have to deal with it. - */ - - if (wk->offchan_tx.wait && !wk->offchan_tx.status) - cfg80211_mgmt_tx_status(wk->sdata->dev, - (unsigned long) wk->offchan_tx.frame, - wk->data, wk->data_len, false, GFP_KERNEL); + struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); + struct ieee80211_local *local = sdata->local; - return WORK_DONE_DESTROY; + return ieee80211_cancel_roc(local, cookie, false); } -static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, +static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, struct ieee80211_channel *chan, bool offchan, enum nl80211_channel_type channel_type, bool channel_type_valid, unsigned int wait, const u8 *buf, size_t len, bool no_cck, bool dont_wait_for_ack, u64 *cookie) { - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); struct ieee80211_local *local = sdata->local; struct sk_buff *skb; struct sta_info *sta; - struct ieee80211_work *wk; const struct ieee80211_mgmt *mgmt = (void *)buf; + bool need_offchan = false; u32 flags; - bool is_offchan = false; + int ret; if (dont_wait_for_ack) flags = IEEE80211_TX_CTL_NO_ACK; @@ -2255,33 +2425,28 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, flags = IEEE80211_TX_INTFL_NL80211_FRAME_TX | IEEE80211_TX_CTL_REQ_TX_STATUS; - /* Check that we are on the requested channel for transmission */ - if (chan != local->tmp_channel && - chan != local->oper_channel) - is_offchan = true; - if (channel_type_valid && - (channel_type != local->tmp_channel_type && - channel_type != local->_oper_channel_type)) - is_offchan = true; - - if (chan == local->hw_roc_channel) { - /* TODO: check channel type? */ - is_offchan = false; - flags |= IEEE80211_TX_CTL_TX_OFFCHAN; - } - if (no_cck) flags |= IEEE80211_TX_CTL_NO_CCK_RATE; - if (is_offchan && !offchan) - return -EBUSY; - switch (sdata->vif.type) { case NL80211_IFTYPE_ADHOC: + if (!sdata->vif.bss_conf.ibss_joined) + need_offchan = true; + /* fall through */ +#ifdef CONFIG_MAC80211_MESH + case NL80211_IFTYPE_MESH_POINT: + if (ieee80211_vif_is_mesh(&sdata->vif) && + !sdata->u.mesh.mesh_id_len) + need_offchan = true; + /* fall through */ +#endif case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP_VLAN: case NL80211_IFTYPE_P2P_GO: - case NL80211_IFTYPE_MESH_POINT: + if (sdata->vif.type != NL80211_IFTYPE_ADHOC && + !ieee80211_vif_is_mesh(&sdata->vif) && + !rcu_access_pointer(sdata->bss->beacon)) + need_offchan = true; if (!ieee80211_is_action(mgmt->frame_control) || mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) break; @@ -2293,167 +2458,101 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, break; case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_P2P_CLIENT: + if (!sdata->u.mgd.associated) + need_offchan = true; break; default: return -EOPNOTSUPP; } + mutex_lock(&local->mtx); + + /* Check if the operating channel is the requested channel */ + if (!need_offchan) { + need_offchan = chan != local->oper_channel; + if (channel_type_valid && + channel_type != local->_oper_channel_type) + need_offchan = true; + } + + if (need_offchan && !offchan) { + ret = -EBUSY; + goto out_unlock; + } + skb = dev_alloc_skb(local->hw.extra_tx_headroom + len); - if (!skb) - return -ENOMEM; + if (!skb) { + ret = -ENOMEM; + goto out_unlock; + } skb_reserve(skb, local->hw.extra_tx_headroom); memcpy(skb_put(skb, len), buf, len); IEEE80211_SKB_CB(skb)->flags = flags; - if (flags & IEEE80211_TX_CTL_TX_OFFCHAN) - IEEE80211_SKB_CB(skb)->hw_queue = - local->hw.offchannel_tx_hw_queue; - skb->dev = sdata->dev; - *cookie = (unsigned long) skb; - - if (is_offchan && local->ops->remain_on_channel) { - unsigned int duration; - int ret; - - mutex_lock(&local->mtx); - /* - * If the duration is zero, then the driver - * wouldn't actually do anything. Set it to - * 100 for now. - * - * TODO: cancel the off-channel operation - * when we get the SKB's TX status and - * the wait time was zero before. - */ - duration = 100; - if (wait) - duration = wait; - ret = ieee80211_remain_on_channel_hw(local, dev, chan, - channel_type, - duration, cookie); - if (ret) { - kfree_skb(skb); - mutex_unlock(&local->mtx); - return ret; - } - - local->hw_roc_for_tx = true; - local->hw_roc_duration = wait; - - /* - * queue up frame for transmission after - * ieee80211_ready_on_channel call - */ + if (!need_offchan) { + *cookie = (unsigned long) skb; + ieee80211_tx_skb(sdata, skb); + ret = 0; + goto out_unlock; + } - /* modify cookie to prevent API mismatches */ - *cookie ^= 2; - IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_TX_OFFCHAN; + IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_TX_OFFCHAN; + if (local->hw.flags & IEEE80211_HW_QUEUE_CONTROL) IEEE80211_SKB_CB(skb)->hw_queue = local->hw.offchannel_tx_hw_queue; - local->hw_roc_skb = skb; - local->hw_roc_skb_for_status = skb; - mutex_unlock(&local->mtx); - - return 0; - } - - /* - * Can transmit right away if the channel was the - * right one and there's no wait involved... If a - * wait is involved, we might otherwise not be on - * the right channel for long enough! - */ - if (!is_offchan && !wait && !sdata->vif.bss_conf.idle) { - ieee80211_tx_skb(sdata, skb); - return 0; - } - wk = kzalloc(sizeof(*wk) + len, GFP_KERNEL); - if (!wk) { + /* This will handle all kinds of coalescing and immediate TX */ + ret = ieee80211_start_roc_work(local, sdata, chan, channel_type, + wait, cookie, skb); + if (ret) kfree_skb(skb); - return -ENOMEM; - } - - wk->type = IEEE80211_WORK_OFFCHANNEL_TX; - wk->chan = chan; - wk->chan_type = channel_type; - wk->sdata = sdata; - wk->done = ieee80211_offchan_tx_done; - wk->offchan_tx.frame = skb; - wk->offchan_tx.wait = wait; - wk->data_len = len; - memcpy(wk->data, buf, len); - - ieee80211_add_work(wk); - return 0; + out_unlock: + mutex_unlock(&local->mtx); + return ret; } static int ieee80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, - struct net_device *dev, + struct wireless_dev *wdev, u64 cookie) { - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct ieee80211_local *local = sdata->local; - struct ieee80211_work *wk; - int ret = -ENOENT; - - mutex_lock(&local->mtx); - - if (local->ops->cancel_remain_on_channel) { - cookie ^= 2; - ret = ieee80211_cancel_remain_on_channel_hw(local, cookie); - - if (ret == 0) { - kfree_skb(local->hw_roc_skb); - local->hw_roc_skb = NULL; - local->hw_roc_skb_for_status = NULL; - } - - mutex_unlock(&local->mtx); - - return ret; - } - - list_for_each_entry(wk, &local->work_list, list) { - if (wk->sdata != sdata) - continue; - - if (wk->type != IEEE80211_WORK_OFFCHANNEL_TX) - continue; - - if (cookie != (unsigned long) wk->offchan_tx.frame) - continue; - - wk->timeout = jiffies; - - ieee80211_queue_work(&local->hw, &local->work_work); - ret = 0; - break; - } - mutex_unlock(&local->mtx); + struct ieee80211_local *local = wiphy_priv(wiphy); - return ret; + return ieee80211_cancel_roc(local, cookie, true); } static void ieee80211_mgmt_frame_register(struct wiphy *wiphy, - struct net_device *dev, + struct wireless_dev *wdev, u16 frame_type, bool reg) { struct ieee80211_local *local = wiphy_priv(wiphy); + struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); - if (frame_type != (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ)) - return; + switch (frame_type) { + case IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH: + if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { + struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; - if (reg) - local->probe_req_reg++; - else - local->probe_req_reg--; + if (reg) + ifibss->auth_frame_registrations++; + else + ifibss->auth_frame_registrations--; + } + break; + case IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ: + if (reg) + local->probe_req_reg++; + else + local->probe_req_reg--; - ieee80211_queue_work(&local->hw, &local->reconfig_filter); + ieee80211_queue_work(&local->hw, &local->reconfig_filter); + break; + default: + break; + } } static int ieee80211_set_antenna(struct wiphy *wiphy, u32 tx_ant, u32 rx_ant) @@ -2573,8 +2672,8 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev, tf->u.setup_req.capability = cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); - ieee80211_add_srates_ie(&sdata->vif, skb, false); - ieee80211_add_ext_srates_ie(&sdata->vif, skb, false); + ieee80211_add_srates_ie(sdata, skb, false); + ieee80211_add_ext_srates_ie(sdata, skb, false); ieee80211_tdls_add_ext_capab(skb); break; case WLAN_TDLS_SETUP_RESPONSE: @@ -2587,8 +2686,8 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev, tf->u.setup_resp.capability = cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); - ieee80211_add_srates_ie(&sdata->vif, skb, false); - ieee80211_add_ext_srates_ie(&sdata->vif, skb, false); + ieee80211_add_srates_ie(sdata, skb, false); + ieee80211_add_ext_srates_ie(sdata, skb, false); ieee80211_tdls_add_ext_capab(skb); break; case WLAN_TDLS_SETUP_CONFIRM: @@ -2648,8 +2747,8 @@ ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev, mgmt->u.action.u.tdls_discover_resp.capability = cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); - ieee80211_add_srates_ie(&sdata->vif, skb, false); - ieee80211_add_ext_srates_ie(&sdata->vif, skb, false); + ieee80211_add_srates_ie(sdata, skb, false); + ieee80211_add_ext_srates_ie(sdata, skb, false); ieee80211_tdls_add_ext_capab(skb); break; default: @@ -2679,9 +2778,8 @@ static int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, !sdata->u.mgd.associated) return -EINVAL; -#ifdef CONFIG_MAC80211_VERBOSE_TDLS_DEBUG - printk(KERN_DEBUG "TDLS mgmt action %d peer %pM\n", action_code, peer); -#endif + tdls_dbg(sdata, "TDLS mgmt action %d peer %pM\n", + action_code, peer); skb = dev_alloc_skb(local->hw.extra_tx_headroom + max(sizeof(struct ieee80211_mgmt), @@ -2790,9 +2888,7 @@ static int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, if (sdata->vif.type != NL80211_IFTYPE_STATION) return -EINVAL; -#ifdef CONFIG_MAC80211_VERBOSE_TDLS_DEBUG - printk(KERN_DEBUG "TDLS oper %d peer %pM\n", oper, peer); -#endif + tdls_dbg(sdata, "TDLS oper %d peer %pM\n", oper, peer); switch (oper) { case NL80211_TDLS_ENABLE_LINK: @@ -2889,8 +2985,8 @@ static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev, } static struct ieee80211_channel * -ieee80211_wiphy_get_channel(struct wiphy *wiphy, - enum nl80211_channel_type *type) +ieee80211_cfg_get_channel(struct wiphy *wiphy, struct wireless_dev *wdev, + enum nl80211_channel_type *type) { struct ieee80211_local *local = wiphy_priv(wiphy); @@ -2936,7 +3032,7 @@ struct cfg80211_ops mac80211_config_ops = { #endif .change_bss = ieee80211_change_bss, .set_txq_params = ieee80211_set_txq_params, - .set_channel = ieee80211_set_channel, + .set_monitor_channel = ieee80211_set_monitor_channel, .suspend = ieee80211_suspend, .resume = ieee80211_resume, .scan = ieee80211_scan, @@ -2971,7 +3067,6 @@ struct cfg80211_ops mac80211_config_ops = { .tdls_oper = ieee80211_tdls_oper, .tdls_mgmt = ieee80211_tdls_mgmt, .probe_client = ieee80211_probe_client, - .get_channel = ieee80211_wiphy_get_channel, .set_noack_map = ieee80211_set_noack_map, #ifdef CONFIG_PM .set_wakeup = ieee80211_set_wakeup, @@ -2979,4 +3074,5 @@ struct cfg80211_ops mac80211_config_ops = { .get_et_sset_count = ieee80211_get_et_sset_count, .get_et_stats = ieee80211_get_et_stats, .get_et_strings = ieee80211_get_et_strings, + .get_channel = ieee80211_cfg_get_channel, }; diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index c76cf7230c7..f0f87e5a1d3 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -41,6 +41,10 @@ __ieee80211_get_channel_mode(struct ieee80211_local *local, if (!sdata->u.ap.beacon) continue; break; + case NL80211_IFTYPE_MESH_POINT: + if (!sdata->wdev.mesh_id_len) + continue; + break; default: break; } diff --git a/net/mac80211/debug.h b/net/mac80211/debug.h new file mode 100644 index 00000000000..8f383a57601 --- /dev/null +++ b/net/mac80211/debug.h @@ -0,0 +1,170 @@ +#ifndef __MAC80211_DEBUG_H +#define __MAC80211_DEBUG_H +#include <net/cfg80211.h> + +#ifdef CONFIG_MAC80211_IBSS_DEBUG +#define MAC80211_IBSS_DEBUG 1 +#else +#define MAC80211_IBSS_DEBUG 0 +#endif + +#ifdef CONFIG_MAC80211_PS_DEBUG +#define MAC80211_PS_DEBUG 1 +#else +#define MAC80211_PS_DEBUG 0 +#endif + +#ifdef CONFIG_MAC80211_HT_DEBUG +#define MAC80211_HT_DEBUG 1 +#else +#define MAC80211_HT_DEBUG 0 +#endif + +#ifdef CONFIG_MAC80211_MPL_DEBUG +#define MAC80211_MPL_DEBUG 1 +#else +#define MAC80211_MPL_DEBUG 0 +#endif + +#ifdef CONFIG_MAC80211_MPATH_DEBUG +#define MAC80211_MPATH_DEBUG 1 +#else +#define MAC80211_MPATH_DEBUG 0 +#endif + +#ifdef CONFIG_MAC80211_MHWMP_DEBUG +#define MAC80211_MHWMP_DEBUG 1 +#else +#define MAC80211_MHWMP_DEBUG 0 +#endif + +#ifdef CONFIG_MAC80211_MESH_SYNC_DEBUG +#define MAC80211_MESH_SYNC_DEBUG 1 +#else +#define MAC80211_MESH_SYNC_DEBUG 0 +#endif + +#ifdef CONFIG_MAC80211_TDLS_DEBUG +#define MAC80211_TDLS_DEBUG 1 +#else +#define MAC80211_TDLS_DEBUG 0 +#endif + +#ifdef CONFIG_MAC80211_STA_DEBUG +#define MAC80211_STA_DEBUG 1 +#else +#define MAC80211_STA_DEBUG 0 +#endif + +#ifdef CONFIG_MAC80211_MLME_DEBUG +#define MAC80211_MLME_DEBUG 1 +#else +#define MAC80211_MLME_DEBUG 0 +#endif + +#ifdef CONFIG_MAC80211_MESSAGE_TRACING +void __sdata_info(const char *fmt, ...) __printf(1, 2); +void __sdata_dbg(bool print, const char *fmt, ...) __printf(2, 3); +void __sdata_err(const char *fmt, ...) __printf(1, 2); +void __wiphy_dbg(struct wiphy *wiphy, bool print, const char *fmt, ...) + __printf(3, 4); + +#define _sdata_info(sdata, fmt, ...) \ + __sdata_info("%s: " fmt, (sdata)->name, ##__VA_ARGS__) +#define _sdata_dbg(print, sdata, fmt, ...) \ + __sdata_dbg(print, "%s: " fmt, (sdata)->name, ##__VA_ARGS__) +#define _sdata_err(sdata, fmt, ...) \ + __sdata_err("%s: " fmt, (sdata)->name, ##__VA_ARGS__) +#define _wiphy_dbg(print, wiphy, fmt, ...) \ + __wiphy_dbg(wiphy, print, fmt, ##__VA_ARGS__) +#else +#define _sdata_info(sdata, fmt, ...) \ +do { \ + pr_info("%s: " fmt, \ + (sdata)->name, ##__VA_ARGS__); \ +} while (0) + +#define _sdata_dbg(print, sdata, fmt, ...) \ +do { \ + if (print) \ + pr_debug("%s: " fmt, \ + (sdata)->name, ##__VA_ARGS__); \ +} while (0) + +#define _sdata_err(sdata, fmt, ...) \ +do { \ + pr_err("%s: " fmt, \ + (sdata)->name, ##__VA_ARGS__); \ +} while (0) + +#define _wiphy_dbg(print, wiphy, fmt, ...) \ +do { \ + if (print) \ + wiphy_dbg((wiphy), fmt, ##__VA_ARGS__); \ +} while (0) +#endif + +#define sdata_info(sdata, fmt, ...) \ + _sdata_info(sdata, fmt, ##__VA_ARGS__) +#define sdata_err(sdata, fmt, ...) \ + _sdata_err(sdata, fmt, ##__VA_ARGS__) +#define sdata_dbg(sdata, fmt, ...) \ + _sdata_dbg(1, sdata, fmt, ##__VA_ARGS__) + +#define ht_dbg(sdata, fmt, ...) \ + _sdata_dbg(MAC80211_HT_DEBUG, \ + sdata, fmt, ##__VA_ARGS__) + +#define ht_dbg_ratelimited(sdata, fmt, ...) \ + _sdata_dbg(MAC80211_HT_DEBUG && net_ratelimit(), \ + sdata, fmt, ##__VA_ARGS__) + +#define ibss_dbg(sdata, fmt, ...) \ + _sdata_dbg(MAC80211_IBSS_DEBUG, \ + sdata, fmt, ##__VA_ARGS__) + +#define ps_dbg(sdata, fmt, ...) \ + _sdata_dbg(MAC80211_PS_DEBUG, \ + sdata, fmt, ##__VA_ARGS__) + +#define ps_dbg_hw(hw, fmt, ...) \ + _wiphy_dbg(MAC80211_PS_DEBUG, \ + (hw)->wiphy, fmt, ##__VA_ARGS__) + +#define ps_dbg_ratelimited(sdata, fmt, ...) \ + _sdata_dbg(MAC80211_PS_DEBUG && net_ratelimit(), \ + sdata, fmt, ##__VA_ARGS__) + +#define mpl_dbg(sdata, fmt, ...) \ + _sdata_dbg(MAC80211_MPL_DEBUG, \ + sdata, fmt, ##__VA_ARGS__) + +#define mpath_dbg(sdata, fmt, ...) \ + _sdata_dbg(MAC80211_MPATH_DEBUG, \ + sdata, fmt, ##__VA_ARGS__) + +#define mhwmp_dbg(sdata, fmt, ...) \ + _sdata_dbg(MAC80211_MHWMP_DEBUG, \ + sdata, fmt, ##__VA_ARGS__) + +#define msync_dbg(sdata, fmt, ...) \ + _sdata_dbg(MAC80211_MESH_SYNC_DEBUG, \ + sdata, fmt, ##__VA_ARGS__) + +#define tdls_dbg(sdata, fmt, ...) \ + _sdata_dbg(MAC80211_TDLS_DEBUG, \ + sdata, fmt, ##__VA_ARGS__) + +#define sta_dbg(sdata, fmt, ...) \ + _sdata_dbg(MAC80211_STA_DEBUG, \ + sdata, fmt, ##__VA_ARGS__) + +#define mlme_dbg(sdata, fmt, ...) \ + _sdata_dbg(MAC80211_MLME_DEBUG, \ + sdata, fmt, ##__VA_ARGS__) + +#define mlme_dbg_ratelimited(sdata, fmt, ...) \ + _sdata_dbg(MAC80211_MLME_DEBUG && net_ratelimit(), \ + sdata, fmt, ##__VA_ARGS__) + +#endif /* __MAC80211_DEBUG_H */ diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 778e5916d7c..b8dfb440c8e 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -325,8 +325,6 @@ void debugfs_hw_add(struct ieee80211_local *local) local->rx_handlers_drop_defrag); DEBUGFS_STATS_ADD(rx_handlers_drop_short, local->rx_handlers_drop_short); - DEBUGFS_STATS_ADD(rx_handlers_drop_passive_scan, - local->rx_handlers_drop_passive_scan); DEBUGFS_STATS_ADD(tx_expand_skb_head, local->tx_expand_skb_head); DEBUGFS_STATS_ADD(tx_expand_skb_head_cloned, diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c index 7932767bb48..090d08ff22c 100644 --- a/net/mac80211/debugfs_key.c +++ b/net/mac80211/debugfs_key.c @@ -283,6 +283,11 @@ void ieee80211_debugfs_key_update_default(struct ieee80211_sub_if_data *sdata) lockdep_assert_held(&sdata->local->key_mtx); + if (sdata->debugfs.default_unicast_key) { + debugfs_remove(sdata->debugfs.default_unicast_key); + sdata->debugfs.default_unicast_key = NULL; + } + if (sdata->default_unicast_key) { key = key_mtx_dereference(sdata->local, sdata->default_unicast_key); @@ -290,9 +295,11 @@ void ieee80211_debugfs_key_update_default(struct ieee80211_sub_if_data *sdata) sdata->debugfs.default_unicast_key = debugfs_create_symlink("default_unicast_key", sdata->debugfs.dir, buf); - } else { - debugfs_remove(sdata->debugfs.default_unicast_key); - sdata->debugfs.default_unicast_key = NULL; + } + + if (sdata->debugfs.default_multicast_key) { + debugfs_remove(sdata->debugfs.default_multicast_key); + sdata->debugfs.default_multicast_key = NULL; } if (sdata->default_multicast_key) { @@ -302,9 +309,6 @@ void ieee80211_debugfs_key_update_default(struct ieee80211_sub_if_data *sdata) sdata->debugfs.default_multicast_key = debugfs_create_symlink("default_multicast_key", sdata->debugfs.dir, buf); - } else { - debugfs_remove(sdata->debugfs.default_multicast_key); - sdata->debugfs.default_multicast_key = NULL; } } diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 7ed433c66d6..6d5aec9418e 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -468,48 +468,54 @@ IEEE80211_IF_FILE(fwded_unicast, u.mesh.mshstats.fwded_unicast, DEC); IEEE80211_IF_FILE(fwded_frames, u.mesh.mshstats.fwded_frames, DEC); IEEE80211_IF_FILE(dropped_frames_ttl, u.mesh.mshstats.dropped_frames_ttl, DEC); IEEE80211_IF_FILE(dropped_frames_congestion, - u.mesh.mshstats.dropped_frames_congestion, DEC); + u.mesh.mshstats.dropped_frames_congestion, DEC); IEEE80211_IF_FILE(dropped_frames_no_route, - u.mesh.mshstats.dropped_frames_no_route, DEC); + u.mesh.mshstats.dropped_frames_no_route, DEC); IEEE80211_IF_FILE(estab_plinks, u.mesh.mshstats.estab_plinks, ATOMIC); /* Mesh parameters */ IEEE80211_IF_FILE(dot11MeshMaxRetries, - u.mesh.mshcfg.dot11MeshMaxRetries, DEC); + u.mesh.mshcfg.dot11MeshMaxRetries, DEC); IEEE80211_IF_FILE(dot11MeshRetryTimeout, - u.mesh.mshcfg.dot11MeshRetryTimeout, DEC); + u.mesh.mshcfg.dot11MeshRetryTimeout, DEC); IEEE80211_IF_FILE(dot11MeshConfirmTimeout, - u.mesh.mshcfg.dot11MeshConfirmTimeout, DEC); + u.mesh.mshcfg.dot11MeshConfirmTimeout, DEC); IEEE80211_IF_FILE(dot11MeshHoldingTimeout, - u.mesh.mshcfg.dot11MeshHoldingTimeout, DEC); + u.mesh.mshcfg.dot11MeshHoldingTimeout, DEC); IEEE80211_IF_FILE(dot11MeshTTL, u.mesh.mshcfg.dot11MeshTTL, DEC); IEEE80211_IF_FILE(element_ttl, u.mesh.mshcfg.element_ttl, DEC); IEEE80211_IF_FILE(auto_open_plinks, u.mesh.mshcfg.auto_open_plinks, DEC); IEEE80211_IF_FILE(dot11MeshMaxPeerLinks, - u.mesh.mshcfg.dot11MeshMaxPeerLinks, DEC); + u.mesh.mshcfg.dot11MeshMaxPeerLinks, DEC); IEEE80211_IF_FILE(dot11MeshHWMPactivePathTimeout, - u.mesh.mshcfg.dot11MeshHWMPactivePathTimeout, DEC); + u.mesh.mshcfg.dot11MeshHWMPactivePathTimeout, DEC); IEEE80211_IF_FILE(dot11MeshHWMPpreqMinInterval, - u.mesh.mshcfg.dot11MeshHWMPpreqMinInterval, DEC); + u.mesh.mshcfg.dot11MeshHWMPpreqMinInterval, DEC); IEEE80211_IF_FILE(dot11MeshHWMPperrMinInterval, - u.mesh.mshcfg.dot11MeshHWMPperrMinInterval, DEC); + u.mesh.mshcfg.dot11MeshHWMPperrMinInterval, DEC); IEEE80211_IF_FILE(dot11MeshHWMPnetDiameterTraversalTime, - u.mesh.mshcfg.dot11MeshHWMPnetDiameterTraversalTime, DEC); + u.mesh.mshcfg.dot11MeshHWMPnetDiameterTraversalTime, DEC); IEEE80211_IF_FILE(dot11MeshHWMPmaxPREQretries, - u.mesh.mshcfg.dot11MeshHWMPmaxPREQretries, DEC); + u.mesh.mshcfg.dot11MeshHWMPmaxPREQretries, DEC); IEEE80211_IF_FILE(path_refresh_time, - u.mesh.mshcfg.path_refresh_time, DEC); + u.mesh.mshcfg.path_refresh_time, DEC); IEEE80211_IF_FILE(min_discovery_timeout, - u.mesh.mshcfg.min_discovery_timeout, DEC); + u.mesh.mshcfg.min_discovery_timeout, DEC); IEEE80211_IF_FILE(dot11MeshHWMPRootMode, - u.mesh.mshcfg.dot11MeshHWMPRootMode, DEC); + u.mesh.mshcfg.dot11MeshHWMPRootMode, DEC); IEEE80211_IF_FILE(dot11MeshGateAnnouncementProtocol, - u.mesh.mshcfg.dot11MeshGateAnnouncementProtocol, DEC); + u.mesh.mshcfg.dot11MeshGateAnnouncementProtocol, DEC); IEEE80211_IF_FILE(dot11MeshHWMPRannInterval, - u.mesh.mshcfg.dot11MeshHWMPRannInterval, DEC); + u.mesh.mshcfg.dot11MeshHWMPRannInterval, DEC); IEEE80211_IF_FILE(dot11MeshForwarding, u.mesh.mshcfg.dot11MeshForwarding, DEC); IEEE80211_IF_FILE(rssi_threshold, u.mesh.mshcfg.rssi_threshold, DEC); IEEE80211_IF_FILE(ht_opmode, u.mesh.mshcfg.ht_opmode, DEC); +IEEE80211_IF_FILE(dot11MeshHWMPactivePathToRootTimeout, + u.mesh.mshcfg.dot11MeshHWMPactivePathToRootTimeout, DEC); +IEEE80211_IF_FILE(dot11MeshHWMProotInterval, + u.mesh.mshcfg.dot11MeshHWMProotInterval, DEC); +IEEE80211_IF_FILE(dot11MeshHWMPconfirmationInterval, + u.mesh.mshcfg.dot11MeshHWMPconfirmationInterval, DEC); #endif #define DEBUGFS_ADD_MODE(name, mode) \ @@ -607,9 +613,13 @@ static void add_mesh_config(struct ieee80211_sub_if_data *sdata) MESHPARAMS_ADD(min_discovery_timeout); MESHPARAMS_ADD(dot11MeshHWMPRootMode); MESHPARAMS_ADD(dot11MeshHWMPRannInterval); + MESHPARAMS_ADD(dot11MeshForwarding); MESHPARAMS_ADD(dot11MeshGateAnnouncementProtocol); MESHPARAMS_ADD(rssi_threshold); MESHPARAMS_ADD(ht_opmode); + MESHPARAMS_ADD(dot11MeshHWMPactivePathToRootTimeout); + MESHPARAMS_ADD(dot11MeshHWMProotInterval); + MESHPARAMS_ADD(dot11MeshHWMPconfirmationInterval); #undef MESHPARAMS_ADD } #endif @@ -685,6 +695,7 @@ void ieee80211_debugfs_rename_netdev(struct ieee80211_sub_if_data *sdata) sprintf(buf, "netdev:%s", sdata->name); if (!debugfs_rename(dir->d_parent, dir, dir->d_parent, buf)) - printk(KERN_ERR "mac80211: debugfs: failed to rename debugfs " - "dir to %s\n", buf); + sdata_err(sdata, + "debugfs: failed to rename debugfs dir to %s\n", + buf); } diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 6d33a0c743a..df920319910 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -3,7 +3,7 @@ #include <net/mac80211.h> #include "ieee80211_i.h" -#include "driver-trace.h" +#include "trace.h" static inline void check_sdata_in_driver(struct ieee80211_sub_if_data *sdata) { @@ -27,14 +27,6 @@ static inline void drv_tx(struct ieee80211_local *local, struct sk_buff *skb) local->ops->tx(&local->hw, skb); } -static inline void drv_tx_frags(struct ieee80211_local *local, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - struct sk_buff_head *skbs) -{ - local->ops->tx_frags(&local->hw, vif, sta, skbs); -} - static inline void drv_get_et_strings(struct ieee80211_sub_if_data *sdata, u32 sset, u8 *data) { @@ -845,4 +837,33 @@ drv_allow_buffered_frames(struct ieee80211_local *local, more_data); trace_drv_return_void(local); } + +static inline int drv_get_rssi(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + struct ieee80211_sta *sta, + s8 *rssi_dbm) +{ + int ret; + + might_sleep(); + + ret = local->ops->get_rssi(&local->hw, &sdata->vif, sta, rssi_dbm); + trace_drv_get_rssi(local, sta, *rssi_dbm, ret); + + return ret; +} + +static inline void drv_mgd_prepare_tx(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata) +{ + might_sleep(); + + check_sdata_in_driver(sdata); + WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_STATION); + + trace_drv_mgd_prepare_tx(local, sdata); + if (local->ops->mgd_prepare_tx) + local->ops->mgd_prepare_tx(&local->hw, &sdata->vif); + trace_drv_return_void(local); +} #endif /* __MAC80211_DRIVER_OPS */ diff --git a/net/mac80211/driver-trace.c b/net/mac80211/driver-trace.c deleted file mode 100644 index 8ed8711b1a6..00000000000 --- a/net/mac80211/driver-trace.c +++ /dev/null @@ -1,9 +0,0 @@ -/* bug in tracepoint.h, it should include this */ -#include <linux/module.h> - -/* sparse isn't too happy with all macros... */ -#ifndef __CHECKER__ -#include "driver-ops.h" -#define CREATE_TRACE_POINTS -#include "driver-trace.h" -#endif diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index 6f8615c54b2..4b4538d6392 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c @@ -305,12 +305,10 @@ void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata, tid = (params & IEEE80211_DELBA_PARAM_TID_MASK) >> 12; initiator = (params & IEEE80211_DELBA_PARAM_INITIATOR_MASK) >> 11; -#ifdef CONFIG_MAC80211_HT_DEBUG - net_dbg_ratelimited("delba from %pM (%s) tid %d reason code %d\n", - mgmt->sa, initiator ? "initiator" : "recipient", - tid, - le16_to_cpu(mgmt->u.action.u.delba.reason_code)); -#endif /* CONFIG_MAC80211_HT_DEBUG */ + ht_dbg_ratelimited(sdata, "delba from %pM (%s) tid %d reason code %d\n", + mgmt->sa, initiator ? "initiator" : "recipient", + tid, + le16_to_cpu(mgmt->u.action.u.delba.reason_code)); if (initiator == WLAN_BACK_INITIATOR) __ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_INITIATOR, 0, diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 33d9d0c3e3d..5746d62faba 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -82,8 +82,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, local->oper_channel = chan; channel_type = ifibss->channel_type; - if (channel_type > NL80211_CHAN_HT20 && - !cfg80211_can_beacon_sec_chan(local->hw.wiphy, chan, channel_type)) + if (!cfg80211_can_beacon_sec_chan(local->hw.wiphy, chan, channel_type)) channel_type = NL80211_CHAN_HT20; if (!ieee80211_set_channel_type(local, sdata, channel_type)) { /* can only fail due to HT40+/- mismatch */ @@ -262,11 +261,7 @@ static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta, memcpy(addr, sta->sta.addr, ETH_ALEN); -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - wiphy_debug(sdata->local->hw.wiphy, - "Adding new IBSS station %pM (dev=%s)\n", - addr, sdata->name); -#endif + ibss_dbg(sdata, "Adding new IBSS station %pM\n", addr); sta_info_pre_move_state(sta, IEEE80211_STA_AUTH); sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC); @@ -280,12 +275,10 @@ static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta, /* If it fails, maybe we raced another insertion? */ if (sta_info_insert_rcu(sta)) return sta_info_get(sdata, addr); - if (auth) { -#ifdef CONFIG_MAC80211_IBSS_DEBUG - printk(KERN_DEBUG "TX Auth SA=%pM DA=%pM BSSID=%pM" - "(auth_transaction=1)\n", sdata->vif.addr, - sdata->u.ibss.bssid, addr); -#endif + if (auth && !sdata->u.ibss.auth_frame_registrations) { + ibss_dbg(sdata, + "TX Auth SA=%pM DA=%pM BSSID=%pM (auth_transaction=1)\n", + sdata->vif.addr, sdata->u.ibss.bssid, addr); ieee80211_send_auth(sdata, 1, WLAN_AUTH_OPEN, NULL, 0, addr, sdata->u.ibss.bssid, NULL, 0, 0); } @@ -308,7 +301,7 @@ ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, * allow new one to be added. */ if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) { - net_dbg_ratelimited("%s: No room for a new IBSS STA entry %pM\n", + net_info_ratelimited("%s: No room for a new IBSS STA entry %pM\n", sdata->name, addr); rcu_read_lock(); return NULL; @@ -355,11 +348,9 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata, if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1) return; -#ifdef CONFIG_MAC80211_IBSS_DEBUG - printk(KERN_DEBUG "%s: RX Auth SA=%pM DA=%pM BSSID=%pM." - "(auth_transaction=%d)\n", - sdata->name, mgmt->sa, mgmt->da, mgmt->bssid, auth_transaction); -#endif + ibss_dbg(sdata, + "RX Auth SA=%pM DA=%pM BSSID=%pM (auth_transaction=%d)\n", + mgmt->sa, mgmt->da, mgmt->bssid, auth_transaction); sta_info_destroy_addr(sdata, mgmt->sa); ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, 0, false); rcu_read_unlock(); @@ -422,15 +413,10 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, ieee80211_mandatory_rates(local, band); if (sta->sta.supp_rates[band] != prev_rates) { -#ifdef CONFIG_MAC80211_IBSS_DEBUG - printk(KERN_DEBUG - "%s: updated supp_rates set " - "for %pM based on beacon" - "/probe_resp (0x%x -> 0x%x)\n", - sdata->name, sta->sta.addr, - prev_rates, - sta->sta.supp_rates[band]); -#endif + ibss_dbg(sdata, + "updated supp_rates set for %pM based on beacon/probe_resp (0x%x -> 0x%x)\n", + sta->sta.addr, prev_rates, + sta->sta.supp_rates[band]); rates_updated = true; } } else { @@ -545,22 +531,18 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, rx_timestamp = drv_get_tsf(local, sdata); } -#ifdef CONFIG_MAC80211_IBSS_DEBUG - printk(KERN_DEBUG "RX beacon SA=%pM BSSID=" - "%pM TSF=0x%llx BCN=0x%llx diff=%lld @%lu\n", - mgmt->sa, mgmt->bssid, - (unsigned long long)rx_timestamp, - (unsigned long long)beacon_timestamp, - (unsigned long long)(rx_timestamp - beacon_timestamp), - jiffies); -#endif + ibss_dbg(sdata, + "RX beacon SA=%pM BSSID=%pM TSF=0x%llx BCN=0x%llx diff=%lld @%lu\n", + mgmt->sa, mgmt->bssid, + (unsigned long long)rx_timestamp, + (unsigned long long)beacon_timestamp, + (unsigned long long)(rx_timestamp - beacon_timestamp), + jiffies); if (beacon_timestamp > rx_timestamp) { -#ifdef CONFIG_MAC80211_IBSS_DEBUG - printk(KERN_DEBUG "%s: beacon TSF higher than " - "local TSF - IBSS merge with BSSID %pM\n", - sdata->name, mgmt->bssid); -#endif + ibss_dbg(sdata, + "beacon TSF higher than local TSF - IBSS merge with BSSID %pM\n", + mgmt->bssid); ieee80211_sta_join_ibss(sdata, bss); supp_rates = ieee80211_sta_get_rates(local, elems, band, NULL); ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, @@ -586,7 +568,7 @@ void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata, * allow new one to be added. */ if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) { - net_dbg_ratelimited("%s: No room for a new IBSS STA entry %pM\n", + net_info_ratelimited("%s: No room for a new IBSS STA entry %pM\n", sdata->name, addr); return; } @@ -662,8 +644,8 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata) if (ifibss->fixed_channel) return; - printk(KERN_DEBUG "%s: No active IBSS STAs - trying to scan for other " - "IBSS networks with same SSID (merge)\n", sdata->name); + sdata_info(sdata, + "No active IBSS STAs - trying to scan for other IBSS networks with same SSID (merge)\n"); ieee80211_request_internal_scan(sdata, ifibss->ssid, ifibss->ssid_len, NULL); @@ -691,8 +673,7 @@ static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) bssid[0] |= 0x02; } - printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %pM\n", - sdata->name, bssid); + sdata_info(sdata, "Creating new IBSS network, BSSID %pM\n", bssid); capability = WLAN_CAPABILITY_IBSS; @@ -723,10 +704,7 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) lockdep_assert_held(&ifibss->mtx); active_ibss = ieee80211_sta_active_ibss(sdata); -#ifdef CONFIG_MAC80211_IBSS_DEBUG - printk(KERN_DEBUG "%s: sta_find_ibss (active_ibss=%d)\n", - sdata->name, active_ibss); -#endif /* CONFIG_MAC80211_IBSS_DEBUG */ + ibss_dbg(sdata, "sta_find_ibss (active_ibss=%d)\n", active_ibss); if (active_ibss) return; @@ -749,29 +727,24 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) struct ieee80211_bss *bss; bss = (void *)cbss->priv; -#ifdef CONFIG_MAC80211_IBSS_DEBUG - printk(KERN_DEBUG " sta_find_ibss: selected %pM current " - "%pM\n", cbss->bssid, ifibss->bssid); -#endif /* CONFIG_MAC80211_IBSS_DEBUG */ - - printk(KERN_DEBUG "%s: Selected IBSS BSSID %pM" - " based on configured SSID\n", - sdata->name, cbss->bssid); + ibss_dbg(sdata, + "sta_find_ibss: selected %pM current %pM\n", + cbss->bssid, ifibss->bssid); + sdata_info(sdata, + "Selected IBSS BSSID %pM based on configured SSID\n", + cbss->bssid); ieee80211_sta_join_ibss(sdata, bss); ieee80211_rx_bss_put(local, bss); return; } -#ifdef CONFIG_MAC80211_IBSS_DEBUG - printk(KERN_DEBUG " did not try to join ibss\n"); -#endif /* CONFIG_MAC80211_IBSS_DEBUG */ + ibss_dbg(sdata, "sta_find_ibss: did not try to join ibss\n"); /* Selected IBSS not found in current scan results - try to scan */ if (time_after(jiffies, ifibss->last_scan_completed + IEEE80211_SCAN_INTERVAL)) { - printk(KERN_DEBUG "%s: Trigger new scan to find an IBSS to " - "join\n", sdata->name); + sdata_info(sdata, "Trigger new scan to find an IBSS to join\n"); ieee80211_request_internal_scan(sdata, ifibss->ssid, ifibss->ssid_len, @@ -785,9 +758,8 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) ieee80211_sta_create_ibss(sdata); return; } - printk(KERN_DEBUG "%s: IBSS not allowed on" - " %d MHz\n", sdata->name, - local->hw.conf.channel->center_freq); + sdata_info(sdata, "IBSS not allowed on %d MHz\n", + local->hw.conf.channel->center_freq); /* No IBSS found - decrease scan interval and continue * scanning. */ @@ -822,12 +794,9 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, tx_last_beacon = drv_tx_last_beacon(local); -#ifdef CONFIG_MAC80211_IBSS_DEBUG - printk(KERN_DEBUG "%s: RX ProbeReq SA=%pM DA=%pM BSSID=%pM" - " (tx_last_beacon=%d)\n", - sdata->name, mgmt->sa, mgmt->da, - mgmt->bssid, tx_last_beacon); -#endif /* CONFIG_MAC80211_IBSS_DEBUG */ + ibss_dbg(sdata, + "RX ProbeReq SA=%pM DA=%pM BSSID=%pM (tx_last_beacon=%d)\n", + mgmt->sa, mgmt->da, mgmt->bssid, tx_last_beacon); if (!tx_last_beacon && is_multicast_ether_addr(mgmt->da)) return; @@ -840,11 +809,8 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, pos = mgmt->u.probe_req.variable; if (pos[0] != WLAN_EID_SSID || pos + 2 + pos[1] > end) { -#ifdef CONFIG_MAC80211_IBSS_DEBUG - printk(KERN_DEBUG "%s: Invalid SSID IE in ProbeReq " - "from %pM\n", - sdata->name, mgmt->sa); -#endif + ibss_dbg(sdata, "Invalid SSID IE in ProbeReq from %pM\n", + mgmt->sa); return; } if (pos[1] != 0 && @@ -861,10 +827,7 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, resp = (struct ieee80211_mgmt *) skb->data; memcpy(resp->da, mgmt->sa, ETH_ALEN); -#ifdef CONFIG_MAC80211_IBSS_DEBUG - printk(KERN_DEBUG "%s: Sending ProbeResp to %pM\n", - sdata->name, resp->da); -#endif /* CONFIG_MAC80211_IBSS_DEBUG */ + ibss_dbg(sdata, "Sending ProbeResp to %pM\n", resp->da); IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; ieee80211_tx_skb(sdata, skb); } diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 3f3cd50fff1..bb61f7718c4 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -30,6 +30,7 @@ #include <net/mac80211.h> #include "key.h" #include "sta_info.h" +#include "debug.h" struct ieee80211_local; @@ -55,11 +56,14 @@ struct ieee80211_local; #define TU_TO_JIFFIES(x) (usecs_to_jiffies((x) * 1024)) #define TU_TO_EXP_TIME(x) (jiffies + TU_TO_JIFFIES(x)) +/* + * Some APs experience problems when working with U-APSD. Decrease the + * probability of that happening by using legacy mode for all ACs but VO. + * The AP that caused us trouble was a Cisco 4410N. It ignores our + * setting, and always treats non-VO ACs as legacy. + */ #define IEEE80211_DEFAULT_UAPSD_QUEUES \ - (IEEE80211_WMM_IE_STA_QOSINFO_AC_BK | \ - IEEE80211_WMM_IE_STA_QOSINFO_AC_BE | \ - IEEE80211_WMM_IE_STA_QOSINFO_AC_VI | \ - IEEE80211_WMM_IE_STA_QOSINFO_AC_VO) + IEEE80211_WMM_IE_STA_QOSINFO_AC_VO #define IEEE80211_DEFAULT_MAX_SP_LEN \ IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL @@ -81,6 +85,8 @@ struct ieee80211_bss { size_t ssid_len; u8 ssid[IEEE80211_MAX_SSID_LEN]; + u32 device_ts; + u8 dtim_period; bool wmm_used; @@ -203,7 +209,6 @@ typedef unsigned __bitwise__ ieee80211_rx_result; * enum ieee80211_packet_rx_flags - packet RX flags * @IEEE80211_RX_RA_MATCH: frame is destined to interface currently processed * (incl. multicast frames) - * @IEEE80211_RX_IN_SCAN: received while scanning * @IEEE80211_RX_FRAGMENTED: fragmented frame * @IEEE80211_RX_AMSDU: a-MSDU packet * @IEEE80211_RX_MALFORMED_ACTION_FRM: action frame is malformed @@ -213,7 +218,6 @@ typedef unsigned __bitwise__ ieee80211_rx_result; * @rx_flags field of &struct ieee80211_rx_status. */ enum ieee80211_packet_rx_flags { - IEEE80211_RX_IN_SCAN = BIT(0), IEEE80211_RX_RA_MATCH = BIT(1), IEEE80211_RX_FRAGMENTED = BIT(2), IEEE80211_RX_AMSDU = BIT(3), @@ -317,55 +321,30 @@ struct mesh_preq_queue { u8 flags; }; -enum ieee80211_work_type { - IEEE80211_WORK_ABORT, - IEEE80211_WORK_REMAIN_ON_CHANNEL, - IEEE80211_WORK_OFFCHANNEL_TX, -}; - -/** - * enum work_done_result - indicates what to do after work was done - * - * @WORK_DONE_DESTROY: This work item is no longer needed, destroy. - * @WORK_DONE_REQUEUE: This work item was reset to be reused, and - * should be requeued. - */ -enum work_done_result { - WORK_DONE_DESTROY, - WORK_DONE_REQUEUE, -}; +#if HZ/100 == 0 +#define IEEE80211_ROC_MIN_LEFT 1 +#else +#define IEEE80211_ROC_MIN_LEFT (HZ/100) +#endif -struct ieee80211_work { +struct ieee80211_roc_work { struct list_head list; + struct list_head dependents; - struct rcu_head rcu_head; + struct delayed_work work; struct ieee80211_sub_if_data *sdata; - enum work_done_result (*done)(struct ieee80211_work *wk, - struct sk_buff *skb); - struct ieee80211_channel *chan; enum nl80211_channel_type chan_type; - unsigned long timeout; - enum ieee80211_work_type type; + bool started, abort, hw_begun, notified; - bool started; + unsigned long hw_start_time; - union { - struct { - u32 duration; - } remain; - struct { - struct sk_buff *frame; - u32 wait; - bool status; - } offchan_tx; - }; - - size_t data_len; - u8 data[]; + u32 duration, req_duration; + struct sk_buff *frame; + u64 mgmt_tx_cookie; }; /* flags used in struct ieee80211_if_managed.flags */ @@ -399,7 +378,6 @@ struct ieee80211_mgd_auth_data { struct ieee80211_mgd_assoc_data { struct cfg80211_bss *bss; const u8 *supp_rates; - const u8 *ht_operation_ie; unsigned long timeout; int tries; @@ -414,6 +392,8 @@ struct ieee80211_mgd_assoc_data { bool sent_assoc; bool synced; + u8 ap_ht_param; + size_t ie_len; u8 ie[]; }; @@ -532,6 +512,7 @@ struct ieee80211_if_ibss { bool privacy; bool control_port; + unsigned int auth_frame_registrations; u8 bssid[ETH_ALEN] __aligned(2); u8 ssid[IEEE80211_MAX_SSID_LEN]; @@ -701,6 +682,9 @@ struct ieee80211_sub_if_data { /* TID bitmap for NoAck policy */ u16 noack_map; + /* bit field of ACM bits (BIT(802.1D tag)) */ + u8 wmm_acm; + struct ieee80211_key __rcu *keys[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS]; struct ieee80211_key __rcu *default_unicast_key; struct ieee80211_key __rcu *default_multicast_key; @@ -847,13 +831,6 @@ struct ieee80211_local { const struct ieee80211_ops *ops; /* - * work stuff, potentially off-channel (in the future) - */ - struct list_head work_list; - struct timer_list work_timer; - struct work_struct work_work; - - /* * private workqueue to mac80211. mac80211 makes this accessible * via ieee80211_queue_work() */ @@ -912,6 +889,9 @@ struct ieee80211_local { /* device is started */ bool started; + /* device is during a HW reconfig */ + bool in_reconfig; + /* wowlan is enabled -- don't reconfig on resume */ bool wowlan; @@ -985,14 +965,14 @@ struct ieee80211_local { int scan_channel_idx; int scan_ies_len; - bool sched_scanning; struct ieee80211_sched_scan_ies sched_scan_ies; struct work_struct sched_scan_stopped_work; + struct ieee80211_sub_if_data __rcu *sched_scan_sdata; unsigned long leave_oper_channel_time; enum mac80211_scan_state next_scan_state; struct delayed_work scan_work; - struct ieee80211_sub_if_data *scan_sdata; + struct ieee80211_sub_if_data __rcu *scan_sdata; enum nl80211_channel_type _oper_channel_type; struct ieee80211_channel *oper_channel, *csa_channel; @@ -1034,7 +1014,6 @@ struct ieee80211_local { unsigned int rx_handlers_drop_nullfunc; unsigned int rx_handlers_drop_defrag; unsigned int rx_handlers_drop_short; - unsigned int rx_handlers_drop_passive_scan; unsigned int tx_expand_skb_head; unsigned int tx_expand_skb_head_cloned; unsigned int rx_expand_skb_head; @@ -1050,7 +1029,6 @@ struct ieee80211_local { int total_ps_buffered; /* total number of all buffered unicast and * multicast packets for power saving stations */ - unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */ bool pspolling; bool offchannel_ps_enabled; @@ -1087,14 +1065,12 @@ struct ieee80211_local { } debugfs; #endif - struct ieee80211_channel *hw_roc_channel; - struct net_device *hw_roc_dev; - struct sk_buff *hw_roc_skb, *hw_roc_skb_for_status; + /* + * Remain-on-channel support + */ + struct list_head roc_list; struct work_struct hw_roc_start, hw_roc_done; - enum nl80211_channel_type hw_roc_channel_type; - unsigned int hw_roc_duration; - u32 hw_roc_cookie; - bool hw_roc_for_tx; + unsigned long hw_roc_start_time; struct idr ack_status_frames; spinlock_t ack_status_lock; @@ -1114,6 +1090,12 @@ IEEE80211_DEV_TO_SUB_IF(struct net_device *dev) return netdev_priv(dev); } +static inline struct ieee80211_sub_if_data * +IEEE80211_WDEV_TO_SUB_IF(struct wireless_dev *wdev) +{ + return container_of(wdev, struct ieee80211_sub_if_data, wdev); +} + /* this struct represents 802.11n's RA/TID combination */ struct ieee80211_ra_tid { u8 ra[ETH_ALEN]; @@ -1264,8 +1246,7 @@ int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, struct cfg80211_scan_request *req); void ieee80211_scan_cancel(struct ieee80211_local *local); void ieee80211_run_deferred_scan(struct ieee80211_local *local); -ieee80211_rx_result -ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); +void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb); void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local); struct ieee80211_bss * @@ -1290,19 +1271,23 @@ void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local, bool offchannel_ps_enable); void ieee80211_offchannel_return(struct ieee80211_local *local, bool offchannel_ps_disable); -void ieee80211_hw_roc_setup(struct ieee80211_local *local); +void ieee80211_roc_setup(struct ieee80211_local *local); +void ieee80211_start_next_roc(struct ieee80211_local *local); +void ieee80211_roc_purge(struct ieee80211_sub_if_data *sdata); +void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc); +void ieee80211_sw_roc_work(struct work_struct *work); +void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc); /* interface handling */ int ieee80211_iface_init(void); void ieee80211_iface_exit(void); int ieee80211_if_add(struct ieee80211_local *local, const char *name, - struct net_device **new_dev, enum nl80211_iftype type, + struct wireless_dev **new_wdev, enum nl80211_iftype type, struct vif_params *params); int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, enum nl80211_iftype type); void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata); void ieee80211_remove_interfaces(struct ieee80211_local *local); -u32 __ieee80211_recalc_idle(struct ieee80211_local *local); void ieee80211_recalc_idle(struct ieee80211_local *local); void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata, const int offset); @@ -1499,18 +1484,12 @@ u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, struct ieee80211_channel *channel, enum nl80211_channel_type channel_type, u16 prot_mode); - -/* internal work items */ -void ieee80211_work_init(struct ieee80211_local *local); -void ieee80211_add_work(struct ieee80211_work *wk); -void free_work(struct ieee80211_work *wk); -void ieee80211_work_purge(struct ieee80211_sub_if_data *sdata); -int ieee80211_wk_remain_on_channel(struct ieee80211_sub_if_data *sdata, - struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type, - unsigned int duration, u64 *cookie); -int ieee80211_wk_cancel_remain_on_channel( - struct ieee80211_sub_if_data *sdata, u64 cookie); +u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, + u32 cap); +int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata, + struct sk_buff *skb, bool need_basic); +int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata, + struct sk_buff *skb, bool need_basic); /* channel management */ enum ieee80211_chan_mode { diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 8664111d056..bfb57dcc153 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -43,6 +43,128 @@ */ +static u32 ieee80211_idle_off(struct ieee80211_local *local, + const char *reason) +{ + if (!(local->hw.conf.flags & IEEE80211_CONF_IDLE)) + return 0; + + local->hw.conf.flags &= ~IEEE80211_CONF_IDLE; + return IEEE80211_CONF_CHANGE_IDLE; +} + +static u32 ieee80211_idle_on(struct ieee80211_local *local) +{ + if (local->hw.conf.flags & IEEE80211_CONF_IDLE) + return 0; + + drv_flush(local, false); + + local->hw.conf.flags |= IEEE80211_CONF_IDLE; + return IEEE80211_CONF_CHANGE_IDLE; +} + +static u32 __ieee80211_recalc_idle(struct ieee80211_local *local) +{ + struct ieee80211_sub_if_data *sdata; + int count = 0; + bool working = false, scanning = false; + unsigned int led_trig_start = 0, led_trig_stop = 0; + struct ieee80211_roc_work *roc; + +#ifdef CONFIG_PROVE_LOCKING + WARN_ON(debug_locks && !lockdep_rtnl_is_held() && + !lockdep_is_held(&local->iflist_mtx)); +#endif + lockdep_assert_held(&local->mtx); + + list_for_each_entry(sdata, &local->interfaces, list) { + if (!ieee80211_sdata_running(sdata)) { + sdata->vif.bss_conf.idle = true; + continue; + } + + sdata->old_idle = sdata->vif.bss_conf.idle; + + /* do not count disabled managed interfaces */ + if (sdata->vif.type == NL80211_IFTYPE_STATION && + !sdata->u.mgd.associated && + !sdata->u.mgd.auth_data && + !sdata->u.mgd.assoc_data) { + sdata->vif.bss_conf.idle = true; + continue; + } + /* do not count unused IBSS interfaces */ + if (sdata->vif.type == NL80211_IFTYPE_ADHOC && + !sdata->u.ibss.ssid_len) { + sdata->vif.bss_conf.idle = true; + continue; + } + /* count everything else */ + sdata->vif.bss_conf.idle = false; + count++; + } + + if (!local->ops->remain_on_channel) { + list_for_each_entry(roc, &local->roc_list, list) { + working = true; + roc->sdata->vif.bss_conf.idle = false; + } + } + + sdata = rcu_dereference_protected(local->scan_sdata, + lockdep_is_held(&local->mtx)); + if (sdata && !(local->hw.flags & IEEE80211_HW_SCAN_WHILE_IDLE)) { + scanning = true; + sdata->vif.bss_conf.idle = false; + } + + list_for_each_entry(sdata, &local->interfaces, list) { + if (sdata->vif.type == NL80211_IFTYPE_MONITOR || + sdata->vif.type == NL80211_IFTYPE_AP_VLAN) + continue; + if (sdata->old_idle == sdata->vif.bss_conf.idle) + continue; + if (!ieee80211_sdata_running(sdata)) + continue; + ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE); + } + + if (working || scanning) + led_trig_start |= IEEE80211_TPT_LEDTRIG_FL_WORK; + else + led_trig_stop |= IEEE80211_TPT_LEDTRIG_FL_WORK; + + if (count) + led_trig_start |= IEEE80211_TPT_LEDTRIG_FL_CONNECTED; + else + led_trig_stop |= IEEE80211_TPT_LEDTRIG_FL_CONNECTED; + + ieee80211_mod_tpt_led_trig(local, led_trig_start, led_trig_stop); + + if (working) + return ieee80211_idle_off(local, "working"); + if (scanning) + return ieee80211_idle_off(local, "scanning"); + if (!count) + return ieee80211_idle_on(local); + else + return ieee80211_idle_off(local, "in use"); + + return 0; +} + +void ieee80211_recalc_idle(struct ieee80211_local *local) +{ + u32 chg; + + mutex_lock(&local->iflist_mtx); + chg = __ieee80211_recalc_idle(local); + mutex_unlock(&local->iflist_mtx); + if (chg) + ieee80211_hw_config(local, chg); +} + static int ieee80211_change_mtu(struct net_device *dev, int new_mtu) { int meshhdrlen; @@ -57,9 +179,6 @@ static int ieee80211_change_mtu(struct net_device *dev, int new_mtu) return -EINVAL; } -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - printk(KERN_DEBUG "%s: setting MTU %d\n", dev->name, new_mtu); -#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ dev->mtu = new_mtu; return 0; } @@ -100,15 +219,12 @@ static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata, { struct ieee80211_local *local = sdata->local; struct ieee80211_sub_if_data *nsdata; - struct net_device *dev = sdata->dev; ASSERT_RTNL(); /* we hold the RTNL here so can safely walk the list */ list_for_each_entry(nsdata, &local->interfaces, list) { - struct net_device *ndev = nsdata->dev; - - if (ndev != dev && ieee80211_sdata_running(nsdata)) { + if (nsdata != sdata && ieee80211_sdata_running(nsdata)) { /* * Allow only a single IBSS interface to be up at any * time. This is restricted because beacon distribution @@ -127,7 +243,8 @@ static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata, * The remaining checks are only performed for interfaces * with the same MAC address. */ - if (!ether_addr_equal(dev->dev_addr, ndev->dev_addr)) + if (!ether_addr_equal(sdata->vif.addr, + nsdata->vif.addr)) continue; /* @@ -217,17 +334,21 @@ static void ieee80211_set_default_queues(struct ieee80211_sub_if_data *sdata) static int ieee80211_add_virtual_monitor(struct ieee80211_local *local) { struct ieee80211_sub_if_data *sdata; - int ret; + int ret = 0; if (!(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF)) return 0; + mutex_lock(&local->iflist_mtx); + if (local->monitor_sdata) - return 0; + goto out_unlock; sdata = kzalloc(sizeof(*sdata) + local->hw.vif_data_size, GFP_KERNEL); - if (!sdata) - return -ENOMEM; + if (!sdata) { + ret = -ENOMEM; + goto out_unlock; + } /* set up data */ sdata->local = local; @@ -241,18 +362,19 @@ static int ieee80211_add_virtual_monitor(struct ieee80211_local *local) if (WARN_ON(ret)) { /* ok .. stupid driver, it asked for this! */ kfree(sdata); - return ret; + goto out_unlock; } ret = ieee80211_check_queues(sdata); if (ret) { kfree(sdata); - return ret; + goto out_unlock; } rcu_assign_pointer(local->monitor_sdata, sdata); - - return 0; + out_unlock: + mutex_unlock(&local->iflist_mtx); + return ret; } static void ieee80211_del_virtual_monitor(struct ieee80211_local *local) @@ -262,10 +384,12 @@ static void ieee80211_del_virtual_monitor(struct ieee80211_local *local) if (!(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF)) return; - sdata = rtnl_dereference(local->monitor_sdata); + mutex_lock(&local->iflist_mtx); + sdata = rcu_dereference_protected(local->monitor_sdata, + lockdep_is_held(&local->iflist_mtx)); if (!sdata) - return; + goto out_unlock; rcu_assign_pointer(local->monitor_sdata, NULL); synchronize_net(); @@ -273,6 +397,8 @@ static void ieee80211_del_virtual_monitor(struct ieee80211_local *local) drv_remove_interface(local, sdata); kfree(sdata); + out_unlock: + mutex_unlock(&local->iflist_mtx); } /* @@ -520,7 +646,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, clear_bit(SDATA_STATE_RUNNING, &sdata->state); - if (local->scan_sdata == sdata) + if (rcu_access_pointer(local->scan_sdata) == sdata) ieee80211_scan_cancel(local); /* @@ -528,10 +654,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, */ netif_tx_stop_all_queues(sdata->dev); - /* - * Purge work for this interface. - */ - ieee80211_work_purge(sdata); + ieee80211_roc_purge(sdata); /* * Remove all stations associated with this interface. @@ -637,18 +760,6 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, ieee80211_configure_filter(local); break; default: - mutex_lock(&local->mtx); - if (local->hw_roc_dev == sdata->dev && - local->hw_roc_channel) { - /* ignore return value since this is racy */ - drv_cancel_remain_on_channel(local); - ieee80211_queue_work(&local->hw, &local->hw_roc_done); - } - mutex_unlock(&local->mtx); - - flush_work(&local->hw_roc_start); - flush_work(&local->hw_roc_done); - flush_work(&sdata->work); /* * When we get here, the interface is marked down. @@ -823,7 +934,7 @@ static u16 ieee80211_monitor_select_queue(struct net_device *dev, hdr = (void *)((u8 *)skb->data + le16_to_cpu(rtap->it_len)); - return ieee80211_select_queue_80211(local, skb, hdr); + return ieee80211_select_queue_80211(sdata, skb, hdr); } static const struct net_device_ops ieee80211_monitorif_ops = { @@ -1238,7 +1349,7 @@ static void ieee80211_assign_perm_addr(struct ieee80211_local *local, if (__ffs64(mask) + hweight64(mask) != fls64(mask)) { /* not a contiguous mask ... not handled now! */ - printk(KERN_DEBUG "not contiguous\n"); + pr_info("not contiguous\n"); break; } @@ -1284,7 +1395,7 @@ static void ieee80211_assign_perm_addr(struct ieee80211_local *local, } int ieee80211_if_add(struct ieee80211_local *local, const char *name, - struct net_device **new_dev, enum nl80211_iftype type, + struct wireless_dev **new_wdev, enum nl80211_iftype type, struct vif_params *params) { struct net_device *ndev; @@ -1364,6 +1475,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, sdata->u.mgd.use_4addr = params->use_4addr; } + ndev->features |= local->hw.netdev_features; + ret = register_netdevice(ndev); if (ret) goto fail; @@ -1372,8 +1485,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, list_add_tail_rcu(&sdata->list, &local->interfaces); mutex_unlock(&local->iflist_mtx); - if (new_dev) - *new_dev = ndev; + if (new_wdev) + *new_wdev = &sdata->wdev; return 0; @@ -1421,138 +1534,6 @@ void ieee80211_remove_interfaces(struct ieee80211_local *local) list_del(&unreg_list); } -static u32 ieee80211_idle_off(struct ieee80211_local *local, - const char *reason) -{ - if (!(local->hw.conf.flags & IEEE80211_CONF_IDLE)) - return 0; - -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - wiphy_debug(local->hw.wiphy, "device no longer idle - %s\n", reason); -#endif - - local->hw.conf.flags &= ~IEEE80211_CONF_IDLE; - return IEEE80211_CONF_CHANGE_IDLE; -} - -static u32 ieee80211_idle_on(struct ieee80211_local *local) -{ - if (local->hw.conf.flags & IEEE80211_CONF_IDLE) - return 0; - -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - wiphy_debug(local->hw.wiphy, "device now idle\n"); -#endif - - drv_flush(local, false); - - local->hw.conf.flags |= IEEE80211_CONF_IDLE; - return IEEE80211_CONF_CHANGE_IDLE; -} - -u32 __ieee80211_recalc_idle(struct ieee80211_local *local) -{ - struct ieee80211_sub_if_data *sdata; - int count = 0; - bool working = false, scanning = false, hw_roc = false; - struct ieee80211_work *wk; - unsigned int led_trig_start = 0, led_trig_stop = 0; - -#ifdef CONFIG_PROVE_LOCKING - WARN_ON(debug_locks && !lockdep_rtnl_is_held() && - !lockdep_is_held(&local->iflist_mtx)); -#endif - lockdep_assert_held(&local->mtx); - - list_for_each_entry(sdata, &local->interfaces, list) { - if (!ieee80211_sdata_running(sdata)) { - sdata->vif.bss_conf.idle = true; - continue; - } - - sdata->old_idle = sdata->vif.bss_conf.idle; - - /* do not count disabled managed interfaces */ - if (sdata->vif.type == NL80211_IFTYPE_STATION && - !sdata->u.mgd.associated && - !sdata->u.mgd.auth_data && - !sdata->u.mgd.assoc_data) { - sdata->vif.bss_conf.idle = true; - continue; - } - /* do not count unused IBSS interfaces */ - if (sdata->vif.type == NL80211_IFTYPE_ADHOC && - !sdata->u.ibss.ssid_len) { - sdata->vif.bss_conf.idle = true; - continue; - } - /* count everything else */ - sdata->vif.bss_conf.idle = false; - count++; - } - - list_for_each_entry(wk, &local->work_list, list) { - working = true; - wk->sdata->vif.bss_conf.idle = false; - } - - if (local->scan_sdata && - !(local->hw.flags & IEEE80211_HW_SCAN_WHILE_IDLE)) { - scanning = true; - local->scan_sdata->vif.bss_conf.idle = false; - } - - if (local->hw_roc_channel) - hw_roc = true; - - list_for_each_entry(sdata, &local->interfaces, list) { - if (sdata->vif.type == NL80211_IFTYPE_MONITOR || - sdata->vif.type == NL80211_IFTYPE_AP_VLAN) - continue; - if (sdata->old_idle == sdata->vif.bss_conf.idle) - continue; - if (!ieee80211_sdata_running(sdata)) - continue; - ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE); - } - - if (working || scanning || hw_roc) - led_trig_start |= IEEE80211_TPT_LEDTRIG_FL_WORK; - else - led_trig_stop |= IEEE80211_TPT_LEDTRIG_FL_WORK; - - if (count) - led_trig_start |= IEEE80211_TPT_LEDTRIG_FL_CONNECTED; - else - led_trig_stop |= IEEE80211_TPT_LEDTRIG_FL_CONNECTED; - - ieee80211_mod_tpt_led_trig(local, led_trig_start, led_trig_stop); - - if (hw_roc) - return ieee80211_idle_off(local, "hw remain-on-channel"); - if (working) - return ieee80211_idle_off(local, "working"); - if (scanning) - return ieee80211_idle_off(local, "scanning"); - if (!count) - return ieee80211_idle_on(local); - else - return ieee80211_idle_off(local, "in use"); - - return 0; -} - -void ieee80211_recalc_idle(struct ieee80211_local *local) -{ - u32 chg; - - mutex_lock(&local->iflist_mtx); - chg = __ieee80211_recalc_idle(local); - mutex_unlock(&local->iflist_mtx); - if (chg) - ieee80211_hw_config(local, chg); -} - static int netdev_notify(struct notifier_block *nb, unsigned long state, void *ndev) diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 5bb600d93d7..7ae678ba5d6 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -139,7 +139,7 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key) } if (ret != -ENOSPC && ret != -EOPNOTSUPP) - wiphy_err(key->local->hw.wiphy, + sdata_err(sdata, "failed to set key (%d, %pM) to hardware (%d)\n", key->conf.keyidx, sta ? sta->sta.addr : bcast_addr, ret); @@ -186,7 +186,7 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) sta ? &sta->sta : NULL, &key->conf); if (ret) - wiphy_err(key->local->hw.wiphy, + sdata_err(sdata, "failed to remove key (%d, %pM) from hardware (%d)\n", key->conf.keyidx, sta ? sta->sta.addr : bcast_addr, ret); @@ -194,26 +194,6 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; } -void ieee80211_key_removed(struct ieee80211_key_conf *key_conf) -{ - struct ieee80211_key *key; - - key = container_of(key_conf, struct ieee80211_key, conf); - - might_sleep(); - assert_key_lock(key->local); - - key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; - - /* - * Flush TX path to avoid attempts to use this key - * after this function returns. Until then, drivers - * must be prepared to handle the key. - */ - synchronize_rcu(); -} -EXPORT_SYMBOL_GPL(ieee80211_key_removed); - static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx, bool uni, bool multi) { diff --git a/net/mac80211/main.c b/net/mac80211/main.c index f5548e95325..c26e231c733 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -322,7 +322,8 @@ static void ieee80211_restart_work(struct work_struct *work) mutex_lock(&local->mtx); WARN(test_bit(SCAN_HW_SCANNING, &local->scanning) || - local->sched_scanning, + rcu_dereference_protected(local->sched_scan_sdata, + lockdep_is_held(&local->mtx)), "%s called with hardware scan in progress\n", __func__); mutex_unlock(&local->mtx); @@ -345,6 +346,13 @@ void ieee80211_restart_hw(struct ieee80211_hw *hw) ieee80211_stop_queues_by_reason(hw, IEEE80211_QUEUE_STOP_REASON_SUSPEND); + /* + * Stop all Rx during the reconfig. We don't want state changes + * or driver callbacks while this is in progress. + */ + local->in_reconfig = true; + barrier(); + schedule_work(&local->restart_work); } EXPORT_SYMBOL(ieee80211_restart_hw); @@ -455,7 +463,9 @@ static const struct ieee80211_txrx_stypes ieee80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = { [NL80211_IFTYPE_ADHOC] = { .tx = 0xffff, - .rx = BIT(IEEE80211_STYPE_ACTION >> 4), + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | + BIT(IEEE80211_STYPE_AUTH >> 4) | + BIT(IEEE80211_STYPE_DEAUTH >> 4), }, [NL80211_IFTYPE_STATION] = { .tx = 0xffff, @@ -578,7 +588,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, local->hw.priv = (char *)local + ALIGN(sizeof(*local), NETDEV_ALIGN); - BUG_ON(!ops->tx && !ops->tx_frags); + BUG_ON(!ops->tx); BUG_ON(!ops->start); BUG_ON(!ops->stop); BUG_ON(!ops->config); @@ -625,8 +635,6 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work); - ieee80211_work_init(local); - INIT_WORK(&local->restart_work, ieee80211_restart_work); INIT_WORK(&local->reconfig_filter, ieee80211_reconfig_filter); @@ -669,7 +677,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, ieee80211_led_names(local); - ieee80211_hw_roc_setup(local); + ieee80211_roc_setup(local); return &local->hw; } @@ -681,7 +689,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) int result, i; enum ieee80211_band band; int channels, max_bitrates; - bool supp_ht; + bool supp_ht, supp_vht; + netdev_features_t feature_whitelist; static const u32 cipher_suites[] = { /* keep WEP first, it may be removed below */ WLAN_CIPHER_SUITE_WEP40, @@ -698,16 +707,21 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) local->hw.offchannel_tx_hw_queue >= local->hw.queues)) return -EINVAL; - if ((hw->wiphy->wowlan.flags || hw->wiphy->wowlan.n_patterns) #ifdef CONFIG_PM - && (!local->ops->suspend || !local->ops->resume) -#endif - ) + if ((hw->wiphy->wowlan.flags || hw->wiphy->wowlan.n_patterns) && + (!local->ops->suspend || !local->ops->resume)) return -EINVAL; +#endif if ((hw->flags & IEEE80211_HW_SCAN_WHILE_IDLE) && !local->ops->hw_scan) return -EINVAL; + /* Only HW csum features are currently compatible with mac80211 */ + feature_whitelist = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | + NETIF_F_HW_CSUM; + if (WARN_ON(hw->netdev_features & ~feature_whitelist)) + return -EINVAL; + if (hw->max_report_rates == 0) hw->max_report_rates = hw->max_rates; @@ -719,6 +733,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) channels = 0; max_bitrates = 0; supp_ht = false; + supp_vht = false; for (band = 0; band < IEEE80211_NUM_BANDS; band++) { struct ieee80211_supported_band *sband; @@ -736,6 +751,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) if (max_bitrates < sband->n_bitrates) max_bitrates = sband->n_bitrates; supp_ht = supp_ht || sband->ht_cap.ht_supported; + supp_vht = supp_vht || sband->vht_cap.vht_supported; } local->int_scan_req = kzalloc(sizeof(*local->int_scan_req) + @@ -811,6 +827,10 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) if (supp_ht) local->scan_ies_len += 2 + sizeof(struct ieee80211_ht_cap); + if (supp_vht) + local->scan_ies_len += + 2 + sizeof(struct ieee80211_vht_capabilities); + if (!local->ops->hw_scan) { /* For hw_scan, driver needs to set these up. */ local->hw.wiphy->max_scan_ssids = 4; @@ -1009,12 +1029,6 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) rtnl_unlock(); - /* - * Now all work items will be gone, but the - * timer might still be armed, so delete it - */ - del_timer_sync(&local->work_timer); - cancel_work_sync(&local->restart_work); cancel_work_sync(&local->reconfig_filter); diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 2913113c583..6fac18c0423 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -133,7 +133,7 @@ bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie) } /** - * mesh_accept_plinks_update: update accepting_plink in local mesh beacons + * mesh_accept_plinks_update - update accepting_plink in local mesh beacons * * @sdata: mesh interface in which mesh beacons are going to be updated */ @@ -443,7 +443,7 @@ static void ieee80211_mesh_path_root_timer(unsigned long data) void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh) { - if (ifmsh->mshcfg.dot11MeshHWMPRootMode) + if (ifmsh->mshcfg.dot11MeshHWMPRootMode > IEEE80211_ROOTMODE_ROOT) set_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags); else { clear_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags); @@ -523,11 +523,6 @@ static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata, { bool free_plinks; -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - printk(KERN_DEBUG "%s: running mesh housekeeping\n", - sdata->name); -#endif - ieee80211_sta_expire(sdata, IEEE80211_MESH_PEER_INACTIVITY_LIMIT); mesh_path_expire(sdata); @@ -542,11 +537,17 @@ static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata, static void ieee80211_mesh_rootpath(struct ieee80211_sub_if_data *sdata) { struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; + u32 interval; mesh_path_tx_root_frame(sdata); + + if (ifmsh->mshcfg.dot11MeshHWMPRootMode == IEEE80211_PROACTIVE_RANN) + interval = ifmsh->mshcfg.dot11MeshHWMPRannInterval; + else + interval = ifmsh->mshcfg.dot11MeshHWMProotInterval; + mod_timer(&ifmsh->mesh_path_root_timer, - round_jiffies(TU_TO_EXP_TIME( - ifmsh->mshcfg.dot11MeshHWMPRannInterval))); + round_jiffies(TU_TO_EXP_TIME(interval))); } #ifdef CONFIG_PM diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index e3642756f8f..faaa39bcfd1 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -104,6 +104,7 @@ enum mesh_deferred_task_flags { * an mpath to a hash bucket on a path table. * @rann_snd_addr: the RANN sender address * @rann_metric: the aggregated path metric towards the root node + * @last_preq_to_root: Timestamp of last PREQ sent to root * @is_root: the destination station of this path is a root node * @is_gate: the destination station of this path is a mesh gate * @@ -131,6 +132,7 @@ struct mesh_path { spinlock_t state_lock; u8 rann_snd_addr[ETH_ALEN]; u32 rann_metric; + unsigned long last_preq_to_root; bool is_root; bool is_gate; }; @@ -245,7 +247,7 @@ void mesh_rmc_free(struct ieee80211_sub_if_data *sdata); int mesh_rmc_init(struct ieee80211_sub_if_data *sdata); void ieee80211s_init(void); void ieee80211s_update_metric(struct ieee80211_local *local, - struct sta_info *stainfo, struct sk_buff *skb); + struct sta_info *sta, struct sk_buff *skb); void ieee80211s_stop(void); void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata); void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata); diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 9b59658e865..494bc39f61a 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -13,13 +13,6 @@ #include "wme.h" #include "mesh.h" -#ifdef CONFIG_MAC80211_VERBOSE_MHWMP_DEBUG -#define mhwmp_dbg(fmt, args...) \ - printk(KERN_DEBUG "Mesh HWMP (%s): " fmt "\n", sdata->name, ##args) -#else -#define mhwmp_dbg(fmt, args...) do { (void)(0); } while (0) -#endif - #define TEST_FRAME_LEN 8192 #define MAX_METRIC 0xffffffff #define ARITH_SHIFT 8 @@ -98,6 +91,8 @@ static inline u32 u16_field_get(u8 *preq_elem, int offset, bool ae) #define max_preq_retries(s) (s->u.mesh.mshcfg.dot11MeshHWMPmaxPREQretries) #define disc_timeout_jiff(s) \ msecs_to_jiffies(sdata->u.mesh.mshcfg.min_discovery_timeout) +#define root_path_confirmation_jiffies(s) \ + msecs_to_jiffies(sdata->u.mesh.mshcfg.dot11MeshHWMPconfirmationInterval) enum mpath_frame_type { MPATH_PREQ = 0, @@ -142,19 +137,19 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags, switch (action) { case MPATH_PREQ: - mhwmp_dbg("sending PREQ to %pM", target); + mhwmp_dbg(sdata, "sending PREQ to %pM\n", target); ie_len = 37; pos = skb_put(skb, 2 + ie_len); *pos++ = WLAN_EID_PREQ; break; case MPATH_PREP: - mhwmp_dbg("sending PREP to %pM", target); + mhwmp_dbg(sdata, "sending PREP to %pM\n", target); ie_len = 31; pos = skb_put(skb, 2 + ie_len); *pos++ = WLAN_EID_PREP; break; case MPATH_RANN: - mhwmp_dbg("sending RANN from %pM", orig_addr); + mhwmp_dbg(sdata, "sending RANN from %pM\n", orig_addr); ie_len = sizeof(struct ieee80211_rann_ie); pos = skb_put(skb, 2 + ie_len); *pos++ = WLAN_EID_RANN; @@ -303,7 +298,7 @@ int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn, } void ieee80211s_update_metric(struct ieee80211_local *local, - struct sta_info *stainfo, struct sk_buff *skb) + struct sta_info *sta, struct sk_buff *skb) { struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; @@ -315,15 +310,14 @@ void ieee80211s_update_metric(struct ieee80211_local *local, failed = !(txinfo->flags & IEEE80211_TX_STAT_ACK); /* moving average, scaled to 100 */ - stainfo->fail_avg = ((80 * stainfo->fail_avg + 5) / 100 + 20 * failed); - if (stainfo->fail_avg > 95) - mesh_plink_broken(stainfo); + sta->fail_avg = ((80 * sta->fail_avg + 5) / 100 + 20 * failed); + if (sta->fail_avg > 95) + mesh_plink_broken(sta); } static u32 airtime_link_metric_get(struct ieee80211_local *local, struct sta_info *sta) { - struct ieee80211_supported_band *sband; struct rate_info rinfo; /* This should be adjusted for each device */ int device_constant = 1 << ARITH_SHIFT; @@ -333,8 +327,6 @@ static u32 airtime_link_metric_get(struct ieee80211_local *local, u32 tx_time, estimated_retx; u64 result; - sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; - if (sta->fail_avg >= 100) return MAX_METRIC; @@ -519,10 +511,11 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, struct mesh_path *mpath = NULL; u8 *target_addr, *orig_addr; const u8 *da; - u8 target_flags, ttl; - u32 orig_sn, target_sn, lifetime; + u8 target_flags, ttl, flags; + u32 orig_sn, target_sn, lifetime, orig_metric; bool reply = false; bool forward = true; + bool root_is_gate; /* Update target SN, if present */ target_addr = PREQ_IE_TARGET_ADDR(preq_elem); @@ -530,11 +523,15 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, target_sn = PREQ_IE_TARGET_SN(preq_elem); orig_sn = PREQ_IE_ORIG_SN(preq_elem); target_flags = PREQ_IE_TARGET_F(preq_elem); + orig_metric = metric; + /* Proactive PREQ gate announcements */ + flags = PREQ_IE_FLAGS(preq_elem); + root_is_gate = !!(flags & RANN_FLAG_IS_GATE); - mhwmp_dbg("received PREQ from %pM", orig_addr); + mhwmp_dbg(sdata, "received PREQ from %pM\n", orig_addr); if (ether_addr_equal(target_addr, sdata->vif.addr)) { - mhwmp_dbg("PREQ is for us"); + mhwmp_dbg(sdata, "PREQ is for us\n"); forward = false; reply = true; metric = 0; @@ -544,6 +541,22 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, target_sn = ++ifmsh->sn; ifmsh->last_sn_update = jiffies; } + } else if (is_broadcast_ether_addr(target_addr) && + (target_flags & IEEE80211_PREQ_TO_FLAG)) { + rcu_read_lock(); + mpath = mesh_path_lookup(orig_addr, sdata); + if (mpath) { + if (flags & IEEE80211_PREQ_PROACTIVE_PREP_FLAG) { + reply = true; + target_addr = sdata->vif.addr; + target_sn = ++ifmsh->sn; + metric = 0; + ifmsh->last_sn_update = jiffies; + } + if (root_is_gate) + mesh_path_add_gate(mpath); + } + rcu_read_unlock(); } else { rcu_read_lock(); mpath = mesh_path_lookup(target_addr, sdata); @@ -570,19 +583,20 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, lifetime = PREQ_IE_LIFETIME(preq_elem); ttl = ifmsh->mshcfg.element_ttl; if (ttl != 0) { - mhwmp_dbg("replying to the PREQ"); + mhwmp_dbg(sdata, "replying to the PREQ\n"); mesh_path_sel_frame_tx(MPATH_PREP, 0, orig_addr, cpu_to_le32(orig_sn), 0, target_addr, cpu_to_le32(target_sn), mgmt->sa, 0, ttl, cpu_to_le32(lifetime), cpu_to_le32(metric), 0, sdata); - } else + } else { ifmsh->mshstats.dropped_frames_ttl++; + } } if (forward && ifmsh->mshcfg.dot11MeshForwarding) { u32 preq_id; - u8 hopcount, flags; + u8 hopcount; ttl = PREQ_IE_TTL(preq_elem); lifetime = PREQ_IE_LIFETIME(preq_elem); @@ -590,13 +604,19 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, ifmsh->mshstats.dropped_frames_ttl++; return; } - mhwmp_dbg("forwarding the PREQ from %pM", orig_addr); + mhwmp_dbg(sdata, "forwarding the PREQ from %pM\n", orig_addr); --ttl; - flags = PREQ_IE_FLAGS(preq_elem); preq_id = PREQ_IE_PREQ_ID(preq_elem); hopcount = PREQ_IE_HOPCOUNT(preq_elem) + 1; da = (mpath && mpath->is_root) ? mpath->rann_snd_addr : broadcast_addr; + + if (flags & IEEE80211_PREQ_PROACTIVE_PREP_FLAG) { + target_addr = PREQ_IE_TARGET_ADDR(preq_elem); + target_sn = PREQ_IE_TARGET_SN(preq_elem); + metric = orig_metric; + } + mesh_path_sel_frame_tx(MPATH_PREQ, flags, orig_addr, cpu_to_le32(orig_sn), target_flags, target_addr, cpu_to_le32(target_sn), da, @@ -631,7 +651,8 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata, u8 next_hop[ETH_ALEN]; u32 target_sn, orig_sn, lifetime; - mhwmp_dbg("received PREP from %pM", PREP_IE_ORIG_ADDR(prep_elem)); + mhwmp_dbg(sdata, "received PREP from %pM\n", + PREP_IE_ORIG_ADDR(prep_elem)); orig_addr = PREP_IE_ORIG_ADDR(prep_elem); if (ether_addr_equal(orig_addr, sdata->vif.addr)) @@ -744,11 +765,6 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata, bool root_is_gate; ttl = rann->rann_ttl; - if (ttl <= 1) { - ifmsh->mshstats.dropped_frames_ttl++; - return; - } - ttl--; flags = rann->rann_flags; root_is_gate = !!(flags & RANN_FLAG_IS_GATE); orig_addr = rann->rann_addr; @@ -762,8 +778,9 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata, if (ether_addr_equal(orig_addr, sdata->vif.addr)) return; - mhwmp_dbg("received RANN from %pM via neighbour %pM (is_gate=%d)", - orig_addr, mgmt->sa, root_is_gate); + mhwmp_dbg(sdata, + "received RANN from %pM via neighbour %pM (is_gate=%d)\n", + orig_addr, mgmt->sa, root_is_gate); rcu_read_lock(); sta = sta_info_get(sdata, mgmt->sa); @@ -785,34 +802,50 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata, } } + if (!(SN_LT(mpath->sn, orig_sn)) && + !(mpath->sn == orig_sn && metric < mpath->rann_metric)) { + rcu_read_unlock(); + return; + } + if ((!(mpath->flags & (MESH_PATH_ACTIVE | MESH_PATH_RESOLVING)) || - time_after(jiffies, mpath->exp_time - 1*HZ)) && - !(mpath->flags & MESH_PATH_FIXED)) { - mhwmp_dbg("%s time to refresh root mpath %pM", sdata->name, - orig_addr); + (time_after(jiffies, mpath->last_preq_to_root + + root_path_confirmation_jiffies(sdata)) || + time_before(jiffies, mpath->last_preq_to_root))) && + !(mpath->flags & MESH_PATH_FIXED) && (ttl != 0)) { + mhwmp_dbg(sdata, + "time to refresh root mpath %pM\n", + orig_addr); mesh_queue_preq(mpath, PREQ_Q_F_START | PREQ_Q_F_REFRESH); + mpath->last_preq_to_root = jiffies; } - if ((SN_LT(mpath->sn, orig_sn) || (mpath->sn == orig_sn && - metric < mpath->rann_metric)) && ifmsh->mshcfg.dot11MeshForwarding) { + mpath->sn = orig_sn; + mpath->rann_metric = metric + metric_txsta; + mpath->is_root = true; + /* Recording RANNs sender address to send individually + * addressed PREQs destined for root mesh STA */ + memcpy(mpath->rann_snd_addr, mgmt->sa, ETH_ALEN); + + if (root_is_gate) + mesh_path_add_gate(mpath); + + if (ttl <= 1) { + ifmsh->mshstats.dropped_frames_ttl++; + rcu_read_unlock(); + return; + } + ttl--; + + if (ifmsh->mshcfg.dot11MeshForwarding) { mesh_path_sel_frame_tx(MPATH_RANN, flags, orig_addr, cpu_to_le32(orig_sn), 0, NULL, 0, broadcast_addr, hopcount, ttl, cpu_to_le32(interval), cpu_to_le32(metric + metric_txsta), 0, sdata); - mpath->sn = orig_sn; - mpath->rann_metric = metric + metric_txsta; - /* Recording RANNs sender address to send individually - * addressed PREQs destined for root mesh STA */ - memcpy(mpath->rann_snd_addr, mgmt->sa, ETH_ALEN); } - mpath->is_root = true; - - if (root_is_gate) - mesh_path_add_gate(mpath); - rcu_read_unlock(); } @@ -889,7 +922,7 @@ static void mesh_queue_preq(struct mesh_path *mpath, u8 flags) preq_node = kmalloc(sizeof(struct mesh_preq_queue), GFP_ATOMIC); if (!preq_node) { - mhwmp_dbg("could not allocate PREQ node"); + mhwmp_dbg(sdata, "could not allocate PREQ node\n"); return; } @@ -898,7 +931,7 @@ static void mesh_queue_preq(struct mesh_path *mpath, u8 flags) spin_unlock_bh(&ifmsh->mesh_preq_queue_lock); kfree(preq_node); if (printk_ratelimit()) - mhwmp_dbg("PREQ node queue full"); + mhwmp_dbg(sdata, "PREQ node queue full\n"); return; } @@ -1021,12 +1054,15 @@ enddiscovery: kfree(preq_node); } -/* mesh_nexthop_resolve - lookup next hop for given skb and start path - * discovery if no forwarding information is found. +/** + * mesh_nexthop_resolve - lookup next hop; conditionally start path discovery * * @skb: 802.11 frame to be sent * @sdata: network subif the frame will be sent through * + * Lookup next hop for given skb and start path discovery if no + * forwarding information is found. + * * Returns: 0 if the next hop was found and -ENOENT if the frame was queued. * skb is freeed here if no mpath could be allocated. */ @@ -1146,7 +1182,7 @@ void mesh_path_timer(unsigned long data) if (!mpath->is_gate && mesh_gate_num(sdata) > 0) { ret = mesh_path_send_to_gates(mpath); if (ret) - mhwmp_dbg("no gate was reachable"); + mhwmp_dbg(sdata, "no gate was reachable\n"); } else mesh_path_flush_pending(mpath); } @@ -1157,13 +1193,34 @@ mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata) { struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; u32 interval = ifmsh->mshcfg.dot11MeshHWMPRannInterval; - u8 flags; + u8 flags, target_flags = 0; flags = (ifmsh->mshcfg.dot11MeshGateAnnouncementProtocol) ? RANN_FLAG_IS_GATE : 0; - mesh_path_sel_frame_tx(MPATH_RANN, flags, sdata->vif.addr, + + switch (ifmsh->mshcfg.dot11MeshHWMPRootMode) { + case IEEE80211_PROACTIVE_RANN: + mesh_path_sel_frame_tx(MPATH_RANN, flags, sdata->vif.addr, cpu_to_le32(++ifmsh->sn), 0, NULL, 0, broadcast_addr, - 0, sdata->u.mesh.mshcfg.element_ttl, + 0, ifmsh->mshcfg.element_ttl, cpu_to_le32(interval), 0, 0, sdata); + break; + case IEEE80211_PROACTIVE_PREQ_WITH_PREP: + flags |= IEEE80211_PREQ_PROACTIVE_PREP_FLAG; + case IEEE80211_PROACTIVE_PREQ_NO_PREP: + interval = ifmsh->mshcfg.dot11MeshHWMPactivePathToRootTimeout; + target_flags |= IEEE80211_PREQ_TO_FLAG | + IEEE80211_PREQ_USN_FLAG; + mesh_path_sel_frame_tx(MPATH_PREQ, flags, sdata->vif.addr, + cpu_to_le32(++ifmsh->sn), target_flags, + (u8 *) broadcast_addr, 0, broadcast_addr, + 0, ifmsh->mshcfg.element_ttl, + cpu_to_le32(interval), + 0, cpu_to_le32(ifmsh->preq_id++), sdata); + break; + default: + mhwmp_dbg(sdata, "Proactive mechanism not supported\n"); + return; + } } diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index b39224d8255..075bc535c60 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -18,12 +18,6 @@ #include "ieee80211_i.h" #include "mesh.h" -#ifdef CONFIG_MAC80211_VERBOSE_MPATH_DEBUG -#define mpath_dbg(fmt, args...) printk(KERN_DEBUG fmt, ##args) -#else -#define mpath_dbg(fmt, args...) do { (void)(0); } while (0) -#endif - /* There will be initially 2^INIT_PATHS_SIZE_ORDER buckets */ #define INIT_PATHS_SIZE_ORDER 2 @@ -322,9 +316,8 @@ static void mesh_path_move_to_queue(struct mesh_path *gate_mpath, spin_lock_irqsave(&gate_mpath->frame_queue.lock, flags); skb_queue_splice(&gateq, &gate_mpath->frame_queue); - mpath_dbg("Mpath queue for gate %pM has %d frames\n", - gate_mpath->dst, - skb_queue_len(&gate_mpath->frame_queue)); + mpath_dbg(gate_mpath->sdata, "Mpath queue for gate %pM has %d frames\n", + gate_mpath->dst, skb_queue_len(&gate_mpath->frame_queue)); spin_unlock_irqrestore(&gate_mpath->frame_queue.lock, flags); if (!copy) @@ -446,9 +439,9 @@ int mesh_path_add_gate(struct mesh_path *mpath) hlist_add_head_rcu(&new_gate->list, tbl->known_gates); spin_unlock_bh(&tbl->gates_lock); rcu_read_unlock(); - mpath_dbg("Mesh path (%s): Recorded new gate: %pM. %d known gates\n", - mpath->sdata->name, mpath->dst, - mpath->sdata->u.mesh.num_gates); + mpath_dbg(mpath->sdata, + "Mesh path: Recorded new gate: %pM. %d known gates\n", + mpath->dst, mpath->sdata->u.mesh.num_gates); return 0; err_rcu: rcu_read_unlock(); @@ -477,8 +470,8 @@ static int mesh_gate_del(struct mesh_table *tbl, struct mesh_path *mpath) spin_unlock_bh(&tbl->gates_lock); mpath->sdata->u.mesh.num_gates--; mpath->is_gate = false; - mpath_dbg("Mesh path (%s): Deleted gate: %pM. " - "%d known gates\n", mpath->sdata->name, + mpath_dbg(mpath->sdata, + "Mesh path: Deleted gate: %pM. %d known gates\n", mpath->dst, mpath->sdata->u.mesh.num_gates); break; } @@ -785,7 +778,7 @@ static void __mesh_path_del(struct mesh_table *tbl, struct mpath_node *node) /** * mesh_path_flush_by_nexthop - Deletes mesh paths if their next hop matches * - * @sta - mesh peer to match + * @sta: mesh peer to match * * RCU notes: this function is called when a mesh plink transitions from * PLINK_ESTAB to any other state, since PLINK_ESTAB state is the only one that @@ -840,7 +833,7 @@ static void table_flush_by_iface(struct mesh_table *tbl, * * This function deletes both mesh paths as well as mesh portal paths. * - * @sdata - interface data to match + * @sdata: interface data to match * */ void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata) @@ -946,19 +939,20 @@ int mesh_path_send_to_gates(struct mesh_path *mpath) continue; if (gate->mpath->flags & MESH_PATH_ACTIVE) { - mpath_dbg("Forwarding to %pM\n", gate->mpath->dst); + mpath_dbg(sdata, "Forwarding to %pM\n", gate->mpath->dst); mesh_path_move_to_queue(gate->mpath, from_mpath, copy); from_mpath = gate->mpath; copy = true; } else { - mpath_dbg("Not forwarding %p\n", gate->mpath); - mpath_dbg("flags %x\n", gate->mpath->flags); + mpath_dbg(sdata, + "Not forwarding %p (flags %#x)\n", + gate->mpath, gate->mpath->flags); } } hlist_for_each_entry_rcu(gate, n, known_gates, list) if (gate->mpath->sdata == sdata) { - mpath_dbg("Sending to %pM\n", gate->mpath->dst); + mpath_dbg(sdata, "Sending to %pM\n", gate->mpath->dst); mesh_path_tx_pending(gate->mpath); } diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 60ef235c9d9..af671b984df 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -13,12 +13,6 @@ #include "rate.h" #include "mesh.h" -#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG -#define mpl_dbg(fmt, args...) printk(KERN_DEBUG fmt, ##args) -#else -#define mpl_dbg(fmt, args...) do { (void)(0); } while (0) -#endif - #define PLINK_GET_LLID(p) (p + 2) #define PLINK_GET_PLID(p) (p + 4) @@ -105,7 +99,7 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata, return sta; } -/* +/** * mesh_set_ht_prot_mode - set correct HT protection mode * * Section 9.23.3.5 of IEEE 80211-2012 describes the protection rules for HT @@ -134,12 +128,14 @@ static u32 mesh_set_ht_prot_mode(struct ieee80211_sub_if_data *sdata) switch (sta->ch_type) { case NL80211_CHAN_NO_HT: - mpl_dbg("mesh_plink %pM: nonHT sta (%pM) is present", + mpl_dbg(sdata, + "mesh_plink %pM: nonHT sta (%pM) is present\n", sdata->vif.addr, sta->sta.addr); non_ht_sta = true; goto out; case NL80211_CHAN_HT20: - mpl_dbg("mesh_plink %pM: HT20 sta (%pM) is present", + mpl_dbg(sdata, + "mesh_plink %pM: HT20 sta (%pM) is present\n", sdata->vif.addr, sta->sta.addr); ht20_sta = true; default: @@ -160,7 +156,8 @@ out: sdata->vif.bss_conf.ht_operation_mode = ht_opmode; sdata->u.mesh.mshcfg.ht_opmode = ht_opmode; changed = BSS_CHANGED_HT; - mpl_dbg("mesh_plink %pM: protection mode changed to %d", + mpl_dbg(sdata, + "mesh_plink %pM: protection mode changed to %d\n", sdata->vif.addr, ht_opmode); } @@ -261,8 +258,8 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, pos = skb_put(skb, 2); memcpy(pos + 2, &plid, 2); } - if (ieee80211_add_srates_ie(&sdata->vif, skb, true) || - ieee80211_add_ext_srates_ie(&sdata->vif, skb, true) || + if (ieee80211_add_srates_ie(sdata, skb, true) || + ieee80211_add_ext_srates_ie(sdata, skb, true) || mesh_add_rsn_ie(skb, sdata) || mesh_add_meshid_ie(skb, sdata) || mesh_add_meshconf_ie(skb, sdata)) @@ -323,7 +320,8 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, return 0; } -/* mesh_peer_init - initialize new mesh peer and return resulting sta_info +/** + * mesh_peer_init - initialize new mesh peer and return resulting sta_info * * @sdata: local meshif * @addr: peer's address @@ -437,7 +435,8 @@ static void mesh_plink_timer(unsigned long data) spin_unlock_bh(&sta->lock); return; } - mpl_dbg("Mesh plink timer for %pM fired on state %d\n", + mpl_dbg(sta->sdata, + "Mesh plink timer for %pM fired on state %d\n", sta->sta.addr, sta->plink_state); reason = 0; llid = sta->llid; @@ -450,7 +449,8 @@ static void mesh_plink_timer(unsigned long data) /* retry timer */ if (sta->plink_retries < dot11MeshMaxRetries(sdata)) { u32 rand; - mpl_dbg("Mesh plink for %pM (retry, timeout): %d %d\n", + mpl_dbg(sta->sdata, + "Mesh plink for %pM (retry, timeout): %d %d\n", sta->sta.addr, sta->plink_retries, sta->plink_timeout); get_random_bytes(&rand, sizeof(u32)); @@ -530,7 +530,8 @@ int mesh_plink_open(struct sta_info *sta) sta->plink_state = NL80211_PLINK_OPN_SNT; mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata)); spin_unlock_bh(&sta->lock); - mpl_dbg("Mesh plink: starting establishment with %pM\n", + mpl_dbg(sdata, + "Mesh plink: starting establishment with %pM\n", sta->sta.addr); return mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_OPEN, @@ -565,7 +566,6 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m u8 *baseaddr; u32 changed = 0; __le16 plid, llid, reason; -#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG static const char *mplstates[] = { [NL80211_PLINK_LISTEN] = "LISTEN", [NL80211_PLINK_OPN_SNT] = "OPN-SNT", @@ -575,14 +575,14 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m [NL80211_PLINK_HOLDING] = "HOLDING", [NL80211_PLINK_BLOCKED] = "BLOCKED" }; -#endif /* need action_code, aux */ if (len < IEEE80211_MIN_ACTION_SIZE + 3) return; if (is_multicast_ether_addr(mgmt->da)) { - mpl_dbg("Mesh plink: ignore frame from multicast address"); + mpl_dbg(sdata, + "Mesh plink: ignore frame from multicast address\n"); return; } @@ -595,12 +595,14 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m } ieee802_11_parse_elems(baseaddr, len - baselen, &elems); if (!elems.peering) { - mpl_dbg("Mesh plink: missing necessary peer link ie\n"); + mpl_dbg(sdata, + "Mesh plink: missing necessary peer link ie\n"); return; } if (elems.rsn_len && sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) { - mpl_dbg("Mesh plink: can't establish link with secure peer\n"); + mpl_dbg(sdata, + "Mesh plink: can't establish link with secure peer\n"); return; } @@ -610,14 +612,15 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m (ftype == WLAN_SP_MESH_PEERING_CONFIRM && ie_len != 6) || (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len != 6 && ie_len != 8)) { - mpl_dbg("Mesh plink: incorrect plink ie length %d %d\n", - ftype, ie_len); + mpl_dbg(sdata, + "Mesh plink: incorrect plink ie length %d %d\n", + ftype, ie_len); return; } if (ftype != WLAN_SP_MESH_PEERING_CLOSE && (!elems.mesh_id || !elems.mesh_config)) { - mpl_dbg("Mesh plink: missing necessary ie\n"); + mpl_dbg(sdata, "Mesh plink: missing necessary ie\n"); return; } /* Note the lines below are correct, the llid in the frame is the plid @@ -632,21 +635,21 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m sta = sta_info_get(sdata, mgmt->sa); if (!sta && ftype != WLAN_SP_MESH_PEERING_OPEN) { - mpl_dbg("Mesh plink: cls or cnf from unknown peer\n"); + mpl_dbg(sdata, "Mesh plink: cls or cnf from unknown peer\n"); rcu_read_unlock(); return; } if (ftype == WLAN_SP_MESH_PEERING_OPEN && !rssi_threshold_check(sta, sdata)) { - mpl_dbg("Mesh plink: %pM does not meet rssi threshold\n", + mpl_dbg(sdata, "Mesh plink: %pM does not meet rssi threshold\n", mgmt->sa); rcu_read_unlock(); return; } if (sta && !test_sta_flag(sta, WLAN_STA_AUTH)) { - mpl_dbg("Mesh plink: Action frame from non-authed peer\n"); + mpl_dbg(sdata, "Mesh plink: Action frame from non-authed peer\n"); rcu_read_unlock(); return; } @@ -683,7 +686,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m } else if (!sta) { /* ftype == WLAN_SP_MESH_PEERING_OPEN */ if (!mesh_plink_free_count(sdata)) { - mpl_dbg("Mesh plink error: no more free plinks\n"); + mpl_dbg(sdata, "Mesh plink error: no more free plinks\n"); rcu_read_unlock(); return; } @@ -724,7 +727,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m event = CLS_ACPT; break; default: - mpl_dbg("Mesh plink: unknown frame subtype\n"); + mpl_dbg(sdata, "Mesh plink: unknown frame subtype\n"); rcu_read_unlock(); return; } @@ -734,13 +737,14 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m /* allocate sta entry if necessary and update info */ sta = mesh_peer_init(sdata, mgmt->sa, &elems); if (!sta) { - mpl_dbg("Mesh plink: failed to init peer!\n"); + mpl_dbg(sdata, "Mesh plink: failed to init peer!\n"); rcu_read_unlock(); return; } } - mpl_dbg("Mesh plink (peer, state, llid, plid, event): %pM %s %d %d %d\n", + mpl_dbg(sdata, + "Mesh plink (peer, state, llid, plid, event): %pM %s %d %d %d\n", mgmt->sa, mplstates[sta->plink_state], le16_to_cpu(sta->llid), le16_to_cpu(sta->plid), event); @@ -851,7 +855,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m mesh_plink_inc_estab_count(sdata); changed |= mesh_set_ht_prot_mode(sdata); changed |= BSS_CHANGED_BEACON; - mpl_dbg("Mesh plink with %pM ESTABLISHED\n", + mpl_dbg(sdata, "Mesh plink with %pM ESTABLISHED\n", sta->sta.addr); break; default: @@ -887,7 +891,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m mesh_plink_inc_estab_count(sdata); changed |= mesh_set_ht_prot_mode(sdata); changed |= BSS_CHANGED_BEACON; - mpl_dbg("Mesh plink with %pM ESTABLISHED\n", + mpl_dbg(sdata, "Mesh plink with %pM ESTABLISHED\n", sta->sta.addr); mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CONFIRM, diff --git a/net/mac80211/mesh_sync.c b/net/mac80211/mesh_sync.c index 38d30e8ce6d..accfa00ffcd 100644 --- a/net/mac80211/mesh_sync.c +++ b/net/mac80211/mesh_sync.c @@ -12,13 +12,6 @@ #include "mesh.h" #include "driver-ops.h" -#ifdef CONFIG_MAC80211_VERBOSE_MESH_SYNC_DEBUG -#define msync_dbg(fmt, args...) \ - printk(KERN_DEBUG "Mesh sync (%s): " fmt "\n", sdata->name, ##args) -#else -#define msync_dbg(fmt, args...) do { (void)(0); } while (0) -#endif - /* This is not in the standard. It represents a tolerable tbtt drift below * which we do no TSF adjustment. */ @@ -65,14 +58,14 @@ void mesh_sync_adjust_tbtt(struct ieee80211_sub_if_data *sdata) spin_lock_bh(&ifmsh->sync_offset_lock); if (ifmsh->sync_offset_clockdrift_max < beacon_int_fraction) { - msync_dbg("TBTT : max clockdrift=%lld; adjusting", - (long long) ifmsh->sync_offset_clockdrift_max); + msync_dbg(sdata, "TBTT : max clockdrift=%lld; adjusting\n", + (long long) ifmsh->sync_offset_clockdrift_max); tsfdelta = -ifmsh->sync_offset_clockdrift_max; ifmsh->sync_offset_clockdrift_max = 0; } else { - msync_dbg("TBTT : max clockdrift=%lld; adjusting by %llu", - (long long) ifmsh->sync_offset_clockdrift_max, - (unsigned long long) beacon_int_fraction); + msync_dbg(sdata, "TBTT : max clockdrift=%lld; adjusting by %llu\n", + (long long) ifmsh->sync_offset_clockdrift_max, + (unsigned long long) beacon_int_fraction); tsfdelta = -beacon_int_fraction; ifmsh->sync_offset_clockdrift_max -= beacon_int_fraction; } @@ -120,7 +113,7 @@ static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, if (elems->mesh_config && mesh_peer_tbtt_adjusting(elems)) { clear_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN); - msync_dbg("STA %pM : is adjusting TBTT", sta->sta.addr); + msync_dbg(sdata, "STA %pM : is adjusting TBTT\n", sta->sta.addr); goto no_sync; } @@ -169,7 +162,8 @@ static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, if (test_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN)) { s64 t_clockdrift = sta->t_offset_setpoint - sta->t_offset; - msync_dbg("STA %pM : sta->t_offset=%lld, sta->t_offset_setpoint=%lld, t_clockdrift=%lld", + msync_dbg(sdata, + "STA %pM : sta->t_offset=%lld, sta->t_offset_setpoint=%lld, t_clockdrift=%lld\n", sta->sta.addr, (long long) sta->t_offset, (long long) @@ -178,7 +172,8 @@ static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, if (t_clockdrift > TOFFSET_MAXIMUM_ADJUSTMENT || t_clockdrift < -TOFFSET_MAXIMUM_ADJUSTMENT) { - msync_dbg("STA %pM : t_clockdrift=%lld too large, setpoint reset", + msync_dbg(sdata, + "STA %pM : t_clockdrift=%lld too large, setpoint reset\n", sta->sta.addr, (long long) t_clockdrift); clear_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN); @@ -197,8 +192,8 @@ static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, } else { sta->t_offset_setpoint = sta->t_offset - TOFFSET_SET_MARGIN; set_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN); - msync_dbg("STA %pM : offset was invalid, " - " sta->t_offset=%lld", + msync_dbg(sdata, + "STA %pM : offset was invalid, sta->t_offset=%lld\n", sta->sta.addr, (long long) sta->t_offset); rcu_read_unlock(); @@ -226,17 +221,15 @@ static void mesh_sync_offset_adjust_tbtt(struct ieee80211_sub_if_data *sdata) * to the driver tsf setter, we punt * the tsf adjustment to the mesh tasklet */ - msync_dbg("TBTT : kicking off TBTT " - "adjustment with " - "clockdrift_max=%lld", - ifmsh->sync_offset_clockdrift_max); + msync_dbg(sdata, + "TBTT : kicking off TBTT adjustment with clockdrift_max=%lld\n", + ifmsh->sync_offset_clockdrift_max); set_bit(MESH_WORK_DRIFT_ADJUST, &ifmsh->wrkq_flags); } else { - msync_dbg("TBTT : max clockdrift=%lld; " - "too small to adjust", - (long long) - ifmsh->sync_offset_clockdrift_max); + msync_dbg(sdata, + "TBTT : max clockdrift=%lld; too small to adjust\n", + (long long)ifmsh->sync_offset_clockdrift_max); ifmsh->sync_offset_clockdrift_max = 0; } spin_unlock_bh(&ifmsh->sync_offset_lock); @@ -268,7 +261,7 @@ static void mesh_sync_vendor_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, const u8 *oui; WARN_ON(sdata->u.mesh.mesh_sp_id != IEEE80211_SYNC_METHOD_VENDOR); - msync_dbg("called mesh_sync_vendor_rx_bcn_presp"); + msync_dbg(sdata, "called mesh_sync_vendor_rx_bcn_presp\n"); oui = mesh_get_vendor_oui(sdata); /* here you would implement the vendor offset tracking for this oui */ } @@ -278,7 +271,7 @@ static void mesh_sync_vendor_adjust_tbtt(struct ieee80211_sub_if_data *sdata) const u8 *oui; WARN_ON(sdata->u.mesh.mesh_sp_id != IEEE80211_SYNC_METHOD_VENDOR); - msync_dbg("called mesh_sync_vendor_adjust_tbtt"); + msync_dbg(sdata, "called mesh_sync_vendor_adjust_tbtt\n"); oui = mesh_get_vendor_oui(sdata); /* here you would implement the vendor tsf adjustment for this oui */ } diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 0db5d34a06b..cef0c9e79ab 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -258,12 +258,11 @@ static int ieee80211_compatible_rates(const u8 *supp_rates, int supp_rates_len, } static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata, - struct sk_buff *skb, const u8 *ht_oper_ie, + struct sk_buff *skb, u8 ap_ht_param, struct ieee80211_supported_band *sband, struct ieee80211_channel *channel, enum ieee80211_smps_mode smps) { - struct ieee80211_ht_operation *ht_oper; u8 *pos; u32 flags = channel->flags; u16 cap; @@ -271,21 +270,13 @@ static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata, BUILD_BUG_ON(sizeof(ht_cap) != sizeof(sband->ht_cap)); - if (!ht_oper_ie) - return; - - if (ht_oper_ie[1] < sizeof(struct ieee80211_ht_operation)) - return; - memcpy(&ht_cap, &sband->ht_cap, sizeof(ht_cap)); ieee80211_apply_htcap_overrides(sdata, &ht_cap); - ht_oper = (struct ieee80211_ht_operation *)(ht_oper_ie + 2); - /* determine capability flags */ cap = ht_cap.cap; - switch (ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { + switch (ap_ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: if (flags & IEEE80211_CHAN_NO_HT40PLUS) { cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; @@ -509,7 +500,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) } if (!(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) - ieee80211_add_ht_ie(sdata, skb, assoc_data->ht_operation_ie, + ieee80211_add_ht_ie(sdata, skb, assoc_data->ap_ht_param, sband, local->oper_channel, ifmgd->ap_smps); /* if present, add any custom non-vendor IEs that go after HT */ @@ -550,6 +541,8 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) memcpy(pos, assoc_data->ie + offset, noffset - offset); } + drv_mgd_prepare_tx(local, sdata); + IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; ieee80211_tx_skb(sdata, skb); } @@ -589,6 +582,9 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, if (!(ifmgd->flags & IEEE80211_STA_MFP_ENABLED)) IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; + + drv_mgd_prepare_tx(local, sdata); + ieee80211_tx_skb(sdata, skb); } } @@ -911,9 +907,6 @@ static bool ieee80211_powersave_allowed(struct ieee80211_sub_if_data *sdata) if (!mgd->associated) return false; - if (!mgd->associated->beacon_ies) - return false; - if (mgd->flags & (IEEE80211_STA_BEACON_POLL | IEEE80211_STA_CONNECTION_POLL)) return false; @@ -939,11 +932,6 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) return; } - if (!list_empty(&local->work_list)) { - local->ps_sdata = NULL; - goto change; - } - list_for_each_entry(sdata, &local->interfaces, list) { if (!ieee80211_sdata_running(sdata)) continue; @@ -1016,7 +1004,6 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) local->ps_sdata = NULL; } - change: ieee80211_change_ps(local); } @@ -1121,7 +1108,7 @@ void ieee80211_dynamic_ps_timer(unsigned long data) } /* MLME */ -static void ieee80211_sta_wmm_params(struct ieee80211_local *local, +static bool ieee80211_sta_wmm_params(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, u8 *wmm_param, size_t wmm_param_len) { @@ -1132,23 +1119,23 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, u8 *pos, uapsd_queues = 0; if (!local->ops->conf_tx) - return; + return false; if (local->hw.queues < IEEE80211_NUM_ACS) - return; + return false; if (!wmm_param) - return; + return false; if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1) - return; + return false; if (ifmgd->flags & IEEE80211_STA_UAPSD_ENABLED) uapsd_queues = ifmgd->uapsd_queues; count = wmm_param[6] & 0x0f; if (count == ifmgd->wmm_last_param_set) - return; + return false; ifmgd->wmm_last_param_set = count; pos = wmm_param + 8; @@ -1156,7 +1143,7 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, memset(¶ms, 0, sizeof(params)); - local->wmm_acm = 0; + sdata->wmm_acm = 0; for (; left >= 4; left -= 4, pos += 4) { int aci = (pos[0] >> 5) & 0x03; int acm = (pos[0] >> 4) & 0x01; @@ -1167,21 +1154,21 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, case 1: /* AC_BK */ queue = 3; if (acm) - local->wmm_acm |= BIT(1) | BIT(2); /* BK/- */ + sdata->wmm_acm |= BIT(1) | BIT(2); /* BK/- */ if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BK) uapsd = true; break; case 2: /* AC_VI */ queue = 1; if (acm) - local->wmm_acm |= BIT(4) | BIT(5); /* CL/VI */ + sdata->wmm_acm |= BIT(4) | BIT(5); /* CL/VI */ if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VI) uapsd = true; break; case 3: /* AC_VO */ queue = 0; if (acm) - local->wmm_acm |= BIT(6) | BIT(7); /* VO/NC */ + sdata->wmm_acm |= BIT(6) | BIT(7); /* VO/NC */ if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO) uapsd = true; break; @@ -1189,7 +1176,7 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, default: queue = 2; if (acm) - local->wmm_acm |= BIT(0) | BIT(3); /* BE/EE */ + sdata->wmm_acm |= BIT(0) | BIT(3); /* BE/EE */ if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BE) uapsd = true; break; @@ -1201,23 +1188,21 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, params.txop = get_unaligned_le16(pos + 2); params.uapsd = uapsd; -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - wiphy_debug(local->hw.wiphy, - "WMM queue=%d aci=%d acm=%d aifs=%d " - "cWmin=%d cWmax=%d txop=%d uapsd=%d\n", - queue, aci, acm, - params.aifs, params.cw_min, params.cw_max, - params.txop, params.uapsd); -#endif + mlme_dbg(sdata, + "WMM queue=%d aci=%d acm=%d aifs=%d cWmin=%d cWmax=%d txop=%d uapsd=%d\n", + queue, aci, acm, + params.aifs, params.cw_min, params.cw_max, + params.txop, params.uapsd); sdata->tx_conf[queue] = params; if (drv_conf_tx(local, sdata, queue, ¶ms)) - wiphy_debug(local->hw.wiphy, - "failed to set TX queue parameters for queue %d\n", - queue); + sdata_err(sdata, + "failed to set TX queue parameters for queue %d\n", + queue); } /* enable WMM or activate new settings */ sdata->vif.bss_conf.qos = true; + return true; } static void __ieee80211_stop_poll(struct ieee80211_sub_if_data *sdata) @@ -1284,13 +1269,8 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; bss_info_changed |= BSS_CHANGED_ASSOC; - /* set timing information */ - bss_conf->beacon_int = cbss->beacon_interval; - bss_conf->last_tsf = cbss->tsf; - - bss_info_changed |= BSS_CHANGED_BEACON_INT; bss_info_changed |= ieee80211_handle_bss_capability(sdata, - cbss->capability, bss->has_erp_value, bss->erp_value); + bss_conf->assoc_capability, bss->has_erp_value, bss->erp_value); sdata->u.mgd.beacon_timeout = usecs_to_jiffies(ieee80211_tu_to_usec( IEEE80211_BEACON_LOSS_COUNT * bss_conf->beacon_int)); @@ -1380,6 +1360,21 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, } mutex_unlock(&local->sta_mtx); + /* + * if we want to get out of ps before disassoc (why?) we have + * to do it before sending disassoc, as otherwise the null-packet + * won't be valid. + */ + if (local->hw.conf.flags & IEEE80211_CONF_PS) { + local->hw.conf.flags &= ~IEEE80211_CONF_PS; + ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); + } + local->ps_sdata = NULL; + + /* flush out any pending frame (e.g. DELBA) before deauth/disassoc */ + if (tx) + drv_flush(local, false); + /* deauthenticate/disassociate now */ if (tx || frame_buf) ieee80211_send_deauth_disassoc(sdata, ifmgd->bssid, stype, @@ -1411,12 +1406,6 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, del_timer_sync(&local->dynamic_ps_timer); cancel_work_sync(&local->dynamic_ps_enable_work); - if (local->hw.conf.flags & IEEE80211_CONF_PS) { - local->hw.conf.flags &= ~IEEE80211_CONF_PS; - ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); - } - local->ps_sdata = NULL; - /* Disable ARP filtering */ if (sdata->vif.bss_conf.arp_filter_enabled) { sdata->vif.bss_conf.arp_filter_enabled = false; @@ -1581,11 +1570,12 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata, goto out; } -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG if (beacon) - net_dbg_ratelimited("%s: detected beacon loss from AP - sending probe request\n", - sdata->name); -#endif + mlme_dbg_ratelimited(sdata, + "detected beacon loss from AP - sending probe request\n"); + + ieee80211_cqm_rssi_notify(&sdata->vif, + NL80211_CQM_RSSI_BEACON_LOSS_EVENT, GFP_KERNEL); /* * The driver/our work has already reported this event or the @@ -1627,6 +1617,7 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw, { struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + struct cfg80211_bss *cbss; struct sk_buff *skb; const u8 *ssid; int ssid_len; @@ -1636,16 +1627,22 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw, ASSERT_MGD_MTX(ifmgd); - if (!ifmgd->associated) + if (ifmgd->associated) + cbss = ifmgd->associated; + else if (ifmgd->auth_data) + cbss = ifmgd->auth_data->bss; + else if (ifmgd->assoc_data) + cbss = ifmgd->assoc_data->bss; + else return NULL; - ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID); + ssid = ieee80211_bss_get_ie(cbss, WLAN_EID_SSID); if (WARN_ON_ONCE(ssid == NULL)) ssid_len = 0; else ssid_len = ssid[1]; - skb = ieee80211_build_probe_req(sdata, ifmgd->associated->bssid, + skb = ieee80211_build_probe_req(sdata, cbss->bssid, (u32) -1, ssid + 2, ssid_len, NULL, 0, true); @@ -1668,8 +1665,7 @@ static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata) memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN); - printk(KERN_DEBUG "%s: Connection to AP %pM lost.\n", - sdata->name, bssid); + sdata_info(sdata, "Connection to AP %pM lost\n", bssid); ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, @@ -1765,6 +1761,7 @@ static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata, if (!elems.challenge) return; auth_data->expected_transaction = 4; + drv_mgd_prepare_tx(sdata->local, sdata); ieee80211_send_auth(sdata, 3, auth_data->algorithm, elems.challenge - 2, elems.challenge_len + 2, auth_data->bss->bssid, auth_data->bss->bssid, @@ -1803,9 +1800,10 @@ ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, return RX_MGMT_NONE; if (status_code != WLAN_STATUS_SUCCESS) { - printk(KERN_DEBUG "%s: %pM denied authentication (status %d)\n", - sdata->name, mgmt->sa, status_code); - goto out; + sdata_info(sdata, "%pM denied authentication (status %d)\n", + mgmt->sa, status_code); + ieee80211_destroy_auth_data(sdata, false); + return RX_MGMT_CFG80211_RX_AUTH; } switch (ifmgd->auth_data->algorithm) { @@ -1826,8 +1824,7 @@ ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, return RX_MGMT_NONE; } - printk(KERN_DEBUG "%s: authenticated\n", sdata->name); - out: + sdata_info(sdata, "authenticated\n"); ifmgd->auth_data->done = true; ifmgd->auth_data->timeout = jiffies + IEEE80211_AUTH_WAIT_ASSOC; run_again(ifmgd, ifmgd->auth_data->timeout); @@ -1840,8 +1837,7 @@ ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, goto out_err; } if (sta_info_move_state(sta, IEEE80211_STA_AUTH)) { - printk(KERN_DEBUG "%s: failed moving %pM to auth\n", - sdata->name, bssid); + sdata_info(sdata, "failed moving %pM to auth\n", bssid); goto out_err; } mutex_unlock(&sdata->local->sta_mtx); @@ -1875,8 +1871,8 @@ ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); - printk(KERN_DEBUG "%s: deauthenticated from %pM (Reason: %u)\n", - sdata->name, bssid, reason_code); + sdata_info(sdata, "deauthenticated from %pM (Reason: %u)\n", + bssid, reason_code); ieee80211_set_disassoc(sdata, 0, 0, false, NULL); @@ -1906,8 +1902,8 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); - printk(KERN_DEBUG "%s: disassociated from %pM (Reason: %u)\n", - sdata->name, mgmt->sa, reason_code); + sdata_info(sdata, "disassociated from %pM (Reason: %u)\n", + mgmt->sa, reason_code); ieee80211_set_disassoc(sdata, 0, 0, false, NULL); @@ -1999,17 +1995,15 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info); if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14))) - printk(KERN_DEBUG - "%s: invalid AID value 0x%x; bits 15:14 not set\n", - sdata->name, aid); + sdata_info(sdata, "invalid AID value 0x%x; bits 15:14 not set\n", + aid); aid &= ~(BIT(15) | BIT(14)); ifmgd->broken_ap = false; if (aid == 0 || aid > IEEE80211_MAX_AID) { - printk(KERN_DEBUG - "%s: invalid AID value %d (out of range), turn off PS\n", - sdata->name, aid); + sdata_info(sdata, "invalid AID value %d (out of range), turn off PS\n", + aid); aid = 0; ifmgd->broken_ap = true; } @@ -2018,8 +2012,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); if (!elems.supp_rates) { - printk(KERN_DEBUG "%s: no SuppRates element in AssocResp\n", - sdata->name); + sdata_info(sdata, "no SuppRates element in AssocResp\n"); return false; } @@ -2059,9 +2052,9 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, if (!err && !(ifmgd->flags & IEEE80211_STA_CONTROL_PORT)) err = sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED); if (err) { - printk(KERN_DEBUG - "%s: failed to move station %pM to desired state\n", - sdata->name, sta->sta.addr); + sdata_info(sdata, + "failed to move station %pM to desired state\n", + sta->sta.addr); WARN_ON(__sta_info_destroy(sta)); mutex_unlock(&sdata->local->sta_mtx); return false; @@ -2144,10 +2137,10 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); aid = le16_to_cpu(mgmt->u.assoc_resp.aid); - printk(KERN_DEBUG "%s: RX %sssocResp from %pM (capab=0x%x " - "status=%d aid=%d)\n", - sdata->name, reassoc ? "Rea" : "A", mgmt->sa, - capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14)))); + sdata_info(sdata, + "RX %sssocResp from %pM (capab=0x%x status=%d aid=%d)\n", + reassoc ? "Rea" : "A", mgmt->sa, + capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14)))); pos = mgmt->u.assoc_resp.variable; ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); @@ -2158,9 +2151,9 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, u32 tu, ms; tu = get_unaligned_le32(elems.timeout_int + 1); ms = tu * 1024 / 1000; - printk(KERN_DEBUG "%s: %pM rejected association temporarily; " - "comeback duration %u TU (%u ms)\n", - sdata->name, mgmt->sa, tu, ms); + sdata_info(sdata, + "%pM rejected association temporarily; comeback duration %u TU (%u ms)\n", + mgmt->sa, tu, ms); assoc_data->timeout = jiffies + msecs_to_jiffies(ms); if (ms > IEEE80211_ASSOC_TIMEOUT) run_again(ifmgd, assoc_data->timeout); @@ -2170,8 +2163,8 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, *bss = assoc_data->bss; if (status_code != WLAN_STATUS_SUCCESS) { - printk(KERN_DEBUG "%s: %pM denied association (code=%d)\n", - sdata->name, mgmt->sa, status_code); + sdata_info(sdata, "%pM denied association (code=%d)\n", + mgmt->sa, status_code); ieee80211_destroy_assoc_data(sdata, false); } else { if (!ieee80211_assoc_success(sdata, *bss, mgmt, len)) { @@ -2180,7 +2173,7 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, cfg80211_put_bss(*bss); return RX_MGMT_CFG80211_ASSOC_TIMEOUT; } - printk(KERN_DEBUG "%s: associated\n", sdata->name); + sdata_info(sdata, "associated\n"); /* * destroy assoc_data afterwards, as otherwise an idle @@ -2280,7 +2273,7 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, if (ifmgd->auth_data && !ifmgd->auth_data->bss->proberesp_ies && ether_addr_equal(mgmt->bssid, ifmgd->auth_data->bss->bssid)) { /* got probe response, continue with auth */ - printk(KERN_DEBUG "%s: direct probe responded\n", sdata->name); + sdata_info(sdata, "direct probe responded\n"); ifmgd->auth_data->tries = 0; ifmgd->auth_data->timeout = jiffies; run_again(ifmgd, ifmgd->auth_data->timeout); @@ -2416,10 +2409,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, } if (ifmgd->flags & IEEE80211_STA_BEACON_POLL) { -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - net_dbg_ratelimited("%s: cancelling probereq poll due to a received beacon\n", - sdata->name); -#endif + mlme_dbg_ratelimited(sdata, + "cancelling probereq poll due to a received beacon\n"); mutex_lock(&local->mtx); ifmgd->flags &= ~IEEE80211_STA_BEACON_POLL; ieee80211_run_deferred_scan(local); @@ -2445,14 +2436,6 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, directed_tim = ieee80211_check_tim(elems.tim, elems.tim_len, ifmgd->aid); - if (ncrc != ifmgd->beacon_crc || !ifmgd->beacon_crc_valid) { - ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, - true); - - ieee80211_sta_wmm_params(local, sdata, elems.wmm_param, - elems.wmm_param_len); - } - if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) { if (directed_tim) { if (local->hw.conf.dynamic_ps_timeout > 0) { @@ -2483,6 +2466,13 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, ifmgd->beacon_crc = ncrc; ifmgd->beacon_crc_valid = true; + ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, + true); + + if (ieee80211_sta_wmm_params(local, sdata, elems.wmm_param, + elems.wmm_param_len)) + changed |= BSS_CHANGED_QOS; + if (elems.erp_info && elems.erp_info_len >= 1) { erp_valid = true; erp_value = elems.erp_info[0]; @@ -2642,8 +2632,8 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata) auth_data->tries++; if (auth_data->tries > IEEE80211_AUTH_MAX_TRIES) { - printk(KERN_DEBUG "%s: authentication with %pM timed out\n", - sdata->name, auth_data->bss->bssid); + sdata_info(sdata, "authentication with %pM timed out\n", + auth_data->bss->bssid); /* * Most likely AP is not in the range so remove the @@ -2654,10 +2644,12 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata) return -ETIMEDOUT; } + drv_mgd_prepare_tx(local, sdata); + if (auth_data->bss->proberesp_ies) { - printk(KERN_DEBUG "%s: send auth to %pM (try %d/%d)\n", - sdata->name, auth_data->bss->bssid, auth_data->tries, - IEEE80211_AUTH_MAX_TRIES); + sdata_info(sdata, "send auth to %pM (try %d/%d)\n", + auth_data->bss->bssid, auth_data->tries, + IEEE80211_AUTH_MAX_TRIES); auth_data->expected_transaction = 2; ieee80211_send_auth(sdata, 1, auth_data->algorithm, @@ -2667,9 +2659,9 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata) } else { const u8 *ssidie; - printk(KERN_DEBUG "%s: direct probe to %pM (try %d/%i)\n", - sdata->name, auth_data->bss->bssid, auth_data->tries, - IEEE80211_AUTH_MAX_TRIES); + sdata_info(sdata, "direct probe to %pM (try %d/%i)\n", + auth_data->bss->bssid, auth_data->tries, + IEEE80211_AUTH_MAX_TRIES); ssidie = ieee80211_bss_get_ie(auth_data->bss, WLAN_EID_SSID); if (!ssidie) @@ -2697,8 +2689,8 @@ static int ieee80211_do_assoc(struct ieee80211_sub_if_data *sdata) assoc_data->tries++; if (assoc_data->tries > IEEE80211_ASSOC_MAX_TRIES) { - printk(KERN_DEBUG "%s: association with %pM timed out\n", - sdata->name, assoc_data->bss->bssid); + sdata_info(sdata, "association with %pM timed out\n", + assoc_data->bss->bssid); /* * Most likely AP is not in the range so remove the @@ -2709,9 +2701,9 @@ static int ieee80211_do_assoc(struct ieee80211_sub_if_data *sdata) return -ETIMEDOUT; } - printk(KERN_DEBUG "%s: associate with %pM (try %d/%d)\n", - sdata->name, assoc_data->bss->bssid, assoc_data->tries, - IEEE80211_ASSOC_MAX_TRIES); + sdata_info(sdata, "associate with %pM (try %d/%d)\n", + assoc_data->bss->bssid, assoc_data->tries, + IEEE80211_ASSOC_MAX_TRIES); ieee80211_send_assoc(sdata); assoc_data->timeout = jiffies + IEEE80211_ASSOC_TIMEOUT; @@ -2784,45 +2776,31 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) ieee80211_reset_ap_probe(sdata); else if (ifmgd->nullfunc_failed) { if (ifmgd->probe_send_count < max_tries) { -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - wiphy_debug(local->hw.wiphy, - "%s: No ack for nullfunc frame to" - " AP %pM, try %d/%i\n", - sdata->name, bssid, - ifmgd->probe_send_count, max_tries); -#endif + mlme_dbg(sdata, + "No ack for nullfunc frame to AP %pM, try %d/%i\n", + bssid, ifmgd->probe_send_count, + max_tries); ieee80211_mgd_probe_ap_send(sdata); } else { -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - wiphy_debug(local->hw.wiphy, - "%s: No ack for nullfunc frame to" - " AP %pM, disconnecting.\n", - sdata->name, bssid); -#endif + mlme_dbg(sdata, + "No ack for nullfunc frame to AP %pM, disconnecting.\n", + bssid); ieee80211_sta_connection_lost(sdata, bssid, WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY); } } else if (time_is_after_jiffies(ifmgd->probe_timeout)) run_again(ifmgd, ifmgd->probe_timeout); else if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) { -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - wiphy_debug(local->hw.wiphy, - "%s: Failed to send nullfunc to AP %pM" - " after %dms, disconnecting.\n", - sdata->name, - bssid, probe_wait_ms); -#endif + mlme_dbg(sdata, + "Failed to send nullfunc to AP %pM after %dms, disconnecting\n", + bssid, probe_wait_ms); ieee80211_sta_connection_lost(sdata, bssid, WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY); } else if (ifmgd->probe_send_count < max_tries) { -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - wiphy_debug(local->hw.wiphy, - "%s: No probe response from AP %pM" - " after %dms, try %d/%i\n", - sdata->name, - bssid, probe_wait_ms, - ifmgd->probe_send_count, max_tries); -#endif + mlme_dbg(sdata, + "No probe response from AP %pM after %dms, try %d/%i\n", + bssid, probe_wait_ms, + ifmgd->probe_send_count, max_tries); ieee80211_mgd_probe_ap_send(sdata); } else { /* @@ -2937,11 +2915,8 @@ void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata) sdata->flags &= ~IEEE80211_SDATA_DISCONNECT_RESUME; mutex_lock(&ifmgd->mtx); if (ifmgd->associated) { -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - wiphy_debug(sdata->local->hw.wiphy, - "%s: driver requested disconnect after resume.\n", - sdata->name); -#endif + mlme_dbg(sdata, + "driver requested disconnect after resume\n"); ieee80211_sta_connection_lost(sdata, ifmgd->associated->bssid, WLAN_REASON_UNSPECIFIED); @@ -2999,7 +2974,7 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) /* scan finished notification */ void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local) { - struct ieee80211_sub_if_data *sdata = local->scan_sdata; + struct ieee80211_sub_if_data *sdata; /* Restart STA timers */ rcu_read_lock(); @@ -3029,7 +3004,7 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, struct ieee80211_local *local = sdata->local; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_bss *bss = (void *)cbss->priv; - struct sta_info *sta; + struct sta_info *sta = NULL; bool have_sta = false; int err; int ht_cfreq; @@ -3082,13 +3057,11 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, * since we look at probe response/beacon data here * it should be OK. */ - printk(KERN_DEBUG - "%s: Wrong control channel: center-freq: %d" - " ht-cfreq: %d ht->primary_chan: %d" - " band: %d. Disabling HT.\n", - sdata->name, cbss->channel->center_freq, - ht_cfreq, ht_oper->primary_chan, - cbss->channel->band); + sdata_info(sdata, + "Wrong control channel: center-freq: %d ht-cfreq: %d ht->primary_chan: %d band: %d - Disabling HT\n", + cbss->channel->center_freq, + ht_cfreq, ht_oper->primary_chan, + cbss->channel->band); ht_oper = NULL; } } @@ -3112,9 +3085,8 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, if (!ieee80211_set_channel_type(local, sdata, channel_type)) { /* can only fail due to HT40+/- mismatch */ channel_type = NL80211_CHAN_HT20; - printk(KERN_DEBUG - "%s: disabling 40 MHz due to multi-vif mismatch\n", - sdata->name); + sdata_info(sdata, + "disabling 40 MHz due to multi-vif mismatch\n"); ifmgd->flags |= IEEE80211_STA_DISABLE_40MHZ; WARN_ON(!ieee80211_set_channel_type(local, sdata, channel_type)); @@ -3123,7 +3095,7 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, local->oper_channel = cbss->channel; ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); - if (!have_sta) { + if (sta) { u32 rates = 0, basic_rates = 0; bool have_higher_than_11mbit; int min_rate = INT_MAX, min_rate_index = -1; @@ -3143,9 +3115,8 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, * we can connect -- with a warning. */ if (!basic_rates && min_rate_index >= 0) { - printk(KERN_DEBUG - "%s: No basic rates, using min rate instead.\n", - sdata->name); + sdata_info(sdata, + "No basic rates, using min rate instead\n"); basic_rates = BIT(min_rate_index); } @@ -3161,9 +3132,15 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, memcpy(ifmgd->bssid, cbss->bssid, ETH_ALEN); - /* tell driver about BSSID and basic rates */ + /* set timing information */ + sdata->vif.bss_conf.beacon_int = cbss->beacon_interval; + sdata->vif.bss_conf.sync_tsf = cbss->tsf; + sdata->vif.bss_conf.sync_device_ts = bss->device_ts; + + /* tell driver about BSSID, basic rates and timing */ ieee80211_bss_info_change_notify(sdata, - BSS_CHANGED_BSSID | BSS_CHANGED_BASIC_RATES); + BSS_CHANGED_BSSID | BSS_CHANGED_BASIC_RATES | + BSS_CHANGED_BEACON_INT); if (assoc) sta_info_pre_move_state(sta, IEEE80211_STA_AUTH); @@ -3171,9 +3148,9 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, err = sta_info_insert(sta); sta = NULL; if (err) { - printk(KERN_DEBUG - "%s: failed to insert STA entry for the AP (error %d)\n", - sdata->name, err); + sdata_info(sdata, + "failed to insert STA entry for the AP (error %d)\n", + err); return err; } } else @@ -3251,8 +3228,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, if (ifmgd->associated) ieee80211_set_disassoc(sdata, 0, 0, false, NULL); - printk(KERN_DEBUG "%s: authenticate with %pM\n", - sdata->name, req->bss->bssid); + sdata_info(sdata, "authenticate with %pM\n", req->bss->bssid); err = ieee80211_prep_connection(sdata, req->bss, false); if (err) @@ -3287,7 +3263,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, struct ieee80211_bss *bss = (void *)req->bss->priv; struct ieee80211_mgd_assoc_data *assoc_data; struct ieee80211_supported_band *sband; - const u8 *ssidie; + const u8 *ssidie, *ht_ie; int i, err; ssidie = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID); @@ -3335,11 +3311,15 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, * We can set this to true for non-11n hardware, that'll be checked * separately along with the peer capabilities. */ - for (i = 0; i < req->crypto.n_ciphers_pairwise; i++) + for (i = 0; i < req->crypto.n_ciphers_pairwise; i++) { if (req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP40 || req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_TKIP || - req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) + req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) { ifmgd->flags |= IEEE80211_STA_DISABLE_11N; + netdev_info(sdata->dev, + "disabling HT due to WEP/TKIP use\n"); + } + } if (req->flags & ASSOC_REQ_DISABLE_HT) ifmgd->flags |= IEEE80211_STA_DISABLE_11N; @@ -3347,8 +3327,11 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, /* Also disable HT if we don't support it or the AP doesn't use WMM */ sband = local->hw.wiphy->bands[req->bss->channel->band]; if (!sband->ht_cap.ht_supported || - local->hw.queues < IEEE80211_NUM_ACS || !bss->wmm_used) + local->hw.queues < IEEE80211_NUM_ACS || !bss->wmm_used) { ifmgd->flags |= IEEE80211_STA_DISABLE_11N; + netdev_info(sdata->dev, + "disabling HT as WMM/QoS is not supported\n"); + } memcpy(&ifmgd->ht_capa, &req->ht_capa, sizeof(ifmgd->ht_capa)); memcpy(&ifmgd->ht_capa_mask, &req->ht_capa_mask, @@ -3374,8 +3357,13 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, (local->hw.queues >= IEEE80211_NUM_ACS); assoc_data->supp_rates = bss->supp_rates; assoc_data->supp_rates_len = bss->supp_rates_len; - assoc_data->ht_operation_ie = - ieee80211_bss_get_ie(req->bss, WLAN_EID_HT_OPERATION); + + ht_ie = ieee80211_bss_get_ie(req->bss, WLAN_EID_HT_OPERATION); + if (ht_ie && ht_ie[1] >= sizeof(struct ieee80211_ht_operation)) + assoc_data->ap_ht_param = + ((struct ieee80211_ht_operation *)(ht_ie + 2))->ht_param; + else + ifmgd->flags |= IEEE80211_STA_DISABLE_11N; if (bss->wmm_used && bss->uapsd_supported && (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)) { @@ -3422,8 +3410,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, * Wait up to one beacon interval ... * should this be more if we miss one? */ - printk(KERN_DEBUG "%s: waiting for beacon from %pM\n", - sdata->name, ifmgd->bssid); + sdata_info(sdata, "waiting for beacon from %pM\n", + ifmgd->bssid); assoc_data->timeout = TU_TO_EXP_TIME(req->bss->beacon_interval); } else { assoc_data->have_beacon = true; @@ -3442,8 +3430,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, corrupt_type = "beacon"; } else if (bss->corrupt_data & IEEE80211_BSS_CORRUPT_PROBE_RESP) corrupt_type = "probe response"; - printk(KERN_DEBUG "%s: associating with AP with corrupt %s\n", - sdata->name, corrupt_type); + sdata_info(sdata, "associating with AP with corrupt %s\n", + corrupt_type); } err = 0; @@ -3472,9 +3460,9 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, return 0; } - printk(KERN_DEBUG - "%s: deauthenticating from %pM by local choice (reason=%d)\n", - sdata->name, req->bssid, req->reason_code); + sdata_info(sdata, + "deauthenticating from %pM by local choice (reason=%d)\n", + req->bssid, req->reason_code); if (ifmgd->associated && ether_addr_equal(ifmgd->associated->bssid, req->bssid)) @@ -3516,8 +3504,9 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, return -ENOLINK; } - printk(KERN_DEBUG "%s: disassociating from %pM by local choice (reason=%d)\n", - sdata->name, req->bss->bssid, req->reason_code); + sdata_info(sdata, + "disassociating from %pM by local choice (reason=%d)\n", + req->bss->bssid, req->reason_code); memcpy(bssid, req->bss->bssid, ETH_ALEN); ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DISASSOC, @@ -3558,10 +3547,3 @@ void ieee80211_cqm_rssi_notify(struct ieee80211_vif *vif, cfg80211_cqm_rssi_notify(sdata->dev, rssi_event, gfp); } EXPORT_SYMBOL(ieee80211_cqm_rssi_notify); - -unsigned char ieee80211_get_operstate(struct ieee80211_vif *vif) -{ - struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); - return sdata->dev->operstate; -} -EXPORT_SYMBOL(ieee80211_get_operstate); diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c index 935aa4b6dee..635c3250c66 100644 --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c @@ -15,7 +15,7 @@ #include <linux/export.h> #include <net/mac80211.h> #include "ieee80211_i.h" -#include "driver-trace.h" +#include "driver-ops.h" /* * Tell our hardware to disable PS. @@ -24,8 +24,7 @@ * because we *may* be doing work on-operating channel, and want our * hardware unconditionally awake, but still let the AP send us normal frames. */ -static void ieee80211_offchannel_ps_enable(struct ieee80211_sub_if_data *sdata, - bool tell_ap) +static void ieee80211_offchannel_ps_enable(struct ieee80211_sub_if_data *sdata) { struct ieee80211_local *local = sdata->local; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; @@ -46,8 +45,8 @@ static void ieee80211_offchannel_ps_enable(struct ieee80211_sub_if_data *sdata, ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); } - if (tell_ap && (!local->offchannel_ps_enabled || - !(local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK))) + if (!local->offchannel_ps_enabled || + !(local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)) /* * If power save was enabled, no need to send a nullfunc * frame because AP knows that we are sleeping. But if the @@ -132,7 +131,7 @@ void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local, if (offchannel_ps_enable && (sdata->vif.type == NL80211_IFTYPE_STATION) && sdata->u.mgd.associated) - ieee80211_offchannel_ps_enable(sdata, true); + ieee80211_offchannel_ps_enable(sdata); } } mutex_unlock(&local->iflist_mtx); @@ -181,34 +180,58 @@ void ieee80211_offchannel_return(struct ieee80211_local *local, mutex_unlock(&local->iflist_mtx); } +void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc) +{ + if (roc->notified) + return; + + if (roc->mgmt_tx_cookie) { + if (!WARN_ON(!roc->frame)) { + ieee80211_tx_skb(roc->sdata, roc->frame); + roc->frame = NULL; + } + } else { + cfg80211_ready_on_channel(&roc->sdata->wdev, (unsigned long)roc, + roc->chan, roc->chan_type, + roc->req_duration, GFP_KERNEL); + } + + roc->notified = true; +} + static void ieee80211_hw_roc_start(struct work_struct *work) { struct ieee80211_local *local = container_of(work, struct ieee80211_local, hw_roc_start); - struct ieee80211_sub_if_data *sdata; + struct ieee80211_roc_work *roc, *dep, *tmp; mutex_lock(&local->mtx); - if (!local->hw_roc_channel) { - mutex_unlock(&local->mtx); - return; - } + if (list_empty(&local->roc_list)) + goto out_unlock; - if (local->hw_roc_skb) { - sdata = IEEE80211_DEV_TO_SUB_IF(local->hw_roc_dev); - ieee80211_tx_skb(sdata, local->hw_roc_skb); - local->hw_roc_skb = NULL; - } else { - cfg80211_ready_on_channel(local->hw_roc_dev, - local->hw_roc_cookie, - local->hw_roc_channel, - local->hw_roc_channel_type, - local->hw_roc_duration, - GFP_KERNEL); - } + roc = list_first_entry(&local->roc_list, struct ieee80211_roc_work, + list); + + if (!roc->started) + goto out_unlock; - ieee80211_recalc_idle(local); + roc->hw_begun = true; + roc->hw_start_time = local->hw_roc_start_time; + ieee80211_handle_roc_started(roc); + list_for_each_entry_safe(dep, tmp, &roc->dependents, list) { + ieee80211_handle_roc_started(dep); + + if (dep->duration > roc->duration) { + u32 dur = dep->duration; + dep->duration = dur - roc->duration; + roc->duration = dur; + list_del(&dep->list); + list_add(&dep->list, &roc->list); + } + } + out_unlock: mutex_unlock(&local->mtx); } @@ -216,52 +239,181 @@ void ieee80211_ready_on_channel(struct ieee80211_hw *hw) { struct ieee80211_local *local = hw_to_local(hw); + local->hw_roc_start_time = jiffies; + trace_api_ready_on_channel(local); ieee80211_queue_work(hw, &local->hw_roc_start); } EXPORT_SYMBOL_GPL(ieee80211_ready_on_channel); -static void ieee80211_hw_roc_done(struct work_struct *work) +void ieee80211_start_next_roc(struct ieee80211_local *local) { - struct ieee80211_local *local = - container_of(work, struct ieee80211_local, hw_roc_done); + struct ieee80211_roc_work *roc; - mutex_lock(&local->mtx); + lockdep_assert_held(&local->mtx); - if (!local->hw_roc_channel) { - mutex_unlock(&local->mtx); + if (list_empty(&local->roc_list)) { + ieee80211_run_deferred_scan(local); return; } - /* was never transmitted */ - if (local->hw_roc_skb) { - u64 cookie; + roc = list_first_entry(&local->roc_list, struct ieee80211_roc_work, + list); - cookie = local->hw_roc_cookie ^ 2; + if (WARN_ON_ONCE(roc->started)) + return; + + if (local->ops->remain_on_channel) { + int ret, duration = roc->duration; + + /* XXX: duplicated, see ieee80211_start_roc_work() */ + if (!duration) + duration = 10; + + ret = drv_remain_on_channel(local, roc->chan, + roc->chan_type, + duration); + + roc->started = true; + + if (ret) { + wiphy_warn(local->hw.wiphy, + "failed to start next HW ROC (%d)\n", ret); + /* + * queue the work struct again to avoid recursion + * when multiple failures occur + */ + ieee80211_remain_on_channel_expired(&local->hw); + } + } else { + /* delay it a bit */ + ieee80211_queue_delayed_work(&local->hw, &roc->work, + round_jiffies_relative(HZ/2)); + } +} - cfg80211_mgmt_tx_status(local->hw_roc_dev, cookie, - local->hw_roc_skb->data, - local->hw_roc_skb->len, false, - GFP_KERNEL); +void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc) +{ + struct ieee80211_roc_work *dep, *tmp; - kfree_skb(local->hw_roc_skb); - local->hw_roc_skb = NULL; - local->hw_roc_skb_for_status = NULL; + /* was never transmitted */ + if (roc->frame) { + cfg80211_mgmt_tx_status(&roc->sdata->wdev, + (unsigned long)roc->frame, + roc->frame->data, roc->frame->len, + false, GFP_KERNEL); + kfree_skb(roc->frame); } - if (!local->hw_roc_for_tx) - cfg80211_remain_on_channel_expired(local->hw_roc_dev, - local->hw_roc_cookie, - local->hw_roc_channel, - local->hw_roc_channel_type, + if (!roc->mgmt_tx_cookie) + cfg80211_remain_on_channel_expired(&roc->sdata->wdev, + (unsigned long)roc, + roc->chan, roc->chan_type, GFP_KERNEL); - local->hw_roc_channel = NULL; - local->hw_roc_cookie = 0; + list_for_each_entry_safe(dep, tmp, &roc->dependents, list) + ieee80211_roc_notify_destroy(dep); + + kfree(roc); +} + +void ieee80211_sw_roc_work(struct work_struct *work) +{ + struct ieee80211_roc_work *roc = + container_of(work, struct ieee80211_roc_work, work.work); + struct ieee80211_sub_if_data *sdata = roc->sdata; + struct ieee80211_local *local = sdata->local; + bool started; + + mutex_lock(&local->mtx); + + if (roc->abort) + goto finish; + + if (WARN_ON(list_empty(&local->roc_list))) + goto out_unlock; + + if (WARN_ON(roc != list_first_entry(&local->roc_list, + struct ieee80211_roc_work, + list))) + goto out_unlock; - ieee80211_recalc_idle(local); + if (!roc->started) { + struct ieee80211_roc_work *dep; + /* start this ROC */ + + /* switch channel etc */ + ieee80211_recalc_idle(local); + + local->tmp_channel = roc->chan; + local->tmp_channel_type = roc->chan_type; + ieee80211_hw_config(local, 0); + + /* tell userspace or send frame */ + ieee80211_handle_roc_started(roc); + list_for_each_entry(dep, &roc->dependents, list) + ieee80211_handle_roc_started(dep); + + /* if it was pure TX, just finish right away */ + if (!roc->duration) + goto finish; + + roc->started = true; + ieee80211_queue_delayed_work(&local->hw, &roc->work, + msecs_to_jiffies(roc->duration)); + } else { + /* finish this ROC */ + finish: + list_del(&roc->list); + started = roc->started; + ieee80211_roc_notify_destroy(roc); + + if (started) { + drv_flush(local, false); + + local->tmp_channel = NULL; + ieee80211_hw_config(local, 0); + + ieee80211_offchannel_return(local, true); + } + + ieee80211_recalc_idle(local); + + if (started) + ieee80211_start_next_roc(local); + } + + out_unlock: + mutex_unlock(&local->mtx); +} + +static void ieee80211_hw_roc_done(struct work_struct *work) +{ + struct ieee80211_local *local = + container_of(work, struct ieee80211_local, hw_roc_done); + struct ieee80211_roc_work *roc; + + mutex_lock(&local->mtx); + + if (list_empty(&local->roc_list)) + goto out_unlock; + + roc = list_first_entry(&local->roc_list, struct ieee80211_roc_work, + list); + + if (!roc->started) + goto out_unlock; + + list_del(&roc->list); + + ieee80211_roc_notify_destroy(roc); + + /* if there's another roc, start it now */ + ieee80211_start_next_roc(local); + + out_unlock: mutex_unlock(&local->mtx); } @@ -275,8 +427,47 @@ void ieee80211_remain_on_channel_expired(struct ieee80211_hw *hw) } EXPORT_SYMBOL_GPL(ieee80211_remain_on_channel_expired); -void ieee80211_hw_roc_setup(struct ieee80211_local *local) +void ieee80211_roc_setup(struct ieee80211_local *local) { INIT_WORK(&local->hw_roc_start, ieee80211_hw_roc_start); INIT_WORK(&local->hw_roc_done, ieee80211_hw_roc_done); + INIT_LIST_HEAD(&local->roc_list); +} + +void ieee80211_roc_purge(struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_local *local = sdata->local; + struct ieee80211_roc_work *roc, *tmp; + LIST_HEAD(tmp_list); + + mutex_lock(&local->mtx); + list_for_each_entry_safe(roc, tmp, &local->roc_list, list) { + if (roc->sdata != sdata) + continue; + + if (roc->started && local->ops->remain_on_channel) { + /* can race, so ignore return value */ + drv_cancel_remain_on_channel(local); + } + + list_move_tail(&roc->list, &tmp_list); + roc->abort = true; + } + + ieee80211_start_next_roc(local); + mutex_unlock(&local->mtx); + + list_for_each_entry_safe(roc, tmp, &tmp_list, list) { + if (local->ops->remain_on_channel) { + list_del(&roc->list); + ieee80211_roc_notify_destroy(roc); + } else { + ieee80211_queue_delayed_work(&local->hw, &roc->work, 0); + + /* work will clean up etc */ + flush_delayed_work(&roc->work); + } + } + + WARN_ON_ONCE(!list_empty(&tmp_list)); } diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index af1c4e26e96..5c572e7a1a7 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c @@ -77,6 +77,17 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) int err = drv_suspend(local, wowlan); if (err < 0) { local->quiescing = false; + local->wowlan = false; + if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) { + mutex_lock(&local->sta_mtx); + list_for_each_entry(sta, + &local->sta_list, list) { + clear_sta_flag(sta, WLAN_STA_BLOCK_BA); + } + mutex_unlock(&local->sta_mtx); + } + ieee80211_wake_queues_by_reason(hw, + IEEE80211_QUEUE_STOP_REASON_SUSPEND); return err; } else if (err > 0) { WARN_ON(err != 1); diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index f9e51ef8dfa..fb1d4aa65e8 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c @@ -626,8 +626,12 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, #ifdef CONFIG_MAC80211_DEBUGFS /* use fixed index if set */ - if (mp->fixed_rate_idx != -1) - sample_idx = mp->fixed_rate_idx; + if (mp->fixed_rate_idx != -1) { + mi->max_tp_rate = mp->fixed_rate_idx; + mi->max_tp_rate2 = mp->fixed_rate_idx; + mi->max_prob_rate = mp->fixed_rate_idx; + sample_idx = -1; + } #endif if (sample_idx >= 0) { diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 965e6ec0adb..0cb4edee6af 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -94,7 +94,7 @@ ieee80211_rx_radiotap_len(struct ieee80211_local *local, return len; } -/* +/** * ieee80211_add_rx_radiotap_header - add radiotap header * * add a radiotap header containing all the fields which the hardware provided. @@ -413,29 +413,6 @@ static void ieee80211_verify_alignment(struct ieee80211_rx_data *rx) /* rx handlers */ -static ieee80211_rx_result debug_noinline -ieee80211_rx_h_passive_scan(struct ieee80211_rx_data *rx) -{ - struct ieee80211_local *local = rx->local; - struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); - struct sk_buff *skb = rx->skb; - - if (likely(!(status->rx_flags & IEEE80211_RX_IN_SCAN) && - !local->sched_scanning)) - return RX_CONTINUE; - - if (test_bit(SCAN_HW_SCANNING, &local->scanning) || - test_bit(SCAN_SW_SCANNING, &local->scanning) || - test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning) || - local->sched_scanning) - return ieee80211_scan_rx(rx->sdata, skb); - - /* scanning finished during invoking of handlers */ - I802_DEBUG_INC(local->rx_handlers_drop_passive_scan); - return RX_DROP_UNUSABLE; -} - - static int ieee80211_is_unicast_robust_mgmt_frame(struct sk_buff *skb) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; @@ -554,11 +531,11 @@ static inline u16 seq_sub(u16 sq1, u16 sq2) } -static void ieee80211_release_reorder_frame(struct ieee80211_hw *hw, +static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata, struct tid_ampdu_rx *tid_agg_rx, int index) { - struct ieee80211_local *local = hw_to_local(hw); + struct ieee80211_local *local = sdata->local; struct sk_buff *skb = tid_agg_rx->reorder_buf[index]; struct ieee80211_rx_status *status; @@ -578,7 +555,7 @@ no_frame: tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num); } -static void ieee80211_release_reorder_frames(struct ieee80211_hw *hw, +static void ieee80211_release_reorder_frames(struct ieee80211_sub_if_data *sdata, struct tid_ampdu_rx *tid_agg_rx, u16 head_seq_num) { @@ -589,7 +566,7 @@ static void ieee80211_release_reorder_frames(struct ieee80211_hw *hw, while (seq_less(tid_agg_rx->head_seq_num, head_seq_num)) { index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % tid_agg_rx->buf_size; - ieee80211_release_reorder_frame(hw, tid_agg_rx, index); + ieee80211_release_reorder_frame(sdata, tid_agg_rx, index); } } @@ -604,7 +581,7 @@ static void ieee80211_release_reorder_frames(struct ieee80211_hw *hw, */ #define HT_RX_REORDER_BUF_TIMEOUT (HZ / 10) -static void ieee80211_sta_reorder_release(struct ieee80211_hw *hw, +static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata, struct tid_ampdu_rx *tid_agg_rx) { int index, j; @@ -632,12 +609,9 @@ static void ieee80211_sta_reorder_release(struct ieee80211_hw *hw, HT_RX_REORDER_BUF_TIMEOUT)) goto set_release_timer; -#ifdef CONFIG_MAC80211_HT_DEBUG - if (net_ratelimit()) - wiphy_debug(hw->wiphy, - "release an RX reorder frame due to timeout on earlier frames\n"); -#endif - ieee80211_release_reorder_frame(hw, tid_agg_rx, j); + ht_dbg_ratelimited(sdata, + "release an RX reorder frame due to timeout on earlier frames\n"); + ieee80211_release_reorder_frame(sdata, tid_agg_rx, j); /* * Increment the head seq# also for the skipped slots. @@ -647,7 +621,7 @@ static void ieee80211_sta_reorder_release(struct ieee80211_hw *hw, skipped = 0; } } else while (tid_agg_rx->reorder_buf[index]) { - ieee80211_release_reorder_frame(hw, tid_agg_rx, index); + ieee80211_release_reorder_frame(sdata, tid_agg_rx, index); index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % tid_agg_rx->buf_size; } @@ -677,7 +651,7 @@ static void ieee80211_sta_reorder_release(struct ieee80211_hw *hw, * rcu_read_lock protection. It returns false if the frame * can be processed immediately, true if it was consumed. */ -static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, +static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata, struct tid_ampdu_rx *tid_agg_rx, struct sk_buff *skb) { @@ -706,7 +680,8 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, if (!seq_less(mpdu_seq_num, head_seq_num + buf_size)) { head_seq_num = seq_inc(seq_sub(mpdu_seq_num, buf_size)); /* release stored frames up to new head to stack */ - ieee80211_release_reorder_frames(hw, tid_agg_rx, head_seq_num); + ieee80211_release_reorder_frames(sdata, tid_agg_rx, + head_seq_num); } /* Now the new frame is always in the range of the reordering buffer */ @@ -736,7 +711,7 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, tid_agg_rx->reorder_buf[index] = skb; tid_agg_rx->reorder_time[index] = jiffies; tid_agg_rx->stored_mpdu_num++; - ieee80211_sta_reorder_release(hw, tid_agg_rx); + ieee80211_sta_reorder_release(sdata, tid_agg_rx); out: spin_unlock(&tid_agg_rx->reorder_lock); @@ -751,7 +726,6 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx) { struct sk_buff *skb = rx->skb; struct ieee80211_local *local = rx->local; - struct ieee80211_hw *hw = &local->hw; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); struct sta_info *sta = rx->sta; @@ -813,7 +787,7 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx) * sure that we cannot get to it any more before doing * anything with it. */ - if (ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb)) + if (ieee80211_sta_manage_reorder_buf(rx->sdata, tid_agg_rx, skb)) return; dont_reorder: @@ -1136,24 +1110,18 @@ static void ap_sta_ps_start(struct sta_info *sta) set_sta_flag(sta, WLAN_STA_PS_STA); if (!(local->hw.flags & IEEE80211_HW_AP_LINK_PS)) drv_sta_notify(local, sdata, STA_NOTIFY_SLEEP, &sta->sta); -#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - printk(KERN_DEBUG "%s: STA %pM aid %d enters power save mode\n", - sdata->name, sta->sta.addr, sta->sta.aid); -#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ + ps_dbg(sdata, "STA %pM aid %d enters power save mode\n", + sta->sta.addr, sta->sta.aid); } static void ap_sta_ps_end(struct sta_info *sta) { -#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - printk(KERN_DEBUG "%s: STA %pM aid %d exits power save mode\n", - sta->sdata->name, sta->sta.addr, sta->sta.aid); -#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ + ps_dbg(sta->sdata, "STA %pM aid %d exits power save mode\n", + sta->sta.addr, sta->sta.aid); if (test_sta_flag(sta, WLAN_STA_PS_DRIVER)) { -#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - printk(KERN_DEBUG "%s: STA %pM aid %d driver-ps-blocked\n", - sta->sdata->name, sta->sta.addr, sta->sta.aid); -#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ + ps_dbg(sta->sdata, "STA %pM aid %d driver-ps-blocked\n", + sta->sta.addr, sta->sta.aid); return; } @@ -1383,19 +1351,8 @@ ieee80211_reassemble_add(struct ieee80211_sub_if_data *sdata, if (sdata->fragment_next >= IEEE80211_FRAGMENT_MAX) sdata->fragment_next = 0; - if (!skb_queue_empty(&entry->skb_list)) { -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - struct ieee80211_hdr *hdr = - (struct ieee80211_hdr *) entry->skb_list.next->data; - printk(KERN_DEBUG "%s: RX reassembly removed oldest " - "fragment entry (idx=%d age=%lu seq=%d last_frag=%d " - "addr1=%pM addr2=%pM\n", - sdata->name, idx, - jiffies - entry->first_frag_time, entry->seq, - entry->last_frag, hdr->addr1, hdr->addr2); -#endif + if (!skb_queue_empty(&entry->skb_list)) __skb_queue_purge(&entry->skb_list); - } __skb_queue_tail(&entry->skb_list, *skb); /* no need for locking */ *skb = NULL; @@ -1753,7 +1710,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) */ xmit_skb = skb_copy(skb, GFP_ATOMIC); if (!xmit_skb) - net_dbg_ratelimited("%s: failed to clone multicast frame\n", + net_info_ratelimited("%s: failed to clone multicast frame\n", dev->name); } else { dsta = sta_info_get(sdata, skb->data); @@ -1937,7 +1894,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) ether_addr_equal(sdata->vif.addr, hdr->addr3)) return RX_CONTINUE; - q = ieee80211_select_queue_80211(local, skb, hdr); + q = ieee80211_select_queue_80211(sdata, skb, hdr); if (ieee80211_queue_stopped(&local->hw, q)) { IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_congestion); return RX_DROP_MONITOR; @@ -1957,7 +1914,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) fwd_skb = skb_copy(skb, GFP_ATOMIC); if (!fwd_skb) { - net_dbg_ratelimited("%s: failed to clone mesh frame\n", + net_info_ratelimited("%s: failed to clone mesh frame\n", sdata->name); goto out; } @@ -2060,8 +2017,6 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx) static ieee80211_rx_result debug_noinline ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx) { - struct ieee80211_local *local = rx->local; - struct ieee80211_hw *hw = &local->hw; struct sk_buff *skb = rx->skb; struct ieee80211_bar *bar = (struct ieee80211_bar *)skb->data; struct tid_ampdu_rx *tid_agg_rx; @@ -2098,7 +2053,8 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx) spin_lock(&tid_agg_rx->reorder_lock); /* release stored frames up to start of BAR */ - ieee80211_release_reorder_frames(hw, tid_agg_rx, start_seq_num); + ieee80211_release_reorder_frames(rx->sdata, tid_agg_rx, + start_seq_num); spin_unlock(&tid_agg_rx->reorder_lock); kfree_skb(skb); @@ -2425,7 +2381,7 @@ ieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data *rx) if (rx->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) sig = status->signal; - if (cfg80211_rx_mgmt(rx->sdata->dev, status->freq, sig, + if (cfg80211_rx_mgmt(&rx->sdata->wdev, status->freq, sig, rx->skb->data, rx->skb->len, GFP_ATOMIC)) { if (rx->sta) @@ -2716,7 +2672,6 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_rx_data *rx) goto rxh_next; \ } while (0); - CALL_RXH(ieee80211_rx_h_passive_scan) CALL_RXH(ieee80211_rx_h_check) ieee80211_rx_reorder_ampdu(rx); @@ -2752,7 +2707,7 @@ void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid) return; spin_lock(&tid_agg_rx->reorder_lock); - ieee80211_sta_reorder_release(&sta->local->hw, tid_agg_rx); + ieee80211_sta_reorder_release(sta->sdata, tid_agg_rx); spin_unlock(&tid_agg_rx->reorder_lock); ieee80211_rx_handlers(&rx); @@ -2786,11 +2741,8 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx, return 0; if (ieee80211_is_beacon(hdr->frame_control)) { return 1; - } - else if (!ieee80211_bssid_match(bssid, sdata->u.ibss.bssid)) { - if (!(status->rx_flags & IEEE80211_RX_IN_SCAN)) - return 0; - status->rx_flags &= ~IEEE80211_RX_RA_MATCH; + } else if (!ieee80211_bssid_match(bssid, sdata->u.ibss.bssid)) { + return 0; } else if (!multicast && !ether_addr_equal(sdata->vif.addr, hdr->addr1)) { if (!(sdata->dev->flags & IFF_PROMISC)) @@ -2828,11 +2780,9 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx, * and location updates. Note that mac80211 * itself never looks at these frames. */ - if (!(status->rx_flags & IEEE80211_RX_IN_SCAN) && - ieee80211_is_public_action(hdr, skb->len)) + if (ieee80211_is_public_action(hdr, skb->len)) return 1; - if (!(status->rx_flags & IEEE80211_RX_IN_SCAN) && - !ieee80211_is_beacon(hdr->frame_control)) + if (!ieee80211_is_beacon(hdr->frame_control)) return 0; status->rx_flags &= ~IEEE80211_RX_RA_MATCH; } @@ -2898,7 +2848,6 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx, static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, struct sk_buff *skb) { - struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_sub_if_data *sdata; struct ieee80211_hdr *hdr; @@ -2916,11 +2865,6 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, if (ieee80211_is_data(fc) || ieee80211_is_mgmt(fc)) local->dot11ReceivedFragmentCount++; - if (unlikely(test_bit(SCAN_HW_SCANNING, &local->scanning) || - test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning) || - test_bit(SCAN_SW_SCANNING, &local->scanning))) - status->rx_flags |= IEEE80211_RX_IN_SCAN; - if (ieee80211_is_mgmt(fc)) err = skb_linearize(skb); else @@ -2935,6 +2879,10 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, ieee80211_parse_qos(&rx); ieee80211_verify_alignment(&rx); + if (unlikely(ieee80211_is_probe_resp(hdr->frame_control) || + ieee80211_is_beacon(hdr->frame_control))) + ieee80211_scan_rx(local, skb); + if (ieee80211_is_data(fc)) { prev_sta = NULL; @@ -3032,6 +2980,10 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb) if (unlikely(local->quiescing || local->suspended)) goto drop; + /* We might be during a HW reconfig, prevent Rx for the same reason */ + if (unlikely(local->in_reconfig)) + goto drop; + /* * The same happens when we're not even started, * but that's worth a warning. diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 169da0742c8..bcaee5d1283 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -83,13 +83,14 @@ ieee80211_bss_info_update(struct ieee80211_local *local, cbss = cfg80211_inform_bss_frame(local->hw.wiphy, channel, mgmt, len, signal, GFP_ATOMIC); - if (!cbss) return NULL; cbss->free_priv = ieee80211_rx_bss_free; bss = (void *)cbss->priv; + bss->device_ts = rx_status->device_timestamp; + if (elems->parse_error) { if (beacon) bss->corrupt_data |= IEEE80211_BSS_CORRUPT_BEACON; @@ -114,8 +115,7 @@ ieee80211_bss_info_update(struct ieee80211_local *local, if (elems->tim && (!elems->parse_error || !(bss->valid_data & IEEE80211_BSS_VALID_DTIM))) { - struct ieee80211_tim_ie *tim_ie = - (struct ieee80211_tim_ie *)elems->tim; + struct ieee80211_tim_ie *tim_ie = elems->tim; bss->dtim_period = tim_ie->dtim_period; if (!elems->parse_error) bss->valid_data |= IEEE80211_BSS_VALID_DTIM; @@ -165,52 +165,47 @@ ieee80211_bss_info_update(struct ieee80211_local *local, return bss; } -ieee80211_rx_result -ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) +void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb) { struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); - struct ieee80211_mgmt *mgmt; + struct ieee80211_sub_if_data *sdata1, *sdata2; + struct ieee80211_mgmt *mgmt = (void *)skb->data; struct ieee80211_bss *bss; u8 *elements; struct ieee80211_channel *channel; size_t baselen; int freq; - __le16 fc; - bool presp, beacon = false; + bool beacon; struct ieee802_11_elems elems; - if (skb->len < 2) - return RX_DROP_UNUSABLE; - - mgmt = (struct ieee80211_mgmt *) skb->data; - fc = mgmt->frame_control; + if (skb->len < 24 || + (!ieee80211_is_probe_resp(mgmt->frame_control) && + !ieee80211_is_beacon(mgmt->frame_control))) + return; - if (ieee80211_is_ctl(fc)) - return RX_CONTINUE; + sdata1 = rcu_dereference(local->scan_sdata); + sdata2 = rcu_dereference(local->sched_scan_sdata); - if (skb->len < 24) - return RX_CONTINUE; + if (likely(!sdata1 && !sdata2)) + return; - presp = ieee80211_is_probe_resp(fc); - if (presp) { + if (ieee80211_is_probe_resp(mgmt->frame_control)) { /* ignore ProbeResp to foreign address */ - if (!ether_addr_equal(mgmt->da, sdata->vif.addr)) - return RX_DROP_MONITOR; + if ((!sdata1 || !ether_addr_equal(mgmt->da, sdata1->vif.addr)) && + (!sdata2 || !ether_addr_equal(mgmt->da, sdata2->vif.addr))) + return; - presp = true; elements = mgmt->u.probe_resp.variable; baselen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable); + beacon = false; } else { - beacon = ieee80211_is_beacon(fc); baselen = offsetof(struct ieee80211_mgmt, u.beacon.variable); elements = mgmt->u.beacon.variable; + beacon = true; } - if (!presp && !beacon) - return RX_CONTINUE; - if (baselen > skb->len) - return RX_DROP_MONITOR; + return; ieee802_11_parse_elems(elements, skb->len - baselen, &elems); @@ -220,22 +215,16 @@ ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) else freq = rx_status->freq; - channel = ieee80211_get_channel(sdata->local->hw.wiphy, freq); + channel = ieee80211_get_channel(local->hw.wiphy, freq); if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) - return RX_DROP_MONITOR; + return; - bss = ieee80211_bss_info_update(sdata->local, rx_status, + bss = ieee80211_bss_info_update(local, rx_status, mgmt, skb->len, &elems, channel, beacon); if (bss) - ieee80211_rx_bss_put(sdata->local, bss); - - if (channel == sdata->local->oper_channel) - return RX_CONTINUE; - - dev_kfree_skb(skb); - return RX_QUEUED; + ieee80211_rx_bss_put(local, bss); } /* return false if no more work */ @@ -293,7 +282,13 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted, return; if (was_hw_scan && !aborted && ieee80211_prep_hw_scan(local)) { - int rc = drv_hw_scan(local, local->scan_sdata, local->hw_scan_req); + int rc; + + rc = drv_hw_scan(local, + rcu_dereference_protected(local->scan_sdata, + lockdep_is_held(&local->mtx)), + local->hw_scan_req); + if (rc == 0) return; } @@ -323,7 +318,7 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted, ieee80211_mlme_notify_scan_completed(local); ieee80211_ibss_notify_scan_completed(local); ieee80211_mesh_notify_scan_completed(local); - ieee80211_queue_work(&local->hw, &local->work_work); + ieee80211_start_next_roc(local); } void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) @@ -376,7 +371,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local) static bool ieee80211_can_scan(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata) { - if (!list_empty(&local->work_list)) + if (!list_empty(&local->roc_list)) return false; if (sdata->vif.type == NL80211_IFTYPE_STATION && @@ -394,7 +389,10 @@ void ieee80211_run_deferred_scan(struct ieee80211_local *local) if (!local->scan_req || local->scanning) return; - if (!ieee80211_can_scan(local, local->scan_sdata)) + if (!ieee80211_can_scan(local, + rcu_dereference_protected( + local->scan_sdata, + lockdep_is_held(&local->mtx)))) return; ieee80211_queue_delayed_work(&local->hw, &local->scan_work, @@ -405,9 +403,12 @@ static void ieee80211_scan_state_send_probe(struct ieee80211_local *local, unsigned long *next_delay) { int i; - struct ieee80211_sub_if_data *sdata = local->scan_sdata; + struct ieee80211_sub_if_data *sdata; enum ieee80211_band band = local->hw.conf.channel->band; + sdata = rcu_dereference_protected(local->scan_sdata, + lockdep_is_held(&local->mtx));; + for (i = 0; i < local->scan_req->n_ssids; i++) ieee80211_send_probe_req( sdata, NULL, @@ -439,7 +440,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, if (!ieee80211_can_scan(local, sdata)) { /* wait for the work to finish/time out */ local->scan_req = req; - local->scan_sdata = sdata; + rcu_assign_pointer(local->scan_sdata, sdata); return 0; } @@ -473,7 +474,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, } local->scan_req = req; - local->scan_sdata = sdata; + rcu_assign_pointer(local->scan_sdata, sdata); if (local->ops->hw_scan) { __set_bit(SCAN_HW_SCANNING, &local->scanning); @@ -533,7 +534,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, ieee80211_recalc_idle(local); local->scan_req = NULL; - local->scan_sdata = NULL; + rcu_assign_pointer(local->scan_sdata, NULL); } return rc; @@ -720,7 +721,8 @@ void ieee80211_scan_work(struct work_struct *work) mutex_lock(&local->mtx); - sdata = local->scan_sdata; + sdata = rcu_dereference_protected(local->scan_sdata, + lockdep_is_held(&local->mtx)); /* When scanning on-channel, the first-callback means completed. */ if (test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning)) { @@ -741,7 +743,7 @@ void ieee80211_scan_work(struct work_struct *work) int rc; local->scan_req = NULL; - local->scan_sdata = NULL; + rcu_assign_pointer(local->scan_sdata, NULL); rc = __ieee80211_start_scan(sdata, req); if (rc) { @@ -893,7 +895,9 @@ void ieee80211_scan_cancel(struct ieee80211_local *local) if (test_bit(SCAN_HW_SCANNING, &local->scanning)) { if (local->ops->cancel_hw_scan) - drv_cancel_hw_scan(local, local->scan_sdata); + drv_cancel_hw_scan(local, + rcu_dereference_protected(local->scan_sdata, + lockdep_is_held(&local->mtx))); goto out; } @@ -915,9 +919,9 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, struct ieee80211_local *local = sdata->local; int ret, i; - mutex_lock(&sdata->local->mtx); + mutex_lock(&local->mtx); - if (local->sched_scanning) { + if (rcu_access_pointer(local->sched_scan_sdata)) { ret = -EBUSY; goto out; } @@ -928,6 +932,9 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, } for (i = 0; i < IEEE80211_NUM_BANDS; i++) { + if (!local->hw.wiphy->bands[i]) + continue; + local->sched_scan_ies.ie[i] = kzalloc(2 + IEEE80211_MAX_SSID_LEN + local->scan_ies_len + @@ -948,7 +955,7 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, ret = drv_sched_scan_start(local, sdata, req, &local->sched_scan_ies); if (ret == 0) { - local->sched_scanning = true; + rcu_assign_pointer(local->sched_scan_sdata, sdata); goto out; } @@ -956,7 +963,7 @@ out_free: while (i > 0) kfree(local->sched_scan_ies.ie[--i]); out: - mutex_unlock(&sdata->local->mtx); + mutex_unlock(&local->mtx); return ret; } @@ -965,22 +972,22 @@ int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata) struct ieee80211_local *local = sdata->local; int ret = 0, i; - mutex_lock(&sdata->local->mtx); + mutex_lock(&local->mtx); if (!local->ops->sched_scan_stop) { ret = -ENOTSUPP; goto out; } - if (local->sched_scanning) { + if (rcu_access_pointer(local->sched_scan_sdata)) { for (i = 0; i < IEEE80211_NUM_BANDS; i++) kfree(local->sched_scan_ies.ie[i]); drv_sched_scan_stop(local, sdata); - local->sched_scanning = false; + rcu_assign_pointer(local->sched_scan_sdata, NULL); } out: - mutex_unlock(&sdata->local->mtx); + mutex_unlock(&local->mtx); return ret; } @@ -1004,7 +1011,7 @@ void ieee80211_sched_scan_stopped_work(struct work_struct *work) mutex_lock(&local->mtx); - if (!local->sched_scanning) { + if (!rcu_access_pointer(local->sched_scan_sdata)) { mutex_unlock(&local->mtx); return; } @@ -1012,7 +1019,7 @@ void ieee80211_sched_scan_stopped_work(struct work_struct *work) for (i = 0; i < IEEE80211_NUM_BANDS; i++) kfree(local->sched_scan_ies.ie[i]); - local->sched_scanning = false; + rcu_assign_pointer(local->sched_scan_sdata, NULL); mutex_unlock(&local->mtx); diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index de455f8bbb9..06fa75ceb02 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -169,9 +169,7 @@ void sta_info_free(struct ieee80211_local *local, struct sta_info *sta) if (sta->rate_ctrl) rate_control_free_sta(sta); -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - wiphy_debug(local->hw.wiphy, "Destroyed STA %pM\n", sta->sta.addr); -#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ + sta_dbg(sta->sdata, "Destroyed STA %pM\n", sta->sta.addr); kfree(sta); } @@ -278,9 +276,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, for (i = 0; i < NUM_RX_DATA_QUEUES; i++) sta->last_seq_ctrl[i] = cpu_to_le16(USHRT_MAX); -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - wiphy_debug(local->hw.wiphy, "Allocated STA %pM\n", sta->sta.addr); -#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ + sta_dbg(sdata, "Allocated STA %pM\n", sta->sta.addr); #ifdef CONFIG_MAC80211_MESH sta->plink_state = NL80211_PLINK_LISTEN; @@ -333,9 +329,9 @@ static int sta_info_insert_drv_state(struct ieee80211_local *local, } if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { - printk(KERN_DEBUG - "%s: failed to move IBSS STA %pM to state %d (%d) - keeping it anyway.\n", - sdata->name, sta->sta.addr, state + 1, err); + sdata_info(sdata, + "failed to move IBSS STA %pM to state %d (%d) - keeping it anyway\n", + sta->sta.addr, state + 1, err); err = 0; } @@ -390,9 +386,7 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU) sinfo.generation = local->sta_generation; cfg80211_new_sta(sdata->dev, sta->sta.addr, &sinfo, GFP_KERNEL); -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - wiphy_debug(local->hw.wiphy, "Inserted STA %pM\n", sta->sta.addr); -#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ + sta_dbg(sdata, "Inserted STA %pM\n", sta->sta.addr); /* move reference to rcu-protected */ rcu_read_lock(); @@ -618,10 +612,8 @@ static bool sta_info_cleanup_expire_buffered_ac(struct ieee80211_local *local, break; local->total_ps_buffered--; -#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - printk(KERN_DEBUG "Buffered frame expired (STA %pM)\n", + ps_dbg(sta->sdata, "Buffered frame expired (STA %pM)\n", sta->sta.addr); -#endif dev_kfree_skb(skb); } @@ -747,9 +739,8 @@ int __must_check __sta_info_destroy(struct sta_info *sta) mesh_accept_plinks_update(sdata); #endif -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - wiphy_debug(local->hw.wiphy, "Removed STA %pM\n", sta->sta.addr); -#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ + sta_dbg(sdata, "Removed STA %pM\n", sta->sta.addr); + cancel_work_sync(&sta->drv_unblock_wk); cfg80211_del_sta(sdata->dev, sta->sta.addr, GFP_KERNEL); @@ -889,10 +880,8 @@ void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata, continue; if (time_after(jiffies, sta->last_rx + exp_time)) { -#ifdef CONFIG_MAC80211_IBSS_DEBUG - printk(KERN_DEBUG "%s: expiring inactive STA %pM\n", - sdata->name, sta->sta.addr); -#endif + ibss_dbg(sdata, "expiring inactive STA %pM\n", + sta->sta.addr); WARN_ON(__sta_info_destroy(sta)); } } @@ -990,11 +979,9 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) sta_info_recalc_tim(sta); -#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - printk(KERN_DEBUG "%s: STA %pM aid %d sending %d filtered/%d PS frames " - "since STA not sleeping anymore\n", sdata->name, + ps_dbg(sdata, + "STA %pM aid %d sending %d filtered/%d PS frames since STA not sleeping anymore\n", sta->sta.addr, sta->sta.aid, filtered, buffered); -#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ } static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata, @@ -1384,10 +1371,8 @@ int sta_info_move_state(struct sta_info *sta, return -EINVAL; } -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - printk(KERN_DEBUG "%s: moving STA %pM to state %d\n", - sta->sdata->name, sta->sta.addr, new_state); -#endif + sta_dbg(sta->sdata, "moving STA %pM to state %d\n", + sta->sta.addr, new_state); /* * notify the driver before the actual changes so it can diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 28cfa981cfb..8cd72914cda 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -155,13 +155,10 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, return; } -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - if (net_ratelimit()) - wiphy_debug(local->hw.wiphy, - "dropped TX filtered frame, queue_len=%d PS=%d @%lu\n", - skb_queue_len(&sta->tx_filtered[ac]), - !!test_sta_flag(sta, WLAN_STA_PS_STA), jiffies); -#endif + ps_dbg_ratelimited(sta->sdata, + "dropped TX filtered frame, queue_len=%d PS=%d @%lu\n", + skb_queue_len(&sta->tx_filtered[ac]), + !!test_sta_flag(sta, WLAN_STA_PS_STA), jiffies); dev_kfree_skb(skb); } @@ -520,36 +517,21 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) { u64 cookie = (unsigned long)skb; + acked = info->flags & IEEE80211_TX_STAT_ACK; - if (ieee80211_is_nullfunc(hdr->frame_control) || - ieee80211_is_qos_nullfunc(hdr->frame_control)) { - acked = info->flags & IEEE80211_TX_STAT_ACK; + /* + * TODO: When we have non-netdev frame TX, + * we cannot use skb->dev->ieee80211_ptr + */ + if (ieee80211_is_nullfunc(hdr->frame_control) || + ieee80211_is_qos_nullfunc(hdr->frame_control)) cfg80211_probe_status(skb->dev, hdr->addr1, cookie, acked, GFP_ATOMIC); - } else { - struct ieee80211_work *wk; - - rcu_read_lock(); - list_for_each_entry_rcu(wk, &local->work_list, list) { - if (wk->type != IEEE80211_WORK_OFFCHANNEL_TX) - continue; - if (wk->offchan_tx.frame != skb) - continue; - wk->offchan_tx.status = true; - break; - } - rcu_read_unlock(); - if (local->hw_roc_skb_for_status == skb) { - cookie = local->hw_roc_cookie ^ 2; - local->hw_roc_skb_for_status = NULL; - } - + else cfg80211_mgmt_tx_status( - skb->dev, cookie, skb->data, skb->len, - !!(info->flags & IEEE80211_TX_STAT_ACK), - GFP_ATOMIC); - } + skb->dev->ieee80211_ptr, cookie, skb->data, + skb->len, acked, GFP_ATOMIC); } if (unlikely(info->ack_frame_id)) { @@ -589,7 +571,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) /* send frame to monitor interfaces now */ rtap_len = ieee80211_tx_radiotap_len(info); if (WARN_ON_ONCE(skb_headroom(skb) < rtap_len)) { - printk(KERN_ERR "ieee80211_tx_status: headroom too small\n"); + pr_err("ieee80211_tx_status: headroom too small\n"); dev_kfree_skb(skb); return; } diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c index 51077a956a8..57e14d59e12 100644 --- a/net/mac80211/tkip.c +++ b/net/mac80211/tkip.c @@ -260,17 +260,6 @@ int ieee80211_tkip_decrypt_data(struct crypto_cipher *tfm, keyid = pos[3]; iv32 = get_unaligned_le32(pos + 4); pos += 8; -#ifdef CONFIG_MAC80211_TKIP_DEBUG - { - int i; - printk(KERN_DEBUG "TKIP decrypt: data(len=%zd)", payload_len); - for (i = 0; i < payload_len; i++) - printk(" %02x", payload[i]); - printk("\n"); - printk(KERN_DEBUG "TKIP decrypt: iv16=%04x iv32=%08x\n", - iv16, iv32); - } -#endif if (!(keyid & (1 << 5))) return TKIP_DECRYPT_NO_EXT_IV; @@ -281,16 +270,8 @@ int ieee80211_tkip_decrypt_data(struct crypto_cipher *tfm, if (key->u.tkip.rx[queue].state != TKIP_STATE_NOT_INIT && (iv32 < key->u.tkip.rx[queue].iv32 || (iv32 == key->u.tkip.rx[queue].iv32 && - iv16 <= key->u.tkip.rx[queue].iv16))) { -#ifdef CONFIG_MAC80211_TKIP_DEBUG - printk(KERN_DEBUG "TKIP replay detected for RX frame from " - "%pM (RX IV (%04x,%02x) <= prev. IV (%04x,%02x)\n", - ta, - iv32, iv16, key->u.tkip.rx[queue].iv32, - key->u.tkip.rx[queue].iv16); -#endif + iv16 <= key->u.tkip.rx[queue].iv16))) return TKIP_DECRYPT_REPLAY; - } if (only_iv) { res = TKIP_DECRYPT_OK; @@ -302,22 +283,6 @@ int ieee80211_tkip_decrypt_data(struct crypto_cipher *tfm, key->u.tkip.rx[queue].iv32 != iv32) { /* IV16 wrapped around - perform TKIP phase 1 */ tkip_mixing_phase1(tk, &key->u.tkip.rx[queue], ta, iv32); -#ifdef CONFIG_MAC80211_TKIP_DEBUG - { - int i; - u8 key_offset = NL80211_TKIP_DATA_OFFSET_ENCR_KEY; - printk(KERN_DEBUG "TKIP decrypt: Phase1 TA=%pM" - " TK=", ta); - for (i = 0; i < 16; i++) - printk("%02x ", - key->conf.key[key_offset + i]); - printk("\n"); - printk(KERN_DEBUG "TKIP decrypt: P1K="); - for (i = 0; i < 5; i++) - printk("%04x ", key->u.tkip.rx[queue].p1k[i]); - printk("\n"); - } -#endif } if (key->local->ops->update_tkip_key && key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE && @@ -333,15 +298,6 @@ int ieee80211_tkip_decrypt_data(struct crypto_cipher *tfm, } tkip_mixing_phase2(tk, &key->u.tkip.rx[queue], iv16, rc4key); -#ifdef CONFIG_MAC80211_TKIP_DEBUG - { - int i; - printk(KERN_DEBUG "TKIP decrypt: Phase2 rc4key="); - for (i = 0; i < 16; i++) - printk("%02x ", rc4key[i]); - printk("\n"); - } -#endif res = ieee80211_wep_decrypt_data(tfm, rc4key, 16, pos, payload_len - 12); done: diff --git a/net/mac80211/trace.c b/net/mac80211/trace.c new file mode 100644 index 00000000000..386e45d8a95 --- /dev/null +++ b/net/mac80211/trace.c @@ -0,0 +1,75 @@ +/* bug in tracepoint.h, it should include this */ +#include <linux/module.h> + +/* sparse isn't too happy with all macros... */ +#ifndef __CHECKER__ +#include <net/cfg80211.h> +#include "driver-ops.h" +#include "debug.h" +#define CREATE_TRACE_POINTS +#include "trace.h" + +#ifdef CONFIG_MAC80211_MESSAGE_TRACING +void __sdata_info(const char *fmt, ...) +{ + struct va_format vaf = { + .fmt = fmt, + }; + va_list args; + + va_start(args, fmt); + vaf.va = &args; + + pr_info("%pV", &vaf); + trace_mac80211_info(&vaf); + va_end(args); +} + +void __sdata_dbg(bool print, const char *fmt, ...) +{ + struct va_format vaf = { + .fmt = fmt, + }; + va_list args; + + va_start(args, fmt); + vaf.va = &args; + + if (print) + pr_debug("%pV", &vaf); + trace_mac80211_dbg(&vaf); + va_end(args); +} + +void __sdata_err(const char *fmt, ...) +{ + struct va_format vaf = { + .fmt = fmt, + }; + va_list args; + + va_start(args, fmt); + vaf.va = &args; + + pr_err("%pV", &vaf); + trace_mac80211_err(&vaf); + va_end(args); +} + +void __wiphy_dbg(struct wiphy *wiphy, bool print, const char *fmt, ...) +{ + struct va_format vaf = { + .fmt = fmt, + }; + va_list args; + + va_start(args, fmt); + vaf.va = &args; + + if (print) + wiphy_dbg(wiphy, "%pV", &vaf); + trace_mac80211_dbg(&vaf); + va_end(args); +} +#endif +#endif diff --git a/net/mac80211/driver-trace.h b/net/mac80211/trace.h index 6de00b2c268..c6d33b55b2d 100644 --- a/net/mac80211/driver-trace.h +++ b/net/mac80211/trace.h @@ -306,7 +306,8 @@ TRACE_EVENT(drv_bss_info_changed, __field(u8, dtimper) __field(u16, bcnint) __field(u16, assoc_cap) - __field(u64, timestamp) + __field(u64, sync_tsf) + __field(u32, sync_device_ts) __field(u32, basic_rates) __field(u32, changed) __field(bool, enable_beacon) @@ -325,7 +326,8 @@ TRACE_EVENT(drv_bss_info_changed, __entry->dtimper = info->dtim_period; __entry->bcnint = info->beacon_int; __entry->assoc_cap = info->assoc_capability; - __entry->timestamp = info->last_tsf; + __entry->sync_tsf = info->sync_tsf; + __entry->sync_device_ts = info->sync_device_ts; __entry->basic_rates = info->basic_rates; __entry->enable_beacon = info->enable_beacon; __entry->ht_operation_mode = info->ht_operation_mode; @@ -1218,6 +1220,39 @@ DEFINE_EVENT(release_evt, drv_allow_buffered_frames, TP_ARGS(local, sta, tids, num_frames, reason, more_data) ); +TRACE_EVENT(drv_get_rssi, + TP_PROTO(struct ieee80211_local *local, struct ieee80211_sta *sta, + s8 rssi, int ret), + + TP_ARGS(local, sta, rssi, ret), + + TP_STRUCT__entry( + LOCAL_ENTRY + STA_ENTRY + __field(s8, rssi) + __field(int, ret) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + STA_ASSIGN; + __entry->rssi = rssi; + __entry->ret = ret; + ), + + TP_printk( + LOCAL_PR_FMT STA_PR_FMT " rssi:%d ret:%d", + LOCAL_PR_ARG, STA_PR_ARG, __entry->rssi, __entry->ret + ) +); + +DEFINE_EVENT(local_sdata_evt, drv_mgd_prepare_tx, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata), + + TP_ARGS(local, sdata) +); + /* * Tracing for API calls that drivers call. */ @@ -1606,10 +1641,49 @@ TRACE_EVENT(stop_queue, LOCAL_PR_ARG, __entry->queue, __entry->reason ) ); + +#ifdef CONFIG_MAC80211_MESSAGE_TRACING +#undef TRACE_SYSTEM +#define TRACE_SYSTEM mac80211_msg + +#define MAX_MSG_LEN 100 + +DECLARE_EVENT_CLASS(mac80211_msg_event, + TP_PROTO(struct va_format *vaf), + + TP_ARGS(vaf), + + TP_STRUCT__entry( + __dynamic_array(char, msg, MAX_MSG_LEN) + ), + + TP_fast_assign( + WARN_ON_ONCE(vsnprintf(__get_dynamic_array(msg), + MAX_MSG_LEN, vaf->fmt, + *vaf->va) >= MAX_MSG_LEN); + ), + + TP_printk("%s", __get_str(msg)) +); + +DEFINE_EVENT(mac80211_msg_event, mac80211_info, + TP_PROTO(struct va_format *vaf), + TP_ARGS(vaf) +); +DEFINE_EVENT(mac80211_msg_event, mac80211_dbg, + TP_PROTO(struct va_format *vaf), + TP_ARGS(vaf) +); +DEFINE_EVENT(mac80211_msg_event, mac80211_err, + TP_PROTO(struct va_format *vaf), + TP_ARGS(vaf) +); +#endif + #endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */ #undef TRACE_INCLUDE_PATH #define TRACE_INCLUDE_PATH . #undef TRACE_INCLUDE_FILE -#define TRACE_INCLUDE_FILE driver-trace +#define TRACE_INCLUDE_FILE trace #include <trace/define_trace.h> diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index e453212fa17..acf712ffb5e 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -140,6 +140,8 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, if (r->flags & IEEE80211_RATE_MANDATORY_A) mrate = r->bitrate; break; + case IEEE80211_BAND_60GHZ: + /* TODO, for now fall through */ case IEEE80211_NUM_BANDS: WARN_ON(1); break; @@ -175,12 +177,6 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, return cpu_to_le16(dur); } -static inline int is_ieee80211_device(struct ieee80211_local *local, - struct net_device *dev) -{ - return local == wdev_priv(dev->ieee80211_ptr); -} - /* tx handlers */ static ieee80211_tx_result debug_noinline ieee80211_tx_h_dynamic_ps(struct ieee80211_tx_data *tx) @@ -297,10 +293,10 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx) if (unlikely(!assoc && ieee80211_is_data(hdr->frame_control))) { #ifdef CONFIG_MAC80211_VERBOSE_DEBUG - printk(KERN_DEBUG "%s: dropped data frame to not " - "associated station %pM\n", - tx->sdata->name, hdr->addr1); -#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ + sdata_info(tx->sdata, + "dropped data frame to not associated station %pM\n", + hdr->addr1); +#endif I802_DEBUG_INC(tx->local->tx_handlers_drop_not_assoc); return TX_DROP; } @@ -367,10 +363,7 @@ static void purge_old_ps_buffers(struct ieee80211_local *local) rcu_read_unlock(); local->total_ps_buffered = total; -#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - wiphy_debug(local->hw.wiphy, "PS buffers full - purged %d frames\n", - purged); -#endif + ps_dbg_hw(&local->hw, "PS buffers full - purged %d frames\n", purged); } static ieee80211_tx_result @@ -412,10 +405,8 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx) purge_old_ps_buffers(tx->local); if (skb_queue_len(&tx->sdata->bss->ps_bc_buf) >= AP_MAX_BC_BUFFER) { -#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - net_dbg_ratelimited("%s: BC TX buffer full - dropping the oldest frame\n", - tx->sdata->name); -#endif + ps_dbg(tx->sdata, + "BC TX buffer full - dropping the oldest frame\n"); dev_kfree_skb(skb_dequeue(&tx->sdata->bss->ps_bc_buf)); } else tx->local->total_ps_buffered++; @@ -466,18 +457,15 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) return TX_CONTINUE; } -#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - printk(KERN_DEBUG "STA %pM aid %d: PS buffer for AC %d\n", + ps_dbg(sta->sdata, "STA %pM aid %d: PS buffer for AC %d\n", sta->sta.addr, sta->sta.aid, ac); -#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER) purge_old_ps_buffers(tx->local); if (skb_queue_len(&sta->ps_tx_buf[ac]) >= STA_MAX_TX_BUFFER) { struct sk_buff *old = skb_dequeue(&sta->ps_tx_buf[ac]); -#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - net_dbg_ratelimited("%s: STA %pM TX buffer for AC %d full - dropping oldest frame\n", - tx->sdata->name, sta->sta.addr, ac); -#endif + ps_dbg(tx->sdata, + "STA %pM TX buffer for AC %d full - dropping oldest frame\n", + sta->sta.addr, ac); dev_kfree_skb(old); } else tx->local->total_ps_buffered++; @@ -499,14 +487,11 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) sta_info_recalc_tim(sta); return TX_QUEUED; + } else if (unlikely(test_sta_flag(sta, WLAN_STA_PS_STA))) { + ps_dbg(tx->sdata, + "STA %pM in PS mode, but polling/in SP -> send frame\n", + sta->sta.addr); } -#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - else if (unlikely(test_sta_flag(sta, WLAN_STA_PS_STA))) { - printk(KERN_DEBUG - "%s: STA %pM in PS mode, but polling/in SP -> send frame\n", - tx->sdata->name, sta->sta.addr); - } -#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ return TX_CONTINUE; } @@ -538,7 +523,7 @@ ieee80211_tx_h_check_control_port_protocol(struct ieee80211_tx_data *tx) static ieee80211_tx_result debug_noinline ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) { - struct ieee80211_key *key = NULL; + struct ieee80211_key *key; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; @@ -557,16 +542,23 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) else if (!is_multicast_ether_addr(hdr->addr1) && (key = rcu_dereference(tx->sdata->default_unicast_key))) tx->key = key; - else if (tx->sdata->drop_unencrypted && - (tx->skb->protocol != tx->sdata->control_port_protocol) && - !(info->flags & IEEE80211_TX_CTL_INJECTED) && - (!ieee80211_is_robust_mgmt_frame(hdr) || - (ieee80211_is_action(hdr->frame_control) && - tx->sta && test_sta_flag(tx->sta, WLAN_STA_MFP)))) { + else if (info->flags & IEEE80211_TX_CTL_INJECTED) + tx->key = NULL; + else if (!tx->sdata->drop_unencrypted) + tx->key = NULL; + else if (tx->skb->protocol == tx->sdata->control_port_protocol) + tx->key = NULL; + else if (ieee80211_is_robust_mgmt_frame(hdr) && + !(ieee80211_is_action(hdr->frame_control) && + tx->sta && test_sta_flag(tx->sta, WLAN_STA_MFP))) + tx->key = NULL; + else if (ieee80211_is_mgmt(hdr->frame_control) && + !ieee80211_is_robust_mgmt_frame(hdr)) + tx->key = NULL; + else { I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted); return TX_DROP; - } else - tx->key = NULL; + } if (tx->key) { bool skip_hw = false; @@ -974,8 +966,7 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) info->control.rates[1].idx = -1; info->control.rates[2].idx = -1; info->control.rates[3].idx = -1; - info->control.rates[4].idx = -1; - BUILD_BUG_ON(IEEE80211_TX_MAX_RATES != 5); + BUILD_BUG_ON(IEEE80211_TX_MAX_RATES != 4); info->flags &= ~IEEE80211_TX_CTL_RATE_CTRL_PROBE; } else { hdr->frame_control &= ~morefrags; @@ -1310,11 +1301,8 @@ static bool __ieee80211_tx(struct ieee80211_local *local, break; } - if (local->ops->tx_frags) - drv_tx_frags(local, vif, pubsta, skbs); - else - result = ieee80211_tx_frags(local, vif, pubsta, skbs, - txpending); + result = ieee80211_tx_frags(local, vif, pubsta, skbs, + txpending); ieee80211_tpt_led_trig_tx(local, fc, led_len); ieee80211_led_tx(local, 1); @@ -1836,6 +1824,9 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, /* RA TA mDA mSA AE:DA SA */ mesh_da = mppath->mpp; is_mesh_mcast = 0; + } else if (mpath) { + mesh_da = mpath->dst; + is_mesh_mcast = 0; } else { /* DA TA mSA AE:SA */ mesh_da = bcast; @@ -1965,7 +1956,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, (cpu_to_be16(ethertype) != sdata->control_port_protocol || !ether_addr_equal(sdata->vif.addr, skb->data + ETH_ALEN)))) { #ifdef CONFIG_MAC80211_VERBOSE_DEBUG - net_dbg_ratelimited("%s: dropped frame to %pM (unauthorized port)\n", + net_info_ratelimited("%s: dropped frame to %pM (unauthorized port)\n", dev->name, hdr.addr1); #endif @@ -2437,9 +2428,9 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, *pos++ = WLAN_EID_SSID; *pos++ = 0x0; - if (ieee80211_add_srates_ie(&sdata->vif, skb, true) || + if (ieee80211_add_srates_ie(sdata, skb, true) || mesh_add_ds_params_ie(skb, sdata) || - ieee80211_add_ext_srates_ie(&sdata->vif, skb, true) || + ieee80211_add_ext_srates_ie(sdata, skb, true) || mesh_add_rsn_ie(skb, sdata) || mesh_add_ht_cap_ie(skb, sdata) || mesh_add_ht_oper_ie(skb, sdata) || @@ -2733,7 +2724,7 @@ EXPORT_SYMBOL(ieee80211_get_buffered_bc); void ieee80211_tx_skb_tid(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, int tid) { - int ac = ieee802_1d_to_ac[tid]; + int ac = ieee802_1d_to_ac[tid & 7]; skb_set_mac_header(skb, 0); skb_set_network_header(skb, 0); diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 8dd4712620f..39b82fee490 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -268,6 +268,10 @@ EXPORT_SYMBOL(ieee80211_ctstoself_duration); void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue) { struct ieee80211_sub_if_data *sdata; + int n_acs = IEEE80211_NUM_ACS; + + if (local->hw.queues < IEEE80211_NUM_ACS) + n_acs = 1; list_for_each_entry_rcu(sdata, &local->interfaces, list) { int ac; @@ -279,7 +283,7 @@ void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue) local->queue_stop_reasons[sdata->vif.cab_queue] != 0) continue; - for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { + for (ac = 0; ac < n_acs; ac++) { int ac_queue = sdata->vif.hw_queue[ac]; if (ac_queue == queue || @@ -341,6 +345,7 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue, { struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_sub_if_data *sdata; + int n_acs = IEEE80211_NUM_ACS; trace_stop_queue(local, queue, reason); @@ -352,11 +357,14 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue, __set_bit(reason, &local->queue_stop_reasons[queue]); + if (local->hw.queues < IEEE80211_NUM_ACS) + n_acs = 1; + rcu_read_lock(); list_for_each_entry_rcu(sdata, &local->interfaces, list) { int ac; - for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { + for (ac = 0; ac < n_acs; ac++) { if (sdata->vif.hw_queue[ac] == queue || sdata->vif.cab_queue == queue) netif_stop_subqueue(sdata->dev, ac); @@ -521,6 +529,11 @@ void ieee80211_iterate_active_interfaces( &sdata->vif); } + sdata = rcu_dereference_protected(local->monitor_sdata, + lockdep_is_held(&local->iflist_mtx)); + if (sdata) + iterator(data, sdata->vif.addr, &sdata->vif); + mutex_unlock(&local->iflist_mtx); } EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces); @@ -549,6 +562,10 @@ void ieee80211_iterate_active_interfaces_atomic( &sdata->vif); } + sdata = rcu_dereference(local->monitor_sdata); + if (sdata) + iterator(data, sdata->vif.addr, &sdata->vif); + rcu_read_unlock(); } EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic); @@ -804,7 +821,7 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, struct ieee80211_local *local = sdata->local; struct ieee80211_tx_queue_params qparam; int ac; - bool use_11b; + bool use_11b, enable_qos; int aCWmin, aCWmax; if (!local->ops->conf_tx) @@ -818,6 +835,13 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, use_11b = (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) && !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE); + /* + * By default disable QoS in STA mode for old access points, which do + * not support 802.11e. New APs will provide proper queue parameters, + * that we will configure later. + */ + enable_qos = (sdata->vif.type != NL80211_IFTYPE_STATION); + for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { /* Set defaults according to 802.11-2007 Table 7-37 */ aCWmax = 1023; @@ -826,38 +850,47 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, else aCWmin = 15; - switch (ac) { - case IEEE80211_AC_BK: - qparam.cw_max = aCWmax; - qparam.cw_min = aCWmin; - qparam.txop = 0; - qparam.aifs = 7; - break; - default: /* never happens but let's not leave undefined */ - case IEEE80211_AC_BE: + if (enable_qos) { + switch (ac) { + case IEEE80211_AC_BK: + qparam.cw_max = aCWmax; + qparam.cw_min = aCWmin; + qparam.txop = 0; + qparam.aifs = 7; + break; + /* never happens but let's not leave undefined */ + default: + case IEEE80211_AC_BE: + qparam.cw_max = aCWmax; + qparam.cw_min = aCWmin; + qparam.txop = 0; + qparam.aifs = 3; + break; + case IEEE80211_AC_VI: + qparam.cw_max = aCWmin; + qparam.cw_min = (aCWmin + 1) / 2 - 1; + if (use_11b) + qparam.txop = 6016/32; + else + qparam.txop = 3008/32; + qparam.aifs = 2; + break; + case IEEE80211_AC_VO: + qparam.cw_max = (aCWmin + 1) / 2 - 1; + qparam.cw_min = (aCWmin + 1) / 4 - 1; + if (use_11b) + qparam.txop = 3264/32; + else + qparam.txop = 1504/32; + qparam.aifs = 2; + break; + } + } else { + /* Confiure old 802.11b/g medium access rules. */ qparam.cw_max = aCWmax; qparam.cw_min = aCWmin; qparam.txop = 0; - qparam.aifs = 3; - break; - case IEEE80211_AC_VI: - qparam.cw_max = aCWmin; - qparam.cw_min = (aCWmin + 1) / 2 - 1; - if (use_11b) - qparam.txop = 6016/32; - else - qparam.txop = 3008/32; - qparam.aifs = 2; - break; - case IEEE80211_AC_VO: - qparam.cw_max = (aCWmin + 1) / 2 - 1; - qparam.cw_min = (aCWmin + 1) / 4 - 1; - if (use_11b) - qparam.txop = 3264/32; - else - qparam.txop = 1504/32; qparam.aifs = 2; - break; } qparam.uapsd = false; @@ -866,12 +899,8 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, drv_conf_tx(local, sdata, ac, &qparam); } - /* after reinitialize QoS TX queues setting to default, - * disable QoS at all */ - if (sdata->vif.type != NL80211_IFTYPE_MONITOR) { - sdata->vif.bss_conf.qos = - sdata->vif.type != NL80211_IFTYPE_STATION; + sdata->vif.bss_conf.qos = enable_qos; if (bss_notify) ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_QOS); @@ -979,6 +1008,8 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, int ext_rates_len; sband = local->hw.wiphy->bands[band]; + if (WARN_ON_ONCE(!sband)) + return 0; pos = buffer; @@ -1060,6 +1091,10 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, pos += noffset - offset; } + if (sband->vht_cap.vht_supported) + pos = ieee80211_ie_build_vht_cap(pos, &sband->vht_cap, + sband->vht_cap.cap); + return pos - buffer; } @@ -1267,14 +1302,19 @@ int ieee80211_reconfig(struct ieee80211_local *local) /* add STAs back */ mutex_lock(&local->sta_mtx); list_for_each_entry(sta, &local->sta_list, list) { - if (sta->uploaded) { - enum ieee80211_sta_state state; + enum ieee80211_sta_state state; - for (state = IEEE80211_STA_NOTEXIST; - state < sta->sta_state; state++) - WARN_ON(drv_sta_state(local, sta->sdata, sta, - state, state + 1)); - } + if (!sta->uploaded) + continue; + + /* AP-mode stations will be added later */ + if (sta->sdata->vif.type == NL80211_IFTYPE_AP) + continue; + + for (state = IEEE80211_STA_NOTEXIST; + state < sta->sta_state; state++) + WARN_ON(drv_sta_state(local, sta->sdata, sta, state, + state + 1)); } mutex_unlock(&local->sta_mtx); @@ -1371,12 +1411,33 @@ int ieee80211_reconfig(struct ieee80211_local *local) } } + /* APs are now beaconing, add back stations */ + mutex_lock(&local->sta_mtx); + list_for_each_entry(sta, &local->sta_list, list) { + enum ieee80211_sta_state state; + + if (!sta->uploaded) + continue; + + if (sta->sdata->vif.type != NL80211_IFTYPE_AP) + continue; + + for (state = IEEE80211_STA_NOTEXIST; + state < sta->sta_state; state++) + WARN_ON(drv_sta_state(local, sta->sdata, sta, state, + state + 1)); + } + mutex_unlock(&local->sta_mtx); + /* add back keys */ list_for_each_entry(sdata, &local->interfaces, list) if (ieee80211_sdata_running(sdata)) ieee80211_enable_keys(sdata); wake_up: + local->in_reconfig = false; + barrier(); + /* * Clear the WLAN_STA_BLOCK_BA flag so new aggregation * sessions can be established after a resume. @@ -1661,6 +1722,27 @@ u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, return pos; } +u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, + u32 cap) +{ + __le32 tmp; + + *pos++ = WLAN_EID_VHT_CAPABILITY; + *pos++ = sizeof(struct ieee80211_vht_capabilities); + memset(pos, 0, sizeof(struct ieee80211_vht_capabilities)); + + /* capability flags */ + tmp = cpu_to_le32(cap); + memcpy(pos, &tmp, sizeof(u32)); + pos += sizeof(u32); + + /* VHT MCS set */ + memcpy(pos, &vht_cap->vht_mcs, sizeof(vht_cap->vht_mcs)); + pos += sizeof(vht_cap->vht_mcs); + + return pos; +} + u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, struct ieee80211_channel *channel, enum nl80211_channel_type channel_type, @@ -1726,15 +1808,14 @@ ieee80211_ht_oper_to_channel_type(struct ieee80211_ht_operation *ht_oper) return channel_type; } -int ieee80211_add_srates_ie(struct ieee80211_vif *vif, +int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, bool need_basic) { - struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); struct ieee80211_local *local = sdata->local; struct ieee80211_supported_band *sband; int rate; u8 i, rates, *pos; - u32 basic_rates = vif->bss_conf.basic_rates; + u32 basic_rates = sdata->vif.bss_conf.basic_rates; sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; rates = sband->n_bitrates; @@ -1758,15 +1839,14 @@ int ieee80211_add_srates_ie(struct ieee80211_vif *vif, return 0; } -int ieee80211_add_ext_srates_ie(struct ieee80211_vif *vif, +int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, bool need_basic) { - struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); struct ieee80211_local *local = sdata->local; struct ieee80211_supported_band *sband; int rate; u8 i, exrates, *pos; - u32 basic_rates = vif->bss_conf.basic_rates; + u32 basic_rates = sdata->vif.bss_conf.basic_rates; sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; exrates = sband->n_bitrates; diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index c3d643a6536..cea06e9f26f 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c @@ -52,11 +52,11 @@ static int wme_downgrade_ac(struct sk_buff *skb) } } -static u16 ieee80211_downgrade_queue(struct ieee80211_local *local, +static u16 ieee80211_downgrade_queue(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) { /* in case we are a client verify acm is not set for this ac */ - while (unlikely(local->wmm_acm & BIT(skb->priority))) { + while (unlikely(sdata->wmm_acm & BIT(skb->priority))) { if (wme_downgrade_ac(skb)) { /* * This should not really happen. The AP has marked all @@ -73,10 +73,11 @@ static u16 ieee80211_downgrade_queue(struct ieee80211_local *local, } /* Indicate which queue to use for this fully formed 802.11 frame */ -u16 ieee80211_select_queue_80211(struct ieee80211_local *local, +u16 ieee80211_select_queue_80211(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, struct ieee80211_hdr *hdr) { + struct ieee80211_local *local = sdata->local; u8 *p; if (local->hw.queues < IEEE80211_NUM_ACS) @@ -94,7 +95,7 @@ u16 ieee80211_select_queue_80211(struct ieee80211_local *local, p = ieee80211_get_qos_ctl(hdr); skb->priority = *p & IEEE80211_QOS_CTL_TAG1D_MASK; - return ieee80211_downgrade_queue(local, skb); + return ieee80211_downgrade_queue(sdata, skb); } /* Indicate which queue to use. */ @@ -156,7 +157,7 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, * data frame has */ skb->priority = cfg80211_classify8021d(skb); - return ieee80211_downgrade_queue(local, skb); + return ieee80211_downgrade_queue(sdata, skb); } void ieee80211_set_qos_hdr(struct ieee80211_sub_if_data *sdata, diff --git a/net/mac80211/wme.h b/net/mac80211/wme.h index ca80818b7b6..7fea4bb8acb 100644 --- a/net/mac80211/wme.h +++ b/net/mac80211/wme.h @@ -15,7 +15,7 @@ extern const int ieee802_1d_to_ac[8]; -u16 ieee80211_select_queue_80211(struct ieee80211_local *local, +u16 ieee80211_select_queue_80211(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, struct ieee80211_hdr *hdr); u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, diff --git a/net/mac80211/work.c b/net/mac80211/work.c deleted file mode 100644 index b2650a9d45f..00000000000 --- a/net/mac80211/work.c +++ /dev/null @@ -1,370 +0,0 @@ -/* - * mac80211 work implementation - * - * Copyright 2003-2008, Jouni Malinen <j@w1.fi> - * Copyright 2004, Instant802 Networks, Inc. - * Copyright 2005, Devicescape Software, Inc. - * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> - * Copyright 2007, Michael Wu <flamingice@sourmilk.net> - * Copyright 2009, Johannes Berg <johannes@sipsolutions.net> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/delay.h> -#include <linux/if_ether.h> -#include <linux/skbuff.h> -#include <linux/if_arp.h> -#include <linux/etherdevice.h> -#include <linux/crc32.h> -#include <linux/slab.h> -#include <net/mac80211.h> -#include <asm/unaligned.h> - -#include "ieee80211_i.h" -#include "rate.h" -#include "driver-ops.h" - -enum work_action { - WORK_ACT_NONE, - WORK_ACT_TIMEOUT, -}; - - -/* utils */ -static inline void ASSERT_WORK_MTX(struct ieee80211_local *local) -{ - lockdep_assert_held(&local->mtx); -} - -/* - * We can have multiple work items (and connection probing) - * scheduling this timer, but we need to take care to only - * reschedule it when it should fire _earlier_ than it was - * asked for before, or if it's not pending right now. This - * function ensures that. Note that it then is required to - * run this function for all timeouts after the first one - * has happened -- the work that runs from this timer will - * do that. - */ -static void run_again(struct ieee80211_local *local, - unsigned long timeout) -{ - ASSERT_WORK_MTX(local); - - if (!timer_pending(&local->work_timer) || - time_before(timeout, local->work_timer.expires)) - mod_timer(&local->work_timer, timeout); -} - -void free_work(struct ieee80211_work *wk) -{ - kfree_rcu(wk, rcu_head); -} - -static enum work_action __must_check -ieee80211_remain_on_channel_timeout(struct ieee80211_work *wk) -{ - /* - * First time we run, do nothing -- the generic code will - * have switched to the right channel etc. - */ - if (!wk->started) { - wk->timeout = jiffies + msecs_to_jiffies(wk->remain.duration); - - cfg80211_ready_on_channel(wk->sdata->dev, (unsigned long) wk, - wk->chan, wk->chan_type, - wk->remain.duration, GFP_KERNEL); - - return WORK_ACT_NONE; - } - - return WORK_ACT_TIMEOUT; -} - -static enum work_action __must_check -ieee80211_offchannel_tx(struct ieee80211_work *wk) -{ - if (!wk->started) { - wk->timeout = jiffies + msecs_to_jiffies(wk->offchan_tx.wait); - - /* - * After this, offchan_tx.frame remains but now is no - * longer a valid pointer -- we still need it as the - * cookie for canceling this work/status matching. - */ - ieee80211_tx_skb(wk->sdata, wk->offchan_tx.frame); - - return WORK_ACT_NONE; - } - - return WORK_ACT_TIMEOUT; -} - -static void ieee80211_work_timer(unsigned long data) -{ - struct ieee80211_local *local = (void *) data; - - if (local->quiescing) - return; - - ieee80211_queue_work(&local->hw, &local->work_work); -} - -static void ieee80211_work_work(struct work_struct *work) -{ - struct ieee80211_local *local = - container_of(work, struct ieee80211_local, work_work); - struct ieee80211_work *wk, *tmp; - LIST_HEAD(free_work); - enum work_action rma; - bool remain_off_channel = false; - - /* - * ieee80211_queue_work() should have picked up most cases, - * here we'll pick the rest. - */ - if (WARN(local->suspended, "work scheduled while going to suspend\n")) - return; - - mutex_lock(&local->mtx); - - if (local->scanning) { - mutex_unlock(&local->mtx); - return; - } - - ieee80211_recalc_idle(local); - - list_for_each_entry_safe(wk, tmp, &local->work_list, list) { - bool started = wk->started; - - /* mark work as started if it's on the current off-channel */ - if (!started && local->tmp_channel && - wk->chan == local->tmp_channel && - wk->chan_type == local->tmp_channel_type) { - started = true; - wk->timeout = jiffies; - } - - if (!started && !local->tmp_channel) { - ieee80211_offchannel_stop_vifs(local, true); - - local->tmp_channel = wk->chan; - local->tmp_channel_type = wk->chan_type; - - ieee80211_hw_config(local, 0); - - started = true; - wk->timeout = jiffies; - } - - /* don't try to work with items that aren't started */ - if (!started) - continue; - - if (time_is_after_jiffies(wk->timeout)) { - /* - * This work item isn't supposed to be worked on - * right now, but take care to adjust the timer - * properly. - */ - run_again(local, wk->timeout); - continue; - } - - switch (wk->type) { - default: - WARN_ON(1); - /* nothing */ - rma = WORK_ACT_NONE; - break; - case IEEE80211_WORK_ABORT: - rma = WORK_ACT_TIMEOUT; - break; - case IEEE80211_WORK_REMAIN_ON_CHANNEL: - rma = ieee80211_remain_on_channel_timeout(wk); - break; - case IEEE80211_WORK_OFFCHANNEL_TX: - rma = ieee80211_offchannel_tx(wk); - break; - } - - wk->started = started; - - switch (rma) { - case WORK_ACT_NONE: - /* might have changed the timeout */ - run_again(local, wk->timeout); - break; - case WORK_ACT_TIMEOUT: - list_del_rcu(&wk->list); - synchronize_rcu(); - list_add(&wk->list, &free_work); - break; - default: - WARN(1, "unexpected: %d", rma); - } - } - - list_for_each_entry(wk, &local->work_list, list) { - if (!wk->started) - continue; - if (wk->chan != local->tmp_channel || - wk->chan_type != local->tmp_channel_type) - continue; - remain_off_channel = true; - } - - if (!remain_off_channel && local->tmp_channel) { - local->tmp_channel = NULL; - ieee80211_hw_config(local, 0); - - ieee80211_offchannel_return(local, true); - - /* give connection some time to breathe */ - run_again(local, jiffies + HZ/2); - } - - ieee80211_recalc_idle(local); - ieee80211_run_deferred_scan(local); - - mutex_unlock(&local->mtx); - - list_for_each_entry_safe(wk, tmp, &free_work, list) { - wk->done(wk, NULL); - list_del(&wk->list); - kfree(wk); - } -} - -void ieee80211_add_work(struct ieee80211_work *wk) -{ - struct ieee80211_local *local; - - if (WARN_ON(!wk->chan)) - return; - - if (WARN_ON(!wk->sdata)) - return; - - if (WARN_ON(!wk->done)) - return; - - if (WARN_ON(!ieee80211_sdata_running(wk->sdata))) - return; - - wk->started = false; - - local = wk->sdata->local; - mutex_lock(&local->mtx); - list_add_tail(&wk->list, &local->work_list); - mutex_unlock(&local->mtx); - - ieee80211_queue_work(&local->hw, &local->work_work); -} - -void ieee80211_work_init(struct ieee80211_local *local) -{ - INIT_LIST_HEAD(&local->work_list); - setup_timer(&local->work_timer, ieee80211_work_timer, - (unsigned long)local); - INIT_WORK(&local->work_work, ieee80211_work_work); -} - -void ieee80211_work_purge(struct ieee80211_sub_if_data *sdata) -{ - struct ieee80211_local *local = sdata->local; - struct ieee80211_work *wk; - bool cleanup = false; - - mutex_lock(&local->mtx); - list_for_each_entry(wk, &local->work_list, list) { - if (wk->sdata != sdata) - continue; - cleanup = true; - wk->type = IEEE80211_WORK_ABORT; - wk->started = true; - wk->timeout = jiffies; - } - mutex_unlock(&local->mtx); - - /* run cleanups etc. */ - if (cleanup) - ieee80211_work_work(&local->work_work); - - mutex_lock(&local->mtx); - list_for_each_entry(wk, &local->work_list, list) { - if (wk->sdata != sdata) - continue; - WARN_ON(1); - break; - } - mutex_unlock(&local->mtx); -} - -static enum work_done_result ieee80211_remain_done(struct ieee80211_work *wk, - struct sk_buff *skb) -{ - /* - * We are done serving the remain-on-channel command. - */ - cfg80211_remain_on_channel_expired(wk->sdata->dev, (unsigned long) wk, - wk->chan, wk->chan_type, - GFP_KERNEL); - - return WORK_DONE_DESTROY; -} - -int ieee80211_wk_remain_on_channel(struct ieee80211_sub_if_data *sdata, - struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type, - unsigned int duration, u64 *cookie) -{ - struct ieee80211_work *wk; - - wk = kzalloc(sizeof(*wk), GFP_KERNEL); - if (!wk) - return -ENOMEM; - - wk->type = IEEE80211_WORK_REMAIN_ON_CHANNEL; - wk->chan = chan; - wk->chan_type = channel_type; - wk->sdata = sdata; - wk->done = ieee80211_remain_done; - - wk->remain.duration = duration; - - *cookie = (unsigned long) wk; - - ieee80211_add_work(wk); - - return 0; -} - -int ieee80211_wk_cancel_remain_on_channel(struct ieee80211_sub_if_data *sdata, - u64 cookie) -{ - struct ieee80211_local *local = sdata->local; - struct ieee80211_work *wk, *tmp; - bool found = false; - - mutex_lock(&local->mtx); - list_for_each_entry_safe(wk, tmp, &local->work_list, list) { - if ((unsigned long) wk == cookie) { - wk->timeout = jiffies; - found = true; - break; - } - } - mutex_unlock(&local->mtx); - - if (!found) - return -ENOENT; - - ieee80211_queue_work(&local->hw, &local->work_work); - - return 0; -} |