mac80211 & nl80211: add support to abort a scan request on tx
Wei Ni [Tue, 22 Nov 2011 10:17:43 +0000 (18:17 +0800)]
This fix comes from:
https://gerrit.chromium.org/gerrit/#change,5744
https://gerrit.chromium.org/gerrit/#change,5745

So that it can work with the related wpa_supplicant tool.

BUG=895591

Change-Id: Ie81f6d6052bd45dab13c936f9f0c5f4eb277496a
Original-Signed-off-by: Wei Ni <wni@nvidia.com>
Signed-off-by: Rhyland Klein <rklein@nvidia.com>
Reviewed-on: http://git-master/r/111333
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com>

include/linux/nl80211.h
include/net/cfg80211.h
net/mac80211/ieee80211_i.h
net/mac80211/scan.c
net/wireless/nl80211.c

index 8ad70dc..bec6bca 100644 (file)
@@ -967,6 +967,8 @@ enum nl80211_commands {
  * @NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX: Bitmap of antennas which are available
  *     for configuration as RX antennas via the above parameters.
  *
+ * @NL80211_ATTR_SCAN_FLAGS: scan request control flags (u32)
+ *
  * @NL80211_ATTR_MCAST_RATE: Multicast tx rate (in 100 kbps) for IBSS
  *
  * @NL80211_ATTR_OFFCHANNEL_TX_OK: For management frame TX, the frame may be
@@ -1206,6 +1208,8 @@ enum nl80211_attrs {
        NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX,
        NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX,
 
+       NL80211_ATTR_SCAN_FLAGS,
+
        NL80211_ATTR_SUPPORT_MESH_AUTH,
        NL80211_ATTR_STA_PLINK_STATE,
 
@@ -2207,6 +2211,18 @@ enum nl80211_tx_power_setting {
 };
 
 /**
+ * enum nl80211_scan_flags -  scan request control flags
+ *
+ * Scan request control flags are used to control the handling
+ * of NL80211_CMD_TRIGGER_SCAN, requests.
+ *
+ * @NL80211_SCAN_FLAG_TX_ABORT: abort scan if tx collides
+ */
+enum nl80211_scan_flags {
+       NL80211_SCAN_FLAG_TX_ABORT      = 1<<0,
+};
+
+/**
  * enum nl80211_wowlan_packet_pattern_attr - WoWLAN packet pattern attribute
  * @__NL80211_WOWLAN_PKTPAT_INVALID: invalid number for nested attribute
  * @NL80211_WOWLAN_PKTPAT_PATTERN: the pattern, values where the mask has
index dc4ae12..251a2f9 100644 (file)
@@ -784,6 +784,15 @@ struct cfg80211_ssid {
 };
 
 /**
+ * enum cfg80211_scan_flag -  scan request control flags
+ *
+ * @CFG80211_SCAN__FLAG_TX_ABORT: abort scan on pending transmit
+ */
+enum cfg80211_scan_flags {
+       CFG80211_SCAN_FLAG_TX_ABORT     = NL80211_SCAN_FLAG_TX_ABORT,
+};
+
+/**
  * struct cfg80211_scan_request - scan request description
  *
  * @ssids: SSIDs to scan for (active scan only)
@@ -792,6 +801,7 @@ struct cfg80211_ssid {
  * @n_channels: total number of channels to scan
  * @ie: optional information element(s) to add into Probe Request or %NULL
  * @ie_len: length of ie in octets
+ * @flags: bit field of flags controlling operation
  * @rates: bitmap of rates to advertise for each band
  * @wiphy: the wiphy this was for
  * @dev: the interface
@@ -803,6 +813,7 @@ struct cfg80211_scan_request {
        u32 n_channels;
        const u8 *ie;
        size_t ie_len;
+       u32 flags;
 
        u32 rates[IEEE80211_NUM_BANDS];
 
index 9fab144..8624f27 100644 (file)
@@ -718,6 +718,10 @@ enum {
  *     about us leaving the channel and stop all associated STA interfaces
  * @SCAN_ENTER_OPER_CHANNEL: Enter the operating channel again, notify the
  *     AP about us being back and restart all associated STA interfaces
+ * @SCAN_ABORT: Abnormally terminate the scan operation, set only when
+ *     on the operating channel
+ * @SCAN_ENTER_OPER_CHANNEL_ABORT: Return to the operating channel then
+ *     terminate the scan operation
  */
 enum mac80211_scan_state {
        SCAN_DECISION,
@@ -725,6 +729,8 @@ enum mac80211_scan_state {
        SCAN_SEND_PROBE,
        SCAN_LEAVE_OPER_CHANNEL,
        SCAN_ENTER_OPER_CHANNEL,
+       SCAN_ABORT,
+       SCAN_ENTER_OPER_CHANNEL_ABORT,
 };
 
 struct ieee80211_local {
index 6f09eca..4aa2cec 100644 (file)
@@ -477,6 +477,7 @@ static void ieee80211_scan_state_decision(struct ieee80211_local *local,
        unsigned long min_beacon_int = 0;
        struct ieee80211_sub_if_data *sdata;
        struct ieee80211_channel *next_chan;
+       enum mac80211_scan_state next_scan_state;
 
        /*
         * check if at least one STA interface is associated,
@@ -512,13 +513,21 @@ static void ieee80211_scan_state_decision(struct ieee80211_local *local,
                /* We're currently on operating channel. */
                if (next_chan == local->oper_channel)
                        /* We don't need to move off of operating channel. */
-                       local->next_scan_state = SCAN_SET_CHANNEL;
-               else
+                       next_scan_state = SCAN_SET_CHANNEL;
+               else {
                        /*
                         * We do need to leave operating channel, as next
-                        * scan is somewhere else.
+                        * scan is somewhere else, unless
+                        * there is pending traffic and the scan request is
+                        * marked to abort when this happens
                         */
-                       local->next_scan_state = SCAN_LEAVE_OPER_CHANNEL;
+                       if (associated && !tx_empty &&
+                           (local->scan_req->flags &
+                               CFG80211_SCAN_FLAG_TX_ABORT))
+                               next_scan_state = SCAN_ABORT;
+                       else
+                               next_scan_state = SCAN_LEAVE_OPER_CHANNEL;
+               }
        } else {
                /*
                 * we're currently scanning a different channel, let's
@@ -547,12 +556,24 @@ static void ieee80211_scan_state_decision(struct ieee80211_local *local,
                                usecs_to_jiffies(min_beacon_int * 1024) *
                                local->hw.conf.listen_interval);
 
-               if (associated && ( !tx_empty || bad_latency ||
-                   listen_int_exceeded))
-                       local->next_scan_state = SCAN_ENTER_OPER_CHANNEL;
+               if (associated && !tx_empty) {
+                       if (unlikely(local->scan_req->flags &
+                               CFG80211_SCAN_FLAG_TX_ABORT)) {
+                               /*
+                                * Scan request is marked to abort when there
+                                * is outbound traffic.  Mark state to return
+                                * the operating channel and then abort.  This
+                                * happens as soon as possible.
+                                */
+                               next_scan_state = SCAN_ENTER_OPER_CHANNEL_ABORT;
+                       } else
+                               next_scan_state = SCAN_ENTER_OPER_CHANNEL;
+               } else if (associated && (bad_latency || listen_int_exceeded))
+                       next_scan_state = SCAN_ENTER_OPER_CHANNEL;
                else
-                       local->next_scan_state = SCAN_SET_CHANNEL;
+                       next_scan_state = SCAN_SET_CHANNEL;
        }
+       local->next_scan_state = next_scan_state;
 
        *next_delay = 0;
 }
@@ -596,8 +617,13 @@ static void ieee80211_scan_state_enter_oper_channel(struct ieee80211_local *loca
         */
        ieee80211_offchannel_return(local, true, false);
 
-       *next_delay = HZ / 5;
-       local->next_scan_state = SCAN_DECISION;
+       if (local->next_scan_state == SCAN_ENTER_OPER_CHANNEL) {
+               *next_delay = HZ / 5;
+               local->next_scan_state = SCAN_DECISION;
+       } else {
+               *next_delay = 0;
+               local->next_scan_state = SCAN_ABORT;
+       }
 }
 
 static void ieee80211_scan_state_set_channel(struct ieee80211_local *local,
@@ -741,11 +767,15 @@ void ieee80211_scan_work(struct work_struct *work)
                        ieee80211_scan_state_send_probe(local, &next_delay);
                        break;
                case SCAN_LEAVE_OPER_CHANNEL:
+               case SCAN_ENTER_OPER_CHANNEL_ABORT:
                        ieee80211_scan_state_leave_oper_channel(local, &next_delay);
                        break;
                case SCAN_ENTER_OPER_CHANNEL:
                        ieee80211_scan_state_enter_oper_channel(local, &next_delay);
                        break;
+               case SCAN_ABORT:
+                       aborted = true;
+                       goto out_complete;
                }
        } while (next_delay == 0);
 
