From 44713c41b7857936322397eb8f75d14b6e913d4b Mon Sep 17 00:00:00 2001 From: Wei Ni Date: Tue, 22 Nov 2011 18:17:43 +0800 Subject: mac80211 & nl80211: add support to abort a scan request on tx 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 Signed-off-by: Rhyland Klein Reviewed-on: http://git-master/r/111333 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Bharat Nihalani --- net/mac80211/ieee80211_i.h | 6 ++++++ net/mac80211/scan.c | 50 ++++++++++++++++++++++++++++++++++++---------- net/wireless/nl80211.c | 7 +++++++ 3 files changed, 53 insertions(+), 10 deletions(-) (limited to 'net') diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 9fab144cc9f5..8624f27441f2 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -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 { diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 6f09eca01112..4aa2cec04f31 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -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); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index d7b91a351f84..84400e3a17b6 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -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; -- cgit v1.2.3