*/
#define IEEE80211_BSS_ARP_ADDR_LIST_LEN 4
+/**
+ * enum ieee80211_rssi_event - RSSI threshold event
+ * An indicator for when RSSI goes below/above a certain threshold.
+ * @RSSI_EVENT_HIGH: AP's rssi crossed the high threshold set by the driver.
+ * @RSSI_EVENT_LOW: AP's rssi crossed the low threshold set by the driver.
+ */
+enum ieee80211_rssi_event {
+ RSSI_EVENT_HIGH,
+ RSSI_EVENT_LOW,
+};
+
/**
* struct ieee80211_bss_conf - holds the BSS's changing parameters
*
* @set_bitrate_mask: Set a mask of rates to be used for rate control selection
* when transmitting a frame. Currently only legacy rates are handled.
* The callback can sleep.
+ * @rssi_callback: Notify driver when the average RSSI goes above/below
+ * thresholds that were registered previously. The callback can sleep.
*/
struct ieee80211_ops {
void (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb);
bool (*tx_frames_pending)(struct ieee80211_hw *hw);
int (*set_bitrate_mask)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
const struct cfg80211_bitrate_mask *mask);
+ void (*rssi_callback)(struct ieee80211_hw *hw,
+ enum ieee80211_rssi_event rssi_event);
};
/**
return ieee80211_iftype_p2p(vif->type, vif->p2p);
}
+void ieee80211_enable_rssi_reports(struct ieee80211_vif *vif,
+ int rssi_min_thold,
+ int rssi_max_thold);
+
+void ieee80211_disable_rssi_reports(struct ieee80211_vif *vif);
#endif /* MAC80211_H */
trace_drv_return_void(local);
}
+static inline void drv_rssi_callback(struct ieee80211_local *local,
+ const enum ieee80211_rssi_event event)
+{
+ trace_drv_rssi_callback(local, event);
+ if (local->ops->rssi_callback)
+ local->ops->rssi_callback(&local->hw, event);
+ trace_drv_return_void(local);
+}
#endif /* __MAC80211_DRIVER_OPS */
LOCAL_PR_ARG, VIF_PR_ARG)
);
+TRACE_EVENT(drv_rssi_callback,
+ TP_PROTO(struct ieee80211_local *local,
+ enum ieee80211_rssi_event rssi_event),
+
+ TP_ARGS(local, rssi_event),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ __field(u32, rssi_event)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ __entry->rssi_event = rssi_event;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT " rssi_event:%d",
+ LOCAL_PR_ARG, __entry->rssi_event
+ )
+);
+
/*
* Tracing for API calls that drivers call.
*/
TP_printk(VIF_PR_FMT, VIF_PR_ARG)
);
+TRACE_EVENT(api_enable_rssi_reports,
+ TP_PROTO(struct ieee80211_sub_if_data *sdata,
+ int rssi_min_thold, int rssi_max_thold),
+
+ TP_ARGS(sdata, rssi_min_thold, rssi_max_thold),
+
+ TP_STRUCT__entry(
+ VIF_ENTRY
+ __field(int, rssi_min_thold)
+ __field(int, rssi_max_thold)
+ ),
+
+ TP_fast_assign(
+ VIF_ASSIGN;
+ __entry->rssi_min_thold = rssi_min_thold;
+ __entry->rssi_max_thold = rssi_max_thold;
+ ),
+
+ TP_printk(
+ VIF_PR_FMT " rssi_min_thold =%d, rssi_max_thold = %d",
+ VIF_PR_ARG, __entry->rssi_min_thold, __entry->rssi_max_thold
+ )
+);
+
/*
* Tracing for internal functions
* (which may also be called in response to driver calls)
* generated for the current association.
*/
int last_cqm_event_signal;
+
+ /*
+ * State variables for keeping track of RSSI of the AP currently
+ * connected to and informing driver when RSSI has gone
+ * below/above a certain threshold.
+ */
+ int rssi_min_thold, rssi_max_thold;
+ int last_ave_beacon_signal;
};
struct ieee80211_if_ibss {
ifmgd->ave_beacon_signal = rx_status->signal * 16;
ifmgd->last_cqm_event_signal = 0;
ifmgd->count_beacon_signal = 1;
+ ifmgd->last_ave_beacon_signal = 0;
} else {
ifmgd->ave_beacon_signal =
(IEEE80211_SIGNAL_AVE_WEIGHT * rx_status->signal * 16 +
ifmgd->ave_beacon_signal) / 16;
ifmgd->count_beacon_signal++;
}
+
+ if (ifmgd->rssi_min_thold != ifmgd->rssi_max_thold &&
+ ifmgd->count_beacon_signal >= IEEE80211_SIGNAL_AVE_MIN_COUNT) {
+ int sig = ifmgd->ave_beacon_signal;
+ int last_sig = ifmgd->last_ave_beacon_signal;
+
+ /*
+ * if signal crosses either of the boundaries, invoke callback
+ * with appropriate parameters
+ */
+ if (sig > ifmgd->rssi_max_thold &&
+ (last_sig <= ifmgd->rssi_min_thold || last_sig == 0)) {
+ ifmgd->last_ave_beacon_signal = sig;
+ drv_rssi_callback(local, RSSI_EVENT_HIGH);
+ } else if (sig < ifmgd->rssi_min_thold &&
+ (last_sig >= ifmgd->rssi_max_thold ||
+ last_sig == 0)) {
+ ifmgd->last_ave_beacon_signal = sig;
+ drv_rssi_callback(local, RSSI_EVENT_LOW);
+ }
+ }
+
if (bss_conf->cqm_rssi_thold &&
ifmgd->count_beacon_signal >= IEEE80211_SIGNAL_AVE_MIN_COUNT &&
!(local->hw.flags & IEEE80211_HW_SUPPORTS_CQM_RSSI)) {
return pos;
}
+
+static void _ieee80211_enable_rssi_reports(struct ieee80211_sub_if_data *sdata,
+ int rssi_min_thold,
+ int rssi_max_thold)
+{
+ trace_api_enable_rssi_reports(sdata, rssi_min_thold, rssi_max_thold);
+
+ if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION))
+ return;
+
+ /*
+ * Scale up threshold values before storing it, as the RSSI averaging
+ * algorithm uses a scaled up value as well. Change this scaling
+ * factor if the RSSI averaging algorithm changes.
+ */
+ sdata->u.mgd.rssi_min_thold = rssi_min_thold*16;
+ sdata->u.mgd.rssi_max_thold = rssi_max_thold*16;
+}
+
+void ieee80211_enable_rssi_reports(struct ieee80211_vif *vif,
+ int rssi_min_thold,
+ int rssi_max_thold)
+{
+ struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+
+ WARN_ON(rssi_min_thold == rssi_max_thold ||
+ rssi_min_thold > rssi_max_thold);
+
+ _ieee80211_enable_rssi_reports(sdata, rssi_min_thold,
+ rssi_max_thold);
+}
+EXPORT_SYMBOL(ieee80211_enable_rssi_reports);
+
+void ieee80211_disable_rssi_reports(struct ieee80211_vif *vif)
+{
+ struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+
+ _ieee80211_enable_rssi_reports(sdata, 0, 0);
+}
+EXPORT_SYMBOL(ieee80211_disable_rssi_reports);