index d7b91a3..84400e3 100644 (file)
@@ -131,6 +131,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
        [NL80211_ATTR_MGMT_SUBTYPE] = { .type = NLA_U8 },
        [NL80211_ATTR_IE] = { .type = NLA_BINARY,
                              .len = IEEE80211_MAX_DATA_LEN },
+       [NL80211_ATTR_SCAN_FLAGS] = { .type = NLA_U32 },
        [NL80211_ATTR_SCAN_FREQUENCIES] = { .type = NLA_NESTED },
        [NL80211_ATTR_SCAN_SSIDS] = { .type = NLA_NESTED },
 
@@ -3457,6 +3458,10 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
                       request->ie_len);
        }
 
+       if (info->attrs[NL80211_ATTR_SCAN_FLAGS])
+               request->flags = nla_get_u32(
+                       info->attrs[NL80211_ATTR_SCAN_FLAGS]);
+
        for (i = 0; i < IEEE80211_NUM_BANDS; i++)
                if (wiphy->bands[i])
                        request->rates[i] =
@@ -6158,6 +6163,8 @@ static int nl80211_add_scan_req(struct sk_buff *msg,
        if (req->ie)
                NLA_PUT(msg, NL80211_ATTR_IE, req->ie_len, req->ie);
 
+       NLA_PUT_U8(msg, NL80211_ATTR_SCAN_FLAGS, req->flags);
+
        return 0;
  nla_put_failure:
        return -ENOBUFS;