mesh: Add mesh interface creation command for mesh gate
The mesh gate is used to bridge (or route) between mesh network and another network. For example, mesh gate acts as router between mesh network and IEEE 802.11 BSS network. This command makes a virtual mesh interface to be used for mesh gate. This command expects to be used like this. wpa_cli -i wlan0 MESH_INTERFACE_ADD ifname=mesh0 wpa_cli -i mesh0 add_network wpa_cli -i mesh0 set_network 0 ssid '"commell_2X_mmm"' wpa_cli -i mesh0 set_network 0 mode 5 wpa_cli -i mesh0 set_network 0 frequency 2412 wpa_cli -i mesh0 set_network 0 key_mgmt SAE wpa_cli -i mesh0 set_network 0 psk '"01234567"' wpa_cli -i mesh0 mesh_group_add 0 wpa_cli -i wlan0 mesh_group_remove mesh0 Signed-off-by: Masashi Honma <masashi.honma@gmail.com>
This commit is contained in:
parent
bd0b620371
commit
5b78493f3b
8 changed files with 166 additions and 19 deletions
|
@ -1244,7 +1244,12 @@ enum wpa_driver_if_type {
|
||||||
* WPA_IF_P2P_DEVICE - P2P Device interface is used to indentify the
|
* WPA_IF_P2P_DEVICE - P2P Device interface is used to indentify the
|
||||||
* abstracted P2P Device function in the driver
|
* abstracted P2P Device function in the driver
|
||||||
*/
|
*/
|
||||||
WPA_IF_P2P_DEVICE
|
WPA_IF_P2P_DEVICE,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* WPA_IF_MESH - Mesh interface
|
||||||
|
*/
|
||||||
|
WPA_IF_MESH,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct wpa_init_params {
|
struct wpa_init_params {
|
||||||
|
|
|
@ -5594,12 +5594,14 @@ static enum nl80211_iftype wpa_driver_nl80211_if_type(
|
||||||
return NL80211_IFTYPE_P2P_GO;
|
return NL80211_IFTYPE_P2P_GO;
|
||||||
case WPA_IF_P2P_DEVICE:
|
case WPA_IF_P2P_DEVICE:
|
||||||
return NL80211_IFTYPE_P2P_DEVICE;
|
return NL80211_IFTYPE_P2P_DEVICE;
|
||||||
|
case WPA_IF_MESH:
|
||||||
|
return NL80211_IFTYPE_MESH_POINT;
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef CONFIG_P2P
|
#if defined(CONFIG_P2P) || defined(CONFIG_MESH)
|
||||||
|
|
||||||
static int nl80211_addr_in_use(struct nl80211_global *global, const u8 *addr)
|
static int nl80211_addr_in_use(struct nl80211_global *global, const u8 *addr)
|
||||||
{
|
{
|
||||||
|
@ -5613,8 +5615,7 @@ static int nl80211_addr_in_use(struct nl80211_global *global, const u8 *addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int nl80211_p2p_interface_addr(struct wpa_driver_nl80211_data *drv,
|
static int nl80211_vif_addr(struct wpa_driver_nl80211_data *drv, u8 *new_addr)
|
||||||
u8 *new_addr)
|
|
||||||
{
|
{
|
||||||
unsigned int idx;
|
unsigned int idx;
|
||||||
|
|
||||||
|
@ -5631,13 +5632,13 @@ static int nl80211_p2p_interface_addr(struct wpa_driver_nl80211_data *drv,
|
||||||
if (idx == 64)
|
if (idx == 64)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "nl80211: Assigned new P2P Interface Address "
|
wpa_printf(MSG_DEBUG, "nl80211: Assigned new virtual interface address "
|
||||||
MACSTR, MAC2STR(new_addr));
|
MACSTR, MAC2STR(new_addr));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* CONFIG_P2P */
|
#endif /* CONFIG_P2P || CONFIG_MESH */
|
||||||
|
|
||||||
|
|
||||||
struct wdev_info {
|
struct wdev_info {
|
||||||
|
@ -5724,10 +5725,10 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_P2P
|
#if defined(CONFIG_P2P) || defined(CONFIG_MESH)
|
||||||
if (!addr &&
|
if (!addr &&
|
||||||
(type == WPA_IF_P2P_CLIENT || type == WPA_IF_P2P_GROUP ||
|
(type == WPA_IF_P2P_CLIENT || type == WPA_IF_P2P_GROUP ||
|
||||||
type == WPA_IF_P2P_GO)) {
|
type == WPA_IF_P2P_GO || type == WPA_IF_MESH)) {
|
||||||
/* Enforce unique P2P Interface Address */
|
/* Enforce unique P2P Interface Address */
|
||||||
u8 new_addr[ETH_ALEN];
|
u8 new_addr[ETH_ALEN];
|
||||||
|
|
||||||
|
@ -5739,8 +5740,9 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
|
||||||
}
|
}
|
||||||
if (nl80211_addr_in_use(drv->global, new_addr)) {
|
if (nl80211_addr_in_use(drv->global, new_addr)) {
|
||||||
wpa_printf(MSG_DEBUG, "nl80211: Allocate new address "
|
wpa_printf(MSG_DEBUG, "nl80211: Allocate new address "
|
||||||
"for P2P group interface");
|
"for %s interface", type == WPA_IF_MESH ?
|
||||||
if (nl80211_p2p_interface_addr(drv, new_addr) < 0) {
|
"mesh" : "P2P group");
|
||||||
|
if (nl80211_vif_addr(drv, new_addr) < 0) {
|
||||||
if (added)
|
if (added)
|
||||||
nl80211_remove_iface(drv, ifidx);
|
nl80211_remove_iface(drv, ifidx);
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -5754,7 +5756,7 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
|
||||||
}
|
}
|
||||||
os_memcpy(if_addr, new_addr, ETH_ALEN);
|
os_memcpy(if_addr, new_addr, ETH_ALEN);
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_P2P */
|
#endif /* CONFIG_P2P || CONFIG_MESH */
|
||||||
|
|
||||||
if (type == WPA_IF_AP_BSS) {
|
if (type == WPA_IF_AP_BSS) {
|
||||||
struct i802_bss *new_bss = os_zalloc(sizeof(*new_bss));
|
struct i802_bss *new_bss = os_zalloc(sizeof(*new_bss));
|
||||||
|
|
|
@ -2423,6 +2423,27 @@ static int wpa_supplicant_ctrl_iface_scan_results(
|
||||||
|
|
||||||
#ifdef CONFIG_MESH
|
#ifdef CONFIG_MESH
|
||||||
|
|
||||||
|
static int wpa_supplicant_ctrl_iface_mesh_interface_add(
|
||||||
|
struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len)
|
||||||
|
{
|
||||||
|
char *pos, ifname[IFNAMSIZ + 1];
|
||||||
|
|
||||||
|
ifname[0] = '\0';
|
||||||
|
|
||||||
|
pos = os_strstr(cmd, "ifname=");
|
||||||
|
if (pos) {
|
||||||
|
pos += 7;
|
||||||
|
os_strlcpy(ifname, pos, sizeof(ifname));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wpas_mesh_add_interface(wpa_s, ifname, sizeof(ifname)) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
os_strlcpy(reply, ifname, max_len);
|
||||||
|
return os_strlen(ifname);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int wpa_supplicant_ctrl_iface_mesh_group_add(
|
static int wpa_supplicant_ctrl_iface_mesh_group_add(
|
||||||
struct wpa_supplicant *wpa_s, char *cmd)
|
struct wpa_supplicant *wpa_s, char *cmd)
|
||||||
{
|
{
|
||||||
|
@ -2463,17 +2484,32 @@ static int wpa_supplicant_ctrl_iface_mesh_group_add(
|
||||||
static int wpa_supplicant_ctrl_iface_mesh_group_remove(
|
static int wpa_supplicant_ctrl_iface_mesh_group_remove(
|
||||||
struct wpa_supplicant *wpa_s, char *cmd)
|
struct wpa_supplicant *wpa_s, char *cmd)
|
||||||
{
|
{
|
||||||
/*
|
struct wpa_supplicant *orig;
|
||||||
* TODO: Support a multiple mesh and other iface type combinations
|
struct wpa_global *global;
|
||||||
*/
|
int found = 0;
|
||||||
if (os_strcmp(cmd, wpa_s->ifname) != 0) {
|
|
||||||
wpa_printf(MSG_DEBUG,
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE: MESH_GROUP_REMOVE ifname=%s", cmd);
|
||||||
"CTRL_IFACE: MESH_GROUP_REMOVE unknown interface name: %s",
|
|
||||||
|
global = wpa_s->global;
|
||||||
|
orig = wpa_s;
|
||||||
|
|
||||||
|
for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
|
||||||
|
if (os_strcmp(wpa_s->ifname, cmd) == 0) {
|
||||||
|
found = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
wpa_printf(MSG_ERROR,
|
||||||
|
"CTRL_IFACE: MESH_GROUP_REMOVE ifname=%s not found",
|
||||||
cmd);
|
cmd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
if (wpa_s->mesh_if_created && wpa_s == orig) {
|
||||||
wpa_printf(MSG_DEBUG, "CTRL_IFACE: MESH_GROUP_REMOVE ifname=%s", cmd);
|
wpa_printf(MSG_ERROR,
|
||||||
|
"CTRL_IFACE: MESH_GROUP_REMOVE can't remove itself");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
wpa_s->reassociate = 0;
|
wpa_s->reassociate = 0;
|
||||||
wpa_s->disconnected = 1;
|
wpa_s->disconnected = 1;
|
||||||
|
@ -2486,6 +2522,9 @@ static int wpa_supplicant_ctrl_iface_mesh_group_remove(
|
||||||
*/
|
*/
|
||||||
wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
|
wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
|
||||||
|
|
||||||
|
if (wpa_s->mesh_if_created)
|
||||||
|
wpa_supplicant_remove_iface(global, wpa_s, 0);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7175,6 +7214,12 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
|
||||||
reply_len = -1;
|
reply_len = -1;
|
||||||
#endif /* CONFIG_IBSS_RSN */
|
#endif /* CONFIG_IBSS_RSN */
|
||||||
#ifdef CONFIG_MESH
|
#ifdef CONFIG_MESH
|
||||||
|
} else if (os_strncmp(buf, "MESH_INTERFACE_ADD ", 19) == 0) {
|
||||||
|
reply_len = wpa_supplicant_ctrl_iface_mesh_interface_add(
|
||||||
|
wpa_s, buf + 19, reply, reply_size);
|
||||||
|
} else if (os_strcmp(buf, "MESH_INTERFACE_ADD") == 0) {
|
||||||
|
reply_len = wpa_supplicant_ctrl_iface_mesh_interface_add(
|
||||||
|
wpa_s, "", reply, reply_size);
|
||||||
} else if (os_strncmp(buf, "MESH_GROUP_ADD ", 15) == 0) {
|
} else if (os_strncmp(buf, "MESH_GROUP_ADD ", 15) == 0) {
|
||||||
if (wpa_supplicant_ctrl_iface_mesh_group_add(wpa_s, buf + 15))
|
if (wpa_supplicant_ctrl_iface_mesh_group_add(wpa_s, buf + 15))
|
||||||
reply_len = -1;
|
reply_len = -1;
|
||||||
|
|
|
@ -474,3 +474,62 @@ int wpas_mesh_scan_result_text(const u8 *ies, size_t ies_len, char *buf,
|
||||||
{
|
{
|
||||||
return mesh_attr_text(ies, ies_len, buf, end);
|
return mesh_attr_text(ies, ies_len, buf, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int wpas_mesh_get_ifname(struct wpa_supplicant *wpa_s, char *ifname,
|
||||||
|
size_t len)
|
||||||
|
{
|
||||||
|
char *ifname_ptr = wpa_s->ifname;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
res = os_snprintf(ifname, len, "mesh-%s-%d", ifname_ptr,
|
||||||
|
wpa_s->mesh_if_idx);
|
||||||
|
if (os_snprintf_error(len, res) ||
|
||||||
|
(os_strlen(ifname) >= IFNAMSIZ &&
|
||||||
|
os_strlen(wpa_s->ifname) < IFNAMSIZ)) {
|
||||||
|
/* Try to avoid going over the IFNAMSIZ length limit */
|
||||||
|
res = os_snprintf(ifname, len, "mesh-%d", wpa_s->mesh_if_idx);
|
||||||
|
if (os_snprintf_error(len, res))
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
wpa_s->mesh_if_idx++;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int wpas_mesh_add_interface(struct wpa_supplicant *wpa_s, char *ifname,
|
||||||
|
size_t len)
|
||||||
|
{
|
||||||
|
struct wpa_interface iface;
|
||||||
|
struct wpa_supplicant *mesh_wpa_s;
|
||||||
|
u8 addr[ETH_ALEN];
|
||||||
|
|
||||||
|
if (ifname[0] == '\0' && wpas_mesh_get_ifname(wpa_s, ifname, len) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (wpa_drv_if_add(wpa_s, WPA_IF_MESH, ifname, NULL, NULL, NULL, addr,
|
||||||
|
NULL) < 0) {
|
||||||
|
wpa_printf(MSG_ERROR,
|
||||||
|
"mesh: Failed to create new mesh interface");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
wpa_printf(MSG_INFO, "mesh: Created virtual interface %s addr "
|
||||||
|
MACSTR, ifname, MAC2STR(addr));
|
||||||
|
|
||||||
|
os_memset(&iface, 0, sizeof(iface));
|
||||||
|
iface.ifname = ifname;
|
||||||
|
iface.driver = wpa_s->driver->name;
|
||||||
|
iface.driver_param = wpa_s->conf->driver_param;
|
||||||
|
iface.ctrl_interface = wpa_s->conf->ctrl_interface;
|
||||||
|
|
||||||
|
mesh_wpa_s = wpa_supplicant_add_iface(wpa_s->global, &iface);
|
||||||
|
if (!mesh_wpa_s) {
|
||||||
|
wpa_printf(MSG_ERROR,
|
||||||
|
"mesh: Failed to create new wpa_supplicant interface");
|
||||||
|
wpa_supplicant_remove_iface(wpa_s->global, wpa_s, 0);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
mesh_wpa_s->mesh_if_created = 1;
|
||||||
|
mesh_wpa_s->parent = wpa_s;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -16,6 +16,8 @@ void wpa_supplicant_mesh_iface_deinit(struct wpa_supplicant *wpa_s,
|
||||||
struct hostapd_iface *ifmsh);
|
struct hostapd_iface *ifmsh);
|
||||||
int wpas_mesh_scan_result_text(const u8 *ies, size_t ies_len, char *buf,
|
int wpas_mesh_scan_result_text(const u8 *ies, size_t ies_len, char *buf,
|
||||||
char *end);
|
char *end);
|
||||||
|
int wpas_mesh_add_interface(struct wpa_supplicant *wpa_s, char *ifname,
|
||||||
|
size_t len);
|
||||||
|
|
||||||
#ifdef CONFIG_MESH
|
#ifdef CONFIG_MESH
|
||||||
|
|
||||||
|
|
|
@ -1754,6 +1754,13 @@ static int wpa_cli_cmd_roam(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||||
|
|
||||||
#ifdef CONFIG_MESH
|
#ifdef CONFIG_MESH
|
||||||
|
|
||||||
|
static int wpa_cli_cmd_mesh_interface_add(struct wpa_ctrl *ctrl, int argc,
|
||||||
|
char *argv[])
|
||||||
|
{
|
||||||
|
return wpa_cli_cmd(ctrl, "MESH_INTERFACE_ADD", 0, argc, argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int wpa_cli_cmd_mesh_group_add(struct wpa_ctrl *ctrl, int argc,
|
static int wpa_cli_cmd_mesh_group_add(struct wpa_ctrl *ctrl, int argc,
|
||||||
char *argv[])
|
char *argv[])
|
||||||
{
|
{
|
||||||
|
@ -2834,6 +2841,9 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
|
||||||
cli_cmd_flag_none,
|
cli_cmd_flag_none,
|
||||||
"<addr> = roam to the specified BSS" },
|
"<addr> = roam to the specified BSS" },
|
||||||
#ifdef CONFIG_MESH
|
#ifdef CONFIG_MESH
|
||||||
|
{ "mesh_interface_add", wpa_cli_cmd_mesh_interface_add, NULL,
|
||||||
|
cli_cmd_flag_none,
|
||||||
|
"[ifname] = Create a new mesh interface" },
|
||||||
{ "mesh_group_add", wpa_cli_cmd_mesh_group_add, NULL,
|
{ "mesh_group_add", wpa_cli_cmd_mesh_group_add, NULL,
|
||||||
cli_cmd_flag_none,
|
cli_cmd_flag_none,
|
||||||
"<network id> = join a mesh network (disable others)" },
|
"<network id> = join a mesh network (disable others)" },
|
||||||
|
|
|
@ -4085,6 +4085,10 @@ int wpa_supplicant_remove_iface(struct wpa_global *global,
|
||||||
int terminate)
|
int terminate)
|
||||||
{
|
{
|
||||||
struct wpa_supplicant *prev;
|
struct wpa_supplicant *prev;
|
||||||
|
#ifdef CONFIG_MESH
|
||||||
|
unsigned int mesh_if_created = wpa_s->mesh_if_created;
|
||||||
|
char *ifname = NULL;
|
||||||
|
#endif /* CONFIG_MESH */
|
||||||
|
|
||||||
/* Remove interface from the global list of interfaces */
|
/* Remove interface from the global list of interfaces */
|
||||||
prev = global->ifaces;
|
prev = global->ifaces;
|
||||||
|
@ -4100,12 +4104,30 @@ int wpa_supplicant_remove_iface(struct wpa_global *global,
|
||||||
|
|
||||||
wpa_dbg(wpa_s, MSG_DEBUG, "Removing interface %s", wpa_s->ifname);
|
wpa_dbg(wpa_s, MSG_DEBUG, "Removing interface %s", wpa_s->ifname);
|
||||||
|
|
||||||
|
#ifdef CONFIG_MESH
|
||||||
|
if (mesh_if_created) {
|
||||||
|
ifname = os_strdup(wpa_s->ifname);
|
||||||
|
if (ifname == NULL) {
|
||||||
|
wpa_dbg(wpa_s, MSG_ERROR,
|
||||||
|
"mesh: Failed to malloc ifname");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_MESH */
|
||||||
|
|
||||||
if (global->p2p_group_formation == wpa_s)
|
if (global->p2p_group_formation == wpa_s)
|
||||||
global->p2p_group_formation = NULL;
|
global->p2p_group_formation = NULL;
|
||||||
if (global->p2p_invite_group == wpa_s)
|
if (global->p2p_invite_group == wpa_s)
|
||||||
global->p2p_invite_group = NULL;
|
global->p2p_invite_group = NULL;
|
||||||
wpa_supplicant_deinit_iface(wpa_s, 1, terminate);
|
wpa_supplicant_deinit_iface(wpa_s, 1, terminate);
|
||||||
|
|
||||||
|
#ifdef CONFIG_MESH
|
||||||
|
if (mesh_if_created) {
|
||||||
|
wpa_drv_if_remove(global->ifaces, WPA_IF_MESH, ifname);
|
||||||
|
os_free(ifname);
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_MESH */
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -697,6 +697,8 @@ struct wpa_supplicant {
|
||||||
struct hostapd_iface *ifmsh;
|
struct hostapd_iface *ifmsh;
|
||||||
#ifdef CONFIG_MESH
|
#ifdef CONFIG_MESH
|
||||||
struct mesh_rsn *mesh_rsn;
|
struct mesh_rsn *mesh_rsn;
|
||||||
|
int mesh_if_idx;
|
||||||
|
unsigned int mesh_if_created:1;
|
||||||
#endif /* CONFIG_MESH */
|
#endif /* CONFIG_MESH */
|
||||||
|
|
||||||
unsigned int off_channel_freq;
|
unsigned int off_channel_freq;
|
||||||
|
|
Loading…
Reference in a new issue