u8 bssid[ETH_ALEN];
int associated;
+ u8 ssid[32];
+ size_t ssid_len;
};
static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx,
void *timeout_ctx);
-static int wpa_driver_nl80211_set_mode(void *priv, int mode);
+static int wpa_driver_nl80211_set_mode(struct wpa_driver_nl80211_data *drv,
+ int mode);
#ifdef WEXT_COMPAT
static int wpa_driver_nl80211_flush_pmkid(void *priv);
#endif /* WEXT_COMPAT */
static int wpa_driver_nl80211_get_ssid(void *priv, u8 *ssid)
{
struct wpa_driver_nl80211_data *drv = priv;
- struct iwreq iwr;
- int ret = 0;
+#ifdef WEXT_COMPAT
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) {
+ struct iwreq iwr;
+ int ret = 0;
- os_memset(&iwr, 0, sizeof(iwr));
- os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
- iwr.u.essid.pointer = (caddr_t) ssid;
- iwr.u.essid.length = 32;
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.essid.pointer = (caddr_t) ssid;
+ iwr.u.essid.length = 32;
- if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) {
- perror("ioctl[SIOCGIWESSID]");
- ret = -1;
- } else {
- ret = iwr.u.essid.length;
- if (ret > 32)
- ret = 32;
- /* Some drivers include nul termination in the SSID, so let's
- * remove it here before further processing. WE-21 changes this
- * to explicitly require the length _not_ to include nul
- * termination. */
- if (ret > 0 && ssid[ret - 1] == '\0' &&
- drv->we_version_compiled < 21)
- ret--;
- }
+ if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) {
+ perror("ioctl[SIOCGIWESSID]");
+ ret = -1;
+ } else {
+ ret = iwr.u.essid.length;
+ if (ret > 32)
+ ret = 32;
+ /*
+ * Some drivers include nul termination in the SSID, so
+ * let's remove it here before further processing.
+ * WE-21 changes this to explicitly require the length
+ * _not_ to include nul termination.
+ */
+ if (ret > 0 && ssid[ret - 1] == '\0' &&
+ drv->we_version_compiled < 21)
+ ret--;
+ }
- return ret;
+ return ret;
+ }
+#endif /* WEXT_COMPAT */
+ if (!drv->associated)
+ return -1;
+ os_memcpy(ssid, drv->ssid, drv->ssid_len);
+ return drv->ssid_len;
}
struct wiphy_info_data {
int max_scan_ssids;
+ int ap_supported;
};
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;
}
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;
}
{
int flags;
+ drv->ifindex = if_nametoindex(drv->ifname);
+
+ if (wpa_driver_nl80211_set_mode(drv, 0) < 0) {
+ wpa_printf(MSG_DEBUG, "nl80211: Could not configure driver to "
+ "use managed mode");
+ }
+
if (wpa_driver_nl80211_get_ifflags(drv, &flags) != 0) {
wpa_printf(MSG_ERROR, "Could not get interface '%s' flags",
drv->ifname);
wpa_driver_nl80211_flush_pmkid(drv);
#endif /* WEXT_COMPAT */
- if (wpa_driver_nl80211_set_mode(drv, 0) < 0) {
- wpa_printf(MSG_DEBUG, "nl80211: Could not configure driver to "
- "use managed mode");
- }
-
wpa_driver_nl80211_get_range(drv);
- drv->ifindex = if_nametoindex(drv->ifname);
-
wpa_driver_nl80211_capa(drv);
wpa_driver_nl80211_send_oper_ifla(drv, 1, IF_OPER_DORMANT);
(void) wpa_driver_nl80211_set_bssid(drv,
(u8 *) "\x00\x00\x00\x00\x00\x00");
#endif /* WEXT_COMPAT */
+ wpa_driver_nl80211_set_auth_param(drv, IW_AUTH_DROP_UNENCRYPTED, 0);
wpa_driver_nl80211_send_oper_ifla(priv, 0, IF_OPER_UP);
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);
#endif /* WEXT_COMPAT */
-static int wpa_driver_nl80211_set_drop_unencrypted(void *priv,
- int enabled)
-{
- struct wpa_driver_nl80211_data *drv = priv;
- wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-#ifdef WEXT_COMPAT
- drv->use_crypt = enabled;
-#endif /* WEXT_COMPAT */
- return wpa_driver_nl80211_set_auth_param(drv, IW_AUTH_DROP_UNENCRYPTED,
- enabled);
-}
-
-
#ifdef WEXT_COMPAT
static int wpa_driver_nl80211_mlme_wext(struct wpa_driver_nl80211_data *drv,
const u8 *addr, int cmd,
}
+static int wpa_driver_nl80211_set_auth_alg(struct wpa_driver_nl80211_data *drv,
+ int auth_alg)
+{
+ int algs = 0, res;
+
+ if (auth_alg & AUTH_ALG_OPEN_SYSTEM)
+ algs |= IW_AUTH_ALG_OPEN_SYSTEM;
+ if (auth_alg & AUTH_ALG_SHARED_KEY)
+ algs |= IW_AUTH_ALG_SHARED_KEY;
+ if (auth_alg & AUTH_ALG_LEAP)
+ algs |= IW_AUTH_ALG_LEAP;
+ if (algs == 0) {
+ /* at least one algorithm should be set */
+ algs = IW_AUTH_ALG_OPEN_SYSTEM;
+ }
+
+ res = wpa_driver_nl80211_set_auth_param(drv, IW_AUTH_80211_AUTH_ALG,
+ algs);
+ drv->auth_alg_fallback = res == -2;
+ return res;
+}
+
+
static int wpa_driver_nl80211_associate_wext(
void *priv, struct wpa_driver_associate_params *params)
{
wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+ wpa_driver_nl80211_set_mode(drv, params->mode);
+ wpa_driver_nl80211_set_auth_alg(drv, params->auth_alg);
+
/*
* If the driver did not support SIOCSIWAUTH, fallback to
* SIOCSIWENCODE here.
return ret;
}
-
-
-static int wpa_driver_nl80211_set_auth_alg(void *priv, int auth_alg)
-{
- struct wpa_driver_nl80211_data *drv = priv;
- int algs = 0, res;
-
- if (drv->capa.flags & WPA_DRIVER_FLAGS_SME)
- return 0;
-
- if (auth_alg & AUTH_ALG_OPEN_SYSTEM)
- algs |= IW_AUTH_ALG_OPEN_SYSTEM;
- if (auth_alg & AUTH_ALG_SHARED_KEY)
- algs |= IW_AUTH_ALG_SHARED_KEY;
- if (auth_alg & AUTH_ALG_LEAP)
- algs |= IW_AUTH_ALG_LEAP;
- if (algs == 0) {
- /* at least one algorithm should be set */
- algs = IW_AUTH_ALG_OPEN_SYSTEM;
- }
-
- res = wpa_driver_nl80211_set_auth_param(drv, IW_AUTH_80211_AUTH_ALG,
- algs);
- drv->auth_alg_fallback = res == -2;
- return res;
-}
#endif /* WEXT_COMPAT */
}
+#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)
{
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);
+
#ifdef WEXT_COMPAT
if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME))
return wpa_driver_nl80211_associate_wext(drv, params);
params->ssid, params->ssid_len);
NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
params->ssid);
+ if (params->ssid_len > sizeof(drv->ssid))
+ goto nla_put_failure;
+ os_memcpy(drv->ssid, params->ssid, params->ssid_len);
+ drv->ssid_len = params->ssid_len;
}
wpa_hexdump(MSG_DEBUG, " * IEs", params->wpa_ie, params->wpa_ie_len);
if (params->wpa_ie)
/**
* wpa_driver_nl80211_set_mode - Set wireless mode (infra/adhoc), SIOCSIWMODE
- * @priv: Pointer to private wext data from wpa_driver_nl80211_init()
+ * @drv: Pointer to private driver data from wpa_driver_nl80211_init()
* @mode: 0 = infra/BSS (associate with an AP), 1 = adhoc/IBSS
* Returns: 0 on success, -1 on failure
*/
-static int wpa_driver_nl80211_set_mode(void *priv, int mode)
+static int wpa_driver_nl80211_set_mode(struct wpa_driver_nl80211_data *drv,
+ int mode)
{
- struct wpa_driver_nl80211_data *drv = priv;
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)
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)
goto try_again;
nla_put_failure:
- wpa_printf(MSG_ERROR, "nl80211: Failed to set interface mode");
+ wpa_printf(MSG_ERROR, "nl80211: Failed to set interface mode: %d (%s)",
+ ret, strerror(-ret));
return -1;
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 "
- "mode", drv->ifname);
+ "mode(try_again): %d (%s)",
+ drv->ifname, ret, strerror(-ret));
}
/* Ignore return value of get_ifflags to ensure that the device
.get_bssid = wpa_driver_nl80211_get_bssid,
.get_ssid = wpa_driver_nl80211_get_ssid,
.set_key = wpa_driver_nl80211_set_key,
- .set_drop_unencrypted = wpa_driver_nl80211_set_drop_unencrypted,
.scan2 = wpa_driver_nl80211_scan,
.get_scan_results2 = wpa_driver_nl80211_get_scan_results,
.deauthenticate = wpa_driver_nl80211_deauthenticate,
.disassociate = wpa_driver_nl80211_disassociate,
- .set_mode = wpa_driver_nl80211_set_mode,
.authenticate = wpa_driver_nl80211_authenticate,
.associate = wpa_driver_nl80211_associate,
.init = wpa_driver_nl80211_init,
#ifdef WEXT_COMPAT
.set_wpa = wpa_driver_nl80211_set_wpa,
.set_countermeasures = wpa_driver_nl80211_set_countermeasures,
- .set_auth_alg = wpa_driver_nl80211_set_auth_alg,
.add_pmkid = wpa_driver_nl80211_add_pmkid,
.remove_pmkid = wpa_driver_nl80211_remove_pmkid,
.flush_pmkid = wpa_driver_nl80211_flush_pmkid,