Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4364623c authored by Scott Ashcroft's avatar Scott Ashcroft Committed by John W. Linville
Browse files

rndis_wlan: Make connections to TKIP PSK networks work



This patch allows the rndis_wlan driver to connect to TKIP PSK
networks.  It uses the ASSOCIATION_INFORMATION RNDIS call to pull back
the IEs and sends them back to userspace using wireless events. Tested
on a few wireless networks I have access to. Based on the similar
code in ndiswrapper.

Signed-off-by: default avatarScott Ashcroft <scott.ashcroft@talk21.com>
[edit: cleanups]
Signed-off-by: default avatarJussi Kivilinna <jussi.kivilinna@mbnet.fi>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent d4231ca3
Loading
Loading
Loading
Loading
+58 −2
Original line number Diff line number Diff line
@@ -116,6 +116,7 @@ MODULE_PARM_DESC(workaround_interval,
#define OID_802_11_ENCRYPTION_STATUS		ccpu2(0x0d01011b)
#define OID_802_11_ADD_KEY			ccpu2(0x0d01011d)
#define OID_802_11_REMOVE_KEY			ccpu2(0x0d01011e)
#define OID_802_11_ASSOCIATION_INFORMATION	ccpu2(0x0d01011f)
#define OID_802_11_PMKID			ccpu2(0x0d010123)
#define OID_802_11_NETWORK_TYPES_SUPPORTED	ccpu2(0x0d010203)
#define OID_802_11_NETWORK_TYPE_IN_USE		ccpu2(0x0d010204)
@@ -271,6 +272,26 @@ struct ndis_config_param {
	__le32 value_length;
} __attribute__((packed));

struct ndis_80211_assoc_info {
	__le32 length;
	__le16 req_ies;
	struct req_ie {
		__le16 capa;
		__le16 listen_interval;
		u8 cur_ap_address[6];
	} req_ie;
	__le32 req_ie_length;
	__le32 offset_req_ies;
	__le16 resp_ies;
	struct resp_ie {
		__le16 capa;
		__le16 status_code;
		__le16 assoc_id;
	} resp_ie;
	__le32 resp_ie_length;
	__le32 offset_resp_ies;
} __attribute__((packed));

/* these have to match what is in wpa_supplicant */
enum wpa_alg { WPA_ALG_NONE, WPA_ALG_WEP, WPA_ALG_TKIP, WPA_ALG_CCMP };
enum wpa_cipher { CIPHER_NONE, CIPHER_WEP40, CIPHER_TKIP, CIPHER_CCMP,
@@ -674,6 +695,12 @@ static int get_bssid(struct usbnet *usbdev, u8 bssid[ETH_ALEN])
	return ret;
}

static int get_association_info(struct usbnet *usbdev,
			struct ndis_80211_assoc_info *info, int len)
{
	return rndis_query_oid(usbdev, OID_802_11_ASSOCIATION_INFORMATION,
				info, &len);
}

static int is_associated(struct usbnet *usbdev)
{
@@ -2182,11 +2209,40 @@ static void rndis_wext_worker(struct work_struct *work)
	struct usbnet *usbdev = priv->usbdev;
	union iwreq_data evt;
	unsigned char bssid[ETH_ALEN];
	int ret;
	struct ndis_80211_assoc_info *info;
	int assoc_size = sizeof(*info) + IW_CUSTOM_MAX + 32;
	int ret, offset;

	if (test_and_clear_bit(WORK_CONNECTION_EVENT, &priv->work_pending)) {
		ret = get_bssid(usbdev, bssid);
		info = kzalloc(assoc_size, GFP_KERNEL);
		if (!info)
			goto get_bssid;

		/* Get association info IEs from device and send them back to
		 * userspace. */
		ret = get_association_info(usbdev, info, assoc_size);
		if (!ret) {
			evt.data.length = le32_to_cpu(info->req_ie_length);
			if (evt.data.length > 0) {
				offset = le32_to_cpu(info->offset_req_ies);
				wireless_send_event(usbdev->net,
					IWEVASSOCREQIE, &evt,
					(char *)info + offset);
			}

			evt.data.length = le32_to_cpu(info->resp_ie_length);
			if (evt.data.length > 0) {
				offset = le32_to_cpu(info->offset_resp_ies);
				wireless_send_event(usbdev->net,
					IWEVASSOCRESPIE, &evt,
					(char *)info + offset);
			}
		}

		kfree(info);

get_bssid:
		ret = get_bssid(usbdev, bssid);
		if (!ret) {
			evt.data.flags = 0;
			evt.data.length = 0;