diff options
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r-- | net/mac80211/mlme.c | 106 |
1 files changed, 79 insertions, 27 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index b6c163ac22da..8b733cf6f3ea 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -54,6 +54,12 @@ | |||
54 | */ | 54 | */ |
55 | #define IEEE80211_SIGNAL_AVE_WEIGHT 3 | 55 | #define IEEE80211_SIGNAL_AVE_WEIGHT 3 |
56 | 56 | ||
57 | /* | ||
58 | * How many Beacon frames need to have been used in average signal strength | ||
59 | * before starting to indicate signal change events. | ||
60 | */ | ||
61 | #define IEEE80211_SIGNAL_AVE_MIN_COUNT 4 | ||
62 | |||
57 | #define TMR_RUNNING_TIMER 0 | 63 | #define TMR_RUNNING_TIMER 0 |
58 | #define TMR_RUNNING_CHANSW 1 | 64 | #define TMR_RUNNING_CHANSW 1 |
59 | 65 | ||
@@ -86,7 +92,7 @@ enum rx_mgmt_action { | |||
86 | /* utils */ | 92 | /* utils */ |
87 | static inline void ASSERT_MGD_MTX(struct ieee80211_if_managed *ifmgd) | 93 | static inline void ASSERT_MGD_MTX(struct ieee80211_if_managed *ifmgd) |
88 | { | 94 | { |
89 | WARN_ON(!mutex_is_locked(&ifmgd->mtx)); | 95 | lockdep_assert_held(&ifmgd->mtx); |
90 | } | 96 | } |
91 | 97 | ||
92 | /* | 98 | /* |
@@ -109,7 +115,7 @@ static void run_again(struct ieee80211_if_managed *ifmgd, | |||
109 | mod_timer(&ifmgd->timer, timeout); | 115 | mod_timer(&ifmgd->timer, timeout); |
110 | } | 116 | } |
111 | 117 | ||
112 | static void mod_beacon_timer(struct ieee80211_sub_if_data *sdata) | 118 | void ieee80211_sta_reset_beacon_monitor(struct ieee80211_sub_if_data *sdata) |
113 | { | 119 | { |
114 | if (sdata->local->hw.flags & IEEE80211_HW_BEACON_FILTER) | 120 | if (sdata->local->hw.flags & IEEE80211_HW_BEACON_FILTER) |
115 | return; | 121 | return; |
@@ -118,6 +124,19 @@ static void mod_beacon_timer(struct ieee80211_sub_if_data *sdata) | |||
118 | round_jiffies_up(jiffies + IEEE80211_BEACON_LOSS_TIME)); | 124 | round_jiffies_up(jiffies + IEEE80211_BEACON_LOSS_TIME)); |
119 | } | 125 | } |
120 | 126 | ||
127 | void ieee80211_sta_reset_conn_monitor(struct ieee80211_sub_if_data *sdata) | ||
128 | { | ||
129 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
130 | |||
131 | if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) | ||
132 | return; | ||
133 | |||
134 | mod_timer(&sdata->u.mgd.conn_mon_timer, | ||
135 | round_jiffies_up(jiffies + IEEE80211_CONNECTION_IDLE_TIME)); | ||
136 | |||
137 | ifmgd->probe_send_count = 0; | ||
138 | } | ||
139 | |||
121 | static int ecw2cw(int ecw) | 140 | static int ecw2cw(int ecw) |
122 | { | 141 | { |
123 | return (1 << ecw) - 1; | 142 | return (1 << ecw) - 1; |
@@ -778,16 +797,17 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, | |||
778 | params.uapsd = uapsd; | 797 | params.uapsd = uapsd; |
779 | 798 | ||
780 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 799 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
781 | printk(KERN_DEBUG "%s: WMM queue=%d aci=%d acm=%d aifs=%d " | 800 | wiphy_debug(local->hw.wiphy, |
782 | "cWmin=%d cWmax=%d txop=%d uapsd=%d\n", | 801 | "WMM queue=%d aci=%d acm=%d aifs=%d " |
783 | wiphy_name(local->hw.wiphy), queue, aci, acm, | 802 | "cWmin=%d cWmax=%d txop=%d uapsd=%d\n", |
784 | params.aifs, params.cw_min, params.cw_max, params.txop, | 803 | queue, aci, acm, |
785 | params.uapsd); | 804 | params.aifs, params.cw_min, params.cw_max, |
805 | params.txop, params.uapsd); | ||
786 | #endif | 806 | #endif |
787 | if (drv_conf_tx(local, queue, ¶ms)) | 807 | if (drv_conf_tx(local, queue, ¶ms)) |
788 | printk(KERN_DEBUG "%s: failed to set TX queue " | 808 | wiphy_debug(local->hw.wiphy, |
789 | "parameters for queue %d\n", | 809 | "failed to set TX queue parameters for queue %d\n", |
790 | wiphy_name(local->hw.wiphy), queue); | 810 | queue); |
791 | } | 811 | } |
792 | 812 | ||
793 | /* enable WMM or activate new settings */ | 813 | /* enable WMM or activate new settings */ |
@@ -990,6 +1010,11 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
990 | 1010 | ||
991 | if (remove_sta) | 1011 | if (remove_sta) |
992 | sta_info_destroy_addr(sdata, bssid); | 1012 | sta_info_destroy_addr(sdata, bssid); |
1013 | |||
1014 | del_timer_sync(&sdata->u.mgd.conn_mon_timer); | ||
1015 | del_timer_sync(&sdata->u.mgd.bcn_mon_timer); | ||
1016 | del_timer_sync(&sdata->u.mgd.timer); | ||
1017 | del_timer_sync(&sdata->u.mgd.chswitch_timer); | ||
993 | } | 1018 | } |
994 | 1019 | ||
995 | void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, | 1020 | void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, |
@@ -1006,21 +1031,26 @@ void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, | |||
1006 | if (is_multicast_ether_addr(hdr->addr1)) | 1031 | if (is_multicast_ether_addr(hdr->addr1)) |
1007 | return; | 1032 | return; |
1008 | 1033 | ||
1009 | if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) | 1034 | ieee80211_sta_reset_conn_monitor(sdata); |
1010 | return; | ||
1011 | |||
1012 | mod_timer(&sdata->u.mgd.conn_mon_timer, | ||
1013 | round_jiffies_up(jiffies + IEEE80211_CONNECTION_IDLE_TIME)); | ||
1014 | } | 1035 | } |
1015 | 1036 | ||
1016 | static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) | 1037 | static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) |
1017 | { | 1038 | { |
1018 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 1039 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
1019 | const u8 *ssid; | 1040 | const u8 *ssid; |
1041 | u8 *dst = ifmgd->associated->bssid; | ||
1042 | u8 unicast_limit = max(1, IEEE80211_MAX_PROBE_TRIES - 3); | ||
1043 | |||
1044 | /* | ||
1045 | * Try sending broadcast probe requests for the last three | ||
1046 | * probe requests after the first ones failed since some | ||
1047 | * buggy APs only support broadcast probe requests. | ||
1048 | */ | ||
1049 | if (ifmgd->probe_send_count >= unicast_limit) | ||
1050 | dst = NULL; | ||
1020 | 1051 | ||
1021 | ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID); | 1052 | ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID); |
1022 | ieee80211_send_probe_req(sdata, ifmgd->associated->bssid, | 1053 | ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid[1], NULL, 0); |
1023 | ssid + 2, ssid[1], NULL, 0); | ||
1024 | 1054 | ||
1025 | ifmgd->probe_send_count++; | 1055 | ifmgd->probe_send_count++; |
1026 | ifmgd->probe_timeout = jiffies + IEEE80211_PROBE_WAIT; | 1056 | ifmgd->probe_timeout = jiffies + IEEE80211_PROBE_WAIT; |
@@ -1103,8 +1133,11 @@ static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata) | |||
1103 | printk(KERN_DEBUG "Connection to AP %pM lost.\n", bssid); | 1133 | printk(KERN_DEBUG "Connection to AP %pM lost.\n", bssid); |
1104 | 1134 | ||
1105 | ieee80211_set_disassoc(sdata, true); | 1135 | ieee80211_set_disassoc(sdata, true); |
1106 | ieee80211_recalc_idle(local); | ||
1107 | mutex_unlock(&ifmgd->mtx); | 1136 | mutex_unlock(&ifmgd->mtx); |
1137 | |||
1138 | mutex_lock(&local->mtx); | ||
1139 | ieee80211_recalc_idle(local); | ||
1140 | mutex_unlock(&local->mtx); | ||
1108 | /* | 1141 | /* |
1109 | * must be outside lock due to cfg80211, | 1142 | * must be outside lock due to cfg80211, |
1110 | * but that's not a problem. | 1143 | * but that's not a problem. |
@@ -1173,7 +1206,9 @@ ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, | |||
1173 | sdata->name, bssid, reason_code); | 1206 | sdata->name, bssid, reason_code); |
1174 | 1207 | ||
1175 | ieee80211_set_disassoc(sdata, true); | 1208 | ieee80211_set_disassoc(sdata, true); |
1209 | mutex_lock(&sdata->local->mtx); | ||
1176 | ieee80211_recalc_idle(sdata->local); | 1210 | ieee80211_recalc_idle(sdata->local); |
1211 | mutex_unlock(&sdata->local->mtx); | ||
1177 | 1212 | ||
1178 | return RX_MGMT_CFG80211_DEAUTH; | 1213 | return RX_MGMT_CFG80211_DEAUTH; |
1179 | } | 1214 | } |
@@ -1203,7 +1238,9 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1203 | sdata->name, mgmt->sa, reason_code); | 1238 | sdata->name, mgmt->sa, reason_code); |
1204 | 1239 | ||
1205 | ieee80211_set_disassoc(sdata, true); | 1240 | ieee80211_set_disassoc(sdata, true); |
1241 | mutex_lock(&sdata->local->mtx); | ||
1206 | ieee80211_recalc_idle(sdata->local); | 1242 | ieee80211_recalc_idle(sdata->local); |
1243 | mutex_unlock(&sdata->local->mtx); | ||
1207 | return RX_MGMT_CFG80211_DISASSOC; | 1244 | return RX_MGMT_CFG80211_DISASSOC; |
1208 | } | 1245 | } |
1209 | 1246 | ||
@@ -1362,7 +1399,7 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, | |||
1362 | * Also start the timer that will detect beacon loss. | 1399 | * Also start the timer that will detect beacon loss. |
1363 | */ | 1400 | */ |
1364 | ieee80211_sta_rx_notify(sdata, (struct ieee80211_hdr *)mgmt); | 1401 | ieee80211_sta_rx_notify(sdata, (struct ieee80211_hdr *)mgmt); |
1365 | mod_beacon_timer(sdata); | 1402 | ieee80211_sta_reset_beacon_monitor(sdata); |
1366 | 1403 | ||
1367 | return true; | 1404 | return true; |
1368 | } | 1405 | } |
@@ -1465,7 +1502,7 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, | |||
1465 | * we have or will be receiving any beacons or data, so let's | 1502 | * we have or will be receiving any beacons or data, so let's |
1466 | * schedule the timers again, just in case. | 1503 | * schedule the timers again, just in case. |
1467 | */ | 1504 | */ |
1468 | mod_beacon_timer(sdata); | 1505 | ieee80211_sta_reset_beacon_monitor(sdata); |
1469 | 1506 | ||
1470 | mod_timer(&ifmgd->conn_mon_timer, | 1507 | mod_timer(&ifmgd->conn_mon_timer, |
1471 | round_jiffies_up(jiffies + | 1508 | round_jiffies_up(jiffies + |
@@ -1540,15 +1577,18 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
1540 | ifmgd->last_beacon_signal = rx_status->signal; | 1577 | ifmgd->last_beacon_signal = rx_status->signal; |
1541 | if (ifmgd->flags & IEEE80211_STA_RESET_SIGNAL_AVE) { | 1578 | if (ifmgd->flags & IEEE80211_STA_RESET_SIGNAL_AVE) { |
1542 | ifmgd->flags &= ~IEEE80211_STA_RESET_SIGNAL_AVE; | 1579 | ifmgd->flags &= ~IEEE80211_STA_RESET_SIGNAL_AVE; |
1543 | ifmgd->ave_beacon_signal = rx_status->signal; | 1580 | ifmgd->ave_beacon_signal = rx_status->signal * 16; |
1544 | ifmgd->last_cqm_event_signal = 0; | 1581 | ifmgd->last_cqm_event_signal = 0; |
1582 | ifmgd->count_beacon_signal = 1; | ||
1545 | } else { | 1583 | } else { |
1546 | ifmgd->ave_beacon_signal = | 1584 | ifmgd->ave_beacon_signal = |
1547 | (IEEE80211_SIGNAL_AVE_WEIGHT * rx_status->signal * 16 + | 1585 | (IEEE80211_SIGNAL_AVE_WEIGHT * rx_status->signal * 16 + |
1548 | (16 - IEEE80211_SIGNAL_AVE_WEIGHT) * | 1586 | (16 - IEEE80211_SIGNAL_AVE_WEIGHT) * |
1549 | ifmgd->ave_beacon_signal) / 16; | 1587 | ifmgd->ave_beacon_signal) / 16; |
1588 | ifmgd->count_beacon_signal++; | ||
1550 | } | 1589 | } |
1551 | if (bss_conf->cqm_rssi_thold && | 1590 | if (bss_conf->cqm_rssi_thold && |
1591 | ifmgd->count_beacon_signal >= IEEE80211_SIGNAL_AVE_MIN_COUNT && | ||
1552 | !(local->hw.flags & IEEE80211_HW_SUPPORTS_CQM_RSSI)) { | 1592 | !(local->hw.flags & IEEE80211_HW_SUPPORTS_CQM_RSSI)) { |
1553 | int sig = ifmgd->ave_beacon_signal / 16; | 1593 | int sig = ifmgd->ave_beacon_signal / 16; |
1554 | int last_event = ifmgd->last_cqm_event_signal; | 1594 | int last_event = ifmgd->last_cqm_event_signal; |
@@ -1588,7 +1628,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
1588 | * Push the beacon loss detection into the future since | 1628 | * Push the beacon loss detection into the future since |
1589 | * we are processing a beacon from the AP just now. | 1629 | * we are processing a beacon from the AP just now. |
1590 | */ | 1630 | */ |
1591 | mod_beacon_timer(sdata); | 1631 | ieee80211_sta_reset_beacon_monitor(sdata); |
1592 | 1632 | ||
1593 | ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4); | 1633 | ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4); |
1594 | ncrc = ieee802_11_parse_elems_crc(mgmt->u.beacon.variable, | 1634 | ncrc = ieee802_11_parse_elems_crc(mgmt->u.beacon.variable, |
@@ -1751,7 +1791,7 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
1751 | struct ieee80211_local *local = sdata->local; | 1791 | struct ieee80211_local *local = sdata->local; |
1752 | struct ieee80211_work *wk; | 1792 | struct ieee80211_work *wk; |
1753 | 1793 | ||
1754 | mutex_lock(&local->work_mtx); | 1794 | mutex_lock(&local->mtx); |
1755 | list_for_each_entry(wk, &local->work_list, list) { | 1795 | list_for_each_entry(wk, &local->work_list, list) { |
1756 | if (wk->sdata != sdata) | 1796 | if (wk->sdata != sdata) |
1757 | continue; | 1797 | continue; |
@@ -1783,7 +1823,7 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
1783 | free_work(wk); | 1823 | free_work(wk); |
1784 | break; | 1824 | break; |
1785 | } | 1825 | } |
1786 | mutex_unlock(&local->work_mtx); | 1826 | mutex_unlock(&local->mtx); |
1787 | 1827 | ||
1788 | cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len); | 1828 | cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len); |
1789 | } | 1829 | } |
@@ -1840,8 +1880,10 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) | |||
1840 | " after %dms, disconnecting.\n", | 1880 | " after %dms, disconnecting.\n", |
1841 | bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ); | 1881 | bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ); |
1842 | ieee80211_set_disassoc(sdata, true); | 1882 | ieee80211_set_disassoc(sdata, true); |
1843 | ieee80211_recalc_idle(local); | ||
1844 | mutex_unlock(&ifmgd->mtx); | 1883 | mutex_unlock(&ifmgd->mtx); |
1884 | mutex_lock(&local->mtx); | ||
1885 | ieee80211_recalc_idle(local); | ||
1886 | mutex_unlock(&local->mtx); | ||
1845 | /* | 1887 | /* |
1846 | * must be outside lock due to cfg80211, | 1888 | * must be outside lock due to cfg80211, |
1847 | * but that's not a problem. | 1889 | * but that's not a problem. |
@@ -1917,6 +1959,8 @@ void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata) | |||
1917 | * time -- the code here is properly synchronised. | 1959 | * time -- the code here is properly synchronised. |
1918 | */ | 1960 | */ |
1919 | 1961 | ||
1962 | cancel_work_sync(&ifmgd->request_smps_work); | ||
1963 | |||
1920 | cancel_work_sync(&ifmgd->beacon_connection_loss_work); | 1964 | cancel_work_sync(&ifmgd->beacon_connection_loss_work); |
1921 | if (del_timer_sync(&ifmgd->timer)) | 1965 | if (del_timer_sync(&ifmgd->timer)) |
1922 | set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running); | 1966 | set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running); |
@@ -1952,6 +1996,7 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) | |||
1952 | INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work); | 1996 | INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work); |
1953 | INIT_WORK(&ifmgd->beacon_connection_loss_work, | 1997 | INIT_WORK(&ifmgd->beacon_connection_loss_work, |
1954 | ieee80211_beacon_connection_loss_work); | 1998 | ieee80211_beacon_connection_loss_work); |
1999 | INIT_WORK(&ifmgd->request_smps_work, ieee80211_request_smps_work); | ||
1955 | setup_timer(&ifmgd->timer, ieee80211_sta_timer, | 2000 | setup_timer(&ifmgd->timer, ieee80211_sta_timer, |
1956 | (unsigned long) sdata); | 2001 | (unsigned long) sdata); |
1957 | setup_timer(&ifmgd->bcn_mon_timer, ieee80211_sta_bcn_mon_timer, | 2002 | setup_timer(&ifmgd->bcn_mon_timer, ieee80211_sta_bcn_mon_timer, |
@@ -2249,6 +2294,9 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
2249 | else | 2294 | else |
2250 | ifmgd->flags &= ~IEEE80211_STA_CONTROL_PORT; | 2295 | ifmgd->flags &= ~IEEE80211_STA_CONTROL_PORT; |
2251 | 2296 | ||
2297 | sdata->control_port_protocol = req->crypto.control_port_ethertype; | ||
2298 | sdata->control_port_no_encrypt = req->crypto.control_port_no_encrypt; | ||
2299 | |||
2252 | ieee80211_add_work(wk); | 2300 | ieee80211_add_work(wk); |
2253 | return 0; | 2301 | return 0; |
2254 | } | 2302 | } |
@@ -2275,7 +2323,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, | |||
2275 | 2323 | ||
2276 | mutex_unlock(&ifmgd->mtx); | 2324 | mutex_unlock(&ifmgd->mtx); |
2277 | 2325 | ||
2278 | mutex_lock(&local->work_mtx); | 2326 | mutex_lock(&local->mtx); |
2279 | list_for_each_entry(wk, &local->work_list, list) { | 2327 | list_for_each_entry(wk, &local->work_list, list) { |
2280 | if (wk->sdata != sdata) | 2328 | if (wk->sdata != sdata) |
2281 | continue; | 2329 | continue; |
@@ -2294,7 +2342,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, | |||
2294 | free_work(wk); | 2342 | free_work(wk); |
2295 | break; | 2343 | break; |
2296 | } | 2344 | } |
2297 | mutex_unlock(&local->work_mtx); | 2345 | mutex_unlock(&local->mtx); |
2298 | 2346 | ||
2299 | /* | 2347 | /* |
2300 | * If somebody requests authentication and we haven't | 2348 | * If somebody requests authentication and we haven't |
@@ -2319,7 +2367,9 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, | |||
2319 | if (assoc_bss) | 2367 | if (assoc_bss) |
2320 | sta_info_destroy_addr(sdata, bssid); | 2368 | sta_info_destroy_addr(sdata, bssid); |
2321 | 2369 | ||
2370 | mutex_lock(&sdata->local->mtx); | ||
2322 | ieee80211_recalc_idle(sdata->local); | 2371 | ieee80211_recalc_idle(sdata->local); |
2372 | mutex_unlock(&sdata->local->mtx); | ||
2323 | 2373 | ||
2324 | return 0; | 2374 | return 0; |
2325 | } | 2375 | } |
@@ -2357,7 +2407,9 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, | |||
2357 | cookie, !req->local_state_change); | 2407 | cookie, !req->local_state_change); |
2358 | sta_info_destroy_addr(sdata, bssid); | 2408 | sta_info_destroy_addr(sdata, bssid); |
2359 | 2409 | ||
2410 | mutex_lock(&sdata->local->mtx); | ||
2360 | ieee80211_recalc_idle(sdata->local); | 2411 | ieee80211_recalc_idle(sdata->local); |
2412 | mutex_unlock(&sdata->local->mtx); | ||
2361 | 2413 | ||
2362 | return 0; | 2414 | return 0; |
2363 | } | 2415 | } |