Parcourir la source

Initial step in adding simple AP mode support into wpa_supplicant

This version is adding the configuration option (mode=2) for this and
driver capability reporting to figure out whether AP mode can be used.
However, this does not actually implement any real functionality yet.
Jouni Malinen il y a 16 ans
Parent
commit
1581b38b67

+ 2 - 0
src/drivers/driver.h

@@ -396,6 +396,8 @@ struct wpa_driver_capa {
 /* Driver provides separate commands for authentication and association (SME in
  * wpa_supplicant). */
 #define WPA_DRIVER_FLAGS_SME		0x00000020
+/* Driver supports AP mode */
+#define WPA_DRIVER_FLAGS_AP		0x00000040
 	unsigned int flags;
 
 	int max_scan_ssids;

+ 80 - 5
src/drivers/driver_nl80211.c

@@ -1274,6 +1274,7 @@ nla_put_failure:
 
 struct wiphy_info_data {
 	int max_scan_ssids;
+	int ap_supported;
 };
 
 
@@ -1290,6 +1291,18 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
 		info->max_scan_ssids =
 			nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]);
 
+	if (tb[NL80211_ATTR_SUPPORTED_IFTYPES]) {
+		struct nlattr *nl_mode;
+		int i;
+		nla_for_each_nested(nl_mode,
+				    tb[NL80211_ATTR_SUPPORTED_IFTYPES], i) {
+			if (nl_mode->nla_type == NL80211_IFTYPE_AP) {
+				info->ap_supported = 1;
+				break;
+			}
+		}
+	}
+
 	return NL_SKIP;
 }
 
@@ -1325,6 +1338,8 @@ static void wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
 		return;
 	drv->has_capability = 1;
 	drv->capa.max_scan_ssids = info.max_scan_ssids;
+	if (info.ap_supported)
+		drv->capa.flags |= WPA_DRIVER_FLAGS_AP;
 }
 
 
@@ -1536,6 +1551,7 @@ static void wpa_driver_nl80211_deinit(void *priv)
 
 	if (wpa_driver_nl80211_get_ifflags(drv, &flags) == 0)
 		(void) wpa_driver_nl80211_set_ifflags(drv, flags & ~IFF_UP);
+	wpa_driver_nl80211_set_mode(drv, 0);
 
 	close(drv->wext_event_sock);
 	close(drv->ioctl_sock);
@@ -2311,6 +2327,48 @@ nla_put_failure:
 }
 
 
+#ifdef CONFIG_AP
+static int wpa_driver_nl80211_set_freq2(
+	struct wpa_driver_nl80211_data *drv,
+	struct wpa_driver_associate_params *params)
+{
+	struct nl_msg *msg;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -1;
+
+	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
+		    NL80211_CMD_SET_WIPHY, 0);
+
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+	/* TODO: proper channel configuration */
+	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, 2437);
+
+	if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
+		return 0;
+nla_put_failure:
+	return -1;
+}
+
+
+static int wpa_driver_nl80211_ap(struct wpa_driver_nl80211_data *drv,
+				 struct wpa_driver_associate_params *params)
+{
+	if (wpa_driver_nl80211_set_mode(drv, params->mode) ||
+	    wpa_driver_nl80211_set_freq2(drv, params))
+		return -1;
+
+	/* TODO: setup monitor interface (and add code somewhere to remove this
+	 * when AP mode is stopped; associate with mode != 2 or drv_deinit) */
+	/* TODO: setup beacon */
+
+	return 0;
+}
+#endif /* CONFIG_AP */
+
+
 static int wpa_driver_nl80211_associate(
 	void *priv, struct wpa_driver_associate_params *params)
 {
@@ -2318,6 +2376,11 @@ static int wpa_driver_nl80211_associate(
 	int ret = -1;
 	struct nl_msg *msg;
 
+#ifdef CONFIG_AP
+	if (params->mode == 2)
+		return wpa_driver_nl80211_ap(drv, params);
+#endif /* CONFIG_AP */
+
 	wpa_driver_nl80211_set_auth_param(drv, IW_AUTH_DROP_UNENCRYPTED,
 					  params->drop_unencrypted);
 
@@ -2390,6 +2453,21 @@ static int wpa_driver_nl80211_set_mode(struct wpa_driver_nl80211_data *drv,
 {
 	int ret = -1, flags;
 	struct nl_msg *msg;
+	int nlmode;
+
+	switch (mode) {
+	case 0:
+		nlmode = NL80211_IFTYPE_STATION;
+		break;
+	case 1:
+		nlmode = NL80211_IFTYPE_ADHOC;
+		break;
+	case 2:
+		nlmode = NL80211_IFTYPE_AP;
+		break;
+	default:
+		return -1;
+	}
 
 	msg = nlmsg_alloc();
 	if (!msg)
@@ -2398,8 +2476,7 @@ static int wpa_driver_nl80211_set_mode(struct wpa_driver_nl80211_data *drv,
 	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
 		    0, NL80211_CMD_SET_INTERFACE, 0);
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-	NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE,
-		    mode ? NL80211_IFTYPE_ADHOC : NL80211_IFTYPE_STATION);
+	NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, nlmode);
 
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
 	if (!ret)
@@ -2428,9 +2505,7 @@ try_again:
 		genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
 			    0, NL80211_CMD_SET_INTERFACE, 0);
 		NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-		NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE,
-			    mode ? NL80211_IFTYPE_ADHOC :
-			    NL80211_IFTYPE_STATION);
+		NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, nlmode);
 		ret = send_and_recv_msgs(drv, msg, NULL, NULL);
 		if (ret) {
 			wpa_printf(MSG_ERROR, "Failed to set interface %s "

+ 4 - 0
wpa_supplicant/Makefile

@@ -620,6 +620,10 @@ LIBS += -ldl -rdynamic
 endif
 endif
 
+ifdef CONFIG_AP
+CFLAGS += -DCONFIG_AP
+endif
+
 ifdef CONFIG_EAP_SERVER
 CFLAGS += -DEAP_SERVER
 OBJS_h += ../src/eap_server/eap.o

+ 1 - 1
wpa_supplicant/config.c

@@ -1366,7 +1366,7 @@ static const struct parse_data ssid_fields[] = {
 	{ STRe(pac_file) },
 	{ INTe(fragment_size) },
 #endif /* IEEE8021X_EAPOL */
-	{ INT_RANGE(mode, 0, 1) },
+	{ INT_RANGE(mode, 0, 2) },
 	{ INT_RANGE(proactive_key_caching, 0, 1) },
 	{ INT_RANGE(disabled, 0, 1) },
 	{ STR(id_str) },

+ 2 - 0
wpa_supplicant/config_ssid.h

@@ -271,6 +271,8 @@ struct wpa_ssid {
 	 *
 	 * 1 = IBSS (ad-hoc, peer-to-peer)
 	 *
+	 * 2 = AP (access point)
+	 *
 	 * Note: IBSS can only be used with key_mgmt NONE (plaintext and
 	 * static WEP) and key_mgmt=WPA-NONE (fixed group key TKIP/CCMP). In
 	 * addition, ap_scan has to be set to 2 for IBSS. WPA-None requires

+ 40 - 0
wpa_supplicant/wpa_supplicant.c

@@ -919,6 +919,31 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
 }
 
 
+#ifdef CONFIG_AP
+static void wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
+				     struct wpa_ssid *ssid)
+{
+	struct wpa_driver_associate_params params;
+
+	if (ssid->ssid == NULL || ssid->ssid_len == 0) {
+		wpa_printf(MSG_ERROR, "No SSID configured for AP mode");
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "Setting up AP (SSID='%s')",
+		   wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
+
+	os_memset(&params, 0, sizeof(params));
+	params.ssid = ssid->ssid;
+	params.ssid_len = ssid->ssid_len;
+	params.mode = ssid->mode;
+
+	if (wpa_drv_associate(wpa_s, &params) < 0)
+		wpa_msg(wpa_s, MSG_INFO, "Failed to start AP functionality");
+}
+#endif /* CONFIG_AP */
+
+
 /**
  * wpa_supplicant_associate - Request association
  * @wpa_s: Pointer to wpa_supplicant data
@@ -940,6 +965,21 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
 	struct wpa_driver_capa capa;
 	int assoc_failed = 0;
 
+	if (ssid->mode == 2) {
+#ifdef CONFIG_AP
+		if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_AP)) {
+			wpa_printf(MSG_INFO, "Driver does not support AP "
+				   "mode");
+			return;
+		}
+		wpa_supplicant_create_ap(wpa_s, ssid);
+#else /* CONFIG_AP */
+		wpa_printf(MSG_ERROR, "AP mode support not included in the "
+			   "build");
+#endif /* CONFIG_AP */
+		return;
+	}
+
 	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) {
 		sme_authenticate(wpa_s, bss, ssid);
 		return;

+ 1 - 0
wpa_supplicant/wpa_supplicant.conf

@@ -242,6 +242,7 @@ fast_reauth=1
 # mode: IEEE 802.11 operation mode
 # 0 = infrastructure (Managed) mode, i.e., associate with an AP (default)
 # 1 = IBSS (ad-hoc, peer-to-peer)
+# 2 = AP (access point)
 # Note: IBSS can only be used with key_mgmt NONE (plaintext and static WEP)
 # and key_mgmt=WPA-NONE (fixed group key TKIP/CCMP). In addition, ap_scan has
 # to be set to 2 for IBSS. WPA-None requires following network block options: