Merge branch 'pm-core'
[deliverable/linux.git] / drivers / net / wireless / mac80211_hwsim.c
index c00a7daaa4bc7be08c290cb2f159fb2e3a0ff19c..c32889a1e39cf53d4e2d1ab3a4bfc2b8b492af1e 100644 (file)
@@ -495,6 +495,9 @@ struct mac80211_hwsim_data {
        const struct ieee80211_regdomain *regd;
 
        struct ieee80211_channel *tmp_chan;
+       struct ieee80211_channel *roc_chan;
+       u32 roc_duration;
+       struct delayed_work roc_start;
        struct delayed_work roc_done;
        struct delayed_work hw_scan;
        struct cfg80211_scan_request *hw_scan_request;
@@ -514,6 +517,7 @@ struct mac80211_hwsim_data {
        bool ps_poll_pending;
        struct dentry *debugfs;
 
+       uintptr_t pending_cookie;
        struct sk_buff_head pending;    /* packets pending */
        /*
         * Only radios in the same group can communicate together (the
@@ -810,6 +814,9 @@ static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw,
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_skb);
        struct ieee80211_rate *txrate = ieee80211_get_tx_rate(hw, info);
 
+       if (WARN_ON(!txrate))
+               return;
+
        if (!netif_running(hwsim_mon))
                return;
 
@@ -960,6 +967,7 @@ static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw,
        unsigned int hwsim_flags = 0;
        int i;
        struct hwsim_tx_rate tx_attempts[IEEE80211_TX_MAX_RATES];
+       uintptr_t cookie;
 
        if (data->ps != PS_DISABLED)
                hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
@@ -1018,7 +1026,10 @@ static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw,
                goto nla_put_failure;
 
        /* We create a cookie to identify this skb */
-       if (nla_put_u64(skb, HWSIM_ATTR_COOKIE, (unsigned long) my_skb))
+       data->pending_cookie++;
+       cookie = data->pending_cookie;
+       info->rate_driver_data[0] = (void *)cookie;
+       if (nla_put_u64(skb, HWSIM_ATTR_COOKIE, cookie))
                goto nla_put_failure;
 
        genlmsg_end(skb, msg_head);
@@ -1247,6 +1258,7 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
 {
        struct mac80211_hwsim_data *data = hw->priv;
        struct ieee80211_tx_info *txi = IEEE80211_SKB_CB(skb);
+       struct ieee80211_hdr *hdr = (void *)skb->data;
        struct ieee80211_chanctx_conf *chanctx_conf;
        struct ieee80211_channel *channel;
        bool ack;
@@ -1292,6 +1304,22 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
                                       ARRAY_SIZE(txi->control.rates));
 
        txi->rate_driver_data[0] = channel;
+
+       if (skb->len >= 24 + 8 &&
+           ieee80211_is_probe_resp(hdr->frame_control)) {
+               /* fake header transmission time */
+               struct ieee80211_mgmt *mgmt;
+               struct ieee80211_rate *txrate;
+               u64 ts;
+
+               mgmt = (struct ieee80211_mgmt *)skb->data;
+               txrate = ieee80211_get_tx_rate(hw, txi);
+               ts = mac80211_hwsim_get_tsf_raw();
+               mgmt->u.probe_resp.timestamp =
+                       cpu_to_le64(ts + data->tsf_offset +
+                                   24 * 8 * 10 / txrate->bitrate);
+       }
+
        mac80211_hwsim_monitor_rx(hw, skb, channel);
 
        /* wmediumd mode check */
@@ -1871,7 +1899,8 @@ static void hw_scan_work(struct work_struct *work)
                    req->channels[hwsim->scan_chan_idx]->center_freq);
 
        hwsim->tmp_chan = req->channels[hwsim->scan_chan_idx];
-       if (hwsim->tmp_chan->flags & IEEE80211_CHAN_NO_IR ||
+       if (hwsim->tmp_chan->flags & (IEEE80211_CHAN_NO_IR |
+                                     IEEE80211_CHAN_RADAR) ||
            !req->n_ssids) {
                dwell = 120;
        } else {
@@ -1987,6 +2016,23 @@ static void mac80211_hwsim_sw_scan_complete(struct ieee80211_hw *hw,
        mutex_unlock(&hwsim->mutex);
 }
 
+static void hw_roc_start(struct work_struct *work)
+{
+       struct mac80211_hwsim_data *hwsim =
+               container_of(work, struct mac80211_hwsim_data, roc_start.work);
+
+       mutex_lock(&hwsim->mutex);
+
+       wiphy_debug(hwsim->hw->wiphy, "hwsim ROC begins\n");
+       hwsim->tmp_chan = hwsim->roc_chan;
+       ieee80211_ready_on_channel(hwsim->hw);
+
+       ieee80211_queue_delayed_work(hwsim->hw, &hwsim->roc_done,
+                                    msecs_to_jiffies(hwsim->roc_duration));
+
+       mutex_unlock(&hwsim->mutex);
+}
+
 static void hw_roc_done(struct work_struct *work)
 {
        struct mac80211_hwsim_data *hwsim =
@@ -2014,16 +2060,14 @@ static int mac80211_hwsim_roc(struct ieee80211_hw *hw,
                return -EBUSY;
        }
 
-       hwsim->tmp_chan = chan;
+       hwsim->roc_chan = chan;
+       hwsim->roc_duration = duration;
        mutex_unlock(&hwsim->mutex);
 
        wiphy_debug(hw->wiphy, "hwsim ROC (%d MHz, %d ms)\n",
                    chan->center_freq, duration);
+       ieee80211_queue_delayed_work(hw, &hwsim->roc_start, HZ/50);
 
-       ieee80211_ready_on_channel(hw);
-
-       ieee80211_queue_delayed_work(hw, &hwsim->roc_done,
-                                    msecs_to_jiffies(duration));
        return 0;
 }
 
@@ -2031,6 +2075,7 @@ static int mac80211_hwsim_croc(struct ieee80211_hw *hw)
 {
        struct mac80211_hwsim_data *hwsim = hw->priv;
 
+       cancel_delayed_work_sync(&hwsim->roc_start);
        cancel_delayed_work_sync(&hwsim->roc_done);
 
        mutex_lock(&hwsim->mutex);
@@ -2375,6 +2420,7 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
                hw->wiphy->n_iface_combinations = ARRAY_SIZE(hwsim_if_comb);
        }
 
+       INIT_DELAYED_WORK(&data->roc_start, hw_roc_start);
        INIT_DELAYED_WORK(&data->roc_done, hw_roc_done);
        INIT_DELAYED_WORK(&data->hw_scan, hw_scan_work);
 
@@ -2411,6 +2457,7 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
                               NL80211_FEATURE_STATIC_SMPS |
                               NL80211_FEATURE_DYNAMIC_SMPS |
                               NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR;
+       wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_VHT_IBSS);
 
        /* ask mac80211 to reserve space for magic */
        hw->vif_data_size = sizeof(struct hwsim_vif_priv);
@@ -2710,7 +2757,7 @@ static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2,
        struct mac80211_hwsim_data *data2;
        struct ieee80211_tx_info *txi;
        struct hwsim_tx_rate *tx_attempts;
-       unsigned long ret_skb_ptr;
+       u64 ret_skb_cookie;
        struct sk_buff *skb, *tmp;
        const u8 *src;
        unsigned int hwsim_flags;
@@ -2728,7 +2775,7 @@ static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2,
 
        src = (void *)nla_data(info->attrs[HWSIM_ATTR_ADDR_TRANSMITTER]);
        hwsim_flags = nla_get_u32(info->attrs[HWSIM_ATTR_FLAGS]);
-       ret_skb_ptr = nla_get_u64(info->attrs[HWSIM_ATTR_COOKIE]);
+       ret_skb_cookie = nla_get_u64(info->attrs[HWSIM_ATTR_COOKIE]);
 
        data2 = get_hwsim_data_ref_from_addr(src);
        if (!data2)
@@ -2736,7 +2783,12 @@ static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2,
 
        /* look for the skb matching the cookie passed back from user */
        skb_queue_walk_safe(&data2->pending, skb, tmp) {
-               if ((unsigned long)skb == ret_skb_ptr) {
+               u64 skb_cookie;
+
+               txi = IEEE80211_SKB_CB(skb);
+               skb_cookie = (u64)(uintptr_t)txi->rate_driver_data[0];
+
+               if (skb_cookie == ret_skb_cookie) {
                        skb_unlink(skb, &data2->pending);
                        found = true;
                        break;
@@ -2827,10 +2879,25 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2,
 
        /* A frame is received from user space */
        memset(&rx_status, 0, sizeof(rx_status));
-       /* TODO: Check ATTR_FREQ if it exists, and maybe throw away off-channel
-        * packets?
-        */
-       rx_status.freq = data2->channel->center_freq;
+       if (info->attrs[HWSIM_ATTR_FREQ]) {
+               /* throw away off-channel packets, but allow both the temporary
+                * ("hw" scan/remain-on-channel) and regular channel, since the
+                * internal datapath also allows this
+                */
+               mutex_lock(&data2->mutex);
+               rx_status.freq = nla_get_u32(info->attrs[HWSIM_ATTR_FREQ]);
+
+               if (rx_status.freq != data2->channel->center_freq &&
+                   (!data2->tmp_chan ||
+                    rx_status.freq != data2->tmp_chan->center_freq)) {
+                       mutex_unlock(&data2->mutex);
+                       goto out;
+               }
+               mutex_unlock(&data2->mutex);
+       } else {
+               rx_status.freq = data2->channel->center_freq;
+       }
+
        rx_status.band = data2->channel->band;
        rx_status.rate_idx = nla_get_u32(info->attrs[HWSIM_ATTR_RX_RATE]);
        rx_status.signal = nla_get_u32(info->attrs[HWSIM_ATTR_SIGNAL]);
This page took 0.086146 seconds and 5 git commands to generate.