diff options
| author | Johannes Berg <johannes.berg@intel.com> | 2010-08-05 11:02:38 -0400 |
|---|---|---|
| committer | John W. Linville <linville@tuxdriver.com> | 2010-08-16 15:26:40 -0400 |
| commit | 7da7cc1d42d8ce02cca16df8c021e6d657f1f8fd (patch) | |
| tree | 3d18e0b36edfcc015d27f66890cf4a8d60c45bda | |
| parent | 1fdaa46e9f26ccbab5e0eb8c4d4f8e1fbf32c7df (diff) | |
mac80211: per interface idle notification
Sometimes we don't just need to know whether or
not the device is idle, but also per interface.
This adds that reporting capability to mac80211.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
| -rw-r--r-- | include/net/mac80211.h | 6 | ||||
| -rw-r--r-- | net/mac80211/ibss.c | 8 | ||||
| -rw-r--r-- | net/mac80211/ieee80211_i.h | 3 | ||||
| -rw-r--r-- | net/mac80211/iface.c | 53 | ||||
| -rw-r--r-- | net/mac80211/mlme.c | 17 | ||||
| -rw-r--r-- | net/mac80211/scan.c | 2 | ||||
| -rw-r--r-- | net/mac80211/work.c | 8 |
7 files changed, 81 insertions, 16 deletions
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 3f1e03b521ec..3a3c26f647b7 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
| @@ -149,6 +149,7 @@ struct ieee80211_low_level_stats { | |||
| 149 | * @BSS_CHANGED_ARP_FILTER: Hardware ARP filter address list or state changed. | 149 | * @BSS_CHANGED_ARP_FILTER: Hardware ARP filter address list or state changed. |
| 150 | * @BSS_CHANGED_QOS: QoS for this association was enabled/disabled. Note | 150 | * @BSS_CHANGED_QOS: QoS for this association was enabled/disabled. Note |
| 151 | * that it is only ever disabled for station mode. | 151 | * that it is only ever disabled for station mode. |
| 152 | * @BSS_CHANGED_IDLE: Idle changed for this BSS/interface. | ||
| 152 | */ | 153 | */ |
| 153 | enum ieee80211_bss_change { | 154 | enum ieee80211_bss_change { |
| 154 | BSS_CHANGED_ASSOC = 1<<0, | 155 | BSS_CHANGED_ASSOC = 1<<0, |
| @@ -165,6 +166,7 @@ enum ieee80211_bss_change { | |||
| 165 | BSS_CHANGED_IBSS = 1<<11, | 166 | BSS_CHANGED_IBSS = 1<<11, |
| 166 | BSS_CHANGED_ARP_FILTER = 1<<12, | 167 | BSS_CHANGED_ARP_FILTER = 1<<12, |
| 167 | BSS_CHANGED_QOS = 1<<13, | 168 | BSS_CHANGED_QOS = 1<<13, |
| 169 | BSS_CHANGED_IDLE = 1<<14, | ||
| 168 | 170 | ||
| 169 | /* when adding here, make sure to change ieee80211_reconfig */ | 171 | /* when adding here, make sure to change ieee80211_reconfig */ |
| 170 | }; | 172 | }; |
| @@ -223,6 +225,9 @@ enum ieee80211_bss_change { | |||
| 223 | * hardware must not perform any ARP filtering. Note, that the filter will | 225 | * hardware must not perform any ARP filtering. Note, that the filter will |
| 224 | * be enabled also in promiscuous mode. | 226 | * be enabled also in promiscuous mode. |
| 225 | * @qos: This is a QoS-enabled BSS. | 227 | * @qos: This is a QoS-enabled BSS. |
| 228 | * @idle: This interface is idle. There's also a global idle flag in the | ||
| 229 | * hardware config which may be more appropriate depending on what | ||
| 230 | * your driver/device needs to do. | ||
| 226 | */ | 231 | */ |
| 227 | struct ieee80211_bss_conf { | 232 | struct ieee80211_bss_conf { |
| 228 | const u8 *bssid; | 233 | const u8 *bssid; |
| @@ -247,6 +252,7 @@ struct ieee80211_bss_conf { | |||
| 247 | u8 arp_addr_cnt; | 252 | u8 arp_addr_cnt; |
| 248 | bool arp_filter_enabled; | 253 | bool arp_filter_enabled; |
| 249 | bool qos; | 254 | bool qos; |
| 255 | bool idle; | ||
| 250 | }; | 256 | }; |
| 251 | 257 | ||
| 252 | /** | 258 | /** |
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index c691780725a7..32af97108425 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c | |||
| @@ -920,12 +920,14 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, | |||
| 920 | memcpy(sdata->u.ibss.ssid, params->ssid, IEEE80211_MAX_SSID_LEN); | 920 | memcpy(sdata->u.ibss.ssid, params->ssid, IEEE80211_MAX_SSID_LEN); |
| 921 | sdata->u.ibss.ssid_len = params->ssid_len; | 921 | sdata->u.ibss.ssid_len = params->ssid_len; |
| 922 | 922 | ||
| 923 | mutex_unlock(&sdata->u.ibss.mtx); | ||
| 924 | |||
| 925 | mutex_lock(&sdata->local->mtx); | ||
| 923 | ieee80211_recalc_idle(sdata->local); | 926 | ieee80211_recalc_idle(sdata->local); |
| 927 | mutex_unlock(&sdata->local->mtx); | ||
| 924 | 928 | ||
| 925 | ieee80211_queue_work(&sdata->local->hw, &sdata->work); | 929 | ieee80211_queue_work(&sdata->local->hw, &sdata->work); |
| 926 | 930 | ||
| 927 | mutex_unlock(&sdata->u.ibss.mtx); | ||
| 928 | |||
| 929 | return 0; | 931 | return 0; |
| 930 | } | 932 | } |
| 931 | 933 | ||
| @@ -980,7 +982,9 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata) | |||
| 980 | 982 | ||
| 981 | mutex_unlock(&sdata->u.ibss.mtx); | 983 | mutex_unlock(&sdata->u.ibss.mtx); |
| 982 | 984 | ||
| 985 | mutex_lock(&local->mtx); | ||
| 983 | ieee80211_recalc_idle(sdata->local); | 986 | ieee80211_recalc_idle(sdata->local); |
| 987 | mutex_unlock(&local->mtx); | ||
| 984 | 988 | ||
| 985 | return 0; | 989 | return 0; |
| 986 | } | 990 | } |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index b44e03a02da9..98e783c6a363 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
| @@ -497,6 +497,9 @@ struct ieee80211_sub_if_data { | |||
| 497 | */ | 497 | */ |
| 498 | bool ht_opmode_valid; | 498 | bool ht_opmode_valid; |
| 499 | 499 | ||
| 500 | /* to detect idle changes */ | ||
| 501 | bool old_idle; | ||
| 502 | |||
| 500 | /* Fragment table for host-based reassembly */ | 503 | /* Fragment table for host-based reassembly */ |
| 501 | struct ieee80211_fragment_entry fragments[IEEE80211_FRAGMENT_MAX]; | 504 | struct ieee80211_fragment_entry fragments[IEEE80211_FRAGMENT_MAX]; |
| 502 | unsigned int fragment_next; | 505 | unsigned int fragment_next; |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index c1008a9d7bfb..9459aeee0ddc 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
| @@ -309,7 +309,9 @@ static int ieee80211_open(struct net_device *dev) | |||
| 309 | if (sdata->flags & IEEE80211_SDATA_PROMISC) | 309 | if (sdata->flags & IEEE80211_SDATA_PROMISC) |
| 310 | atomic_inc(&local->iff_promiscs); | 310 | atomic_inc(&local->iff_promiscs); |
| 311 | 311 | ||
| 312 | mutex_lock(&local->mtx); | ||
| 312 | hw_reconf_flags |= __ieee80211_recalc_idle(local); | 313 | hw_reconf_flags |= __ieee80211_recalc_idle(local); |
| 314 | mutex_unlock(&local->mtx); | ||
| 313 | 315 | ||
| 314 | local->open_count++; | 316 | local->open_count++; |
| 315 | if (hw_reconf_flags) { | 317 | if (hw_reconf_flags) { |
| @@ -516,7 +518,9 @@ static int ieee80211_stop(struct net_device *dev) | |||
| 516 | 518 | ||
| 517 | sdata->bss = NULL; | 519 | sdata->bss = NULL; |
| 518 | 520 | ||
| 521 | mutex_lock(&local->mtx); | ||
| 519 | hw_reconf_flags |= __ieee80211_recalc_idle(local); | 522 | hw_reconf_flags |= __ieee80211_recalc_idle(local); |
| 523 | mutex_unlock(&local->mtx); | ||
| 520 | 524 | ||
| 521 | ieee80211_recalc_ps(local, -1); | 525 | ieee80211_recalc_ps(local, -1); |
| 522 | 526 | ||
| @@ -1199,28 +1203,61 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local) | |||
| 1199 | { | 1203 | { |
| 1200 | struct ieee80211_sub_if_data *sdata; | 1204 | struct ieee80211_sub_if_data *sdata; |
| 1201 | int count = 0; | 1205 | int count = 0; |
| 1206 | bool working = false, scanning = false; | ||
| 1207 | struct ieee80211_work *wk; | ||
| 1202 | 1208 | ||
| 1203 | if (!list_empty(&local->work_list)) | 1209 | #ifdef CONFIG_PROVE_LOCKING |
| 1204 | return ieee80211_idle_off(local, "working"); | 1210 | WARN_ON(debug_locks && !lockdep_rtnl_is_held() && |
| 1205 | 1211 | !lockdep_is_held(&local->iflist_mtx)); | |
| 1206 | if (local->scanning) | 1212 | #endif |
| 1207 | return ieee80211_idle_off(local, "scanning"); | 1213 | lockdep_assert_held(&local->mtx); |
| 1208 | 1214 | ||
| 1209 | list_for_each_entry(sdata, &local->interfaces, list) { | 1215 | list_for_each_entry(sdata, &local->interfaces, list) { |
| 1210 | if (!ieee80211_sdata_running(sdata)) | 1216 | if (!ieee80211_sdata_running(sdata)) { |
| 1217 | sdata->vif.bss_conf.idle = true; | ||
| 1211 | continue; | 1218 | continue; |
| 1219 | } | ||
| 1220 | |||
| 1221 | sdata->old_idle = sdata->vif.bss_conf.idle; | ||
| 1222 | |||
| 1212 | /* do not count disabled managed interfaces */ | 1223 | /* do not count disabled managed interfaces */ |
| 1213 | if (sdata->vif.type == NL80211_IFTYPE_STATION && | 1224 | if (sdata->vif.type == NL80211_IFTYPE_STATION && |
| 1214 | !sdata->u.mgd.associated) | 1225 | !sdata->u.mgd.associated) { |
| 1226 | sdata->vif.bss_conf.idle = true; | ||
| 1215 | continue; | 1227 | continue; |
| 1228 | } | ||
| 1216 | /* do not count unused IBSS interfaces */ | 1229 | /* do not count unused IBSS interfaces */ |
| 1217 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC && | 1230 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC && |
| 1218 | !sdata->u.ibss.ssid_len) | 1231 | !sdata->u.ibss.ssid_len) { |
| 1232 | sdata->vif.bss_conf.idle = true; | ||
| 1219 | continue; | 1233 | continue; |
| 1234 | } | ||
| 1220 | /* count everything else */ | 1235 | /* count everything else */ |
| 1221 | count++; | 1236 | count++; |
| 1222 | } | 1237 | } |
| 1223 | 1238 | ||
| 1239 | list_for_each_entry(wk, &local->work_list, list) { | ||
| 1240 | working = true; | ||
| 1241 | wk->sdata->vif.bss_conf.idle = false; | ||
| 1242 | } | ||
| 1243 | |||
| 1244 | if (local->scan_sdata) { | ||
| 1245 | scanning = true; | ||
| 1246 | local->scan_sdata->vif.bss_conf.idle = false; | ||
| 1247 | } | ||
| 1248 | |||
| 1249 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
| 1250 | if (sdata->old_idle == sdata->vif.bss_conf.idle) | ||
| 1251 | continue; | ||
| 1252 | if (!ieee80211_sdata_running(sdata)) | ||
| 1253 | continue; | ||
| 1254 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE); | ||
| 1255 | } | ||
| 1256 | |||
| 1257 | if (working) | ||
| 1258 | return ieee80211_idle_off(local, "working"); | ||
| 1259 | if (scanning) | ||
| 1260 | return ieee80211_idle_off(local, "scanning"); | ||
| 1224 | if (!count) | 1261 | if (!count) |
| 1225 | return ieee80211_idle_on(local); | 1262 | return ieee80211_idle_on(local); |
| 1226 | else | 1263 | else |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 17e9257a61d8..82e7cec5179c 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
| @@ -1103,8 +1103,11 @@ static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata) | |||
| 1103 | printk(KERN_DEBUG "Connection to AP %pM lost.\n", bssid); | 1103 | printk(KERN_DEBUG "Connection to AP %pM lost.\n", bssid); |
| 1104 | 1104 | ||
| 1105 | ieee80211_set_disassoc(sdata, true); | 1105 | ieee80211_set_disassoc(sdata, true); |
| 1106 | ieee80211_recalc_idle(local); | ||
| 1107 | mutex_unlock(&ifmgd->mtx); | 1106 | mutex_unlock(&ifmgd->mtx); |
| 1107 | |||
| 1108 | mutex_lock(&local->mtx); | ||
| 1109 | ieee80211_recalc_idle(local); | ||
| 1110 | mutex_unlock(&local->mtx); | ||
| 1108 | /* | 1111 | /* |
| 1109 | * must be outside lock due to cfg80211, | 1112 | * must be outside lock due to cfg80211, |
| 1110 | * but that's not a problem. | 1113 | * but that's not a problem. |
| @@ -1173,7 +1176,9 @@ ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, | |||
| 1173 | sdata->name, bssid, reason_code); | 1176 | sdata->name, bssid, reason_code); |
| 1174 | 1177 | ||
| 1175 | ieee80211_set_disassoc(sdata, true); | 1178 | ieee80211_set_disassoc(sdata, true); |
| 1179 | mutex_lock(&sdata->local->mtx); | ||
| 1176 | ieee80211_recalc_idle(sdata->local); | 1180 | ieee80211_recalc_idle(sdata->local); |
| 1181 | mutex_unlock(&sdata->local->mtx); | ||
| 1177 | 1182 | ||
| 1178 | return RX_MGMT_CFG80211_DEAUTH; | 1183 | return RX_MGMT_CFG80211_DEAUTH; |
| 1179 | } | 1184 | } |
| @@ -1203,7 +1208,9 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, | |||
| 1203 | sdata->name, mgmt->sa, reason_code); | 1208 | sdata->name, mgmt->sa, reason_code); |
| 1204 | 1209 | ||
| 1205 | ieee80211_set_disassoc(sdata, true); | 1210 | ieee80211_set_disassoc(sdata, true); |
| 1211 | mutex_lock(&sdata->local->mtx); | ||
| 1206 | ieee80211_recalc_idle(sdata->local); | 1212 | ieee80211_recalc_idle(sdata->local); |
| 1213 | mutex_unlock(&sdata->local->mtx); | ||
| 1207 | return RX_MGMT_CFG80211_DISASSOC; | 1214 | return RX_MGMT_CFG80211_DISASSOC; |
| 1208 | } | 1215 | } |
| 1209 | 1216 | ||
| @@ -1840,8 +1847,10 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) | |||
| 1840 | " after %dms, disconnecting.\n", | 1847 | " after %dms, disconnecting.\n", |
| 1841 | bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ); | 1848 | bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ); |
| 1842 | ieee80211_set_disassoc(sdata, true); | 1849 | ieee80211_set_disassoc(sdata, true); |
| 1843 | ieee80211_recalc_idle(local); | ||
| 1844 | mutex_unlock(&ifmgd->mtx); | 1850 | mutex_unlock(&ifmgd->mtx); |
| 1851 | mutex_lock(&local->mtx); | ||
| 1852 | ieee80211_recalc_idle(local); | ||
| 1853 | mutex_unlock(&local->mtx); | ||
| 1845 | /* | 1854 | /* |
| 1846 | * must be outside lock due to cfg80211, | 1855 | * must be outside lock due to cfg80211, |
| 1847 | * but that's not a problem. | 1856 | * but that's not a problem. |
| @@ -2319,7 +2328,9 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, | |||
| 2319 | if (assoc_bss) | 2328 | if (assoc_bss) |
| 2320 | sta_info_destroy_addr(sdata, bssid); | 2329 | sta_info_destroy_addr(sdata, bssid); |
| 2321 | 2330 | ||
| 2331 | mutex_lock(&sdata->local->mtx); | ||
| 2322 | ieee80211_recalc_idle(sdata->local); | 2332 | ieee80211_recalc_idle(sdata->local); |
| 2333 | mutex_unlock(&sdata->local->mtx); | ||
| 2323 | 2334 | ||
| 2324 | return 0; | 2335 | return 0; |
| 2325 | } | 2336 | } |
| @@ -2357,7 +2368,9 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, | |||
| 2357 | cookie, !req->local_state_change); | 2368 | cookie, !req->local_state_change); |
| 2358 | sta_info_destroy_addr(sdata, bssid); | 2369 | sta_info_destroy_addr(sdata, bssid); |
| 2359 | 2370 | ||
| 2371 | mutex_lock(&sdata->local->mtx); | ||
| 2360 | ieee80211_recalc_idle(sdata->local); | 2372 | ieee80211_recalc_idle(sdata->local); |
| 2373 | mutex_unlock(&sdata->local->mtx); | ||
| 2361 | 2374 | ||
| 2362 | return 0; | 2375 | return 0; |
| 2363 | } | 2376 | } |
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index f31f549733b1..31f233f7f51a 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
| @@ -304,7 +304,9 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) | |||
| 304 | ieee80211_offchannel_return(local, true); | 304 | ieee80211_offchannel_return(local, true); |
| 305 | 305 | ||
| 306 | done: | 306 | done: |
| 307 | mutex_lock(&local->mtx); | ||
| 307 | ieee80211_recalc_idle(local); | 308 | ieee80211_recalc_idle(local); |
| 309 | mutex_unlock(&local->mtx); | ||
| 308 | ieee80211_mlme_notify_scan_completed(local); | 310 | ieee80211_mlme_notify_scan_completed(local); |
| 309 | ieee80211_ibss_notify_scan_completed(local); | 311 | ieee80211_ibss_notify_scan_completed(local); |
| 310 | ieee80211_mesh_notify_scan_completed(local); | 312 | ieee80211_mesh_notify_scan_completed(local); |
diff --git a/net/mac80211/work.c b/net/mac80211/work.c index b98af64f5862..ae344d1ba056 100644 --- a/net/mac80211/work.c +++ b/net/mac80211/work.c | |||
| @@ -888,10 +888,10 @@ static void ieee80211_work_work(struct work_struct *work) | |||
| 888 | while ((skb = skb_dequeue(&local->work_skb_queue))) | 888 | while ((skb = skb_dequeue(&local->work_skb_queue))) |
| 889 | ieee80211_work_rx_queued_mgmt(local, skb); | 889 | ieee80211_work_rx_queued_mgmt(local, skb); |
| 890 | 890 | ||
| 891 | ieee80211_recalc_idle(local); | ||
| 892 | |||
| 893 | mutex_lock(&local->mtx); | 891 | mutex_lock(&local->mtx); |
| 894 | 892 | ||
| 893 | ieee80211_recalc_idle(local); | ||
| 894 | |||
| 895 | list_for_each_entry_safe(wk, tmp, &local->work_list, list) { | 895 | list_for_each_entry_safe(wk, tmp, &local->work_list, list) { |
| 896 | bool started = wk->started; | 896 | bool started = wk->started; |
| 897 | 897 | ||
| @@ -1001,10 +1001,10 @@ static void ieee80211_work_work(struct work_struct *work) | |||
| 1001 | &local->scan_work, | 1001 | &local->scan_work, |
| 1002 | round_jiffies_relative(0)); | 1002 | round_jiffies_relative(0)); |
| 1003 | 1003 | ||
| 1004 | mutex_unlock(&local->mtx); | ||
| 1005 | |||
| 1006 | ieee80211_recalc_idle(local); | 1004 | ieee80211_recalc_idle(local); |
| 1007 | 1005 | ||
| 1006 | mutex_unlock(&local->mtx); | ||
| 1007 | |||
| 1008 | list_for_each_entry_safe(wk, tmp, &free_work, list) { | 1008 | list_for_each_entry_safe(wk, tmp, &free_work, list) { |
| 1009 | wk->done(wk, NULL); | 1009 | wk->done(wk, NULL); |
| 1010 | list_del(&wk->list); | 1010 | list_del(&wk->list); |
