|
@@ -1648,6 +1648,46 @@ static void wpa_supplicant_ctrl_iface_drop_sa(struct wpa_supplicant *wpa_s)
|
|
|
}
|
|
|
|
|
|
|
|
|
+static int wpa_supplicant_ctrl_iface_roam(struct wpa_supplicant *wpa_s,
|
|
|
+ char *addr)
|
|
|
+{
|
|
|
+ u8 bssid[ETH_ALEN];
|
|
|
+ struct wpa_bss *bss;
|
|
|
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
|
|
|
+
|
|
|
+ if (hwaddr_aton(addr, bssid)) {
|
|
|
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: invalid "
|
|
|
+ "address '%s'", addr);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM " MACSTR, MAC2STR(bssid));
|
|
|
+
|
|
|
+ bss = wpa_bss_get_bssid(wpa_s, bssid);
|
|
|
+ if (!bss) {
|
|
|
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: Target AP not found "
|
|
|
+ "from BSS table");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * TODO: Find best network configuration block from configuration to
|
|
|
+ * allow roaming to other networks
|
|
|
+ */
|
|
|
+
|
|
|
+ if (!ssid) {
|
|
|
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: No network "
|
|
|
+ "configuration known for the target AP");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ wpa_s->reassociate = 1;
|
|
|
+ wpa_supplicant_connect(wpa_s, bss, ssid);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
|
|
|
char *buf, size_t *resp_len)
|
|
|
{
|
|
@@ -1853,6 +1893,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
|
|
|
wpas_notify_resume(wpa_s->global);
|
|
|
} else if (os_strcmp(buf, "DROP_SA") == 0) {
|
|
|
wpa_supplicant_ctrl_iface_drop_sa(wpa_s);
|
|
|
+ } else if (os_strncmp(buf, "ROAM ", 5) == 0) {
|
|
|
+ if (wpa_supplicant_ctrl_iface_roam(wpa_s, buf + 5))
|
|
|
+ reply_len = -1;
|
|
|
} else {
|
|
|
os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
|
|
|
reply_len = 16;
|