+static unsigned int get_tlv(unsigned char *ie, unsigned int ie_size,
+ unsigned int type)
+{
+ unsigned int len = 0;
+
+ while (len + 4 < ie_size) {
+ unsigned int hi = ie[len];
+ unsigned int lo = ie[len + 1];
+ unsigned int tmp_type = (hi << 8) + lo;
+ unsigned int v_len = 0;
+
+ /* hi and lo are used to recreate an unsigned int
+ * based on 2 8bits length unsigned int. */
+
+ hi = ie[len + 2];
+ lo = ie[len + 3];
+ v_len = (hi << 8) + lo;
+
+ if (tmp_type == type) {
+ unsigned int ret_value = 0;
+ unsigned char *value = (unsigned char *)&ret_value;
+
+ SUPPLICANT_DBG("IE: match type 0x%x", type);
+
+ /* Verifying length relevance */
+ if (v_len > sizeof(unsigned int) ||
+ len + 4 + v_len > ie_size)
+ break;
+
+ memcpy(value, ie + len + 4, v_len);
+
+ SUPPLICANT_DBG("returning 0x%x", ret_value);
+ return ret_value;
+ }
+
+ len += v_len + 4;
+ }
+
+ SUPPLICANT_DBG("returning 0");
+ return 0;
+}
+
+static void bss_process_ies(DBusMessageIter *iter, void *user_data)
+{
+ struct g_supplicant_bss *bss = user_data;
+ const unsigned char WPS_OUI[] = { 0x00, 0x50, 0xf2, 0x04 };
+ unsigned char *ie, *ie_end;
+ DBusMessageIter array;
+ int ie_len;
+
+#define WMM_WPA1_WPS_INFO 221
+#define WPS_INFO_MIN_LEN 6
+#define WPS_VERSION_TLV 0x104A
+#define WPS_STATE_TLV 0x1044
+#define WPS_VERSION 0x10
+
+ dbus_message_iter_recurse(iter, &array);
+ dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
+
+ if (ie == NULL || ie_len < 2)
+ return;
+
+ for (ie_end = ie+ie_len; ie+ie[1]+1 <= ie_end; ie += ie[1]+2) {
+ if (ie[0] != WMM_WPA1_WPS_INFO || ie[1] < WPS_INFO_MIN_LEN ||
+ memcmp(ie+2, WPS_OUI, sizeof(WPS_OUI)) != 0)
+ continue;
+
+ SUPPLICANT_DBG("IE: match WPS_OUI");
+
+ if (get_tlv(&ie[6], ie[1],
+ WPS_VERSION_TLV) == WPS_VERSION &&
+ get_tlv(&ie[6], ie[1],
+ WPS_STATE_TLV) != 0)
+ bss->keymgmt |= G_SUPPLICANT_KEYMGMT_WPS;
+ }
+}