Browse Source

nl80211: Add new commands to support mesh interfaces

Create init_mesh, mesh_join, and mesh_leave actions to kernel.

Signed-off-by: Javier Lopez <jlopex@gmail.com>
Signed-off-by: Javier Cardona <javier@cozybit.com>
Signed-off-by: Jason Mobarak <x@jason.mobarak.name>
Signed-off-by: Bob Copeland <me@bobcopeland.com>
Bob Copeland 10 years ago
parent
commit
6c1664f605
5 changed files with 223 additions and 0 deletions
  1. 47 0
      src/drivers/driver.h
  2. 144 0
      src/drivers/driver_nl80211.c
  3. 5 0
      wpa_supplicant/Android.mk
  4. 5 0
      wpa_supplicant/Makefile
  5. 22 0
      wpa_supplicant/driver_i.h

+ 47 - 0
src/drivers/driver.h

@@ -910,6 +910,30 @@ struct wpa_driver_ap_params {
 	struct hostapd_freq_params *freq;
 };
 
+struct wpa_driver_mesh_bss_params {
+#define WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS	0x00000001
+	/*
+	 * TODO: Other mesh configuration parameters would go here.
+	 * See NL80211_MESHCONF_* for all the mesh config parameters.
+	 */
+	unsigned int flags;
+};
+
+struct wpa_driver_mesh_join_params {
+	const u8 *meshid;
+	int meshid_len;
+	const int *basic_rates;
+	const u8 *ies;
+	int ie_len;
+	int freq;
+	struct wpa_driver_mesh_bss_params conf;
+#define WPA_DRIVER_MESH_FLAG_USER_MPM	0x00000001
+#define WPA_DRIVER_MESH_FLAG_DRIVER_MPM	0x00000002
+#define WPA_DRIVER_MESH_FLAG_SAE_AUTH	0x00000004
+#define WPA_DRIVER_MESH_FLAG_AMPE	0x00000008
+	unsigned int flags;
+};
+
 /**
  * struct wpa_driver_capa - Driver capability information
  */
@@ -3025,6 +3049,29 @@ struct wpa_driver_ops {
 	 */
 	int (*disable_transmit_sa)(void *priv, u32 channel, u8 an);
 #endif /* CONFIG_MACSEC */
+
+	/**
+	 * init_mesh - Driver specific initialization for mesh
+	 * @priv: Private driver interface data
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*init_mesh)(void *priv);
+
+	/**
+	 * join_mesh - Join a mesh network
+	 * @priv: Private driver interface data
+	 * @params: Mesh configuration parameters
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*join_mesh)(void *priv,
+			 struct wpa_driver_mesh_join_params *params);
+
+	/**
+	 * leave_mesh - Leave a mesh network
+	 * @priv: Private driver interface data
+	 * Returns 0 on success, -1 on failure
+	 */
+	int (*leave_mesh)(void *priv);
 };
 
 

+ 144 - 0
src/drivers/driver_nl80211.c

@@ -12588,6 +12588,145 @@ static int nl80211_set_mac_addr(void *priv, const u8 *addr)
 }
 
 
+#ifdef CONFIG_MESH
+
+static int wpa_driver_nl80211_init_mesh(void *priv)
+{
+	if (wpa_driver_nl80211_set_mode(priv, NL80211_IFTYPE_MESH_POINT)) {
+		wpa_printf(MSG_INFO,
+			   "nl80211: Failed to set interface into mesh mode");
+		return -1;
+	}
+	return 0;
+}
+
+
+static int
+wpa_driver_nl80211_join_mesh(void *priv,
+			     struct wpa_driver_mesh_join_params *params)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg;
+	struct nlattr *container;
+	int ret = 0;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -1;
+
+	wpa_printf(MSG_DEBUG, "nl80211: mesh join (ifindex=%d)", drv->ifindex);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_JOIN_MESH);
+
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+	/* XXX: need chtype too in case we want HT */
+	if (params->freq) {
+		wpa_printf(MSG_DEBUG, "  * freq=%d", params->freq);
+		NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq);
+	}
+
+	if (params->basic_rates) {
+		u8 rates[NL80211_MAX_SUPP_RATES];
+		u8 rates_len = 0;
+		int i;
+
+		for (i = 0; i < NL80211_MAX_SUPP_RATES; i++) {
+			if (params->basic_rates[i] < 0)
+				break;
+			rates[rates_len++] = params->basic_rates[i] / 5;
+		}
+
+		NLA_PUT(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len, rates);
+	}
+
+	if (params->meshid) {
+		wpa_hexdump_ascii(MSG_DEBUG, "  * SSID",
+				  params->meshid, params->meshid_len);
+		NLA_PUT(msg, NL80211_ATTR_MESH_ID, params->meshid_len,
+			params->meshid);
+	}
+
+	wpa_printf(MSG_DEBUG, "  * flags=%08X", params->flags);
+
+	container = nla_nest_start(msg, NL80211_ATTR_MESH_SETUP);
+	if (!container)
+		goto nla_put_failure;
+
+	if (params->ies) {
+		wpa_hexdump(MSG_DEBUG, "  * IEs", params->ies, params->ie_len);
+		NLA_PUT(msg, NL80211_MESH_SETUP_IE, params->ie_len,
+			params->ies);
+	}
+	/* WPA_DRIVER_MESH_FLAG_OPEN_AUTH is treated as default by nl80211 */
+	if (params->flags & WPA_DRIVER_MESH_FLAG_SAE_AUTH) {
+		NLA_PUT_U8(msg, NL80211_MESH_SETUP_AUTH_PROTOCOL, 0x1);
+		NLA_PUT_FLAG(msg, NL80211_MESH_SETUP_USERSPACE_AUTH);
+	}
+	if (params->flags & WPA_DRIVER_MESH_FLAG_AMPE)
+		NLA_PUT_FLAG(msg, NL80211_MESH_SETUP_USERSPACE_AMPE);
+	if (params->flags & WPA_DRIVER_MESH_FLAG_USER_MPM)
+		NLA_PUT_FLAG(msg, NL80211_MESH_SETUP_USERSPACE_MPM);
+	nla_nest_end(msg, container);
+
+	container = nla_nest_start(msg, NL80211_ATTR_MESH_CONFIG);
+	if (!container)
+		goto nla_put_failure;
+
+	if (!(params->conf.flags & WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS))
+		NLA_PUT_U32(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS, 0);
+	nla_nest_end(msg, container);
+
+	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	msg = NULL;
+	if (ret) {
+		wpa_printf(MSG_DEBUG, "nl80211: mesh join failed: ret=%d (%s)",
+			   ret, strerror(-ret));
+		goto nla_put_failure;
+	}
+	ret = 0;
+	bss->freq = params->freq;
+	wpa_printf(MSG_DEBUG, "nl80211: mesh join request send successfully");
+
+
+nla_put_failure:
+	nlmsg_free(msg);
+	return ret;
+}
+
+
+static int wpa_driver_nl80211_leave_mesh(void *priv)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg;
+	int ret = 0;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -1;
+
+	wpa_printf(MSG_DEBUG, "nl80211: mesh leave (ifindex=%d)", drv->ifindex);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_LEAVE_MESH);
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	msg = NULL;
+	if (ret) {
+		wpa_printf(MSG_DEBUG, "nl80211: mesh leave failed: ret=%d (%s)",
+			   ret, strerror(-ret));
+		goto nla_put_failure;
+	}
+	ret = 0;
+	wpa_printf(MSG_DEBUG, "nl80211: mesh leave request send successfully");
+
+nla_put_failure:
+	nlmsg_free(msg);
+	return ret;
+}
+
+#endif /* CONFIG_MESH */
+
+
 const struct wpa_driver_ops wpa_driver_nl80211_ops = {
 	.name = "nl80211",
 	.desc = "Linux nl80211/cfg80211",
@@ -12681,4 +12820,9 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
 	.set_wowlan = nl80211_set_wowlan,
 	.roaming = nl80211_roaming,
 	.set_mac_addr = nl80211_set_mac_addr,
+#ifdef CONFIG_MESH
+	.init_mesh = wpa_driver_nl80211_init_mesh,
+	.join_mesh = wpa_driver_nl80211_join_mesh,
+	.leave_mesh = wpa_driver_nl80211_leave_mesh,
+#endif /* CONFIG_MESH */
 };

+ 5 - 0
wpa_supplicant/Android.mk

@@ -195,6 +195,11 @@ NEED_SHA256=y
 NEED_AES_OMAC1=y
 endif
 
+ifdef CONFIG_MESH
+NEED_80211_COMMON=y
+L_CFLAGS += -DCONFIG_MESH
+endif
+
 ifdef CONFIG_SAE
 L_CFLAGS += -DCONFIG_SAE
 OBJS += src/common/sae.c

+ 5 - 0
wpa_supplicant/Makefile

@@ -198,6 +198,11 @@ NEED_SHA256=y
 NEED_AES_OMAC1=y
 endif
 
+ifdef CONFIG_MESH
+NEED_80211_COMMON=y
+CFLAGS += -DCONFIG_MESH
+endif
+
 ifdef CONFIG_SAE
 CFLAGS += -DCONFIG_SAE
 OBJS += ../src/common/sae.o

+ 22 - 0
wpa_supplicant/driver_i.h

@@ -65,6 +65,28 @@ static inline int wpa_drv_associate(struct wpa_supplicant *wpa_s,
 	return -1;
 }
 
+static inline int wpa_drv_init_mesh(struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->driver->init_mesh)
+		return wpa_s->driver->init_mesh(wpa_s->drv_priv);
+	return -1;
+}
+
+static inline int wpa_drv_join_mesh(struct wpa_supplicant *wpa_s,
+				    struct wpa_driver_mesh_join_params *params)
+{
+	if (wpa_s->driver->join_mesh)
+		return wpa_s->driver->join_mesh(wpa_s->drv_priv, params);
+	return -1;
+}
+
+static inline int wpa_drv_leave_mesh(struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->driver->leave_mesh)
+		return wpa_s->driver->leave_mesh(wpa_s->drv_priv);
+	return -1;
+}
+
 static inline int wpa_drv_scan(struct wpa_supplicant *wpa_s,
 			       struct wpa_driver_scan_params *params)
 {