Add driver command and event for signal strength monitoring
This commit is contained in:
parent
93910401c9
commit
b625473c6c
4 changed files with 93 additions and 3 deletions
|
@ -1758,6 +1758,22 @@ struct wpa_driver_ops {
|
|||
* @priv: Private driver interface data
|
||||
*/
|
||||
void (*resume)(void *priv);
|
||||
|
||||
/**
|
||||
* signal_monitor - Set signal monitoring parameters
|
||||
* @priv: Private driver interface data
|
||||
* @threshold: Threshold value for signal change events; 0 = disabled
|
||||
* @hysteresis: Minimum change in signal strength before indicating a
|
||||
* new event
|
||||
* Returns: 0 on success, -1 on failure (or if not supported)
|
||||
*
|
||||
* This function can be used to configure monitoring of signal strength
|
||||
* with the current AP. Whenever signal strength drops below the
|
||||
* %threshold value or increases above it, EVENT_SIGNAL_CHANGE event
|
||||
* should be generated assuming the signal strength has changed at
|
||||
* least %hysteresis from the previously indicated signal change event.
|
||||
*/
|
||||
int (*signal_monitor)(void *priv, int threshold, int hysteresis);
|
||||
};
|
||||
|
||||
|
||||
|
@ -2030,7 +2046,16 @@ enum wpa_event_type {
|
|||
* %wpa_supplicant, this event is used only if the send_eapol() handler
|
||||
* is used to override the use of l2_packet for EAPOL frame TX.
|
||||
*/
|
||||
EVENT_EAPOL_RX
|
||||
EVENT_EAPOL_RX,
|
||||
|
||||
/**
|
||||
* EVENT_SIGNAL_CHANGE - Indicate change in signal strength
|
||||
*
|
||||
* This event is used to indicate changes in the signal strength
|
||||
* observed in frames received from the current AP if signal strength
|
||||
* monitoring has been enabled with signal_monitor().
|
||||
*/
|
||||
EVENT_SIGNAL_CHANGE
|
||||
};
|
||||
|
||||
|
||||
|
@ -2402,6 +2427,13 @@ union wpa_event_data {
|
|||
const u8 *data;
|
||||
size_t data_len;
|
||||
} eapol_rx;
|
||||
|
||||
/**
|
||||
* struct signal_change - Data for EVENT_SIGNAL_CHANGE events
|
||||
*/
|
||||
struct signal_change {
|
||||
int above_threshold;
|
||||
} signal_change;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -3274,5 +3274,6 @@ const struct wpa_driver_ops wpa_driver_ndis_ops = {
|
|||
NULL /* disable_11b_rates */,
|
||||
NULL /* deinit_ap */,
|
||||
NULL /* suspend */,
|
||||
NULL /* resume */
|
||||
NULL /* resume */,
|
||||
NULL /* signal_monitor */
|
||||
};
|
||||
|
|
|
@ -859,6 +859,7 @@ static void nl80211_cqm_event(struct wpa_driver_nl80211_data *drv,
|
|||
};
|
||||
struct nlattr *cqm[NL80211_ATTR_CQM_MAX + 1];
|
||||
enum nl80211_cqm_rssi_threshold_event event;
|
||||
union wpa_event_data ed;
|
||||
|
||||
if (tb[NL80211_ATTR_CQM] == NULL ||
|
||||
nla_parse_nested(cqm, NL80211_ATTR_CQM_MAX, tb[NL80211_ATTR_CQM],
|
||||
|
@ -870,13 +871,21 @@ static void nl80211_cqm_event(struct wpa_driver_nl80211_data *drv,
|
|||
if (cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] == NULL)
|
||||
return;
|
||||
event = nla_get_u32(cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT]);
|
||||
|
||||
os_memset(&ed, 0, sizeof(ed));
|
||||
|
||||
if (event == NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH) {
|
||||
wpa_printf(MSG_DEBUG, "nl80211: Connection quality monitor "
|
||||
"event: RSSI high");
|
||||
ed.signal_change.above_threshold = 1;
|
||||
} else if (event == NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW) {
|
||||
wpa_printf(MSG_DEBUG, "nl80211: Connection quality monitor "
|
||||
"event: RSSI low");
|
||||
}
|
||||
ed.signal_change.above_threshold = 0;
|
||||
} else
|
||||
return;
|
||||
|
||||
wpa_supplicant_event(drv->ctx, EVENT_SIGNAL_CHANGE, &ed);
|
||||
}
|
||||
|
||||
|
||||
|
@ -5190,6 +5199,44 @@ static int nl80211_send_ft_action(void *priv, u8 action, const u8 *target_ap,
|
|||
}
|
||||
|
||||
|
||||
static int nl80211_signal_monitor(void *priv, int threshold, int hysteresis)
|
||||
{
|
||||
struct i802_bss *bss = priv;
|
||||
struct wpa_driver_nl80211_data *drv = bss->drv;
|
||||
struct nl_msg *msg, *cqm = NULL;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "nl80211: Signal monitor threshold=%d "
|
||||
"hysteresis=%d", threshold, hysteresis);
|
||||
|
||||
msg = nlmsg_alloc();
|
||||
if (!msg)
|
||||
return -1;
|
||||
|
||||
genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
|
||||
0, NL80211_CMD_SET_CQM, 0);
|
||||
|
||||
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
|
||||
|
||||
cqm = nlmsg_alloc();
|
||||
if (cqm == NULL)
|
||||
return -1;
|
||||
|
||||
NLA_PUT_U32(cqm, NL80211_ATTR_CQM_RSSI_THOLD, threshold);
|
||||
NLA_PUT_U32(cqm, NL80211_ATTR_CQM_RSSI_HYST, hysteresis);
|
||||
nla_put_nested(msg, NL80211_ATTR_CQM, cqm);
|
||||
|
||||
if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
|
||||
return 0;
|
||||
msg = NULL;
|
||||
|
||||
nla_put_failure:
|
||||
if (cqm)
|
||||
nlmsg_free(cqm);
|
||||
nlmsg_free(msg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
const struct wpa_driver_ops wpa_driver_nl80211_ops = {
|
||||
.name = "nl80211",
|
||||
.desc = "Linux nl80211/cfg80211",
|
||||
|
@ -5249,4 +5296,5 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
|
|||
.deinit_ap = wpa_driver_nl80211_deinit_ap,
|
||||
.resume = wpa_driver_nl80211_resume,
|
||||
.send_ft_action = nl80211_send_ft_action,
|
||||
.signal_monitor = nl80211_signal_monitor,
|
||||
};
|
||||
|
|
|
@ -466,4 +466,13 @@ static inline void wpa_drv_resume(struct wpa_supplicant *wpa_s)
|
|||
wpa_s->driver->resume(wpa_s->drv_priv);
|
||||
}
|
||||
|
||||
static inline int wpa_drv_signal_monitor(struct wpa_supplicant *wpa_s,
|
||||
int threshold, int hysteresis)
|
||||
{
|
||||
if (wpa_s->driver->signal_monitor)
|
||||
return wpa_s->driver->signal_monitor(wpa_s->drv_priv,
|
||||
threshold, hysteresis);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif /* DRIVER_I_H */
|
||||
|
|
Loading…
Reference in a new issue