Browse 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 16 years ago
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: