aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJouni Malinen <j@w1.fi>2010-03-28 22:31:04 (GMT)
committerJouni Malinen <j@w1.fi>2010-03-28 22:31:04 (GMT)
commitb625473c6c9ac968bf59932df4582e1fe33466d9 (patch)
treee5b81fbf27fa40d98c4f88d879e78f3d4f1d670e
parent93910401c976f53ade1c29895ca66b2ca9f9b6af (diff)
downloadhostap-b625473c6c9ac968bf59932df4582e1fe33466d9.zip
hostap-b625473c6c9ac968bf59932df4582e1fe33466d9.tar.gz
hostap-b625473c6c9ac968bf59932df4582e1fe33466d9.tar.bz2
Add driver command and event for signal strength monitoring
-rw-r--r--src/drivers/driver.h34
-rw-r--r--src/drivers/driver_ndis.c3
-rw-r--r--src/drivers/driver_nl80211.c50
-rw-r--r--wpa_supplicant/driver_i.h9
4 files changed, 93 insertions, 3 deletions
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 00ca97f..1d51a49 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -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;
};
/**
diff --git a/src/drivers/driver_ndis.c b/src/drivers/driver_ndis.c
index 6f28452..662b1a1 100644
--- a/src/drivers/driver_ndis.c
+++ b/src/drivers/driver_ndis.c
@@ -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 */
};
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 3fe62a7..b1007fe 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -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,
};
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index 8b312a4..71240c3 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -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 */