diff options
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r-- | net/mac80211/mlme.c | 212 |
1 files changed, 147 insertions, 65 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index a4b1dd332e0f..00103f36dcbf 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -1168,11 +1168,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1168 | if (!conf) { | 1168 | if (!conf) { |
1169 | sdata_info(sdata, | 1169 | sdata_info(sdata, |
1170 | "no channel context assigned to vif?, disconnecting\n"); | 1170 | "no channel context assigned to vif?, disconnecting\n"); |
1171 | ieee80211_queue_work(&local->hw, | 1171 | goto drop_connection; |
1172 | &ifmgd->csa_connection_drop_work); | ||
1173 | mutex_unlock(&local->chanctx_mtx); | ||
1174 | mutex_unlock(&local->mtx); | ||
1175 | return; | ||
1176 | } | 1172 | } |
1177 | 1173 | ||
1178 | chanctx = container_of(conf, struct ieee80211_chanctx, conf); | 1174 | chanctx = container_of(conf, struct ieee80211_chanctx, conf); |
@@ -1181,11 +1177,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1181 | !(local->hw.flags & IEEE80211_HW_CHANCTX_STA_CSA)) { | 1177 | !(local->hw.flags & IEEE80211_HW_CHANCTX_STA_CSA)) { |
1182 | sdata_info(sdata, | 1178 | sdata_info(sdata, |
1183 | "driver doesn't support chan-switch with channel contexts\n"); | 1179 | "driver doesn't support chan-switch with channel contexts\n"); |
1184 | ieee80211_queue_work(&local->hw, | 1180 | goto drop_connection; |
1185 | &ifmgd->csa_connection_drop_work); | ||
1186 | mutex_unlock(&local->chanctx_mtx); | ||
1187 | mutex_unlock(&local->mtx); | ||
1188 | return; | ||
1189 | } | 1181 | } |
1190 | 1182 | ||
1191 | ch_switch.timestamp = timestamp; | 1183 | ch_switch.timestamp = timestamp; |
@@ -1197,11 +1189,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1197 | if (drv_pre_channel_switch(sdata, &ch_switch)) { | 1189 | if (drv_pre_channel_switch(sdata, &ch_switch)) { |
1198 | sdata_info(sdata, | 1190 | sdata_info(sdata, |
1199 | "preparing for channel switch failed, disconnecting\n"); | 1191 | "preparing for channel switch failed, disconnecting\n"); |
1200 | ieee80211_queue_work(&local->hw, | 1192 | goto drop_connection; |
1201 | &ifmgd->csa_connection_drop_work); | ||
1202 | mutex_unlock(&local->chanctx_mtx); | ||
1203 | mutex_unlock(&local->mtx); | ||
1204 | return; | ||
1205 | } | 1193 | } |
1206 | 1194 | ||
1207 | res = ieee80211_vif_reserve_chanctx(sdata, &csa_ie.chandef, | 1195 | res = ieee80211_vif_reserve_chanctx(sdata, &csa_ie.chandef, |
@@ -1210,11 +1198,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1210 | sdata_info(sdata, | 1198 | sdata_info(sdata, |
1211 | "failed to reserve channel context for channel switch, disconnecting (err=%d)\n", | 1199 | "failed to reserve channel context for channel switch, disconnecting (err=%d)\n", |
1212 | res); | 1200 | res); |
1213 | ieee80211_queue_work(&local->hw, | 1201 | goto drop_connection; |
1214 | &ifmgd->csa_connection_drop_work); | ||
1215 | mutex_unlock(&local->chanctx_mtx); | ||
1216 | mutex_unlock(&local->mtx); | ||
1217 | return; | ||
1218 | } | 1202 | } |
1219 | mutex_unlock(&local->chanctx_mtx); | 1203 | mutex_unlock(&local->chanctx_mtx); |
1220 | 1204 | ||
@@ -1244,6 +1228,11 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1244 | mod_timer(&ifmgd->chswitch_timer, | 1228 | mod_timer(&ifmgd->chswitch_timer, |
1245 | TU_TO_EXP_TIME((csa_ie.count - 1) * | 1229 | TU_TO_EXP_TIME((csa_ie.count - 1) * |
1246 | cbss->beacon_interval)); | 1230 | cbss->beacon_interval)); |
1231 | return; | ||
1232 | drop_connection: | ||
1233 | ieee80211_queue_work(&local->hw, &ifmgd->csa_connection_drop_work); | ||
1234 | mutex_unlock(&local->chanctx_mtx); | ||
1235 | mutex_unlock(&local->mtx); | ||
1247 | } | 1236 | } |
1248 | 1237 | ||
1249 | static bool | 1238 | static bool |
@@ -1633,9 +1622,6 @@ void ieee80211_dynamic_ps_timer(unsigned long data) | |||
1633 | { | 1622 | { |
1634 | struct ieee80211_local *local = (void *) data; | 1623 | struct ieee80211_local *local = (void *) data; |
1635 | 1624 | ||
1636 | if (local->quiescing || local->suspended) | ||
1637 | return; | ||
1638 | |||
1639 | ieee80211_queue_work(&local->hw, &local->dynamic_ps_enable_work); | 1625 | ieee80211_queue_work(&local->hw, &local->dynamic_ps_enable_work); |
1640 | } | 1626 | } |
1641 | 1627 | ||
@@ -2260,7 +2246,7 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) | |||
2260 | else | 2246 | else |
2261 | ssid_len = ssid[1]; | 2247 | ssid_len = ssid[1]; |
2262 | 2248 | ||
2263 | ieee80211_send_probe_req(sdata, sdata->vif.addr, NULL, | 2249 | ieee80211_send_probe_req(sdata, sdata->vif.addr, dst, |
2264 | ssid + 2, ssid_len, NULL, | 2250 | ssid + 2, ssid_len, NULL, |
2265 | 0, (u32) -1, true, 0, | 2251 | 0, (u32) -1, true, 0, |
2266 | ifmgd->associated->channel, false); | 2252 | ifmgd->associated->channel, false); |
@@ -2372,6 +2358,24 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw, | |||
2372 | } | 2358 | } |
2373 | EXPORT_SYMBOL(ieee80211_ap_probereq_get); | 2359 | EXPORT_SYMBOL(ieee80211_ap_probereq_get); |
2374 | 2360 | ||
2361 | static void ieee80211_report_disconnect(struct ieee80211_sub_if_data *sdata, | ||
2362 | const u8 *buf, size_t len, bool tx, | ||
2363 | u16 reason) | ||
2364 | { | ||
2365 | struct ieee80211_event event = { | ||
2366 | .type = MLME_EVENT, | ||
2367 | .u.mlme.data = tx ? DEAUTH_TX_EVENT : DEAUTH_RX_EVENT, | ||
2368 | .u.mlme.reason = reason, | ||
2369 | }; | ||
2370 | |||
2371 | if (tx) | ||
2372 | cfg80211_tx_mlme_mgmt(sdata->dev, buf, len); | ||
2373 | else | ||
2374 | cfg80211_rx_mlme_mgmt(sdata->dev, buf, len); | ||
2375 | |||
2376 | drv_event_callback(sdata->local, sdata, &event); | ||
2377 | } | ||
2378 | |||
2375 | static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata) | 2379 | static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata) |
2376 | { | 2380 | { |
2377 | struct ieee80211_local *local = sdata->local; | 2381 | struct ieee80211_local *local = sdata->local; |
@@ -2397,8 +2401,9 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata) | |||
2397 | } | 2401 | } |
2398 | mutex_unlock(&local->mtx); | 2402 | mutex_unlock(&local->mtx); |
2399 | 2403 | ||
2400 | cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf, | 2404 | ieee80211_report_disconnect(sdata, frame_buf, sizeof(frame_buf), true, |
2401 | IEEE80211_DEAUTH_FRAME_LEN); | 2405 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY); |
2406 | |||
2402 | sdata_unlock(sdata); | 2407 | sdata_unlock(sdata); |
2403 | } | 2408 | } |
2404 | 2409 | ||
@@ -2522,6 +2527,10 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, | |||
2522 | u8 bssid[ETH_ALEN]; | 2527 | u8 bssid[ETH_ALEN]; |
2523 | u16 auth_alg, auth_transaction, status_code; | 2528 | u16 auth_alg, auth_transaction, status_code; |
2524 | struct sta_info *sta; | 2529 | struct sta_info *sta; |
2530 | struct ieee80211_event event = { | ||
2531 | .type = MLME_EVENT, | ||
2532 | .u.mlme.data = AUTH_EVENT, | ||
2533 | }; | ||
2525 | 2534 | ||
2526 | sdata_assert_lock(sdata); | 2535 | sdata_assert_lock(sdata); |
2527 | 2536 | ||
@@ -2554,6 +2563,9 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, | |||
2554 | mgmt->sa, status_code); | 2563 | mgmt->sa, status_code); |
2555 | ieee80211_destroy_auth_data(sdata, false); | 2564 | ieee80211_destroy_auth_data(sdata, false); |
2556 | cfg80211_rx_mlme_mgmt(sdata->dev, (u8 *)mgmt, len); | 2565 | cfg80211_rx_mlme_mgmt(sdata->dev, (u8 *)mgmt, len); |
2566 | event.u.mlme.status = MLME_DENIED; | ||
2567 | event.u.mlme.reason = status_code; | ||
2568 | drv_event_callback(sdata->local, sdata, &event); | ||
2557 | return; | 2569 | return; |
2558 | } | 2570 | } |
2559 | 2571 | ||
@@ -2576,6 +2588,8 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, | |||
2576 | return; | 2588 | return; |
2577 | } | 2589 | } |
2578 | 2590 | ||
2591 | event.u.mlme.status = MLME_SUCCESS; | ||
2592 | drv_event_callback(sdata->local, sdata, &event); | ||
2579 | sdata_info(sdata, "authenticated\n"); | 2593 | sdata_info(sdata, "authenticated\n"); |
2580 | ifmgd->auth_data->done = true; | 2594 | ifmgd->auth_data->done = true; |
2581 | ifmgd->auth_data->timeout = jiffies + IEEE80211_AUTH_WAIT_ASSOC; | 2595 | ifmgd->auth_data->timeout = jiffies + IEEE80211_AUTH_WAIT_ASSOC; |
@@ -2694,7 +2708,7 @@ static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, | |||
2694 | 2708 | ||
2695 | ieee80211_set_disassoc(sdata, 0, 0, false, NULL); | 2709 | ieee80211_set_disassoc(sdata, 0, 0, false, NULL); |
2696 | 2710 | ||
2697 | cfg80211_rx_mlme_mgmt(sdata->dev, (u8 *)mgmt, len); | 2711 | ieee80211_report_disconnect(sdata, (u8 *)mgmt, len, false, reason_code); |
2698 | } | 2712 | } |
2699 | 2713 | ||
2700 | 2714 | ||
@@ -2720,7 +2734,7 @@ static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, | |||
2720 | 2734 | ||
2721 | ieee80211_set_disassoc(sdata, 0, 0, false, NULL); | 2735 | ieee80211_set_disassoc(sdata, 0, 0, false, NULL); |
2722 | 2736 | ||
2723 | cfg80211_rx_mlme_mgmt(sdata->dev, (u8 *)mgmt, len); | 2737 | ieee80211_report_disconnect(sdata, (u8 *)mgmt, len, false, reason_code); |
2724 | } | 2738 | } |
2725 | 2739 | ||
2726 | static void ieee80211_get_rates(struct ieee80211_supported_band *sband, | 2740 | static void ieee80211_get_rates(struct ieee80211_supported_band *sband, |
@@ -2982,10 +2996,14 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, | |||
2982 | 2996 | ||
2983 | rate_control_rate_init(sta); | 2997 | rate_control_rate_init(sta); |
2984 | 2998 | ||
2985 | if (ifmgd->flags & IEEE80211_STA_MFP_ENABLED) | 2999 | if (ifmgd->flags & IEEE80211_STA_MFP_ENABLED) { |
2986 | set_sta_flag(sta, WLAN_STA_MFP); | 3000 | set_sta_flag(sta, WLAN_STA_MFP); |
3001 | sta->sta.mfp = true; | ||
3002 | } else { | ||
3003 | sta->sta.mfp = false; | ||
3004 | } | ||
2987 | 3005 | ||
2988 | sta->sta.wme = elems.wmm_param; | 3006 | sta->sta.wme = elems.wmm_param && local->hw.queues >= IEEE80211_NUM_ACS; |
2989 | 3007 | ||
2990 | err = sta_info_move_state(sta, IEEE80211_STA_ASSOC); | 3008 | err = sta_info_move_state(sta, IEEE80211_STA_ASSOC); |
2991 | if (!err && !(ifmgd->flags & IEEE80211_STA_CONTROL_PORT)) | 3009 | if (!err && !(ifmgd->flags & IEEE80211_STA_CONTROL_PORT)) |
@@ -3055,6 +3073,10 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
3055 | u8 *pos; | 3073 | u8 *pos; |
3056 | bool reassoc; | 3074 | bool reassoc; |
3057 | struct cfg80211_bss *bss; | 3075 | struct cfg80211_bss *bss; |
3076 | struct ieee80211_event event = { | ||
3077 | .type = MLME_EVENT, | ||
3078 | .u.mlme.data = ASSOC_EVENT, | ||
3079 | }; | ||
3058 | 3080 | ||
3059 | sdata_assert_lock(sdata); | 3081 | sdata_assert_lock(sdata); |
3060 | 3082 | ||
@@ -3106,6 +3128,9 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
3106 | sdata_info(sdata, "%pM denied association (code=%d)\n", | 3128 | sdata_info(sdata, "%pM denied association (code=%d)\n", |
3107 | mgmt->sa, status_code); | 3129 | mgmt->sa, status_code); |
3108 | ieee80211_destroy_assoc_data(sdata, false); | 3130 | ieee80211_destroy_assoc_data(sdata, false); |
3131 | event.u.mlme.status = MLME_DENIED; | ||
3132 | event.u.mlme.reason = status_code; | ||
3133 | drv_event_callback(sdata->local, sdata, &event); | ||
3109 | } else { | 3134 | } else { |
3110 | if (!ieee80211_assoc_success(sdata, bss, mgmt, len)) { | 3135 | if (!ieee80211_assoc_success(sdata, bss, mgmt, len)) { |
3111 | /* oops -- internal error -- send timeout for now */ | 3136 | /* oops -- internal error -- send timeout for now */ |
@@ -3113,6 +3138,8 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
3113 | cfg80211_assoc_timeout(sdata->dev, bss); | 3138 | cfg80211_assoc_timeout(sdata->dev, bss); |
3114 | return; | 3139 | return; |
3115 | } | 3140 | } |
3141 | event.u.mlme.status = MLME_SUCCESS; | ||
3142 | drv_event_callback(sdata->local, sdata, &event); | ||
3116 | sdata_info(sdata, "associated\n"); | 3143 | sdata_info(sdata, "associated\n"); |
3117 | 3144 | ||
3118 | /* | 3145 | /* |
@@ -3315,6 +3342,9 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
3315 | ifmgd->count_beacon_signal >= IEEE80211_SIGNAL_AVE_MIN_COUNT) { | 3342 | ifmgd->count_beacon_signal >= IEEE80211_SIGNAL_AVE_MIN_COUNT) { |
3316 | int sig = ifmgd->ave_beacon_signal; | 3343 | int sig = ifmgd->ave_beacon_signal; |
3317 | int last_sig = ifmgd->last_ave_beacon_signal; | 3344 | int last_sig = ifmgd->last_ave_beacon_signal; |
3345 | struct ieee80211_event event = { | ||
3346 | .type = RSSI_EVENT, | ||
3347 | }; | ||
3318 | 3348 | ||
3319 | /* | 3349 | /* |
3320 | * if signal crosses either of the boundaries, invoke callback | 3350 | * if signal crosses either of the boundaries, invoke callback |
@@ -3323,12 +3353,14 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
3323 | if (sig > ifmgd->rssi_max_thold && | 3353 | if (sig > ifmgd->rssi_max_thold && |
3324 | (last_sig <= ifmgd->rssi_min_thold || last_sig == 0)) { | 3354 | (last_sig <= ifmgd->rssi_min_thold || last_sig == 0)) { |
3325 | ifmgd->last_ave_beacon_signal = sig; | 3355 | ifmgd->last_ave_beacon_signal = sig; |
3326 | drv_rssi_callback(local, sdata, RSSI_EVENT_HIGH); | 3356 | event.u.rssi.data = RSSI_EVENT_HIGH; |
3357 | drv_event_callback(local, sdata, &event); | ||
3327 | } else if (sig < ifmgd->rssi_min_thold && | 3358 | } else if (sig < ifmgd->rssi_min_thold && |
3328 | (last_sig >= ifmgd->rssi_max_thold || | 3359 | (last_sig >= ifmgd->rssi_max_thold || |
3329 | last_sig == 0)) { | 3360 | last_sig == 0)) { |
3330 | ifmgd->last_ave_beacon_signal = sig; | 3361 | ifmgd->last_ave_beacon_signal = sig; |
3331 | drv_rssi_callback(local, sdata, RSSI_EVENT_LOW); | 3362 | event.u.rssi.data = RSSI_EVENT_LOW; |
3363 | drv_event_callback(local, sdata, &event); | ||
3332 | } | 3364 | } |
3333 | } | 3365 | } |
3334 | 3366 | ||
@@ -3433,6 +3465,26 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
3433 | if (ifmgd->csa_waiting_bcn) | 3465 | if (ifmgd->csa_waiting_bcn) |
3434 | ieee80211_chswitch_post_beacon(sdata); | 3466 | ieee80211_chswitch_post_beacon(sdata); |
3435 | 3467 | ||
3468 | /* | ||
3469 | * Update beacon timing and dtim count on every beacon appearance. This | ||
3470 | * will allow the driver to use the most updated values. Do it before | ||
3471 | * comparing this one with last received beacon. | ||
3472 | * IMPORTANT: These parameters would possibly be out of sync by the time | ||
3473 | * the driver will use them. The synchronized view is currently | ||
3474 | * guaranteed only in certain callbacks. | ||
3475 | */ | ||
3476 | if (local->hw.flags & IEEE80211_HW_TIMING_BEACON_ONLY) { | ||
3477 | sdata->vif.bss_conf.sync_tsf = | ||
3478 | le64_to_cpu(mgmt->u.beacon.timestamp); | ||
3479 | sdata->vif.bss_conf.sync_device_ts = | ||
3480 | rx_status->device_timestamp; | ||
3481 | if (elems.tim) | ||
3482 | sdata->vif.bss_conf.sync_dtim_count = | ||
3483 | elems.tim->dtim_count; | ||
3484 | else | ||
3485 | sdata->vif.bss_conf.sync_dtim_count = 0; | ||
3486 | } | ||
3487 | |||
3436 | if (ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid) | 3488 | if (ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid) |
3437 | return; | 3489 | return; |
3438 | ifmgd->beacon_crc = ncrc; | 3490 | ifmgd->beacon_crc = ncrc; |
@@ -3460,18 +3512,6 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
3460 | else | 3512 | else |
3461 | bss_conf->dtim_period = 1; | 3513 | bss_conf->dtim_period = 1; |
3462 | 3514 | ||
3463 | if (local->hw.flags & IEEE80211_HW_TIMING_BEACON_ONLY) { | ||
3464 | sdata->vif.bss_conf.sync_tsf = | ||
3465 | le64_to_cpu(mgmt->u.beacon.timestamp); | ||
3466 | sdata->vif.bss_conf.sync_device_ts = | ||
3467 | rx_status->device_timestamp; | ||
3468 | if (elems.tim) | ||
3469 | sdata->vif.bss_conf.sync_dtim_count = | ||
3470 | elems.tim->dtim_count; | ||
3471 | else | ||
3472 | sdata->vif.bss_conf.sync_dtim_count = 0; | ||
3473 | } | ||
3474 | |||
3475 | changed |= BSS_CHANGED_BEACON_INFO; | 3515 | changed |= BSS_CHANGED_BEACON_INFO; |
3476 | ifmgd->have_beacon = true; | 3516 | ifmgd->have_beacon = true; |
3477 | 3517 | ||
@@ -3502,8 +3542,9 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
3502 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, | 3542 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, |
3503 | WLAN_REASON_DEAUTH_LEAVING, | 3543 | WLAN_REASON_DEAUTH_LEAVING, |
3504 | true, deauth_buf); | 3544 | true, deauth_buf); |
3505 | cfg80211_tx_mlme_mgmt(sdata->dev, deauth_buf, | 3545 | ieee80211_report_disconnect(sdata, deauth_buf, |
3506 | sizeof(deauth_buf)); | 3546 | sizeof(deauth_buf), true, |
3547 | WLAN_REASON_DEAUTH_LEAVING); | ||
3507 | return; | 3548 | return; |
3508 | } | 3549 | } |
3509 | 3550 | ||
@@ -3621,8 +3662,8 @@ static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata, | |||
3621 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, reason, | 3662 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, reason, |
3622 | tx, frame_buf); | 3663 | tx, frame_buf); |
3623 | 3664 | ||
3624 | cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf, | 3665 | ieee80211_report_disconnect(sdata, frame_buf, sizeof(frame_buf), true, |
3625 | IEEE80211_DEAUTH_FRAME_LEN); | 3666 | reason); |
3626 | } | 3667 | } |
3627 | 3668 | ||
3628 | static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata) | 3669 | static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata) |
@@ -3816,12 +3857,18 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) | |||
3816 | ieee80211_destroy_auth_data(sdata, false); | 3857 | ieee80211_destroy_auth_data(sdata, false); |
3817 | } else if (ieee80211_probe_auth(sdata)) { | 3858 | } else if (ieee80211_probe_auth(sdata)) { |
3818 | u8 bssid[ETH_ALEN]; | 3859 | u8 bssid[ETH_ALEN]; |
3860 | struct ieee80211_event event = { | ||
3861 | .type = MLME_EVENT, | ||
3862 | .u.mlme.data = AUTH_EVENT, | ||
3863 | .u.mlme.status = MLME_TIMEOUT, | ||
3864 | }; | ||
3819 | 3865 | ||
3820 | memcpy(bssid, ifmgd->auth_data->bss->bssid, ETH_ALEN); | 3866 | memcpy(bssid, ifmgd->auth_data->bss->bssid, ETH_ALEN); |
3821 | 3867 | ||
3822 | ieee80211_destroy_auth_data(sdata, false); | 3868 | ieee80211_destroy_auth_data(sdata, false); |
3823 | 3869 | ||
3824 | cfg80211_auth_timeout(sdata->dev, bssid); | 3870 | cfg80211_auth_timeout(sdata->dev, bssid); |
3871 | drv_event_callback(sdata->local, sdata, &event); | ||
3825 | } | 3872 | } |
3826 | } else if (ifmgd->auth_data && ifmgd->auth_data->timeout_started) | 3873 | } else if (ifmgd->auth_data && ifmgd->auth_data->timeout_started) |
3827 | run_again(sdata, ifmgd->auth_data->timeout); | 3874 | run_again(sdata, ifmgd->auth_data->timeout); |
@@ -3831,9 +3878,15 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) | |||
3831 | if ((ifmgd->assoc_data->need_beacon && !ifmgd->have_beacon) || | 3878 | if ((ifmgd->assoc_data->need_beacon && !ifmgd->have_beacon) || |
3832 | ieee80211_do_assoc(sdata)) { | 3879 | ieee80211_do_assoc(sdata)) { |
3833 | struct cfg80211_bss *bss = ifmgd->assoc_data->bss; | 3880 | struct cfg80211_bss *bss = ifmgd->assoc_data->bss; |
3881 | struct ieee80211_event event = { | ||
3882 | .type = MLME_EVENT, | ||
3883 | .u.mlme.data = ASSOC_EVENT, | ||
3884 | .u.mlme.status = MLME_TIMEOUT, | ||
3885 | }; | ||
3834 | 3886 | ||
3835 | ieee80211_destroy_assoc_data(sdata, false); | 3887 | ieee80211_destroy_assoc_data(sdata, false); |
3836 | cfg80211_assoc_timeout(sdata->dev, bss); | 3888 | cfg80211_assoc_timeout(sdata->dev, bss); |
3889 | drv_event_callback(sdata->local, sdata, &event); | ||
3837 | } | 3890 | } |
3838 | } else if (ifmgd->assoc_data && ifmgd->assoc_data->timeout_started) | 3891 | } else if (ifmgd->assoc_data && ifmgd->assoc_data->timeout_started) |
3839 | run_again(sdata, ifmgd->assoc_data->timeout); | 3892 | run_again(sdata, ifmgd->assoc_data->timeout); |
@@ -3905,12 +3958,8 @@ static void ieee80211_sta_bcn_mon_timer(unsigned long data) | |||
3905 | { | 3958 | { |
3906 | struct ieee80211_sub_if_data *sdata = | 3959 | struct ieee80211_sub_if_data *sdata = |
3907 | (struct ieee80211_sub_if_data *) data; | 3960 | (struct ieee80211_sub_if_data *) data; |
3908 | struct ieee80211_local *local = sdata->local; | ||
3909 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 3961 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
3910 | 3962 | ||
3911 | if (local->quiescing) | ||
3912 | return; | ||
3913 | |||
3914 | if (sdata->vif.csa_active && !ifmgd->csa_waiting_bcn) | 3963 | if (sdata->vif.csa_active && !ifmgd->csa_waiting_bcn) |
3915 | return; | 3964 | return; |
3916 | 3965 | ||
@@ -3926,9 +3975,6 @@ static void ieee80211_sta_conn_mon_timer(unsigned long data) | |||
3926 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 3975 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
3927 | struct ieee80211_local *local = sdata->local; | 3976 | struct ieee80211_local *local = sdata->local; |
3928 | 3977 | ||
3929 | if (local->quiescing) | ||
3930 | return; | ||
3931 | |||
3932 | if (sdata->vif.csa_active && !ifmgd->csa_waiting_bcn) | 3978 | if (sdata->vif.csa_active && !ifmgd->csa_waiting_bcn) |
3933 | return; | 3979 | return; |
3934 | 3980 | ||
@@ -3991,6 +4037,34 @@ void ieee80211_mgd_quiesce(struct ieee80211_sub_if_data *sdata) | |||
3991 | IEEE80211_DEAUTH_FRAME_LEN); | 4037 | IEEE80211_DEAUTH_FRAME_LEN); |
3992 | } | 4038 | } |
3993 | 4039 | ||
4040 | /* This is a bit of a hack - we should find a better and more generic | ||
4041 | * solution to this. Normally when suspending, cfg80211 will in fact | ||
4042 | * deauthenticate. However, it doesn't (and cannot) stop an ongoing | ||
4043 | * auth (not so important) or assoc (this is the problem) process. | ||
4044 | * | ||
4045 | * As a consequence, it can happen that we are in the process of both | ||
4046 | * associating and suspending, and receive an association response | ||
4047 | * after cfg80211 has checked if it needs to disconnect, but before | ||
4048 | * we actually set the flag to drop incoming frames. This will then | ||
4049 | * cause the workqueue flush to process the association response in | ||
4050 | * the suspend, resulting in a successful association just before it | ||
4051 | * tries to remove the interface from the driver, which now though | ||
4052 | * has a channel context assigned ... this results in issues. | ||
4053 | * | ||
4054 | * To work around this (for now) simply deauth here again if we're | ||
4055 | * now connected. | ||
4056 | */ | ||
4057 | if (ifmgd->associated && !sdata->local->wowlan) { | ||
4058 | u8 bssid[ETH_ALEN]; | ||
4059 | struct cfg80211_deauth_request req = { | ||
4060 | .reason_code = WLAN_REASON_DEAUTH_LEAVING, | ||
4061 | .bssid = bssid, | ||
4062 | }; | ||
4063 | |||
4064 | memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN); | ||
4065 | ieee80211_mgd_deauth(sdata, &req); | ||
4066 | } | ||
4067 | |||
3994 | sdata_unlock(sdata); | 4068 | sdata_unlock(sdata); |
3995 | } | 4069 | } |
3996 | 4070 | ||
@@ -4379,6 +4453,10 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, | |||
4379 | } else | 4453 | } else |
4380 | WARN_ON_ONCE(!ether_addr_equal(ifmgd->bssid, cbss->bssid)); | 4454 | WARN_ON_ONCE(!ether_addr_equal(ifmgd->bssid, cbss->bssid)); |
4381 | 4455 | ||
4456 | /* Cancel scan to ensure that nothing interferes with connection */ | ||
4457 | if (local->scanning) | ||
4458 | ieee80211_scan_cancel(local); | ||
4459 | |||
4382 | return 0; | 4460 | return 0; |
4383 | } | 4461 | } |
4384 | 4462 | ||
@@ -4467,8 +4545,9 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, | |||
4467 | WLAN_REASON_UNSPECIFIED, | 4545 | WLAN_REASON_UNSPECIFIED, |
4468 | false, frame_buf); | 4546 | false, frame_buf); |
4469 | 4547 | ||
4470 | cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf, | 4548 | ieee80211_report_disconnect(sdata, frame_buf, |
4471 | sizeof(frame_buf)); | 4549 | sizeof(frame_buf), true, |
4550 | WLAN_REASON_UNSPECIFIED); | ||
4472 | } | 4551 | } |
4473 | 4552 | ||
4474 | sdata_info(sdata, "authenticate with %pM\n", req->bss->bssid); | 4553 | sdata_info(sdata, "authenticate with %pM\n", req->bss->bssid); |
@@ -4568,8 +4647,9 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
4568 | WLAN_REASON_UNSPECIFIED, | 4647 | WLAN_REASON_UNSPECIFIED, |
4569 | false, frame_buf); | 4648 | false, frame_buf); |
4570 | 4649 | ||
4571 | cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf, | 4650 | ieee80211_report_disconnect(sdata, frame_buf, |
4572 | sizeof(frame_buf)); | 4651 | sizeof(frame_buf), true, |
4652 | WLAN_REASON_UNSPECIFIED); | ||
4573 | } | 4653 | } |
4574 | 4654 | ||
4575 | if (ifmgd->auth_data && !ifmgd->auth_data->done) { | 4655 | if (ifmgd->auth_data && !ifmgd->auth_data->done) { |
@@ -4859,8 +4939,9 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, | |||
4859 | req->reason_code, tx, | 4939 | req->reason_code, tx, |
4860 | frame_buf); | 4940 | frame_buf); |
4861 | ieee80211_destroy_auth_data(sdata, false); | 4941 | ieee80211_destroy_auth_data(sdata, false); |
4862 | cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf, | 4942 | ieee80211_report_disconnect(sdata, frame_buf, |
4863 | IEEE80211_DEAUTH_FRAME_LEN); | 4943 | sizeof(frame_buf), true, |
4944 | req->reason_code); | ||
4864 | 4945 | ||
4865 | return 0; | 4946 | return 0; |
4866 | } | 4947 | } |
@@ -4874,8 +4955,9 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, | |||
4874 | 4955 | ||
4875 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, | 4956 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, |
4876 | req->reason_code, tx, frame_buf); | 4957 | req->reason_code, tx, frame_buf); |
4877 | cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf, | 4958 | ieee80211_report_disconnect(sdata, frame_buf, |
4878 | IEEE80211_DEAUTH_FRAME_LEN); | 4959 | sizeof(frame_buf), true, |
4960 | req->reason_code); | ||
4879 | return 0; | 4961 | return 0; |
4880 | } | 4962 | } |
4881 | 4963 | ||
@@ -4907,8 +4989,8 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, | |||
4907 | req->reason_code, !req->local_state_change, | 4989 | req->reason_code, !req->local_state_change, |
4908 | frame_buf); | 4990 | frame_buf); |
4909 | 4991 | ||
4910 | cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf, | 4992 | ieee80211_report_disconnect(sdata, frame_buf, sizeof(frame_buf), true, |
4911 | IEEE80211_DEAUTH_FRAME_LEN); | 4993 | req->reason_code); |
4912 | 4994 | ||
4913 | return 0; | 4995 | return 0; |
4914 | } | 4996 | } |