From 603a3f34c44cbcd9f843ed18b5accaf9540d6755 Mon Sep 17 00:00:00 2001 From: Javier Lopez Date: Mon, 1 Sep 2014 00:23:33 -0400 Subject: [PATCH] Add mesh_group_{add,remove} control interface commands Parse MESH_GROUP_ADD/REMOVE commands on ctrl interface and call wpa_supplicant routines. These commands are used to start or join and leave a mesh network. The mesh id is given in the configuration file, therefore there is no need to scan before joining a mesh network. We reuse the connect_without_scan construct used by P2P for that same purpose. Signed-off-by: Javier Cardona Signed-off-by: Javier Lopez --- src/common/wpa_ctrl.h | 2 + wpa_supplicant/ctrl_iface.c | 80 +++++++++++++++++++++++++++++++++ wpa_supplicant/wpa_cli.c | 26 +++++++++++ wpa_supplicant/wpa_supplicant.c | 52 +++++++++++++++++++-- 4 files changed, 157 insertions(+), 3 deletions(-) diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h index af1e77686..a91cc38fd 100644 --- a/src/common/wpa_ctrl.h +++ b/src/common/wpa_ctrl.h @@ -121,6 +121,8 @@ extern "C" { #define WPS_EVENT_ER_SET_SEL_REG "WPS-ER-AP-SET-SEL-REG " /* MESH events */ +#define MESH_GROUP_STARTED "MESH-GROUP-STARTED " +#define MESH_GROUP_REMOVED "MESH-GROUP-REMOVED " #define MESH_PEER_CONNECTED "MESH-PEER-CONNECTED " #define MESH_PEER_DISCONNECTED "MESH-PEER-DISCONNECTED " diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 1c4844ce3..b7eeb14cb 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -2365,6 +2365,77 @@ static int wpa_supplicant_ctrl_iface_scan_results( } +#ifdef CONFIG_MESH + +static int wpa_supplicant_ctrl_iface_mesh_group_add( + struct wpa_supplicant *wpa_s, char *cmd) +{ + int id; + struct wpa_ssid *ssid; + + id = atoi(cmd); + wpa_printf(MSG_DEBUG, "CTRL_IFACE: MESH_GROUP_ADD id=%d", id); + + ssid = wpa_config_get_network(wpa_s->conf, id); + if (ssid == NULL) { + wpa_printf(MSG_DEBUG, + "CTRL_IFACE: Could not find network id=%d", id); + return -1; + } + if (ssid->mode != WPAS_MODE_MESH) { + wpa_printf(MSG_DEBUG, + "CTRL_IFACE: Cannot use MESH_GROUP_ADD on a non mesh network"); + return -1; + } + + /* + * TODO: If necessary write our own group_add function, + * for now we can reuse select_network + */ + wpa_supplicant_select_network(wpa_s, ssid); + + return 0; +} + + +static int wpa_supplicant_ctrl_iface_mesh_group_remove( + struct wpa_supplicant *wpa_s, char *cmd) +{ + if (!cmd) { + wpa_printf(MSG_ERROR, + "CTRL_IFACE: MESH_GROUP_REMOVE ifname cannot be empty"); + return -1; + } + + /* + * TODO: Support a multiple mesh and other iface type combinations + */ + if (os_strcmp(cmd, wpa_s->ifname) != 0) { + wpa_printf(MSG_DEBUG, + "CTRL_IFACE: MESH_GROUP_REMOVE unknown interface name: %s", + cmd); + return -1; + } + + wpa_printf(MSG_DEBUG, "CTRL_IFACE: MESH_GROUP_REMOVE ifname=%s", cmd); + + wpa_s->reassociate = 0; + wpa_s->disconnected = 1; + wpa_supplicant_cancel_sched_scan(wpa_s); + wpa_supplicant_cancel_scan(wpa_s); + + /* + * TODO: If necessary write our own group_remove function, + * for now we can reuse deauthenticate + */ + wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); + + return 0; +} + +#endif /* CONFIG_MESH */ + + static int wpa_supplicant_ctrl_iface_select_network( struct wpa_supplicant *wpa_s, char *cmd) { @@ -6904,6 +6975,15 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, if (wpa_supplicant_ctrl_iface_ibss_rsn(wpa_s, buf + 9)) reply_len = -1; #endif /* CONFIG_IBSS_RSN */ +#ifdef CONFIG_MESH + } else if (os_strncmp(buf, "MESH_GROUP_ADD ", 15) == 0) { + if (wpa_supplicant_ctrl_iface_mesh_group_add(wpa_s, buf + 15)) + reply_len = -1; + } else if (os_strncmp(buf, "MESH_GROUP_REMOVE ", 18) == 0) { + if (wpa_supplicant_ctrl_iface_mesh_group_remove(wpa_s, + buf + 18)) + reply_len = -1; +#endif /* CONFIG_MESH */ #ifdef CONFIG_P2P } else if (os_strncmp(buf, "P2P_FIND ", 9) == 0) { if (p2p_ctrl_find(wpa_s, buf + 9)) diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c index 2bb3b6583..5a3d1f69e 100644 --- a/wpa_supplicant/wpa_cli.c +++ b/wpa_supplicant/wpa_cli.c @@ -1752,6 +1752,24 @@ static int wpa_cli_cmd_roam(struct wpa_ctrl *ctrl, int argc, char *argv[]) } +#ifdef CONFIG_MESH + +static int wpa_cli_cmd_mesh_group_add(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "MESH_GROUP_ADD", 1, argc, argv); +} + + +static int wpa_cli_cmd_mesh_group_remove(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "MESH_GROUP_REMOVE", 1, argc, argv); +} + +#endif /* CONFIG_MESH */ + + #ifdef CONFIG_P2P static int wpa_cli_cmd_p2p_find(struct wpa_ctrl *ctrl, int argc, char *argv[]) @@ -2781,6 +2799,14 @@ static struct wpa_cli_cmd wpa_cli_commands[] = { { "roam", wpa_cli_cmd_roam, wpa_cli_complete_bss, cli_cmd_flag_none, " = roam to the specified BSS" }, +#ifdef CONFIG_MESH + { "mesh_group_add", wpa_cli_cmd_mesh_group_add, NULL, + cli_cmd_flag_none, + " = join a mesh network (disable others)" }, + { "mesh_group_remove", wpa_cli_cmd_mesh_group_remove, NULL, + cli_cmd_flag_none, + " = Remove mesh group interface" }, +#endif /* CONFIG_MESH */ #ifdef CONFIG_P2P { "p2p_find", wpa_cli_cmd_p2p_find, wpa_cli_complete_p2p_find, cli_cmd_flag_none, diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 7e761e71a..695004856 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -52,6 +52,7 @@ #include "hs20_supplicant.h" #include "wnm_sta.h" #include "wpas_kay.h" +#include "mesh.h" const char *wpa_supplicant_version = "wpa_supplicant v" VERSION_STR "\n" @@ -1532,6 +1533,31 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s, return; } + if (ssid->mode == WPAS_MODE_MESH) { +#ifdef CONFIG_MESH + if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_MESH)) { + wpa_msg(wpa_s, MSG_INFO, + "Driver does not support mesh mode"); + return; + } + if (bss) + ssid->frequency = bss->freq; + if (wpa_supplicant_join_mesh(wpa_s, ssid) < 0) { + wpa_msg(wpa_s, MSG_ERROR, "Could not join mesh"); + return; + } + wpa_s->current_bss = bss; + wpa_msg_ctrl(wpa_s, MSG_INFO, MESH_GROUP_STARTED + "ssid=\"%s\" id=%d", + wpa_ssid_txt(ssid->ssid, ssid->ssid_len), + ssid->id); +#else /* CONFIG_MESH */ + wpa_msg(wpa_s, MSG_ERROR, + "mesh mode support not included in the build"); +#endif /* CONFIG_MESH */ + return; + } + #ifdef CONFIG_TDLS if (bss) wpa_tdls_ap_ies(wpa_s->wpa, (const u8 *) (bss + 1), @@ -1879,8 +1905,9 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) params.fixed_bssid = 1; } - if (ssid->mode == WPAS_MODE_IBSS && ssid->frequency > 0 && - params.freq.freq == 0) { + /* Initial frequency for IBSS/mesh */ + if ((ssid->mode == WPAS_MODE_IBSS || ssid->mode == WPAS_MODE_MESH) && + ssid->frequency > 0 && params.freq.freq == 0) { enum hostapd_hw_mode hw_mode; u8 channel; @@ -2143,6 +2170,14 @@ void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s, wpa_tdls_teardown_peers(wpa_s->wpa); #endif /* CONFIG_TDLS */ +#ifdef CONFIG_MESH + if (wpa_s->ifmsh) { + wpa_msg_ctrl(wpa_s, MSG_INFO, MESH_GROUP_REMOVED "%s", + wpa_s->ifname); + wpa_supplicant_leave_mesh(wpa_s); + } +#endif /* CONFIG_MESH */ + if (addr) { wpa_drv_deauthenticate(wpa_s, addr, reason_code); os_memset(&event, 0, sizeof(event)); @@ -2308,8 +2343,12 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s, if (ssid) { wpa_s->current_ssid = ssid; eapol_sm_notify_config(wpa_s->eapol, NULL, NULL); + wpa_s->connect_without_scan = + (ssid->mode == WPAS_MODE_MESH) ? ssid : NULL; + } else { + wpa_s->connect_without_scan = NULL; } - wpa_s->connect_without_scan = NULL; + wpa_s->disconnected = 0; wpa_s->reassociate = 1; @@ -3928,6 +3967,13 @@ static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s, wpa_s->ctrl_iface = NULL; } +#ifdef CONFIG_MESH + if (wpa_s->ifmsh) { + wpa_supplicant_mesh_iface_deinit(wpa_s, wpa_s->ifmsh); + wpa_s->ifmsh = NULL; + } +#endif /* CONFIG_MESH */ + if (wpa_s->conf != NULL) { wpa_config_free(wpa_s->conf); wpa_s->conf = NULL;