From 1581b38b6732e19a2f8fcfc049fdbdcc5183b10e Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Wed, 25 Mar 2009 11:38:47 +0200 Subject: [PATCH] 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. --- src/drivers/driver.h | 2 + src/drivers/driver_nl80211.c | 85 ++++++++++++++++++++++++++++-- wpa_supplicant/Makefile | 4 ++ wpa_supplicant/config.c | 2 +- wpa_supplicant/config_ssid.h | 2 + wpa_supplicant/wpa_supplicant.c | 40 ++++++++++++++ wpa_supplicant/wpa_supplicant.conf | 1 + 7 files changed, 130 insertions(+), 6 deletions(-) diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 29a3c3c09..825799194 100644 --- a/src/drivers/driver.h +++ b/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; diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index a631e180b..a2f0fc7d3 100644 --- a/src/drivers/driver_nl80211.c +++ b/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 " diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile index 2a2d8d3fe..0d213b33e 100644 --- a/wpa_supplicant/Makefile +++ b/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 diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index 9a7937417..355b38f45 100644 --- a/wpa_supplicant/config.c +++ b/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) }, diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h index 5510639c1..817046d08 100644 --- a/wpa_supplicant/config_ssid.h +++ b/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 diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 45ef15a43..45a0a760b 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/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(¶ms, 0, sizeof(params)); + params.ssid = ssid->ssid; + params.ssid_len = ssid->ssid_len; + params.mode = ssid->mode; + + if (wpa_drv_associate(wpa_s, ¶ms) < 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; diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf index 43e81a16d..2e6a15265 100644 --- a/wpa_supplicant/wpa_supplicant.conf +++ b/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: