@@ -679,4 +679,19 @@ enum {
#define VENDOR_HT_CAPAB_OUI_TYPE 0x33 /* 00-90-4c:0x33 */
+/* cipher suite selectors */
+#define WLAN_CIPHER_SUITE_USE_GROUP 0x000FAC00
+#define WLAN_CIPHER_SUITE_WEP40 0x000FAC01
+#define WLAN_CIPHER_SUITE_TKIP 0x000FAC02
+/* reserved: 0x000FAC03 */
+#define WLAN_CIPHER_SUITE_CCMP 0x000FAC04
+#define WLAN_CIPHER_SUITE_WEP104 0x000FAC05
+#define WLAN_CIPHER_SUITE_AES_CMAC 0x000FAC06
+
+/* AKM suite selectors */
+#define WLAN_AKM_SUITE_8021X 0x000FAC01
+#define WLAN_AKM_SUITE_PSK 0x000FAC02
+
+#define WLAN_MAX_KEY_LEN 32
+
#endif /* IEEE802_11_DEFS_H */
@@ -310,6 +310,14 @@ enum nl80211_commands {
NL80211_CMD_JOIN_IBSS,
NL80211_CMD_LEAVE_IBSS,
+ NL80211_CMD_TESTMODE,
+
+ NL80211_CMD_CONNECT,
+ NL80211_CMD_ROAM,
+ NL80211_CMD_DISCONNECT,
+
+ NL80211_CMD_SET_WIPHY_NETNS,
+
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
@@ -619,6 +627,28 @@ enum nl80211_attrs {
NL80211_ATTR_CONTROL_PORT,
+ NL80211_ATTR_TESTDATA,
+
+ NL80211_ATTR_PRIVACY,
+
+ NL80211_ATTR_DISCONNECTED_BY_AP,
+ NL80211_ATTR_STATUS_CODE,
+
+ NL80211_ATTR_CIPHER_SUITES_PAIRWISE,
+ NL80211_ATTR_CIPHER_SUITE_GROUP,
+ NL80211_ATTR_WPA_VERSIONS,
+ NL80211_ATTR_AKM_SUITES,
+
+ NL80211_ATTR_REQ_IE,
+ NL80211_ATTR_RESP_IE,
+
+ NL80211_ATTR_PREV_BSSID,
+
+ NL80211_ATTR_KEY,
+ NL80211_ATTR_KEYS,
+
+ NL80211_ATTR_PID,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -1224,4 +1254,39 @@ enum nl80211_mfp {
NL80211_MFP_REQUIRED,
};
+enum nl80211_wpa_versions {
+ NL80211_WPA_VERSION_1 = 1 << 0,
+ NL80211_WPA_VERSION_2 = 1 << 1,
+};
+
+/**
+ * enum nl80211_key_attributes - key attributes
+ * @__NL80211_KEY_INVALID: invalid
+ * @NL80211_KEY_DATA: (temporal) key data; for TKIP this consists of
+ * 16 bytes encryption key followed by 8 bytes each for TX and RX MIC
+ * keys
+ * @NL80211_KEY_IDX: key ID (u8, 0-3)
+ * @NL80211_KEY_CIPHER: key cipher suite (u32, as defined by IEEE 802.11
+ * section 7.3.2.25.1, e.g. 0x000FAC04)
+ * @NL80211_KEY_SEQ: transmit key sequence number (IV/PN) for TKIP and
+ * CCMP keys, each six bytes in little endian
+ * @NL80211_KEY_DEFAULT: flag indicating default key
+ * @NL80211_KEY_DEFAULT_MGMT: flag indicating default management key
+ * @__NL80211_KEY_AFTER_LAST: internal
+ * @NL80211_KEY_MAX: highest key attribute
+ */
+enum nl80211_key_attributes {
+ __NL80211_KEY_INVALID,
+ NL80211_KEY_DATA,
+ NL80211_KEY_IDX,
+ NL80211_KEY_CIPHER,
+ NL80211_KEY_SEQ,
+ NL80211_KEY_DEFAULT,
+ NL80211_KEY_DEFAULT_MGMT,
+
+ /* keep last */
+ __NL80211_KEY_AFTER_LAST,
+ NL80211_KEY_MAX = __NL80211_KEY_AFTER_LAST - 1
+};
+
#endif /* __LINUX_NL80211_H */
@@ -441,9 +441,11 @@ struct wpa_driver_capa {
#define WPA_DRIVER_FLAGS_WIRED 0x00000010
/* Driver provides separate commands for authentication and association (SME in
* wpa_supplicant). */
-#define WPA_DRIVER_FLAGS_SME 0x00000020
+#define WPA_DRIVER_FLAGS_SME_AUTH 0x00000020
/* Driver supports AP mode */
#define WPA_DRIVER_FLAGS_AP 0x00000040
+/* Driver supports connect API */
+#define WPA_DRIVER_FLAGS_SME_CONNECT 0x00000080
unsigned int flags;
int max_scan_ssids;
@@ -1333,6 +1335,21 @@ struct wpa_driver_ops {
* Returns: 0 on success, -1 on failure
*/
int (*set_supp_port)(void *priv, int authorized);
+
+ /**
+ * connect - Request driver to connect
+ * @priv: private driver interface data
+ * @params: connect parameters
+ * Returns: 0 on success, -1 on failure
+ *
+ * This is an optional function that can be used with drivers that
+ * support connect (both authentication and association) API. If
+ * driver SME is not supported (both connect and authenticate are
+ * not implemented), associate() function is expected to take care
+ * of IEEE 802.11 authentication and association, too.
+ */
+ int (*connect)(void *priv, struct wpa_driver_associate_params *params);
+ int (*disconnect)(void *priv, u8 *addr, int reason_code);
};
/**
@@ -739,6 +739,40 @@ static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv,
wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
}
+static void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
+ enum nl80211_commands cmd, struct nlattr *status,
+ struct nlattr *addr, struct nlattr *req_ie,
+ struct nlattr *resp_ie)
+{
+ union wpa_event_data event;
+
+ os_memset(&event, 0, sizeof(event));
+ if (cmd == NL80211_CMD_CONNECT &&
+ nla_get_u16(status) != WLAN_STATUS_SUCCESS) {
+ if (resp_ie) {
+ event.assoc_reject.resp_ies = nla_data(resp_ie);
+ event.assoc_reject.resp_ies_len = nla_len(resp_ie);
+ }
+ event.assoc_reject.status_code = nla_get_u16(status);
+ wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event);
+ return;
+ }
+
+ drv->associated = 1;
+ if (addr)
+ os_memcpy(drv->bssid, nla_data(addr), ETH_ALEN);
+
+ if (req_ie) {
+ event.assoc_info.req_ies = nla_data(req_ie);
+ event.assoc_info.req_ies_len = nla_len(req_ie);
+ }
+ if (resp_ie) {
+ event.assoc_info.resp_ies = nla_data(resp_ie);
+ event.assoc_info.resp_ies_len = nla_len(resp_ie);
+ }
+
+ wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
+}
static void mlme_timeout_event(struct wpa_driver_nl80211_data *drv,
enum nl80211_commands cmd, struct nlattr *addr)
@@ -895,6 +929,17 @@ static int process_event(struct nl_msg *msg, void *arg)
mlme_event(drv, gnlh->cmd, tb[NL80211_ATTR_FRAME],
tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT]);
break;
+ case NL80211_CMD_CONNECT:
+ case NL80211_CMD_ROAM:
+ mlme_event_connect(drv, gnlh->cmd, tb[NL80211_ATTR_STATUS_CODE],
+ tb[NL80211_ATTR_MAC],
+ tb[NL80211_ATTR_REQ_IE],
+ tb[NL80211_ATTR_RESP_IE]);
+ break;
+ case NL80211_CMD_DISCONNECT:
+ drv->associated = 0;
+ wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
+ break;
#endif /* HOSTAPD */
case NL80211_CMD_MICHAEL_MIC_FAILURE:
mlme_event_michael_mic_failure(drv, tb);
@@ -1003,6 +1048,8 @@ nla_put_failure:
struct wiphy_info_data {
int max_scan_ssids;
int ap_supported;
+ int auth_supported;
+ int connect_supported;
};
@@ -1031,6 +1078,19 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
}
}
+ if (tb[NL80211_ATTR_SUPPORTED_COMMANDS]) {
+ struct nlattr *nl_cmd;
+ int i;
+
+ nla_for_each_nested(nl_cmd,
+ tb[NL80211_ATTR_SUPPORTED_COMMANDS], i) {
+ if (nla_get_u32(nl_cmd) == NL80211_CMD_AUTHENTICATE)
+ info->auth_supported = 1;
+ if (nla_get_u32(nl_cmd) == NL80211_CMD_CONNECT)
+ info->connect_supported = 1;
+ }
+ }
+
return NL_SKIP;
}
@@ -1078,6 +1138,12 @@ static void wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
drv->capa.max_scan_ssids = info.max_scan_ssids;
if (info.ap_supported)
drv->capa.flags |= WPA_DRIVER_FLAGS_AP;
+
+ if (info.auth_supported)
+ drv->capa.flags |= WPA_DRIVER_FLAGS_SME_AUTH;
+
+ if (info.connect_supported)
+ drv->capa.flags |= WPA_DRIVER_FLAGS_SME_CONNECT;
}
#endif /* HOSTAPD */
@@ -1227,8 +1293,6 @@ static void * wpa_driver_nl80211_init(void *ctx, const char *ifname)
return NULL;
}
- drv->capa.flags |= WPA_DRIVER_FLAGS_SME;
-
drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
if (drv->ioctl_sock < 0) {
perror("socket(PF_INET,SOCK_DGRAM)");
@@ -1658,19 +1722,22 @@ static int nl_set_encr(int ifindex, struct wpa_driver_nl80211_data *drv,
case WPA_ALG_WEP:
if (key_len == 5)
NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
- 0x000FAC01);
+ WLAN_CIPHER_SUITE_WEP40);
else
NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
- 0x000FAC05);
+ WLAN_CIPHER_SUITE_WEP104);
break;
case WPA_ALG_TKIP:
- NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC02);
+ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
+ WLAN_CIPHER_SUITE_TKIP);
break;
case WPA_ALG_CCMP:
- NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC04);
+ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
+ WLAN_CIPHER_SUITE_CCMP);
break;
case WPA_ALG_IGTK:
- NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC06);
+ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
+ WLAN_CIPHER_SUITE_AES_CMAC);
break;
default:
wpa_printf(MSG_ERROR, "%s: Unsupported encryption "
@@ -1737,6 +1804,60 @@ nla_put_failure:
#ifndef HOSTAPD
+static int nl80211_set_conn_keys(void *priv,
+ struct wpa_driver_associate_params *params,
+ struct nl_msg *msg)
+{
+ int i, privacy = 0;
+ struct nlattr *nl_keys, *nl_key;
+
+ for (i = 0; i < 4; i++) {
+ if (!params->wep_key[i])
+ continue;
+ privacy = 1;
+ break;
+ }
+ if (!privacy)
+ return 0;
+
+ NLA_PUT_FLAG(msg, NL80211_ATTR_PRIVACY);
+
+ nl_keys = nla_nest_start(msg, NL80211_ATTR_KEYS);
+ if (!nl_keys)
+ goto nla_put_failure;
+
+ for (i = 0; i < 4; i++) {
+ if (!params->wep_key[i])
+ continue;
+
+ nl_key = nla_nest_start(msg, i);
+ if (!nl_key)
+ goto nla_put_failure;
+
+ NLA_PUT(msg, NL80211_KEY_DATA, params->wep_key_len[i],
+ params->wep_key[i]);
+ if (params->wep_key_len[i] == 5)
+ NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
+ WLAN_CIPHER_SUITE_WEP40);
+ else
+ NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
+ WLAN_CIPHER_SUITE_WEP104);
+
+ NLA_PUT_U8(msg, NL80211_KEY_IDX, i);
+
+ if (i == params->wep_tx_keyidx)
+ NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT);
+
+ nla_nest_end(msg, nl_key);
+ }
+ nla_nest_end(msg, nl_keys);
+
+ return 0;
+
+nla_put_failure:
+ return -ENOBUFS;
+}
+
static int wpa_driver_nl80211_set_key(void *priv, wpa_alg alg,
const u8 *addr, int key_idx,
int set_tx, const u8 *seq,
@@ -1883,6 +2004,164 @@ nla_put_failure:
return ret;
}
+static int wpa_driver_nl80211_connect(
+ void *priv, struct wpa_driver_associate_params *params)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ struct nl_msg *msg;
+ enum nl80211_auth_type type;
+ int ret = 0;
+
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME_CONNECT))
+ return -EOPNOTSUPP;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Connect (ifindex=%d)", drv->ifindex);
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
+ NL80211_CMD_CONNECT, 0);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+ if (params->bssid) {
+ wpa_printf(MSG_DEBUG, " * bssid=" MACSTR,
+ MAC2STR(params->bssid));
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid);
+ }
+ if (params->freq) {
+ wpa_printf(MSG_DEBUG, " * freq=%d", params->freq);
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq);
+ }
+ if (params->ssid) {
+ wpa_hexdump_ascii(MSG_DEBUG, " * SSID",
+ 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)
+ NLA_PUT(msg, NL80211_ATTR_IE, params->wpa_ie_len,
+ params->wpa_ie);
+
+ if (params->auth_alg & AUTH_ALG_OPEN_SYSTEM)
+ type = NL80211_AUTHTYPE_OPEN_SYSTEM;
+ else if (params->auth_alg & AUTH_ALG_SHARED_KEY)
+ type = NL80211_AUTHTYPE_SHARED_KEY;
+ else if (params->auth_alg & AUTH_ALG_LEAP)
+ type = NL80211_AUTHTYPE_NETWORK_EAP;
+ else if (params->auth_alg & AUTH_ALG_FT)
+ type = NL80211_AUTHTYPE_FT;
+ else
+ goto nla_put_failure;
+
+ wpa_printf(MSG_DEBUG, " * Auth Type %d", type);
+ NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, type);
+
+ if (params->wpa_ie && params->wpa_ie_len) {
+ enum nl80211_wpa_versions ver;
+
+ if (params->wpa_ie[0] == WLAN_EID_RSN)
+ ver = NL80211_WPA_VERSION_2;
+ else
+ ver = NL80211_WPA_VERSION_1;
+
+ wpa_printf(MSG_DEBUG, " * WPA Version %d", ver);
+ NLA_PUT_U32(msg, NL80211_ATTR_WPA_VERSIONS, ver);
+ }
+
+ if (params->pairwise_suite != CIPHER_NONE) {
+ int cipher = IW_AUTH_CIPHER_NONE;
+
+ switch (params->pairwise_suite) {
+ case CIPHER_WEP40:
+ cipher = WLAN_CIPHER_SUITE_WEP40;
+ break;
+ case CIPHER_WEP104:
+ cipher = WLAN_CIPHER_SUITE_WEP104;
+ break;
+ case CIPHER_CCMP:
+ cipher = WLAN_CIPHER_SUITE_CCMP;
+ break;
+ case CIPHER_TKIP:
+ default:
+ cipher = WLAN_CIPHER_SUITE_TKIP;
+ break;
+ }
+ NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE, cipher);
+ }
+
+ if (params->group_suite != CIPHER_NONE) {
+ int cipher = IW_AUTH_CIPHER_NONE;
+
+ switch (params->group_suite) {
+ case CIPHER_WEP40:
+ cipher = WLAN_CIPHER_SUITE_WEP40;
+ break;
+ case CIPHER_WEP104:
+ cipher = WLAN_CIPHER_SUITE_WEP104;
+ break;
+ case CIPHER_CCMP:
+ cipher = WLAN_CIPHER_SUITE_CCMP;
+ break;
+ case CIPHER_TKIP:
+ default:
+ cipher = WLAN_CIPHER_SUITE_TKIP;
+ break;
+ }
+ NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, cipher);
+ }
+
+ if (params->key_mgmt_suite == KEY_MGMT_802_1X ||
+ params->key_mgmt_suite == KEY_MGMT_PSK) {
+ int mgmt = WLAN_AKM_SUITE_PSK;
+
+ switch (params->key_mgmt_suite) {
+ case KEY_MGMT_802_1X:
+ mgmt = WLAN_AKM_SUITE_8021X;
+ break;
+ case KEY_MGMT_PSK:
+ default:
+ mgmt = WLAN_AKM_SUITE_PSK;
+ break;
+ }
+ NLA_PUT_U32(msg, NL80211_ATTR_AKM_SUITES, mgmt);
+ }
+
+ ret = nl80211_set_conn_keys(drv, params, msg);
+ if (ret)
+ goto nla_put_failure;
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ msg = NULL;
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: MLME connect failed: ret=%d "
+ "(%s)", ret, strerror(-ret));
+ goto nla_put_failure;
+ }
+ ret = 0;
+ wpa_printf(MSG_DEBUG, "nl80211: Connect request send successfully");
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return ret;
+
+}
+
+static int wpa_driver_nl80211_disconnect(void *priv, u8 *addr, int reason_code)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+
+ wpa_printf(MSG_DEBUG, "%s", __func__);
+ drv->associated = 0;
+ return wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DISCONNECT,
+ reason_code);
+}
+
#endif /* HOSTAPD */
@@ -4060,6 +4339,8 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.get_capa = wpa_driver_nl80211_get_capa,
.set_operstate = wpa_driver_nl80211_set_operstate,
.set_supp_port = wpa_driver_nl80211_set_supp_port,
+ .connect = wpa_driver_nl80211_connect,
+ .disconnect = wpa_driver_nl80211_disconnect,
#endif /* HOSTAPD */
.set_country = wpa_driver_nl80211_set_country,
.set_mode = wpa_driver_nl80211_set_mode,
@@ -448,4 +448,22 @@ static inline int wpa_drv_set_supp_port(struct wpa_supplicant *wpa_s,
return 0;
}
+static inline int wpa_drv_connect(struct wpa_supplicant *wpa_s,
+ struct wpa_driver_associate_params *params)
+{
+ if (wpa_s->driver->connect)
+ return wpa_s->driver->connect(wpa_s->drv_priv, params);
+
+ return -1;
+}
+
+static inline int wpa_drv_disconnect(struct wpa_supplicant *wpa_s, u8 *addr,
+ int reason_code)
+{
+ if (wpa_s->driver->disconnect)
+ return wpa_s->driver->disconnect(wpa_s->drv_priv, addr,
+ reason_code);
+ return -1;
+}
+
#endif /* DRIVER_I_H */
@@ -238,6 +238,175 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
*/
}
+void sme_connect(struct wpa_supplicant *wpa_s, struct wpa_scan_res *bss,
+ struct wpa_ssid *ssid)
+{
+ struct wpa_driver_associate_params params;
+ const u8 *ie;
+ int i;
+
+ if (bss == NULL) {
+ wpa_printf(MSG_ERROR, "SME: No scan result available for the "
+ "network");
+ return;
+ }
+
+ os_memset(¶ms, 0, sizeof(params));
+ wpa_s->reassociate = 0;
+
+ params.freq = bss->freq;
+ params.bssid = bss->bssid;
+ ie = wpa_scan_get_ie(bss, WLAN_EID_SSID);
+ if (ie == NULL) {
+ wpa_printf(MSG_ERROR, "SME: SSID not available for the BSS");
+ return;
+ }
+ params.ssid = ie + 2;
+ params.ssid_len = ie[1];
+
+ wpa_s->sme.freq = params.freq;
+ os_memcpy(wpa_s->sme.ssid, params.ssid, params.ssid_len);
+ wpa_s->sme.ssid_len = params.ssid_len;
+
+ params.auth_alg = AUTH_ALG_OPEN_SYSTEM;
+#ifdef IEEE8021X_EAPOL
+ if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
+ if (ssid->leap) {
+ if (ssid->non_leap == 0)
+ params.auth_alg = AUTH_ALG_LEAP;
+ else
+ params.auth_alg |= AUTH_ALG_LEAP;
+ }
+ }
+#endif /* IEEE8021X_EAPOL */
+ wpa_printf(MSG_DEBUG, "Automatic auth_alg selection: 0x%x",
+ params.auth_alg);
+ if (ssid->auth_alg) {
+ params.auth_alg = 0;
+ if (ssid->auth_alg & WPA_AUTH_ALG_OPEN)
+ params.auth_alg |= AUTH_ALG_OPEN_SYSTEM;
+ if (ssid->auth_alg & WPA_AUTH_ALG_SHARED)
+ params.auth_alg |= AUTH_ALG_SHARED_KEY;
+ if (ssid->auth_alg & WPA_AUTH_ALG_LEAP)
+ params.auth_alg |= AUTH_ALG_LEAP;
+ wpa_printf(MSG_DEBUG, "Overriding auth_alg selection: 0x%x",
+ params.auth_alg);
+ }
+
+ for (i = 0; i < NUM_WEP_KEYS; i++) {
+ if (ssid->wep_key_len[i])
+ params.wep_key[i] = ssid->wep_key[i];
+ params.wep_key_len[i] = ssid->wep_key_len[i];
+ }
+ params.wep_tx_keyidx = ssid->wep_tx_keyidx;
+
+ os_memset(wpa_s->bssid, 0, ETH_ALEN);
+ os_memcpy(wpa_s->pending_bssid, bss->bssid, ETH_ALEN);
+
+ if (bss && (wpa_scan_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE) ||
+ wpa_scan_get_ie(bss, WLAN_EID_RSN)) &&
+ (ssid->key_mgmt & (WPA_KEY_MGMT_IEEE8021X | WPA_KEY_MGMT_PSK |
+ WPA_KEY_MGMT_FT_IEEE8021X |
+ WPA_KEY_MGMT_FT_PSK |
+ WPA_KEY_MGMT_IEEE8021X_SHA256 |
+ WPA_KEY_MGMT_PSK_SHA256))) {
+ int try_opportunistic;
+ try_opportunistic = ssid->proactive_key_caching &&
+ (ssid->proto & WPA_PROTO_RSN);
+ if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid,
+ wpa_s->current_ssid,
+ try_opportunistic) == 0)
+ eapol_sm_notify_pmkid_attempt(wpa_s->eapol, 1);
+ wpa_s->sme.assoc_req_ie_len = sizeof(wpa_s->sme.assoc_req_ie);
+ if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
+ wpa_s->sme.assoc_req_ie,
+ &wpa_s->sme.assoc_req_ie_len)) {
+ wpa_printf(MSG_WARNING, "SME: Failed to set WPA key "
+ "management and encryption suites");
+ return;
+ }
+ } else if (ssid->key_mgmt &
+ (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_IEEE8021X |
+ WPA_KEY_MGMT_WPA_NONE | WPA_KEY_MGMT_FT_PSK |
+ WPA_KEY_MGMT_FT_IEEE8021X | WPA_KEY_MGMT_PSK_SHA256 |
+ WPA_KEY_MGMT_IEEE8021X_SHA256)) {
+ wpa_s->sme.assoc_req_ie_len = sizeof(wpa_s->sme.assoc_req_ie);
+ if (wpa_supplicant_set_suites(wpa_s, NULL, ssid,
+ wpa_s->sme.assoc_req_ie,
+ &wpa_s->sme.assoc_req_ie_len)) {
+ wpa_printf(MSG_WARNING, "SME: Failed to set WPA key "
+ "management and encryption suites (no scan "
+ "results)");
+ return;
+ }
+#ifdef CONFIG_WPS
+ } else if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
+ struct wpabuf *wps_ie;
+ wps_ie = wps_build_assoc_req_ie(wpas_wps_get_req_type(ssid));
+ if (wps_ie && wpabuf_len(wps_ie) <=
+ sizeof(wpa_s->sme.assoc_req_ie)) {
+ wpa_s->sme.assoc_req_ie_len = wpabuf_len(wps_ie);
+ os_memcpy(wpa_s->sme.assoc_req_ie, wpabuf_head(wps_ie),
+ wpa_s->sme.assoc_req_ie_len);
+ } else
+ wpa_s->sme.assoc_req_ie_len = 0;
+ wpabuf_free(wps_ie);
+ wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
+#endif /* CONFIG_WPS */
+ } else {
+ wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
+ wpa_s->sme.assoc_req_ie_len = 0;
+ }
+
+#ifdef CONFIG_IEEE80211W
+ switch (ssid->ieee80211w) {
+ case NO_IEEE80211W:
+ wpa_s->sme.mfp = NO_MGMT_FRAME_PROTECTION;
+ break;
+ case IEEE80211W_OPTIONAL:
+ wpa_s->sme.mfp = MGMT_FRAME_PROTECTION_OPTIONAL;
+ break;
+ case IEEE80211W_REQUIRED:
+ wpa_s->sme.mfp = MGMT_FRAME_PROTECTION_REQUIRED;
+ break;
+ }
+ if (ssid->ieee80211w != NO_IEEE80211W && bss) {
+ const u8 *rsn = wpa_scan_get_ie(bss, WLAN_EID_RSN);
+ struct wpa_ie_data _ie;
+ if (rsn && wpa_parse_wpa_ie(rsn, 2 + rsn[1], &_ie) == 0 &&
+ _ie.capabilities &
+ (WPA_CAPABILITY_MFPC | WPA_CAPABILITY_MFPR)) {
+ wpa_printf(MSG_DEBUG, "WPA: Selected AP supports MFP: "
+ "require MFP");
+ wpa_s->sme.mfp = MGMT_FRAME_PROTECTION_REQUIRED;
+ }
+ }
+#endif /* CONFIG_IEEE80211W */
+
+ wpa_supplicant_cancel_scan(wpa_s);
+
+ wpa_msg(wpa_s, MSG_INFO, "Trying to connect with " MACSTR
+ " (SSID='%s' freq=%d MHz)", MAC2STR(params.bssid),
+ wpa_ssid_txt(params.ssid, params.ssid_len), params.freq);
+
+ wpa_clear_keys(wpa_s, bss->bssid);
+ wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATING);
+ wpa_s->current_ssid = ssid;
+ wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid);
+ wpa_supplicant_initiate_eapol(wpa_s);
+
+ params.key_mgmt_suite = key_mgmt2driver(wpa_s->key_mgmt);
+ params.wpa_ie = wpa_s->sme.assoc_req_ie;
+ params.wpa_ie_len = wpa_s->sme.assoc_req_ie_len;
+ params.pairwise_suite = cipher_suite2driver(wpa_s->pairwise_cipher);
+ params.group_suite = cipher_suite2driver(wpa_s->group_cipher);
+
+ if (wpa_drv_connect(wpa_s, ¶ms) < 0) {
+ wpa_msg(wpa_s, MSG_INFO, "Connect to the driver failed");
+ return;
+ }
+}
+
void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data)
{
@@ -19,6 +19,8 @@
void sme_authenticate(struct wpa_supplicant *wpa_s,
struct wpa_scan_res *bss, struct wpa_ssid *ssid);
+void sme_connect(struct wpa_supplicant *wpa_s, struct wpa_scan_res *bss,
+ struct wpa_ssid *ssid);
void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data);
int sme_update_ft_ies(struct wpa_supplicant *wpa_s, const u8 *md,
const u8 *ies, size_t ies_len);
@@ -37,6 +39,12 @@ static inline void sme_authenticate(struct wpa_supplicant *wpa_s,
{
}
+static inline void sme_connect(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_res *bss,
+ struct wpa_ssid *ssid)
+{
+}
+
static inline void sme_event_auth(struct wpa_supplicant *wpa_s,
union wpa_event_data *data)
{
@@ -640,7 +640,7 @@ static void wpa_supplicant_reconfig(int sig, void *eloop_ctx,
}
-static wpa_cipher cipher_suite2driver(int cipher)
+wpa_cipher cipher_suite2driver(int cipher)
{
switch (cipher) {
case WPA_CIPHER_NONE:
@@ -658,7 +658,7 @@ static wpa_cipher cipher_suite2driver(int cipher)
}
-static wpa_key_mgmt key_mgmt2driver(int key_mgmt)
+wpa_key_mgmt key_mgmt2driver(int key_mgmt)
{
switch (key_mgmt) {
case WPA_KEY_MGMT_NONE:
@@ -965,11 +965,16 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
return;
}
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) {
+ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME_AUTH) {
sme_authenticate(wpa_s, bss, ssid);
return;
}
+ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME_CONNECT) {
+ sme_connect(wpa_s, bss, ssid);
+ return;
+ }
+
wpa_s->reassociate = 0;
if (bss) {
#ifdef CONFIG_IEEE80211R
@@ -1303,9 +1308,12 @@ void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
if (!is_zero_ether_addr(wpa_s->bssid)) {
if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
ieee80211_sta_deauthenticate(wpa_s, reason_code);
- else
+ else if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME_AUTH)
wpa_drv_deauthenticate(wpa_s, wpa_s->bssid,
reason_code);
+ else if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME_CONNECT)
+ wpa_drv_disconnect(wpa_s, wpa_s->bssid, reason_code);
+
addr = wpa_s->bssid;
}
wpa_clear_keys(wpa_s, addr);
@@ -392,6 +392,8 @@ int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s);
const char * wpa_supplicant_state_txt(int state);
int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s);
+wpa_cipher cipher_suite2driver(int cipher);
+wpa_key_mgmt key_mgmt2driver(int key_mgmt);
int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
struct wpa_scan_res *bss,
struct wpa_ssid *ssid,
@@ -478,7 +478,7 @@ static int wpa_supplicant_update_ft_ies(void *ctx, const u8 *md,
struct wpa_supplicant *wpa_s = ctx;
if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
return ieee80211_sta_update_ft_ies(wpa_s, md, ies, ies_len);
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
+ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME_AUTH)
return sme_update_ft_ies(wpa_s, md, ies, ies_len);
return wpa_drv_update_ft_ies(wpa_s, md, ies, ies_len);
}
nl80211 driver connect API support. Cc: Johannes Berg <johannes@sipsolutions.net> Cc: Samuel Ortiz <sameo@linux.intel.com> Signed-off-by: Zhu Yi <yi.zhu@intel.com> --- V2: Use auth/assoc as the default operations if they are supported. -- To unsubscribe from this list: send the line "unsubscribe linux-wireless" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html