diff options
Diffstat (limited to 'net/mac80211/iface.c')
-rw-r--r-- | net/mac80211/iface.c | 258 |
1 files changed, 123 insertions, 135 deletions
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 58c2ab3d483a..fbef7a1ada7a 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -43,6 +43,127 @@ | |||
43 | */ | 43 | */ |
44 | 44 | ||
45 | 45 | ||
46 | static u32 ieee80211_idle_off(struct ieee80211_local *local, | ||
47 | const char *reason) | ||
48 | { | ||
49 | if (!(local->hw.conf.flags & IEEE80211_CONF_IDLE)) | ||
50 | return 0; | ||
51 | |||
52 | local->hw.conf.flags &= ~IEEE80211_CONF_IDLE; | ||
53 | return IEEE80211_CONF_CHANGE_IDLE; | ||
54 | } | ||
55 | |||
56 | static u32 ieee80211_idle_on(struct ieee80211_local *local) | ||
57 | { | ||
58 | if (local->hw.conf.flags & IEEE80211_CONF_IDLE) | ||
59 | return 0; | ||
60 | |||
61 | drv_flush(local, false); | ||
62 | |||
63 | local->hw.conf.flags |= IEEE80211_CONF_IDLE; | ||
64 | return IEEE80211_CONF_CHANGE_IDLE; | ||
65 | } | ||
66 | |||
67 | static u32 __ieee80211_recalc_idle(struct ieee80211_local *local) | ||
68 | { | ||
69 | struct ieee80211_sub_if_data *sdata; | ||
70 | int count = 0; | ||
71 | bool working = false, scanning = false; | ||
72 | unsigned int led_trig_start = 0, led_trig_stop = 0; | ||
73 | struct ieee80211_roc_work *roc; | ||
74 | |||
75 | #ifdef CONFIG_PROVE_LOCKING | ||
76 | WARN_ON(debug_locks && !lockdep_rtnl_is_held() && | ||
77 | !lockdep_is_held(&local->iflist_mtx)); | ||
78 | #endif | ||
79 | lockdep_assert_held(&local->mtx); | ||
80 | |||
81 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
82 | if (!ieee80211_sdata_running(sdata)) { | ||
83 | sdata->vif.bss_conf.idle = true; | ||
84 | continue; | ||
85 | } | ||
86 | |||
87 | sdata->old_idle = sdata->vif.bss_conf.idle; | ||
88 | |||
89 | /* do not count disabled managed interfaces */ | ||
90 | if (sdata->vif.type == NL80211_IFTYPE_STATION && | ||
91 | !sdata->u.mgd.associated && | ||
92 | !sdata->u.mgd.auth_data && | ||
93 | !sdata->u.mgd.assoc_data) { | ||
94 | sdata->vif.bss_conf.idle = true; | ||
95 | continue; | ||
96 | } | ||
97 | /* do not count unused IBSS interfaces */ | ||
98 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC && | ||
99 | !sdata->u.ibss.ssid_len) { | ||
100 | sdata->vif.bss_conf.idle = true; | ||
101 | continue; | ||
102 | } | ||
103 | /* count everything else */ | ||
104 | sdata->vif.bss_conf.idle = false; | ||
105 | count++; | ||
106 | } | ||
107 | |||
108 | if (!local->ops->remain_on_channel) { | ||
109 | list_for_each_entry(roc, &local->roc_list, list) { | ||
110 | working = true; | ||
111 | roc->sdata->vif.bss_conf.idle = false; | ||
112 | } | ||
113 | } | ||
114 | |||
115 | if (local->scan_sdata && | ||
116 | !(local->hw.flags & IEEE80211_HW_SCAN_WHILE_IDLE)) { | ||
117 | scanning = true; | ||
118 | local->scan_sdata->vif.bss_conf.idle = false; | ||
119 | } | ||
120 | |||
121 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
122 | if (sdata->vif.type == NL80211_IFTYPE_MONITOR || | ||
123 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | ||
124 | continue; | ||
125 | if (sdata->old_idle == sdata->vif.bss_conf.idle) | ||
126 | continue; | ||
127 | if (!ieee80211_sdata_running(sdata)) | ||
128 | continue; | ||
129 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE); | ||
130 | } | ||
131 | |||
132 | if (working || scanning) | ||
133 | led_trig_start |= IEEE80211_TPT_LEDTRIG_FL_WORK; | ||
134 | else | ||
135 | led_trig_stop |= IEEE80211_TPT_LEDTRIG_FL_WORK; | ||
136 | |||
137 | if (count) | ||
138 | led_trig_start |= IEEE80211_TPT_LEDTRIG_FL_CONNECTED; | ||
139 | else | ||
140 | led_trig_stop |= IEEE80211_TPT_LEDTRIG_FL_CONNECTED; | ||
141 | |||
142 | ieee80211_mod_tpt_led_trig(local, led_trig_start, led_trig_stop); | ||
143 | |||
144 | if (working) | ||
145 | return ieee80211_idle_off(local, "working"); | ||
146 | if (scanning) | ||
147 | return ieee80211_idle_off(local, "scanning"); | ||
148 | if (!count) | ||
149 | return ieee80211_idle_on(local); | ||
150 | else | ||
151 | return ieee80211_idle_off(local, "in use"); | ||
152 | |||
153 | return 0; | ||
154 | } | ||
155 | |||
156 | void ieee80211_recalc_idle(struct ieee80211_local *local) | ||
157 | { | ||
158 | u32 chg; | ||
159 | |||
160 | mutex_lock(&local->iflist_mtx); | ||
161 | chg = __ieee80211_recalc_idle(local); | ||
162 | mutex_unlock(&local->iflist_mtx); | ||
163 | if (chg) | ||
164 | ieee80211_hw_config(local, chg); | ||
165 | } | ||
166 | |||
46 | static int ieee80211_change_mtu(struct net_device *dev, int new_mtu) | 167 | static int ieee80211_change_mtu(struct net_device *dev, int new_mtu) |
47 | { | 168 | { |
48 | int meshhdrlen; | 169 | int meshhdrlen; |
@@ -209,7 +330,7 @@ static void ieee80211_set_default_queues(struct ieee80211_sub_if_data *sdata) | |||
209 | sdata->vif.cab_queue = IEEE80211_INVAL_HW_QUEUE; | 330 | sdata->vif.cab_queue = IEEE80211_INVAL_HW_QUEUE; |
210 | } | 331 | } |
211 | 332 | ||
212 | static int ieee80211_add_virtual_monitor(struct ieee80211_local *local) | 333 | int ieee80211_add_virtual_monitor(struct ieee80211_local *local) |
213 | { | 334 | { |
214 | struct ieee80211_sub_if_data *sdata; | 335 | struct ieee80211_sub_if_data *sdata; |
215 | int ret; | 336 | int ret; |
@@ -250,7 +371,7 @@ static int ieee80211_add_virtual_monitor(struct ieee80211_local *local) | |||
250 | return 0; | 371 | return 0; |
251 | } | 372 | } |
252 | 373 | ||
253 | static void ieee80211_del_virtual_monitor(struct ieee80211_local *local) | 374 | void ieee80211_del_virtual_monitor(struct ieee80211_local *local) |
254 | { | 375 | { |
255 | struct ieee80211_sub_if_data *sdata; | 376 | struct ieee80211_sub_if_data *sdata; |
256 | 377 | ||
@@ -366,12 +487,6 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up) | |||
366 | break; | 487 | break; |
367 | } | 488 | } |
368 | 489 | ||
369 | if (local->monitors == 0 && local->open_count == 0) { | ||
370 | res = ieee80211_add_virtual_monitor(local); | ||
371 | if (res) | ||
372 | goto err_stop; | ||
373 | } | ||
374 | |||
375 | /* must be before the call to ieee80211_configure_filter */ | 490 | /* must be before the call to ieee80211_configure_filter */ |
376 | local->monitors++; | 491 | local->monitors++; |
377 | if (local->monitors == 1) { | 492 | if (local->monitors == 1) { |
@@ -386,8 +501,6 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up) | |||
386 | break; | 501 | break; |
387 | default: | 502 | default: |
388 | if (coming_up) { | 503 | if (coming_up) { |
389 | ieee80211_del_virtual_monitor(local); | ||
390 | |||
391 | res = drv_add_interface(local, sdata); | 504 | res = drv_add_interface(local, sdata); |
392 | if (res) | 505 | if (res) |
393 | goto err_stop; | 506 | goto err_stop; |
@@ -622,7 +735,6 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
622 | if (local->monitors == 0) { | 735 | if (local->monitors == 0) { |
623 | local->hw.conf.flags &= ~IEEE80211_CONF_MONITOR; | 736 | local->hw.conf.flags &= ~IEEE80211_CONF_MONITOR; |
624 | hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR; | 737 | hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR; |
625 | ieee80211_del_virtual_monitor(local); | ||
626 | } | 738 | } |
627 | 739 | ||
628 | ieee80211_adjust_monitor_flags(sdata, -1); | 740 | ieee80211_adjust_monitor_flags(sdata, -1); |
@@ -696,9 +808,6 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
696 | } | 808 | } |
697 | } | 809 | } |
698 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | 810 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); |
699 | |||
700 | if (local->monitors == local->open_count && local->monitors > 0) | ||
701 | ieee80211_add_virtual_monitor(local); | ||
702 | } | 811 | } |
703 | 812 | ||
704 | static int ieee80211_stop(struct net_device *dev) | 813 | static int ieee80211_stop(struct net_device *dev) |
@@ -1403,127 +1512,6 @@ void ieee80211_remove_interfaces(struct ieee80211_local *local) | |||
1403 | list_del(&unreg_list); | 1512 | list_del(&unreg_list); |
1404 | } | 1513 | } |
1405 | 1514 | ||
1406 | static u32 ieee80211_idle_off(struct ieee80211_local *local, | ||
1407 | const char *reason) | ||
1408 | { | ||
1409 | if (!(local->hw.conf.flags & IEEE80211_CONF_IDLE)) | ||
1410 | return 0; | ||
1411 | |||
1412 | local->hw.conf.flags &= ~IEEE80211_CONF_IDLE; | ||
1413 | return IEEE80211_CONF_CHANGE_IDLE; | ||
1414 | } | ||
1415 | |||
1416 | static u32 ieee80211_idle_on(struct ieee80211_local *local) | ||
1417 | { | ||
1418 | if (local->hw.conf.flags & IEEE80211_CONF_IDLE) | ||
1419 | return 0; | ||
1420 | |||
1421 | drv_flush(local, false); | ||
1422 | |||
1423 | local->hw.conf.flags |= IEEE80211_CONF_IDLE; | ||
1424 | return IEEE80211_CONF_CHANGE_IDLE; | ||
1425 | } | ||
1426 | |||
1427 | u32 __ieee80211_recalc_idle(struct ieee80211_local *local) | ||
1428 | { | ||
1429 | struct ieee80211_sub_if_data *sdata; | ||
1430 | int count = 0; | ||
1431 | bool working = false, scanning = false; | ||
1432 | unsigned int led_trig_start = 0, led_trig_stop = 0; | ||
1433 | struct ieee80211_roc_work *roc; | ||
1434 | |||
1435 | #ifdef CONFIG_PROVE_LOCKING | ||
1436 | WARN_ON(debug_locks && !lockdep_rtnl_is_held() && | ||
1437 | !lockdep_is_held(&local->iflist_mtx)); | ||
1438 | #endif | ||
1439 | lockdep_assert_held(&local->mtx); | ||
1440 | |||
1441 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
1442 | if (!ieee80211_sdata_running(sdata)) { | ||
1443 | sdata->vif.bss_conf.idle = true; | ||
1444 | continue; | ||
1445 | } | ||
1446 | |||
1447 | sdata->old_idle = sdata->vif.bss_conf.idle; | ||
1448 | |||
1449 | /* do not count disabled managed interfaces */ | ||
1450 | if (sdata->vif.type == NL80211_IFTYPE_STATION && | ||
1451 | !sdata->u.mgd.associated && | ||
1452 | !sdata->u.mgd.auth_data && | ||
1453 | !sdata->u.mgd.assoc_data) { | ||
1454 | sdata->vif.bss_conf.idle = true; | ||
1455 | continue; | ||
1456 | } | ||
1457 | /* do not count unused IBSS interfaces */ | ||
1458 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC && | ||
1459 | !sdata->u.ibss.ssid_len) { | ||
1460 | sdata->vif.bss_conf.idle = true; | ||
1461 | continue; | ||
1462 | } | ||
1463 | /* count everything else */ | ||
1464 | sdata->vif.bss_conf.idle = false; | ||
1465 | count++; | ||
1466 | } | ||
1467 | |||
1468 | if (!local->ops->remain_on_channel) { | ||
1469 | list_for_each_entry(roc, &local->roc_list, list) { | ||
1470 | working = true; | ||
1471 | roc->sdata->vif.bss_conf.idle = false; | ||
1472 | } | ||
1473 | } | ||
1474 | |||
1475 | if (local->scan_sdata && | ||
1476 | !(local->hw.flags & IEEE80211_HW_SCAN_WHILE_IDLE)) { | ||
1477 | scanning = true; | ||
1478 | local->scan_sdata->vif.bss_conf.idle = false; | ||
1479 | } | ||
1480 | |||
1481 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
1482 | if (sdata->vif.type == NL80211_IFTYPE_MONITOR || | ||
1483 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | ||
1484 | continue; | ||
1485 | if (sdata->old_idle == sdata->vif.bss_conf.idle) | ||
1486 | continue; | ||
1487 | if (!ieee80211_sdata_running(sdata)) | ||
1488 | continue; | ||
1489 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE); | ||
1490 | } | ||
1491 | |||
1492 | if (working || scanning) | ||
1493 | led_trig_start |= IEEE80211_TPT_LEDTRIG_FL_WORK; | ||
1494 | else | ||
1495 | led_trig_stop |= IEEE80211_TPT_LEDTRIG_FL_WORK; | ||
1496 | |||
1497 | if (count) | ||
1498 | led_trig_start |= IEEE80211_TPT_LEDTRIG_FL_CONNECTED; | ||
1499 | else | ||
1500 | led_trig_stop |= IEEE80211_TPT_LEDTRIG_FL_CONNECTED; | ||
1501 | |||
1502 | ieee80211_mod_tpt_led_trig(local, led_trig_start, led_trig_stop); | ||
1503 | |||
1504 | if (working) | ||
1505 | return ieee80211_idle_off(local, "working"); | ||
1506 | if (scanning) | ||
1507 | return ieee80211_idle_off(local, "scanning"); | ||
1508 | if (!count) | ||
1509 | return ieee80211_idle_on(local); | ||
1510 | else | ||
1511 | return ieee80211_idle_off(local, "in use"); | ||
1512 | |||
1513 | return 0; | ||
1514 | } | ||
1515 | |||
1516 | void ieee80211_recalc_idle(struct ieee80211_local *local) | ||
1517 | { | ||
1518 | u32 chg; | ||
1519 | |||
1520 | mutex_lock(&local->iflist_mtx); | ||
1521 | chg = __ieee80211_recalc_idle(local); | ||
1522 | mutex_unlock(&local->iflist_mtx); | ||
1523 | if (chg) | ||
1524 | ieee80211_hw_config(local, chg); | ||
1525 | } | ||
1526 | |||
1527 | static int netdev_notify(struct notifier_block *nb, | 1515 | static int netdev_notify(struct notifier_block *nb, |
1528 | unsigned long state, | 1516 | unsigned long state, |
1529 | void *ndev) | 1517 | void *ndev) |