From f32227ed9ec95524d670f9936f5bf87d4e39fa2b Mon Sep 17 00:00:00 2001 From: Ravi Joshi Date: Sun, 15 Nov 2015 22:05:05 -0800 Subject: [PATCH] Add QCA vendor attribute and event to indicate subnet change status This allows offloaded roaming to inform user space of the change in IP subnet post roaming. The device may have roamed to a network which is in a different subnet which will result in IP connectivity loss. Indicating the change in subnet enables the user space to refresh the IP address or to perform IP subnet validation if unknown status is indicated. The driver indication is reported with a new event from wpa_supplicant in the following format: CTRL-EVENT-SUBNET-STATUS-UPDATE status=<0/1/2> where 0 = unknown 1 = IP subnet unchanged (can continue to use the old IP address) 2 = IP subnet changed (need to get a new IP address) Signed-off-by: Jouni Malinen --- src/common/wpa_ctrl.h | 13 +++++++++++++ src/drivers/driver.h | 6 ++++++ src/drivers/driver_nl80211_event.c | 19 ++++++++++++++++--- wpa_supplicant/events.c | 5 +++++ 4 files changed, 40 insertions(+), 3 deletions(-) diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h index 3de468235..3e0a7ec23 100644 --- a/src/common/wpa_ctrl.h +++ b/src/common/wpa_ctrl.h @@ -77,6 +77,19 @@ extern "C" { /** Regulatory domain channel */ #define WPA_EVENT_REGDOM_CHANGE "CTRL-EVENT-REGDOM-CHANGE " +/** IP subnet status change notification + * + * When using an offloaded roaming mechanism where driver/firmware takes care + * of roaming and IP subnet validation checks post-roaming, this event can + * indicate whether IP subnet has changed. + * + * The event has a status=<0/1/2> parameter where + * 0 = unknown + * 1 = IP subnet unchanged (can continue to use the old IP address) + * 2 = IP subnet changed (need to get a new IP address) + */ +#define WPA_EVENT_SUBNET_STATUS_UPDATE "CTRL-EVENT-SUBNET-STATUS-UPDATE " + /** RSN IBSS 4-way handshakes completed with specified peer */ #define IBSS_RSN_COMPLETED "IBSS-RSN-COMPLETED " diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 09c4fa182..1ed232097 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -4106,6 +4106,12 @@ union wpa_event_data { * ptk_kek_len - The length of ptk_kek */ size_t ptk_kek_len; + + /** + * subnet_status - The subnet status: + * 0 = unknown, 1 = unchanged, 2 = changed + */ + u8 subnet_status; } assoc_info; /** diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c index 721b1b91e..e8cdeeb1b 100644 --- a/src/drivers/driver_nl80211_event.c +++ b/src/drivers/driver_nl80211_event.c @@ -268,7 +268,8 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv, struct nlattr *authorized, struct nlattr *key_replay_ctr, struct nlattr *ptk_kck, - struct nlattr *ptk_kek) + struct nlattr *ptk_kek, + struct nlattr *subnet_status) { union wpa_event_data event; const u8 *ssid; @@ -367,6 +368,17 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv, event.assoc_info.ptk_kek_len = nla_len(ptk_kek); } + if (subnet_status) { + /* + * At least for now, this is only available from + * QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_SUBNET_STATUS and that + * attribute has the same values 0, 1, 2 as are used in the + * variable here, so no mapping between different values are + * needed. + */ + event.assoc_info.subnet_status = nla_get_u8(subnet_status); + } + wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event); } @@ -1600,7 +1612,8 @@ static void qca_nl80211_key_mgmt_auth(struct wpa_driver_nl80211_data *drv, tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AUTHORIZED], tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_KEY_REPLAY_CTR], tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KCK], - tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KEK]); + tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KEK], + tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_SUBNET_STATUS]); } @@ -2084,7 +2097,7 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd, tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_REQ_IE], tb[NL80211_ATTR_RESP_IE], - NULL, NULL, NULL, NULL); + NULL, NULL, NULL, NULL, NULL); break; case NL80211_CMD_CH_SWITCH_NOTIFY: mlme_event_ch_switch(drv, diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index 9bd791b04..547aa9839 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -3256,6 +3256,11 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, wpa_supplicant_event_assoc(wpa_s, data); if (data && data->assoc_info.authorized) wpa_supplicant_event_assoc_auth(wpa_s, data); + if (data) { + wpa_msg(wpa_s, MSG_INFO, + WPA_EVENT_SUBNET_STATUS_UPDATE "status=%u", + data->assoc_info.subnet_status); + } break; case EVENT_DISASSOC: wpas_event_disassoc(wpa_s,