mac80211: introduce flush operation
We've long lacked a good confirmation that frames have really gone out, e.g. before going off-channel for a scan. Add a flush() operation that drivers can implement to provide that confirmation, and use it in a few places: * before scanning sends the nullfunc frames * after scanning sends the nullfunc frames, if any * when going idle, to send any pending frames Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
committed by
John W. Linville
parent
9607e6b66a
commit
a80f7c0b08
@@ -896,6 +896,16 @@ static int mac80211_hwsim_ampdu_action(struct ieee80211_hw *hw,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void mac80211_hwsim_flush(struct ieee80211_hw *hw, bool drop)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* In this special case, there's nothing we need to
|
||||||
|
* do because hwsim does transmission synchronously.
|
||||||
|
* In the future, when it does transmissions via
|
||||||
|
* userspace, we may need to do something.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static const struct ieee80211_ops mac80211_hwsim_ops =
|
static const struct ieee80211_ops mac80211_hwsim_ops =
|
||||||
{
|
{
|
||||||
@@ -912,6 +922,7 @@ static const struct ieee80211_ops mac80211_hwsim_ops =
|
|||||||
.conf_tx = mac80211_hwsim_conf_tx,
|
.conf_tx = mac80211_hwsim_conf_tx,
|
||||||
CFG80211_TESTMODE_CMD(mac80211_hwsim_testmode_cmd)
|
CFG80211_TESTMODE_CMD(mac80211_hwsim_testmode_cmd)
|
||||||
.ampdu_action = mac80211_hwsim_ampdu_action,
|
.ampdu_action = mac80211_hwsim_ampdu_action,
|
||||||
|
.flush = mac80211_hwsim_flush,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@@ -1545,6 +1545,10 @@ enum ieee80211_ampdu_mlme_action {
|
|||||||
* and need to call wiphy_rfkill_set_hw_state() in the callback.
|
* and need to call wiphy_rfkill_set_hw_state() in the callback.
|
||||||
*
|
*
|
||||||
* @testmode_cmd: Implement a cfg80211 test mode command.
|
* @testmode_cmd: Implement a cfg80211 test mode command.
|
||||||
|
*
|
||||||
|
* @flush: Flush all pending frames from the hardware queue, making sure
|
||||||
|
* that the hardware queues are empty. If the parameter @drop is set
|
||||||
|
* to %true, pending frames may be dropped.
|
||||||
*/
|
*/
|
||||||
struct ieee80211_ops {
|
struct ieee80211_ops {
|
||||||
int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb);
|
int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb);
|
||||||
@@ -1601,6 +1605,7 @@ struct ieee80211_ops {
|
|||||||
#ifdef CONFIG_NL80211_TESTMODE
|
#ifdef CONFIG_NL80211_TESTMODE
|
||||||
int (*testmode_cmd)(struct ieee80211_hw *hw, void *data, int len);
|
int (*testmode_cmd)(struct ieee80211_hw *hw, void *data, int len);
|
||||||
#endif
|
#endif
|
||||||
|
void (*flush)(struct ieee80211_hw *hw, bool drop);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -259,4 +259,11 @@ static inline void drv_rfkill_poll(struct ieee80211_local *local)
|
|||||||
if (local->ops->rfkill_poll)
|
if (local->ops->rfkill_poll)
|
||||||
local->ops->rfkill_poll(&local->hw);
|
local->ops->rfkill_poll(&local->hw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void drv_flush(struct ieee80211_local *local, bool drop)
|
||||||
|
{
|
||||||
|
trace_drv_flush(local, drop);
|
||||||
|
if (local->ops->flush)
|
||||||
|
local->ops->flush(&local->hw, drop);
|
||||||
|
}
|
||||||
#endif /* __MAC80211_DRIVER_OPS */
|
#endif /* __MAC80211_DRIVER_OPS */
|
||||||
|
@@ -690,6 +690,27 @@ TRACE_EVENT(drv_ampdu_action,
|
|||||||
LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->action, __entry->tid, __entry->ret
|
LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->action, __entry->tid, __entry->ret
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
TRACE_EVENT(drv_flush,
|
||||||
|
TP_PROTO(struct ieee80211_local *local, bool drop),
|
||||||
|
|
||||||
|
TP_ARGS(local, drop),
|
||||||
|
|
||||||
|
TP_STRUCT__entry(
|
||||||
|
LOCAL_ENTRY
|
||||||
|
__field(bool, drop)
|
||||||
|
),
|
||||||
|
|
||||||
|
TP_fast_assign(
|
||||||
|
LOCAL_ASSIGN;
|
||||||
|
__entry->drop = drop;
|
||||||
|
),
|
||||||
|
|
||||||
|
TP_printk(
|
||||||
|
LOCAL_PR_FMT " drop:%d",
|
||||||
|
LOCAL_PR_ARG, __entry->drop
|
||||||
|
)
|
||||||
|
);
|
||||||
#endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */
|
#endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */
|
||||||
|
|
||||||
#undef TRACE_INCLUDE_PATH
|
#undef TRACE_INCLUDE_PATH
|
||||||
|
@@ -917,6 +917,8 @@ static u32 ieee80211_idle_on(struct ieee80211_local *local)
|
|||||||
wiphy_name(local->hw.wiphy));
|
wiphy_name(local->hw.wiphy));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
drv_flush(local, false);
|
||||||
|
|
||||||
local->hw.conf.flags |= IEEE80211_CONF_IDLE;
|
local->hw.conf.flags |= IEEE80211_CONF_IDLE;
|
||||||
return IEEE80211_CONF_CHANGE_IDLE;
|
return IEEE80211_CONF_CHANGE_IDLE;
|
||||||
}
|
}
|
||||||
|
@@ -418,9 +418,10 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local)
|
|||||||
local->next_scan_state = SCAN_DECISION;
|
local->next_scan_state = SCAN_DECISION;
|
||||||
local->scan_channel_idx = 0;
|
local->scan_channel_idx = 0;
|
||||||
|
|
||||||
|
drv_flush(local, false);
|
||||||
|
|
||||||
ieee80211_configure_filter(local);
|
ieee80211_configure_filter(local);
|
||||||
|
|
||||||
/* TODO: start scan as soon as all nullfunc frames are ACKed */
|
|
||||||
ieee80211_queue_delayed_work(&local->hw,
|
ieee80211_queue_delayed_work(&local->hw,
|
||||||
&local->scan_work,
|
&local->scan_work,
|
||||||
IEEE80211_CHANNEL_TIME);
|
IEEE80211_CHANNEL_TIME);
|
||||||
@@ -584,8 +585,16 @@ static void ieee80211_scan_state_leave_oper_channel(struct ieee80211_local *loca
|
|||||||
|
|
||||||
__set_bit(SCAN_OFF_CHANNEL, &local->scanning);
|
__set_bit(SCAN_OFF_CHANNEL, &local->scanning);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* What if the nullfunc frames didn't arrive?
|
||||||
|
*/
|
||||||
|
drv_flush(local, false);
|
||||||
|
if (local->ops->flush)
|
||||||
|
*next_delay = 0;
|
||||||
|
else
|
||||||
|
*next_delay = HZ / 10;
|
||||||
|
|
||||||
/* advance to the next channel to be scanned */
|
/* advance to the next channel to be scanned */
|
||||||
*next_delay = HZ / 10;
|
|
||||||
local->next_scan_state = SCAN_SET_CHANNEL;
|
local->next_scan_state = SCAN_SET_CHANNEL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user