diff options
author | Johannes Berg <johannes.berg@intel.com> | 2011-11-04 06:18:16 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-11-09 16:13:46 -0500 |
commit | 06500736c5d26bff93a4f358713689073e66d0f5 (patch) | |
tree | 809fb3df5a058e5cedf276e75c25d033405602b3 /net/mac80211 | |
parent | 7f6cf311a594c1e7ca8120367dd1d4c685aabff1 (diff) |
mac80211: support client probe
Support probing clients with null data frames
in AP mode.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211')
-rw-r--r-- | net/mac80211/cfg.c | 68 | ||||
-rw-r--r-- | net/mac80211/status.c | 45 |
2 files changed, 95 insertions, 18 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 1f1056172ef1..e072fea69a30 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -2507,6 +2507,73 @@ static int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, | |||
2507 | return 0; | 2507 | return 0; |
2508 | } | 2508 | } |
2509 | 2509 | ||
2510 | static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev, | ||
2511 | const u8 *peer, u64 *cookie) | ||
2512 | { | ||
2513 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
2514 | struct ieee80211_local *local = sdata->local; | ||
2515 | struct ieee80211_qos_hdr *nullfunc; | ||
2516 | struct sk_buff *skb; | ||
2517 | int size = sizeof(*nullfunc); | ||
2518 | __le16 fc; | ||
2519 | bool qos; | ||
2520 | struct ieee80211_tx_info *info; | ||
2521 | struct sta_info *sta; | ||
2522 | |||
2523 | rcu_read_lock(); | ||
2524 | sta = sta_info_get(sdata, peer); | ||
2525 | if (sta) | ||
2526 | qos = test_sta_flag(sta, WLAN_STA_WME); | ||
2527 | rcu_read_unlock(); | ||
2528 | |||
2529 | if (!sta) | ||
2530 | return -ENOLINK; | ||
2531 | |||
2532 | if (qos) { | ||
2533 | fc = cpu_to_le16(IEEE80211_FTYPE_DATA | | ||
2534 | IEEE80211_STYPE_QOS_NULLFUNC | | ||
2535 | IEEE80211_FCTL_FROMDS); | ||
2536 | } else { | ||
2537 | size -= 2; | ||
2538 | fc = cpu_to_le16(IEEE80211_FTYPE_DATA | | ||
2539 | IEEE80211_STYPE_NULLFUNC | | ||
2540 | IEEE80211_FCTL_FROMDS); | ||
2541 | } | ||
2542 | |||
2543 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + size); | ||
2544 | if (!skb) | ||
2545 | return -ENOMEM; | ||
2546 | |||
2547 | skb->dev = dev; | ||
2548 | |||
2549 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
2550 | |||
2551 | nullfunc = (void *) skb_put(skb, size); | ||
2552 | nullfunc->frame_control = fc; | ||
2553 | nullfunc->duration_id = 0; | ||
2554 | memcpy(nullfunc->addr1, sta->sta.addr, ETH_ALEN); | ||
2555 | memcpy(nullfunc->addr2, sdata->vif.addr, ETH_ALEN); | ||
2556 | memcpy(nullfunc->addr3, sdata->vif.addr, ETH_ALEN); | ||
2557 | nullfunc->seq_ctrl = 0; | ||
2558 | |||
2559 | info = IEEE80211_SKB_CB(skb); | ||
2560 | |||
2561 | info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS | | ||
2562 | IEEE80211_TX_INTFL_NL80211_FRAME_TX; | ||
2563 | |||
2564 | skb_set_queue_mapping(skb, IEEE80211_AC_VO); | ||
2565 | skb->priority = 7; | ||
2566 | if (qos) | ||
2567 | nullfunc->qos_ctrl = cpu_to_le16(7); | ||
2568 | |||
2569 | local_bh_disable(); | ||
2570 | ieee80211_xmit(sdata, skb); | ||
2571 | local_bh_enable(); | ||
2572 | |||
2573 | *cookie = (unsigned long) skb; | ||
2574 | return 0; | ||
2575 | } | ||
2576 | |||
2510 | struct cfg80211_ops mac80211_config_ops = { | 2577 | struct cfg80211_ops mac80211_config_ops = { |
2511 | .add_virtual_intf = ieee80211_add_iface, | 2578 | .add_virtual_intf = ieee80211_add_iface, |
2512 | .del_virtual_intf = ieee80211_del_iface, | 2579 | .del_virtual_intf = ieee80211_del_iface, |
@@ -2572,4 +2639,5 @@ struct cfg80211_ops mac80211_config_ops = { | |||
2572 | .set_rekey_data = ieee80211_set_rekey_data, | 2639 | .set_rekey_data = ieee80211_set_rekey_data, |
2573 | .tdls_oper = ieee80211_tdls_oper, | 2640 | .tdls_oper = ieee80211_tdls_oper, |
2574 | .tdls_mgmt = ieee80211_tdls_mgmt, | 2641 | .tdls_mgmt = ieee80211_tdls_mgmt, |
2642 | .probe_client = ieee80211_probe_client, | ||
2575 | }; | 2643 | }; |
diff --git a/net/mac80211/status.c b/net/mac80211/status.c index e1f69545974a..94702f103cfc 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c | |||
@@ -516,27 +516,36 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
516 | } | 516 | } |
517 | 517 | ||
518 | if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) { | 518 | if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) { |
519 | struct ieee80211_work *wk; | ||
520 | u64 cookie = (unsigned long)skb; | 519 | u64 cookie = (unsigned long)skb; |
521 | 520 | ||
522 | rcu_read_lock(); | 521 | if (ieee80211_is_nullfunc(hdr->frame_control) || |
523 | list_for_each_entry_rcu(wk, &local->work_list, list) { | 522 | ieee80211_is_qos_nullfunc(hdr->frame_control)) { |
524 | if (wk->type != IEEE80211_WORK_OFFCHANNEL_TX) | 523 | bool acked = info->flags & IEEE80211_TX_STAT_ACK; |
525 | continue; | 524 | cfg80211_probe_status(skb->dev, hdr->addr1, |
526 | if (wk->offchan_tx.frame != skb) | 525 | cookie, acked, GFP_ATOMIC); |
527 | continue; | 526 | } else { |
528 | wk->offchan_tx.status = true; | 527 | struct ieee80211_work *wk; |
529 | break; | 528 | |
530 | } | 529 | rcu_read_lock(); |
531 | rcu_read_unlock(); | 530 | list_for_each_entry_rcu(wk, &local->work_list, list) { |
532 | if (local->hw_roc_skb_for_status == skb) { | 531 | if (wk->type != IEEE80211_WORK_OFFCHANNEL_TX) |
533 | cookie = local->hw_roc_cookie ^ 2; | 532 | continue; |
534 | local->hw_roc_skb_for_status = NULL; | 533 | if (wk->offchan_tx.frame != skb) |
535 | } | 534 | continue; |
535 | wk->offchan_tx.status = true; | ||
536 | break; | ||
537 | } | ||
538 | rcu_read_unlock(); | ||
539 | if (local->hw_roc_skb_for_status == skb) { | ||
540 | cookie = local->hw_roc_cookie ^ 2; | ||
541 | local->hw_roc_skb_for_status = NULL; | ||
542 | } | ||
536 | 543 | ||
537 | cfg80211_mgmt_tx_status( | 544 | cfg80211_mgmt_tx_status( |
538 | skb->dev, cookie, skb->data, skb->len, | 545 | skb->dev, cookie, skb->data, skb->len, |
539 | !!(info->flags & IEEE80211_TX_STAT_ACK), GFP_ATOMIC); | 546 | !!(info->flags & IEEE80211_TX_STAT_ACK), |
547 | GFP_ATOMIC); | ||
548 | } | ||
540 | } | 549 | } |
541 | 550 | ||
542 | /* this was a transmitted frame, but now we want to reuse it */ | 551 | /* this was a transmitted frame, but now we want to reuse it */ |