From fafd2bce5a5821b8902b11ab24dffa47dfdbd2d0 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Wed, 6 Feb 2019 13:17:15 +0200 Subject: [PATCH] mac80211: notify driver on subsequent CSA beacons Some drivers may want to track further the CSA beacons, for example to compensate for buggy APs that change the beacon count or quiet mode during CSA flow. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho Signed-off-by: Johannes Berg --- include/net/mac80211.h | 9 +++++++-- net/mac80211/driver-ops.h | 17 ++++++++++++++++- net/mac80211/mlme.c | 27 +++++++++++++++----------- net/mac80211/trace.h | 40 +++++++++++++++++++++++++++++++++++++-- 4 files changed, 77 insertions(+), 16 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index aef7174a7c65..ac2ed8ec662b 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -6,7 +6,7 @@ * Copyright 2007-2010 Johannes Berg * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2015 - 2017 Intel Deutschland GmbH - * Copyright (C) 2018 Intel Corporation + * Copyright (C) 2018 - 2019 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -3646,7 +3646,9 @@ enum ieee80211_reconfig_type { * @abort_channel_switch: This is an optional callback that is called * when channel switch procedure was completed, allowing the * driver to go back to a normal configuration. - * + * @channel_switch_rx_beacon: This is an optional callback that is called + * when channel switch procedure is in progress and additional beacon with + * CSA IE was received, allowing driver to track changes in count. * @join_ibss: Join an IBSS (on an IBSS interface); this is called after all * information in bss_conf is set up and the beacon can be retrieved. A * channel context is bound before this is called. @@ -3951,6 +3953,9 @@ struct ieee80211_ops { struct ieee80211_vif *vif); void (*abort_channel_switch)(struct ieee80211_hw *hw, struct ieee80211_vif *vif); + void (*channel_switch_rx_beacon)(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_channel_switch *ch_switch); int (*join_ibss)(struct ieee80211_hw *hw, struct ieee80211_vif *vif); void (*leave_ibss)(struct ieee80211_hw *hw, struct ieee80211_vif *vif); diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index e069122595d0..28d022a3eee3 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -2,7 +2,7 @@ /* * Portions of this file * Copyright(c) 2016 Intel Deutschland GmbH -* Copyright (C) 2018 Intel Corporation +* Copyright (C) 2018 - 2019 Intel Corporation */ #ifndef __MAC80211_DRIVER_OPS @@ -1066,6 +1066,21 @@ drv_abort_channel_switch(struct ieee80211_sub_if_data *sdata) local->ops->abort_channel_switch(&local->hw, &sdata->vif); } +static inline void +drv_channel_switch_rx_beacon(struct ieee80211_sub_if_data *sdata, + struct ieee80211_channel_switch *ch_switch) +{ + struct ieee80211_local *local = sdata->local; + + if (!check_sdata_in_driver(sdata)) + return; + + trace_drv_channel_switch_rx_beacon(local, sdata, ch_switch); + if (local->ops->channel_switch_rx_beacon) + local->ops->channel_switch_rx_beacon(&local->hw, &sdata->vif, + ch_switch); +} + static inline int drv_join_ibss(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata) { diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 28a275ec6700..411656614e9a 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -7,7 +7,7 @@ * Copyright 2007, Michael Wu * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2015 - 2017 Intel Deutschland GmbH - * Copyright (C) 2018 Intel Corporation + * Copyright (C) 2018 - 2019 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -1312,15 +1312,27 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, res = ieee80211_parse_ch_switch_ie(sdata, elems, current_band, ifmgd->flags, ifmgd->associated->bssid, &csa_ie); + + if (!res) { + ch_switch.timestamp = timestamp; + ch_switch.device_timestamp = device_timestamp; + ch_switch.block_tx = csa_ie.mode; + ch_switch.chandef = csa_ie.chandef; + ch_switch.count = csa_ie.count; + ch_switch.delay = csa_ie.max_switch_time; + } + if (res < 0) { ieee80211_queue_work(&local->hw, &ifmgd->csa_connection_drop_work); return; } - if (res && beacon && sdata->vif.csa_active && - !ifmgd->csa_waiting_bcn) { - ieee80211_sta_abort_chanswitch(sdata); + if (beacon && sdata->vif.csa_active && !ifmgd->csa_waiting_bcn) { + if (res) + ieee80211_sta_abort_chanswitch(sdata); + else + drv_channel_switch_rx_beacon(sdata, &ch_switch); return; } else if (sdata->vif.csa_active || res) { /* disregard subsequent announcements if already processing */ @@ -1378,13 +1390,6 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, goto drop_connection; } - ch_switch.timestamp = timestamp; - ch_switch.device_timestamp = device_timestamp; - ch_switch.block_tx = csa_ie.mode; - ch_switch.chandef = csa_ie.chandef; - ch_switch.count = csa_ie.count; - ch_switch.delay = csa_ie.max_switch_time; - if (drv_pre_channel_switch(sdata, &ch_switch)) { sdata_info(sdata, "preparing for channel switch failed, disconnecting\n"); diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index c1e203fe281e..8ba70d26b82e 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h @@ -1,8 +1,8 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* * Portions of this file -* Copyright(c) 2016 Intel Deutschland GmbH -* Copyright (C) 2018 Intel Corporation +* Copyright(c) 2016-2017 Intel Deutschland GmbH +* Copyright (C) 2018 - 2019 Intel Corporation */ #if !defined(__MAC80211_DRIVER_TRACE) || defined(TRACE_HEADER_MULTI_READ) @@ -2458,6 +2458,42 @@ DEFINE_EVENT(local_sdata_evt, drv_abort_channel_switch, TP_ARGS(local, sdata) ); +TRACE_EVENT(drv_channel_switch_rx_beacon, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + struct ieee80211_channel_switch *ch_switch), + + TP_ARGS(local, sdata, ch_switch), + + TP_STRUCT__entry( + LOCAL_ENTRY + VIF_ENTRY + CHANDEF_ENTRY + __field(u64, timestamp) + __field(u32, device_timestamp) + __field(bool, block_tx) + __field(u8, count) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + VIF_ASSIGN; + CHANDEF_ASSIGN(&ch_switch->chandef) + __entry->timestamp = ch_switch->timestamp; + __entry->device_timestamp = ch_switch->device_timestamp; + __entry->block_tx = ch_switch->block_tx; + __entry->count = ch_switch->count; + ), + + TP_printk( + LOCAL_PR_FMT VIF_PR_FMT + " received a channel switch beacon to " + CHANDEF_PR_FMT " count:%d block_tx:%d timestamp:%llu", + LOCAL_PR_ARG, VIF_PR_ARG, CHANDEF_PR_ARG, __entry->count, + __entry->block_tx, __entry->timestamp + ) +); + TRACE_EVENT(drv_get_txpower, TP_PROTO(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, -- GitLab