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
|
* @priv: Private driver interface data
|
||||||
*/
|
*/
|
||||||
void (*resume)(void *priv);
|
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
|
* %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.
|
* 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;
|
const u8 *data;
|
||||||
size_t data_len;
|
size_t data_len;
|
||||||
} eapol_rx;
|
} 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 /* disable_11b_rates */,
|
||||||
NULL /* deinit_ap */,
|
NULL /* deinit_ap */,
|
||||||
NULL /* suspend */,
|
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];
|
struct nlattr *cqm[NL80211_ATTR_CQM_MAX + 1];
|
||||||
enum nl80211_cqm_rssi_threshold_event event;
|
enum nl80211_cqm_rssi_threshold_event event;
|
||||||
|
union wpa_event_data ed;
|
||||||
|
|
||||||
if (tb[NL80211_ATTR_CQM] == NULL ||
|
if (tb[NL80211_ATTR_CQM] == NULL ||
|
||||||
nla_parse_nested(cqm, NL80211_ATTR_CQM_MAX, tb[NL80211_ATTR_CQM],
|
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)
|
if (cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] == NULL)
|
||||||
return;
|
return;
|
||||||
event = nla_get_u32(cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT]);
|
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) {
|
if (event == NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH) {
|
||||||
wpa_printf(MSG_DEBUG, "nl80211: Connection quality monitor "
|
wpa_printf(MSG_DEBUG, "nl80211: Connection quality monitor "
|
||||||
"event: RSSI high");
|
"event: RSSI high");
|
||||||
|
ed.signal_change.above_threshold = 1;
|
||||||
} else if (event == NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW) {
|
} else if (event == NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW) {
|
||||||
wpa_printf(MSG_DEBUG, "nl80211: Connection quality monitor "
|
wpa_printf(MSG_DEBUG, "nl80211: Connection quality monitor "
|
||||||
"event: RSSI low");
|
"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 = {
|
const struct wpa_driver_ops wpa_driver_nl80211_ops = {
|
||||||
.name = "nl80211",
|
.name = "nl80211",
|
||||||
.desc = "Linux nl80211/cfg80211",
|
.desc = "Linux nl80211/cfg80211",
|
||||||
|
@ -5249,4 +5296,5 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
|
||||||
.deinit_ap = wpa_driver_nl80211_deinit_ap,
|
.deinit_ap = wpa_driver_nl80211_deinit_ap,
|
||||||
.resume = wpa_driver_nl80211_resume,
|
.resume = wpa_driver_nl80211_resume,
|
||||||
.send_ft_action = nl80211_send_ft_action,
|
.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);
|
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 */
|
#endif /* DRIVER_I_H */
|
||||||
|
|
Loading…
Reference in a new issue