diff options
author | Dan Williams <dcbw@redhat.com> | 2005-12-14 19:12:20 +0000 |
---|---|---|
committer | Dan Williams <dcbw@redhat.com> | 2005-12-14 19:12:20 +0000 |
commit | 423383c0e573bdb2463d2abb9181ba5e8490c533 (patch) | |
tree | 44ca11dc0e6f1f62bfc28cbb1ae19ee096b50b97 | |
parent | 1da42ec8355692be864bf0f5721b145de1e679a6 (diff) | |
download | NetworkManager-423383c0e573bdb2463d2abb9181ba5e8490c533.tar.gz |
2005-12-14 Dan Williams <dcbw@redhat.com>
* include/NetworkManager.h
- Add 802.11-specific capability for 802.1x key
management
* src/wpa.[ch]
- Pull in WPA IE and RSN IE parsing code from
wpa_supplicant so we can determine access point
capabilities
- Move WPA-related constants here from NetworkManagerAP.h
and NetworkManagerDevice.c
* src/NetworkManagerDevice.c
src/NetworkManagerAP.[ch]
- Use WPA-related constants from wpa.h
git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@1190 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
-rw-r--r-- | ChangeLog | 17 | ||||
-rw-r--r-- | include/NetworkManager.h | 8 | ||||
-rw-r--r-- | src/NetworkManagerAP.c | 6 | ||||
-rw-r--r-- | src/NetworkManagerAP.h | 3 | ||||
-rw-r--r-- | src/NetworkManagerDevice.c | 10 | ||||
-rw-r--r-- | src/wpa.c | 451 | ||||
-rw-r--r-- | src/wpa.h | 38 |
7 files changed, 519 insertions, 14 deletions
@@ -1,6 +1,23 @@ 2005-12-14 Dan Williams <dcbw@redhat.com> * include/NetworkManager.h + - Add 802.11-specific capability for 802.1x key + management + + * src/wpa.[ch] + - Pull in WPA IE and RSN IE parsing code from + wpa_supplicant so we can determine access point + capabilities + - Move WPA-related constants here from NetworkManagerAP.h + and NetworkManagerDevice.c + + * src/NetworkManagerDevice.c + src/NetworkManagerAP.[ch] + - Use WPA-related constants from wpa.h + +2005-12-14 Dan Williams <dcbw@redhat.com> + + * include/NetworkManager.h - Update and split 802.11 wireless-specific capabilities from generic device capabilities diff --git a/include/NetworkManager.h b/include/NetworkManager.h index 3fc36860e8..e0541ac226 100644 --- a/include/NetworkManager.h +++ b/include/NetworkManager.h @@ -109,10 +109,10 @@ typedef enum NMEncKeyType #define NM_802_11_CAP_KEY_MGMT_WPA_PSK 0x00000002 #define NM_802_11_CAP_KEY_MGMT_WPA2 0x00000004 #define NM_802_11_CAP_KEY_MGMT_WPA2_PSK 0x00000008 -#define NM_802_11_CAP_KEY_MGMT_RESERVED1 0x00000010 -#define NM_802_11_CAP_KEY_MGMT_RESERVED2 0x00000020 -#define NM_802_11_CAP_KEY_MGMT_RESERVED3 0x00000040 -#define NM_802_11_CAP_KEY_MGMT_RESERVED4 0x00000080 +#define NM_802_11_CAP_KEY_MGMT_IEEE8021X 0x00000010 +#define NM_802_11_CAP_KEY_MGMT_RESERVED1 0x00000020 +#define NM_802_11_CAP_KEY_MGMT_RESERVED2 0x00000040 +#define NM_802_11_CAP_KEY_MGMT_RESERVED3 0x00000080 #define NM_802_11_CAP_CIPHER_WEP40 0x00000100 #define NM_802_11_CAP_CIPHER_WEP104 0x00000200 #define NM_802_11_CAP_CIPHER_TKIP 0x00000400 diff --git a/src/NetworkManagerAP.c b/src/NetworkManagerAP.c index fc05d0b7b9..35386c8909 100644 --- a/src/NetworkManagerAP.c +++ b/src/NetworkManagerAP.c @@ -32,6 +32,8 @@ struct NMAccessPoint { guint refcount; + + /* Scanned or cached values */ char * essid; struct ether_addr * address; int mode; /* from IW_MODE_* in wireless.h */ @@ -664,7 +666,7 @@ void nm_ap_set_wpa_ie (NMAccessPoint *ap, const char *wpa_ie, guint32 length) g_return_if_fail (ap != NULL); if (wpa_ie) - g_return_if_fail ((length > 0) && (length <= AP_MAX_WPA_IE_LEN)); + g_return_if_fail ((length > 0) && (length <= WPA_MAX_IE_LEN)); if (ap->wpa_ie) { @@ -695,7 +697,7 @@ void nm_ap_set_rsn_ie (NMAccessPoint *ap, const char *rsn_ie, guint32 length) g_return_if_fail (ap != NULL); if (rsn_ie) - g_return_if_fail ((length > 0) && (length <= AP_MAX_WPA_IE_LEN)); + g_return_if_fail ((length > 0) && (length <= WPA_MAX_IE_LEN)); if (ap->rsn_ie) { diff --git a/src/NetworkManagerAP.h b/src/NetworkManagerAP.h index 114afa7a42..661edbfbe8 100644 --- a/src/NetworkManagerAP.h +++ b/src/NetworkManagerAP.h @@ -25,11 +25,10 @@ #include <glib.h> #include <time.h> #include "NetworkManager.h" +#include "wpa.h" typedef struct NMAccessPoint NMAccessPoint; -#define AP_MAX_WPA_IE_LEN 40 - NMAccessPoint * nm_ap_new (void); NMAccessPoint * nm_ap_new_from_ap (NMAccessPoint *ap); diff --git a/src/NetworkManagerDevice.c b/src/NetworkManagerDevice.c index 328096ef2a..431ebc513a 100644 --- a/src/NetworkManagerDevice.c +++ b/src/NetworkManagerDevice.c @@ -4681,8 +4681,6 @@ static gboolean process_scan_results (NMDevice *dev, const guint8 *res_buf, guin break; #endif case IWEVGENIE: - #define GENERIC_INFO_ELEM 0xdd - #define RSN_INFO_ELEM 0x30 gpos = genie = custom; gend = genie + iwe->u.data.length; if (gend > end) @@ -4693,19 +4691,19 @@ static gboolean process_scan_results (NMDevice *dev, const guint8 *res_buf, guin while ((gpos + 1 < gend) && (gpos + 2 + (u8) gpos[1] <= gend)) { u8 ie = gpos[0], ielen = gpos[1] + 2; - if (ielen > AP_MAX_WPA_IE_LEN) + if (ielen > WPA_MAX_IE_LEN) { gpos += ielen; continue; } switch (ie) { - case GENERIC_INFO_ELEM: + case WPA_GENERIC_INFO_ELEM: if ((ielen < 2 + 4) || (memcmp (&gpos[2], "\x00\x50\xf2\x01", 4) != 0)) break; nm_ap_set_wpa_ie (ap, gpos, ielen); break; - case RSN_INFO_ELEM: + case WPA_RSN_INFO_ELEM: nm_ap_set_rsn_ie (ap, gpos, ielen); break; } @@ -4727,7 +4725,7 @@ static gboolean process_scan_results (NMDevice *dev, const guint8 *res_buf, guin if (bytes & 1) break; bytes /= 2; - if (bytes > AP_MAX_WPA_IE_LEN) + if (bytes > WPA_MAX_IE_LEN) { nm_warning ("get_scan_results(): IE was too long (%d bytes).", bytes); break; diff --git a/src/wpa.c b/src/wpa.c new file mode 100644 index 0000000000..3b37da6a43 --- /dev/null +++ b/src/wpa.c @@ -0,0 +1,451 @@ +/* + * WPA Supplicant - WPA state machine and EAPOL-Key processing + * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this file may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include <stdint.h> +#include <iwlib.h> + +#include "wpa.h" +#include "nm-utils.h" + +/* crack */ +typedef uint64_t u64; +typedef uint32_t u32; +typedef uint16_t u16; +typedef uint8_t u8; +typedef int64_t s64; +typedef int32_t s32; +typedef int16_t s16; +typedef int8_t s8; + +#define WPA_GET_LE16(a) ((u16) (((a)[1] << 8) | (a)[0])) + +#define BIT(n) (1 << (n)) +#define WPA_CAPABILITY_PREAUTH BIT(0) + +#define WPA_REPLAY_COUNTER_LEN 8 +#define WPA_NONCE_LEN 32 + +#define PMKID_LEN 16 + +static const int WPA_SELECTOR_LEN = 4; +static const u8 WPA_OUI_TYPE[] = { 0x00, 0x50, 0xf2, 1 }; +static const u16 WPA_VERSION = 1; +static const u8 WPA_AUTH_KEY_MGMT_NONE[] = { 0x00, 0x50, 0xf2, 0 }; +static const u8 WPA_AUTH_KEY_MGMT_UNSPEC_802_1X[] = { 0x00, 0x50, 0xf2, 1 }; +static const u8 WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X[] = { 0x00, 0x50, 0xf2, 2 }; +static const u8 WPA_CIPHER_SUITE_NONE[] = { 0x00, 0x50, 0xf2, 0 }; +static const u8 WPA_CIPHER_SUITE_WEP40[] = { 0x00, 0x50, 0xf2, 1 }; +static const u8 WPA_CIPHER_SUITE_TKIP[] = { 0x00, 0x50, 0xf2, 2 }; +static const u8 WPA_CIPHER_SUITE_WRAP[] = { 0x00, 0x50, 0xf2, 3 }; +static const u8 WPA_CIPHER_SUITE_CCMP[] = { 0x00, 0x50, 0xf2, 4 }; +static const u8 WPA_CIPHER_SUITE_WEP104[] = { 0x00, 0x50, 0xf2, 5 }; + +/* WPA IE version 1 + * 00-50-f2:1 (OUI:OUI type) + * 0x01 0x00 (version; little endian) + * (all following fields are optional:) + * Group Suite Selector (4 octets) (default: TKIP) + * Pairwise Suite Count (2 octets, little endian) (default: 1) + * Pairwise Suite List (4 * n octets) (default: TKIP) + * Authenticated Key Management Suite Count (2 octets, little endian) + * (default: 1) + * Authenticated Key Management Suite List (4 * n octets) + * (default: unspec 802.1X) + * WPA Capabilities (2 octets, little endian) (default: 0) + */ + +struct wpa_ie_hdr { + u8 elem_id; + u8 len; + u8 oui[3]; + u8 oui_type; + u8 version[2]; +} __attribute__ ((packed)); + + +static const int RSN_SELECTOR_LEN = 4; +static const u16 RSN_VERSION = 1; +static const u8 RSN_AUTH_KEY_MGMT_UNSPEC_802_1X[] = { 0x00, 0x0f, 0xac, 1 }; +static const u8 RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X[] = { 0x00, 0x0f, 0xac, 2 }; +static const u8 RSN_CIPHER_SUITE_NONE[] = { 0x00, 0x0f, 0xac, 0 }; +static const u8 RSN_CIPHER_SUITE_WEP40[] = { 0x00, 0x0f, 0xac, 1 }; +static const u8 RSN_CIPHER_SUITE_TKIP[] = { 0x00, 0x0f, 0xac, 2 }; +static const u8 RSN_CIPHER_SUITE_WRAP[] = { 0x00, 0x0f, 0xac, 3 }; +static const u8 RSN_CIPHER_SUITE_CCMP[] = { 0x00, 0x0f, 0xac, 4 }; +static const u8 RSN_CIPHER_SUITE_WEP104[] = { 0x00, 0x0f, 0xac, 5 }; + +/* EAPOL-Key Key Data Encapsulation + * GroupKey and STAKey require encryption, otherwise, encryption is optional. + */ +static const u8 RSN_KEY_DATA_GROUPKEY[] = { 0x00, 0x0f, 0xac, 1 }; +static const u8 RSN_KEY_DATA_STAKEY[] = { 0x00, 0x0f, 0xac, 2 }; +static const u8 RSN_KEY_DATA_MAC_ADDR[] = { 0x00, 0x0f, 0xac, 3 }; +static const u8 RSN_KEY_DATA_PMKID[] = { 0x00, 0x0f, 0xac, 4 }; + +/* 1/4: PMKID + * 2/4: RSN IE + * 3/4: one or two RSN IEs + GTK IE (encrypted) + * 4/4: empty + * 1/2: GTK IE (encrypted) + * 2/2: empty + */ + +/* RSN IE version 1 + * 0x01 0x00 (version; little endian) + * (all following fields are optional:) + * Group Suite Selector (4 octets) (default: CCMP) + * Pairwise Suite Count (2 octets, little endian) (default: 1) + * Pairwise Suite List (4 * n octets) (default: CCMP) + * Authenticated Key Management Suite Count (2 octets, little endian) + * (default: 1) + * Authenticated Key Management Suite List (4 * n octets) + * (default: unspec 802.1X) + * RSN Capabilities (2 octets, little endian) (default: 0) + * PMKID Count (2 octets) (default: 0) + * PMKID List (16 * n octets) + */ + +struct rsn_ie_hdr { + u8 elem_id; /* WLAN_EID_RSN */ + u8 len; + u8 version[2]; +} __attribute__ ((packed)); + + +#define WPA_KEY_INFO_TYPE_MASK (BIT(0) | BIT(1) | BIT(2)) +#define WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 BIT(0) +#define WPA_KEY_INFO_TYPE_HMAC_SHA1_AES BIT(1) +#define WPA_KEY_INFO_KEY_TYPE BIT(3) /* 1 = Pairwise, 0 = Group key */ +/* bit4..5 is used in WPA, but is reserved in IEEE 802.11i/RSN */ +#define WPA_KEY_INFO_KEY_INDEX_MASK (BIT(4) | BIT(5)) +#define WPA_KEY_INFO_KEY_INDEX_SHIFT 4 +#define WPA_KEY_INFO_INSTALL BIT(6) /* pairwise */ +#define WPA_KEY_INFO_TXRX BIT(6) /* group */ +#define WPA_KEY_INFO_ACK BIT(7) +#define WPA_KEY_INFO_MIC BIT(8) +#define WPA_KEY_INFO_SECURE BIT(9) +#define WPA_KEY_INFO_ERROR BIT(10) +#define WPA_KEY_INFO_REQUEST BIT(11) +#define WPA_KEY_INFO_ENCR_KEY_DATA BIT(12) /* IEEE 802.11i/RSN only */ + + + +static int wpa_selector_to_bitfield(const u8 *s) +{ + if (memcmp(s, WPA_CIPHER_SUITE_NONE, WPA_SELECTOR_LEN) == 0) + return IW_AUTH_CIPHER_NONE; + if (memcmp(s, WPA_CIPHER_SUITE_WEP40, WPA_SELECTOR_LEN) == 0) + return IW_AUTH_CIPHER_WEP40; + if (memcmp(s, WPA_CIPHER_SUITE_TKIP, WPA_SELECTOR_LEN) == 0) + return IW_AUTH_CIPHER_TKIP; + if (memcmp(s, WPA_CIPHER_SUITE_CCMP, WPA_SELECTOR_LEN) == 0) + return IW_AUTH_CIPHER_CCMP; + if (memcmp(s, WPA_CIPHER_SUITE_WEP104, WPA_SELECTOR_LEN) == 0) + return IW_AUTH_CIPHER_WEP104; + return 0; +} + + +static int wpa_key_mgmt_to_bitfield(const u8 *s) +{ + if (memcmp(s, WPA_AUTH_KEY_MGMT_UNSPEC_802_1X, WPA_SELECTOR_LEN) == 0) + return IW_AUTH_KEY_MGMT_802_1X; + if (memcmp(s, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X, WPA_SELECTOR_LEN) == + 0) + return IW_AUTH_KEY_MGMT_PSK; + if (memcmp(s, WPA_AUTH_KEY_MGMT_NONE, WPA_SELECTOR_LEN) == 0) + return 0; + return 0; +} + + +static int rsn_selector_to_bitfield(const u8 *s) +{ + if (memcmp(s, RSN_CIPHER_SUITE_NONE, RSN_SELECTOR_LEN) == 0) + return IW_AUTH_CIPHER_NONE; + if (memcmp(s, RSN_CIPHER_SUITE_WEP40, RSN_SELECTOR_LEN) == 0) + return IW_AUTH_CIPHER_WEP40; + if (memcmp(s, RSN_CIPHER_SUITE_TKIP, RSN_SELECTOR_LEN) == 0) + return IW_AUTH_CIPHER_TKIP; + if (memcmp(s, RSN_CIPHER_SUITE_CCMP, RSN_SELECTOR_LEN) == 0) + return IW_AUTH_CIPHER_CCMP; + if (memcmp(s, RSN_CIPHER_SUITE_WEP104, RSN_SELECTOR_LEN) == 0) + return IW_AUTH_CIPHER_WEP104; + return 0; +} + + +static int rsn_key_mgmt_to_bitfield(const u8 *s) +{ + if (memcmp(s, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X, RSN_SELECTOR_LEN) == 0) + return IW_AUTH_KEY_MGMT_802_1X; + if (memcmp(s, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X, RSN_SELECTOR_LEN) == + 0) + return IW_AUTH_KEY_MGMT_PSK; + return 0; +} + + +static int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len, + struct wpa_ie_data *data) +{ + const struct wpa_ie_hdr *hdr; + const u8 *pos; + int left; + int i, count; + + data->proto = IW_AUTH_WPA_VERSION_WPA; + data->pairwise_cipher = IW_AUTH_CIPHER_TKIP; + data->group_cipher = IW_AUTH_CIPHER_TKIP; + data->key_mgmt = IW_AUTH_KEY_MGMT_802_1X; + data->capabilities = 0; + data->pmkid = NULL; + data->num_pmkid = 0; + + if (wpa_ie_len == 0) { + /* No WPA IE - fail silently */ + return -1; + } + + if (wpa_ie_len < sizeof(struct wpa_ie_hdr)) { + nm_debug ("%s: ie len too short %lu", + __func__, (unsigned long) wpa_ie_len); + return -1; + } + + hdr = (const struct wpa_ie_hdr *) wpa_ie; + + if (hdr->elem_id != WPA_GENERIC_INFO_ELEM || + hdr->len != wpa_ie_len - 2 || + memcmp(hdr->oui, WPA_OUI_TYPE, WPA_SELECTOR_LEN) != 0 || + WPA_GET_LE16(hdr->version) != WPA_VERSION) { + nm_debug ("%s: malformed ie or unknown version", + __func__); + return -1; + } + + pos = (const u8 *) (hdr + 1); + left = wpa_ie_len - sizeof(*hdr); + + if (left >= WPA_SELECTOR_LEN) { + data->group_cipher = wpa_selector_to_bitfield(pos); + pos += WPA_SELECTOR_LEN; + left -= WPA_SELECTOR_LEN; + } else if (left > 0) { + nm_debug ("%s: ie length mismatch, %u too much", + __func__, left); + return -1; + } + + if (left >= 2) { + data->pairwise_cipher = 0; + count = WPA_GET_LE16(pos); + pos += 2; + left -= 2; + if (count == 0 || left < count * WPA_SELECTOR_LEN) { + nm_debug ("%s: ie count botch (pairwise), " + "count %u left %u", __func__, count, left); + return -1; + } + for (i = 0; i < count; i++) { + data->pairwise_cipher |= wpa_selector_to_bitfield(pos); + pos += WPA_SELECTOR_LEN; + left -= WPA_SELECTOR_LEN; + } + } else if (left == 1) { + nm_debug ("%s: ie too short (for key mgmt)", + __func__); + return -1; + } + + if (left >= 2) { + data->key_mgmt = 0; + count = WPA_GET_LE16(pos); + pos += 2; + left -= 2; + if (count == 0 || left < count * WPA_SELECTOR_LEN) { + nm_debug ("%s: ie count botch (key mgmt), " + "count %u left %u", __func__, count, left); + return -1; + } + for (i = 0; i < count; i++) { + data->key_mgmt |= wpa_key_mgmt_to_bitfield(pos); + pos += WPA_SELECTOR_LEN; + left -= WPA_SELECTOR_LEN; + } + } else if (left == 1) { + nm_debug ("%s: ie too short (for capabilities)", + __func__); + return -1; + } + + if (left >= 2) { + if (WPA_GET_LE16 (pos) & WPA_CAPABILITY_PREAUTH) + data->capabilities |= IW_PMKID_CAND_PREAUTH; + pos += 2; + left -= 2; + } + + if (left > 0) { + nm_debug ("%s: ie has %u trailing bytes", + __func__, left); + return -1; + } + + return 0; +} + + +static int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len, + struct wpa_ie_data *data) +{ + const struct rsn_ie_hdr *hdr; + const u8 *pos; + int left; + int i, count; + + data->proto = IW_AUTH_WPA_VERSION_WPA2; + data->pairwise_cipher = IW_AUTH_CIPHER_CCMP; + data->group_cipher = IW_AUTH_CIPHER_CCMP; + data->key_mgmt = IW_AUTH_KEY_MGMT_802_1X; + data->capabilities = 0; + data->pmkid = NULL; + data->num_pmkid = 0; + + if (rsn_ie_len == 0) { + /* No RSN IE - fail silently */ + return -1; + } + + if (rsn_ie_len < sizeof(struct rsn_ie_hdr)) { + nm_debug ("%s: ie len too short %lu", + __func__, (unsigned long) rsn_ie_len); + return -1; + } + + hdr = (const struct rsn_ie_hdr *) rsn_ie; + + if (hdr->elem_id != WPA_RSN_INFO_ELEM || + hdr->len != rsn_ie_len - 2 || + WPA_GET_LE16(hdr->version) != RSN_VERSION) { + nm_debug ("%s: malformed ie or unknown version", + __func__); + return -1; + } + + pos = (const u8 *) (hdr + 1); + left = rsn_ie_len - sizeof(*hdr); + + if (left >= RSN_SELECTOR_LEN) { + data->group_cipher = rsn_selector_to_bitfield(pos); + pos += RSN_SELECTOR_LEN; + left -= RSN_SELECTOR_LEN; + } else if (left > 0) { + nm_debug ("%s: ie length mismatch, %u too much", + __func__, left); + return -1; + } + + if (left >= 2) { + data->pairwise_cipher = 0; + count = WPA_GET_LE16(pos); + pos += 2; + left -= 2; + if (count == 0 || left < count * RSN_SELECTOR_LEN) { + nm_debug ("%s: ie count botch (pairwise), " + "count %u left %u", __func__, count, left); + return -1; + } + for (i = 0; i < count; i++) { + data->pairwise_cipher |= rsn_selector_to_bitfield(pos); + pos += RSN_SELECTOR_LEN; + left -= RSN_SELECTOR_LEN; + } + } else if (left == 1) { + nm_debug ("%s: ie too short (for key mgmt)", + __func__); + return -1; + } + + if (left >= 2) { + data->key_mgmt = 0; + count = WPA_GET_LE16(pos); + pos += 2; + left -= 2; + if (count == 0 || left < count * RSN_SELECTOR_LEN) { + nm_debug ("%s: ie count botch (key mgmt), " + "count %u left %u", __func__, count, left); + return -1; + } + for (i = 0; i < count; i++) { + data->key_mgmt |= rsn_key_mgmt_to_bitfield(pos); + pos += RSN_SELECTOR_LEN; + left -= RSN_SELECTOR_LEN; + } + } else if (left == 1) { + nm_debug ("%s: ie too short (for capabilities)", + __func__); + return -1; + } + + if (left >= 2) { + if (WPA_GET_LE16 (pos) & WPA_CAPABILITY_PREAUTH) + data->capabilities |= IW_PMKID_CAND_PREAUTH; + pos += 2; + left -= 2; + } + + if (left >= 2) { + data->num_pmkid = WPA_GET_LE16(pos); + pos += 2; + left -= 2; + if (left < data->num_pmkid * PMKID_LEN) { + nm_debug ("%s: PMKID underflow " + "(num_pmkid=%d left=%d)", + __func__, data->num_pmkid, left); + data->num_pmkid = 0; + } else { + data->pmkid = pos; + pos += data->num_pmkid * PMKID_LEN; + left -= data->num_pmkid * PMKID_LEN; + } + } + + if (left > 0) { + nm_debug ("%s: ie has %u trailing bytes - ignored", + __func__, left); + } + + return 0; +} + + +/** + * wpa_parse_wpa_ie - Parse WPA/RSN IE + * @wpa_ie: Pointer to WPA or RSN IE + * @wpa_ie_len: Length of the WPA/RSN IE + * @data: Pointer to data area for parsing results + * Returns: 0 on success, -1 on failure + * + * Parse the contents of WPA or RSN IE and write the parsed data into data. + */ +int wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len, + struct wpa_ie_data *data) +{ + if (wpa_ie_len >= 1 && wpa_ie[0] == WPA_RSN_INFO_ELEM) + return wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, data); + else + return wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, data); +} + diff --git a/src/wpa.h b/src/wpa.h new file mode 100644 index 0000000000..2f5035193e --- /dev/null +++ b/src/wpa.h @@ -0,0 +1,38 @@ +/* + * wpa_supplicant - WPA definitions + * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this file may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef WPA_H +#define WPA_H + +#include <stdint.h> + +#define WPA_GENERIC_INFO_ELEM 0xdd +#define WPA_RSN_INFO_ELEM 0x30 + +#define WPA_MAX_IE_LEN 40 + +struct wpa_ie_data { + int proto; + int pairwise_cipher; + int group_cipher; + int key_mgmt; + int capabilities; + int num_pmkid; + const uint8_t *pmkid; +}; + + +int wpa_parse_wpa_ie(const uint8_t *wpa_ie, size_t wpa_ie_len, struct wpa_ie_data *data); + +#endif /* WPA_H */ |