From patchwork Mon Sep 30 18:11:43 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dylan Eskew X-Patchwork-Id: 13816819 X-Patchwork-Delegate: johannes@sipsolutions.net Received: from dispatch1-us1.ppe-hosted.com (dispatch1-us1.ppe-hosted.com [148.163.129.49]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7DF4A1990BB for ; Mon, 30 Sep 2024 18:11:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.163.129.49 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1727719921; cv=none; b=kUicMcX7eJx/3U+nRLKrHdKZWyAVNa/vN0HpL+6woDibHM034cBCfD6Qb8v3tKQDcEdcvm0SrVA4XHLst+BrnKKxG7aDUWKXsM9eH2u73FbbCoKgAGN2Ao3Oq/R4nffrx/zyRz2J9m0gbW4R8gO5bhtU+2y5ZO7CiZRRxDeuzv8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1727719921; c=relaxed/simple; bh=Aj3/rplR8YG2RaFIf0qFHTLc3UKoWfvWXmznhhalgV4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Vf2wB5fTUnS/ZEEumpxGQc4I/aSMAJkwJP+uUPPLw3BOHJ1/pVdQazjYLXlc+/fxZWY3F1dpGYTHhE26+t9Yk4BrKIag9LodUy6aTZUXuXeIXIG1iH4+oljwohPdYuMLGoYX/62zyN+0LVUaoy+1oo2oFIzKvKrNK2jpa9Ru+nE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=candelatech.com; spf=pass smtp.mailfrom=candelatech.com; dkim=pass (1024-bit key) header.d=candelatech.com header.i=@candelatech.com header.b=FuT/XNiV; arc=none smtp.client-ip=148.163.129.49 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=candelatech.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=candelatech.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=candelatech.com header.i=@candelatech.com header.b="FuT/XNiV" X-Virus-Scanned: Proofpoint Essentials engine Received: from mail3.candelatech.com (mail.candelatech.com [208.74.158.173]) by mx1-us1.ppe-hosted.com (PPE Hosted ESMTP Server) with ESMTP id B2241C0069; Mon, 30 Sep 2024 18:11:51 +0000 (UTC) Received: from corvid-conspiracy.candelatech.com (unknown [50.251.239.81]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail3.candelatech.com (Postfix) with ESMTPSA id 3325D13C2B1; Mon, 30 Sep 2024 11:11:51 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 mail3.candelatech.com 3325D13C2B1 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=candelatech.com; s=default; t=1727719911; bh=Aj3/rplR8YG2RaFIf0qFHTLc3UKoWfvWXmznhhalgV4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=FuT/XNiV3wpqNltpQXF583CjG7F1SfcsX4m/g9teDbCpjpxOUbcT5juQ1PDezTGtM VELjGXl/XtZk3e20v65zB57XtWrjbMoo6DlirphbPBF+Bb4737Y2fKDAr5mOSOTmJB huhqoqDq4E4NnmeEYe4S2bInI0WdzfYHs9s6TYIw= From: Dylan Eskew To: johannes@sipsolutions.net Cc: linux-wireless@vger.kernel.org, Dylan Eskew Subject: [PATCH 1/3] iw: scan: add enum for ie ids Date: Mon, 30 Sep 2024 11:11:43 -0700 Message-ID: <20240930181145.1043048-2-dylan.eskew@candelatech.com> X-Mailer: git-send-email 2.46.0 In-Reply-To: <20240930181145.1043048-1-dylan.eskew@candelatech.com> References: <20240930181145.1043048-1-dylan.eskew@candelatech.com> Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MDID: 1727719912-dq0VvaAhFcae X-MDID-O: us5;ut7;1727719912;dq0VvaAhFcae;;b42792dba290a1257c3f0aaf1c60b0ff Formerly, ie ids were hardcoded. This change will improve readability of logic which may explicitly reference an ie id. Signed-off-by: Dylan Eskew --- ieee80211.h | 43 +++++++++++++++++++++++++++ scan.c | 84 +++++++++++++++++++++++++++++++---------------------- 2 files changed, 92 insertions(+), 35 deletions(-) diff --git a/ieee80211.h b/ieee80211.h index 3713a4d..96d5c52 100644 --- a/ieee80211.h +++ b/ieee80211.h @@ -58,6 +58,49 @@ struct ieee80211_vht_cap { struct ieee80211_vht_mcs_info mcs; } __attribute__ ((packed)); +#define NUM_IES 256 +enum elem_id { + EID_SSID = 0, + EID_SUPP_RATES = 1, + EID_DS_PARAMS = 3, + EID_TIM = 5, + EID_IBSS_TIM_PARAMS = 6, + EID_COUNTRY = 7, + EID_BSS_LOAD = 11, + EID_POWER_CONSTRAINT = 32, + EID_TPC_REPORT = 35, + EID_ERP_INFO = 42, + EID_HT_CAPABILITY = 45, + EID_ERP_D4_0 = 47, + EID_RSN = 48, + EID_EXT_SUPP_RATES = 50, + EID_AP_CHAN_REPORT = 51, + EID_SUPP_OP_CLASSES = 59, + EID_HT_OPERATION = 61, + EID_SECONDARY_CH_OFFSET = 62, + EID_MEASUREMENT_PILOT_TX = 66, + EID_RM_ENABLED_CAPABILITIES = 70, + EID_OVERLAP_BSS_SCAN_PARAM = 74, + EID_INTERWORKING = 107, + EID_ADVERTISEMENT = 108, + EID_ROAMING_CONSORTIUM = 111, + EID_MESH_CONFIG = 113, + EID_MESH_ID = 114, + EID_EXT_CAPABILITY = 127, + EID_VHT_CAPABILITY = 191, + EID_VHT_OPERATION = 192, + EID_TRANSMIT_POWER_ENVELOPE = 195, + EID_SHORT_BEACON_INTERVAL = 214, + EID_S1G_CAPABILITY = 217, + EID_VENDOR = 221, + EID_S1G_OPERATION = 232, + EID_EXTENSION = 255, +}; + +enum elem_id_ext { + EID_EXT_HE_CAPABILITY = 35, +}; + #define SUITE(oui, id) (((oui) << 8) | (id)) /* cipher suite selectors */ diff --git a/scan.c b/scan.c index faf406d..83b7f58 100644 --- a/scan.c +++ b/scan.c @@ -1816,40 +1816,54 @@ static void print_ie(const struct ie_print *p, const uint8_t type, uint8_t len, } static const struct ie_print ieprinters[] = { - [0] = { "SSID", print_ssid, 0, 32, - BIT(PRINT_SCAN) | BIT(PRINT_LINK) | BIT(PRINT_LINK_MLO_MLD), }, - [1] = { "Supported rates", print_supprates, 0, 255, BIT(PRINT_SCAN), }, - [3] = { "DS Parameter set", print_ds, 1, 1, BIT(PRINT_SCAN), }, - [5] = { "TIM", print_tim, 4, 255, BIT(PRINT_SCAN), }, - [6] = { "IBSS ATIM window", print_ibssatim, 2, 2, BIT(PRINT_SCAN), }, - [7] = { "Country", print_country, 3, 255, BIT(PRINT_SCAN), }, - [11] = { "BSS Load", print_bss_load, 5, 5, BIT(PRINT_SCAN), }, - [32] = { "Power constraint", print_powerconstraint, 1, 1, BIT(PRINT_SCAN), }, - [35] = { "TPC report", print_tpcreport, 2, 2, BIT(PRINT_SCAN), }, - [42] = { "ERP", print_erp, 1, 255, BIT(PRINT_SCAN), }, - [45] = { "HT capabilities", print_ht_capa, 26, 26, BIT(PRINT_SCAN), }, - [47] = { "ERP D4.0", print_erp, 1, 255, BIT(PRINT_SCAN), }, - [51] = { "AP Channel Report", print_ap_channel_report, 1, 255, BIT(PRINT_SCAN), }, - [59] = { "Supported operating classes", print_supp_op_classes, 1, 255, BIT(PRINT_SCAN), }, - [66] = { "Measurement Pilot Transmission", print_measurement_pilot_tx, 1, 255, BIT(PRINT_SCAN), }, - [74] = { "Overlapping BSS scan params", print_obss_scan_params, 14, 255, BIT(PRINT_SCAN), }, - [61] = { "HT operation", print_ht_op, 22, 22, BIT(PRINT_SCAN), }, - [62] = { "Secondary Channel Offset", print_secchan_offs, 1, 1, BIT(PRINT_SCAN), }, - [191] = { "VHT capabilities", print_vht_capa, 12, 255, BIT(PRINT_SCAN), }, - [192] = { "VHT operation", print_vht_oper, 5, 255, BIT(PRINT_SCAN), }, - [48] = { "RSN", print_rsn, 2, 255, BIT(PRINT_SCAN), }, - [50] = { "Extended supported rates", print_supprates, 0, 255, BIT(PRINT_SCAN), }, - [70] = { "RM enabled capabilities", print_rm_enabled_capabilities, 5, 5, BIT(PRINT_SCAN), }, - [113] = { "MESH Configuration", print_mesh_conf, 7, 7, BIT(PRINT_SCAN), }, - [114] = { "MESH ID", print_ssid, 0, 32, BIT(PRINT_SCAN) | BIT(PRINT_LINK), }, - [127] = { "Extended capabilities", print_capabilities, 0, 255, BIT(PRINT_SCAN), }, - [107] = { "802.11u Interworking", print_interworking, 0, 255, BIT(PRINT_SCAN), }, - [108] = { "802.11u Advertisement", print_11u_advert, 0, 255, BIT(PRINT_SCAN), }, - [111] = { "802.11u Roaming Consortium", print_11u_rcon, 2, 255, BIT(PRINT_SCAN), }, - [195] = { "Transmit Power Envelope", print_tx_power_envelope, 2, 5, BIT(PRINT_SCAN), }, - [214] = { "Short beacon interval", print_short_beacon_int, 2, 2, BIT(PRINT_SCAN), }, - [217] = { "S1G capabilities", print_s1g_capa, 15, 15, BIT(PRINT_SCAN), }, - [232] = { "S1G operation", print_s1g_oper, 6, 6, BIT(PRINT_SCAN), }, + [EID_SSID] = { "SSID", print_ssid, 0, 32, + BIT(PRINT_SCAN) | BIT(PRINT_LINK) | BIT(PRINT_LINK_MLO_MLD), }, + [EID_SUPP_RATES] = { "Supported rates", print_supprates, 0, 255, BIT(PRINT_SCAN), }, + [EID_DS_PARAMS] = { "DS Parameter set", print_ds, 1, 1, BIT(PRINT_SCAN), }, + [EID_TIM] = { "TIM", print_tim, 4, 255, BIT(PRINT_SCAN), }, + [EID_IBSS_TIM_PARAMS] = { "IBSS ATIM window", print_ibssatim, 2, 2, BIT(PRINT_SCAN), }, + [EID_COUNTRY] = { "Country", print_country, 3, 255, BIT(PRINT_SCAN), }, + [EID_BSS_LOAD] = { "BSS Load", print_bss_load, 5, 5, BIT(PRINT_SCAN), }, + [EID_POWER_CONSTRAINT] = { "Power constraint", print_powerconstraint, + 1, 1, BIT(PRINT_SCAN), }, + [EID_TPC_REPORT] = { "TPC report", print_tpcreport, 2, 2, BIT(PRINT_SCAN), }, + [EID_ERP_INFO] = { "ERP", print_erp, 1, 255, BIT(PRINT_SCAN), }, + [EID_HT_CAPABILITY] = { "HT capabilities", print_ht_capa, 26, 26, BIT(PRINT_SCAN), }, + [EID_ERP_D4_0] = { "ERP D4.0", print_erp, 1, 255, BIT(PRINT_SCAN), }, + [EID_AP_CHAN_REPORT] = { "AP Channel Report", print_ap_channel_report, + 1, 255, BIT(PRINT_SCAN), }, + [EID_SUPP_OP_CLASSES] = { "Supported operating classes", + print_supp_op_classes, 1, 255, BIT(PRINT_SCAN), }, + [EID_MEASUREMENT_PILOT_TX] = { "Measurement Pilot Transmission", + print_measurement_pilot_tx, 1, 255, BIT(PRINT_SCAN), }, + [EID_OVERLAP_BSS_SCAN_PARAM] = { "Overlapping BSS scan params", + print_obss_scan_params, 14, 255, BIT(PRINT_SCAN), }, + [EID_HT_OPERATION] = { "HT operation", print_ht_op, 22, 22, BIT(PRINT_SCAN), }, + [EID_SECONDARY_CH_OFFSET] = { "Secondary Channel Offset", + print_secchan_offs, 1, 1, BIT(PRINT_SCAN), }, + [EID_VHT_CAPABILITY] = { "VHT capabilities", print_vht_capa, 12, 255, BIT(PRINT_SCAN), }, + [EID_VHT_OPERATION] = { "VHT operation", print_vht_oper, 5, 255, BIT(PRINT_SCAN), }, + [EID_RSN] = { "RSN", print_rsn, 2, 255, BIT(PRINT_SCAN), }, + [EID_EXT_SUPP_RATES] = { "Extended supported rates", print_supprates, + 0, 255, BIT(PRINT_SCAN), }, + [EID_RM_ENABLED_CAPABILITIES] = { "RM enabled capabilities", + print_rm_enabled_capabilities, 5, 5, BIT(PRINT_SCAN), }, + [EID_MESH_CONFIG] = { "MESH Configuration", print_mesh_conf, 7, 7, BIT(PRINT_SCAN), }, + [EID_MESH_ID] = { "MESH ID", print_ssid, 0, 32, BIT(PRINT_SCAN) | BIT(PRINT_LINK), }, + [EID_EXT_CAPABILITY] = { "Extended capabilities", print_capabilities, + 0, 255, BIT(PRINT_SCAN), }, + [EID_INTERWORKING] = { "802.11u Interworking", print_interworking, + 0, 255, BIT(PRINT_SCAN), }, + [EID_ADVERTISEMENT] = { "802.11u Advertisement", print_11u_advert, + 0, 255, BIT(PRINT_SCAN), }, + [EID_ROAMING_CONSORTIUM] = { "802.11u Roaming Consortium", + print_11u_rcon, 2, 255, BIT(PRINT_SCAN), }, + [EID_TRANSMIT_POWER_ENVELOPE] = { "Transmit Power Envelope", + print_tx_power_envelope, 2, 5, BIT(PRINT_SCAN), }, + [EID_SHORT_BEACON_INTERVAL] = { "Short beacon interval", + print_short_beacon_int, 2, 2, BIT(PRINT_SCAN), }, + [EID_S1G_CAPABILITY] = { "S1G capabilities", print_s1g_capa, 15, 15, BIT(PRINT_SCAN), }, + [EID_S1G_OPERATION] = { "S1G operation", print_s1g_oper, 6, 6, BIT(PRINT_SCAN), }, }; static void print_wifi_wpa(const uint8_t type, uint8_t len, const uint8_t *data, @@ -2385,7 +2399,7 @@ static void print_he_capa(const uint8_t type, uint8_t len, const uint8_t *data, } static const struct ie_print ext_printers[] = { - [35] = { "HE capabilities", print_he_capa, 21, 54, BIT(PRINT_SCAN), }, + [EID_EXT_HE_CAPABILITY] = { "HE capabilities", print_he_capa, 21, 54, BIT(PRINT_SCAN), }, }; static void print_extension(unsigned char len, unsigned char *ie, From patchwork Mon Sep 30 18:11:44 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dylan Eskew X-Patchwork-Id: 13816820 X-Patchwork-Delegate: johannes@sipsolutions.net Received: from dispatch1-us1.ppe-hosted.com (dispatch1-us1.ppe-hosted.com [148.163.129.49]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E685F1991A4 for ; Mon, 30 Sep 2024 18:12:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.163.129.49 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1727719922; cv=none; b=S/YlLa2qQHLZvKBzTgLLF30QLryn/haI1jc6sYpUaNs5TpqTUmK8pgLoT62jUX2dvRt4484+kHw2g1vqH0OoG005bn5NumlSYdB9VY8n3CRxgCw4xiZswyshSwuSAX/hLHhX21MBOv10Ovo7U4gzIBG7bun9oRkprG8WUiteiAU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1727719922; c=relaxed/simple; bh=vRnJwljawtfPv8ouyNb1H3nDmXV3KiPvy610bsOshYk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=SdqIhIUUt7id/EfNww4fgRM5NrQQz0Nv4sFgIA4kr0jMRqxKjlroJ9iXOhAzdRo2oxbhn7mZWoCkWCMGJB6yeu5fEQrGFpnacUTUSJmvFT8kOuMPgepSpt9E3SbNLkLXdj2d5/0wJxCYy4lU0iAmFNnsxCeJ5YOe6KMUUYXegYA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=candelatech.com; spf=pass smtp.mailfrom=candelatech.com; dkim=pass (1024-bit key) header.d=candelatech.com header.i=@candelatech.com header.b=kIOvc0/v; arc=none smtp.client-ip=148.163.129.49 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=candelatech.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=candelatech.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=candelatech.com header.i=@candelatech.com header.b="kIOvc0/v" X-Virus-Scanned: Proofpoint Essentials engine Received: from mail3.candelatech.com (mail.candelatech.com [208.74.158.173]) by mx1-us1.ppe-hosted.com (PPE Hosted ESMTP Server) with ESMTP id 8EBD8B00071; Mon, 30 Sep 2024 18:11:52 +0000 (UTC) Received: from corvid-conspiracy.candelatech.com (unknown [50.251.239.81]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail3.candelatech.com (Postfix) with ESMTPSA id 2414B13C2B0; Mon, 30 Sep 2024 11:11:52 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 mail3.candelatech.com 2414B13C2B0 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=candelatech.com; s=default; t=1727719912; bh=vRnJwljawtfPv8ouyNb1H3nDmXV3KiPvy610bsOshYk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=kIOvc0/vGZEwYfLkenV97ifl2snZZRQvOyDcsywBTgYwPI8dZbj1MEAvkDgXj+jcG sf0eNYd4QIgHZhYxMayiPv8dS9iCJmy8hZuHMJFXTrFthFxGHhWQgUOEhBjPijzeb9 jkf+dbhlO4q9QI0U/Df2h5EtOT0hL5nn2KSGVghY= From: Dylan Eskew To: johannes@sipsolutions.net Cc: linux-wireless@vger.kernel.org, Dylan Eskew Subject: [PATCH 2/3] iw: scan: change parsing from in-place to cached Date: Mon, 30 Sep 2024 11:11:44 -0700 Message-ID: <20240930181145.1043048-3-dylan.eskew@candelatech.com> X-Mailer: git-send-email 2.46.0 In-Reply-To: <20240930181145.1043048-1-dylan.eskew@candelatech.com> References: <20240930181145.1043048-1-dylan.eskew@candelatech.com> Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MDID: 1727719913-f4tLvD-GswC8 X-MDID-O: us5;ut7;1727719913;f4tLvD-GswC8;;b42792dba290a1257c3f0aaf1c60b0ff Since some ies require references to other ies, this introduces the infrastructure to prevent double parsing the ie buffer by caching the ie data rather than reading it in-place. Signed-off-by: Dylan Eskew --- ieee80211.h | 39 +++++++++++++++ scan.c | 138 +++++++++++++++++++++++++++++++++++++++------------- 2 files changed, 142 insertions(+), 35 deletions(-) diff --git a/ieee80211.h b/ieee80211.h index 96d5c52..dc14096 100644 --- a/ieee80211.h +++ b/ieee80211.h @@ -101,6 +101,45 @@ enum elem_id_ext { EID_EXT_HE_CAPABILITY = 35, }; +struct ieee80211_elems { + const __u8 *ie_start; + size_t total_length; + + __u8 seen[32]; + __u8 seen_ext[32]; + + const __u8 *ies[NUM_IES]; + const __u8 *ies_ext[NUM_IES]; + + /* payload lengths of each ie */ + __u8 lengths[NUM_IES]; + __u8 lengths_ext[NUM_IES]; +}; + +static inline void set_seen(struct ieee80211_elems *elems, + const uint8_t type) +{ + elems->seen[type / 8] |= 1 << (type % 8); +} + +static inline void set_seen_ext(struct ieee80211_elems *elems, + const uint8_t type) +{ + elems->seen_ext[type / 8] |= 1 << (type % 8); +} + +static inline int was_seen(struct ieee80211_elems *elems, + const uint8_t type) +{ + return elems->seen[type / 8] & (1 << (type % 8)); +} + +static inline int was_seen_ext(struct ieee80211_elems *elems, + const uint8_t type) +{ + return elems->seen_ext[type / 8] & (1 << (type % 8)); +} + #define SUITE(oui, id) (((oui) << 8) | (id)) /* cipher suite selectors */ diff --git a/scan.c b/scan.c index 83b7f58..6fdaf0b 100644 --- a/scan.c +++ b/scan.c @@ -1782,6 +1782,12 @@ struct ie_print { uint8_t flags; }; +struct element { + __u8 id; + __u8 datalen; + __u8 data[]; +} __attribute__ ((packed)); + static void print_ie(const struct ie_print *p, const uint8_t type, uint8_t len, const uint8_t *data, const struct print_ies_data *ie_buffer) @@ -2332,7 +2338,7 @@ static const struct ie_print wfa_printers[] = { [28] = { "OWE Transition Mode", print_wifi_owe_tarns, 7, 255, BIT(PRINT_SCAN), }, }; -static void print_vendor(unsigned char len, unsigned char *data, +static void print_vendor(unsigned char len, const unsigned char *data, bool unknown, enum print_ie_type ptype) { int i; @@ -2402,31 +2408,88 @@ static const struct ie_print ext_printers[] = { [EID_EXT_HE_CAPABILITY] = { "HE capabilities", print_he_capa, 21, 54, BIT(PRINT_SCAN), }, }; -static void print_extension(unsigned char len, unsigned char *ie, - bool unknown, enum print_ie_type ptype) + +static void print_extension(bool unknown, struct ieee80211_elems *elems, + enum print_ie_type ptype) { - unsigned char tag; + unsigned i; - if (len < 1) { - printf("\tExtension IE: \n"); + if (elems == NULL) return; + + for (i = 0; i < NUM_IES; i++) { + if (!was_seen_ext(elems, i)) + continue; + + if (elems->lengths_ext[i] < 1) { + printf("\tExtension IE %u: \n", i); + continue; + } + + if (i < ARRAY_SIZE(ext_printers) && + ext_printers[i].name && + ext_printers[i].flags & BIT(ptype) && + elems->lengths_ext[i] > 0) { + print_ie(&ext_printers[i], i, elems->lengths_ext[i] - 1, + elems->ies_ext[i], NULL); + } else if (unknown) { + int j; + + printf("\tUnknown Extension ID (%d):", i); + for (j = 1; j < elems->lengths_ext[i]; j++) + printf(" %.2x", elems->ies_ext[i][j]); + printf("\n"); + } } +} - tag = ie[0]; - if (tag < ARRAY_SIZE(ext_printers) && ext_printers[tag].name && - ext_printers[tag].flags & BIT(ptype)) { - print_ie(&ext_printers[tag], tag, len - 1, ie + 1, NULL); +static void parse_ie_ext(const struct element *elem, + struct ieee80211_elems *elems) +{ + const uint8_t type = elem->data[0]; + const uint8_t *data = elem->data + 1; + + if (!elem->datalen) return; - } - if (unknown) { - int i; + set_seen_ext(elems, type); - printf("\tUnknown Extension ID (%d):", ie[0]); - for (i = 1; i < len; i++) - printf(" %.2x", ie[i]); - printf("\n"); + elems->lengths_ext[type] = elem->datalen; + + if (elem->datalen) + elems->ies_ext[type] = data; +} + +static int parse_ies(unsigned char *ie, int ielen, bool unknown, + struct ieee80211_elems *elems) +{ + const struct element *elem; + + if (ie == NULL || ielen < 0 || elems == NULL) + return 1; + + elems->ie_start = ie; + elems->total_length = ielen; + + elem = (const struct element *)ie; + while (ielen >= 2 && ielen - 2 > elem->datalen) { + uint8_t id = elem->id; + uint8_t elen = elem->datalen; + const uint8_t *data = elem->data; + + set_seen(elems, id); + + if (id == EID_EXTENSION) { + parse_ie_ext(elem, elems); + } else if (elen) { + elems->lengths[id] = elen; + elems->ies[id] = data; + } + + ielen -= elem->datalen + 2; + elem = (const struct element *)(elem->data + elem->datalen); } + return 0; } void print_ies(unsigned char *ie, int ielen, bool unknown, @@ -2435,31 +2498,36 @@ void print_ies(unsigned char *ie, int ielen, bool unknown, struct print_ies_data ie_buffer = { .ie = ie, .ielen = ielen }; + struct ieee80211_elems elems = { }; + unsigned i; - if (ie == NULL || ielen < 0) + if (parse_ies(ie, ielen, unknown, &elems)) return; - while (ielen >= 2 && ielen - 2 >= ie[1]) { - if (ie[0] < ARRAY_SIZE(ieprinters) && - ieprinters[ie[0]].name && - ieprinters[ie[0]].flags & BIT(ptype) && - ie[1] > 0) { - print_ie(&ieprinters[ie[0]], - ie[0], ie[1], ie + 2, &ie_buffer); - } else if (ie[0] == 221 /* vendor */) { - print_vendor(ie[1], ie + 2, unknown, ptype); - } else if (ie[0] == 255 /* extension */) { - print_extension(ie[1], ie + 2, unknown, ptype); + for (i = 0; i < NUM_IES; i++) { + if (!was_seen(&elems, i)) + continue; + + if (i < ARRAY_SIZE(ieprinters) && + ieprinters[i].name && + ieprinters[i].flags & BIT(ptype) && + elems.lengths[i] > 0) { + print_ie(&ieprinters[i], i, elems.lengths[i], + elems.ies[i], &ie_buffer); + } + else if (i == EID_VENDOR) { + print_vendor(elems.lengths[i], elems.ies[i], + unknown, ptype); + } else if (i == EID_EXTENSION) { + print_extension(unknown, &elems, ptype); } else if (unknown) { - int i; + int j; - printf("\tUnknown IE (%d):", ie[0]); - for (i=0; i X-Patchwork-Id: 13816817 X-Patchwork-Delegate: johannes@sipsolutions.net Received: from dispatch1-us1.ppe-hosted.com (dispatch1-us1.ppe-hosted.com [148.163.129.52]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 898321990BB for ; Mon, 30 Sep 2024 18:11:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.163.129.52 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1727719918; cv=none; b=H9ay2/MKiRc7oNR/+mYFk39+ljGNinzbqp3WmXykOe47yTS8PPpde6scZYtSyDhV1hO4gIaExOtUNj+K+0PFdsWI2yoEt5648NjRMkh2094f8V49iY5I98hW8ojxVUzpTODUUkcHoDWhq7Orv2GLgK32X98rkTt5UiMhF4hoadI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1727719918; c=relaxed/simple; bh=ZTE8Id1JYuGYMpWje0yiqJi5JpmraZU/LWju1e31m+c=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=pNUhNxf++CWQjpcLep9H/ezaZTKrwDIi3nja5ejW6Mf0qPOanu5DPQ/cg7BVAQWESsx0wx17+jJYtaizOG3abwW96Wc7ErjTPDoKlksfYIHB8RxmouDDOVznXGw4LypfDKT7j291sQ/qBmsYf6dzIiM1fJygB3IEMyp/YXQtqHI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=candelatech.com; spf=pass smtp.mailfrom=candelatech.com; dkim=pass (1024-bit key) header.d=candelatech.com header.i=@candelatech.com header.b=ZLfp+yNs; arc=none smtp.client-ip=148.163.129.52 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=candelatech.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=candelatech.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=candelatech.com header.i=@candelatech.com header.b="ZLfp+yNs" X-Virus-Scanned: Proofpoint Essentials engine Received: from mail3.candelatech.com (mail.candelatech.com [208.74.158.173]) by mx1-us1.ppe-hosted.com (PPE Hosted ESMTP Server) with ESMTP id A4B7CB0008A; Mon, 30 Sep 2024 18:11:53 +0000 (UTC) Received: from corvid-conspiracy.candelatech.com (unknown [50.251.239.81]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail3.candelatech.com (Postfix) with ESMTPSA id 4671913C2B0; Mon, 30 Sep 2024 11:11:53 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 mail3.candelatech.com 4671913C2B0 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=candelatech.com; s=default; t=1727719913; bh=ZTE8Id1JYuGYMpWje0yiqJi5JpmraZU/LWju1e31m+c=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ZLfp+yNsxATGS6uDYkGrZ6DdzppPkUtmCrmQaB5C0GXoj3thcxfOXiuf+5AF/QYR4 falIy7PudgeGp+ayGpfL+vyqz27OomwDYHqIOfG8cJ6BU4LddL2g0wbbH1ZSPFBebd 1REcAx1NUDottDIZf9SEB9pF3IyBEIEITZ0cpJNU= From: Dylan Eskew To: johannes@sipsolutions.net Cc: linux-wireless@vger.kernel.org, Dylan Eskew Subject: [PATCH 3/3] iw: scan: replace passed ie buffer with alias struct Date: Mon, 30 Sep 2024 11:11:45 -0700 Message-ID: <20240930181145.1043048-4-dylan.eskew@candelatech.com> X-Mailer: git-send-email 2.46.0 In-Reply-To: <20240930181145.1043048-1-dylan.eskew@candelatech.com> References: <20240930181145.1043048-1-dylan.eskew@candelatech.com> Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MDID: 1727719914-Z06gr4gvGMVi X-MDID-O: us5;ut7;1727719914;Z06gr4gvGMVi;;b42792dba290a1257c3f0aaf1c60b0ff Prevent needing to reparse the ie buffer by passing the ieee80211_elems struct containing the alias ie pointers. Signed-off-by: Dylan Eskew --- scan.c | 106 ++++++++++++++++++++++++--------------------------------- 1 file changed, 44 insertions(+), 62 deletions(-) diff --git a/scan.c b/scan.c index 6fdaf0b..3210ccc 100644 --- a/scan.c +++ b/scan.c @@ -554,13 +554,8 @@ static void tab_on_first(bool *first) *first = false; } -struct print_ies_data { - unsigned char *ie; - int ielen; -}; - static void print_ssid(const uint8_t type, uint8_t len, const uint8_t *data, - const struct print_ies_data *ie_buffer) + const struct ieee80211_elems *elems) { printf(" "); print_ssid_escaped(len, data); @@ -572,7 +567,7 @@ static void print_ssid(const uint8_t type, uint8_t len, const uint8_t *data, static void print_supprates(const uint8_t type, uint8_t len, const uint8_t *data, - const struct print_ies_data *ie_buffer) + const struct ieee80211_elems *elems) { int i; @@ -595,7 +590,7 @@ static void print_supprates(const uint8_t type, uint8_t len, static void print_rm_enabled_capabilities(const uint8_t type, uint8_t len, const uint8_t *data, - const struct print_ies_data *ie_buffer) + const struct ieee80211_elems *elems) { __u64 capa = ((__u64) data[0]) | ((__u64) data[1]) << 8 | @@ -649,7 +644,7 @@ static void print_rm_enabled_capabilities(const uint8_t type, uint8_t len, } static void print_ds(const uint8_t type, uint8_t len, const uint8_t *data, - const struct print_ies_data *ie_buffer) + const struct ieee80211_elems *elems) { printf(" channel %d\n", data[0]); } @@ -669,7 +664,7 @@ static const char *country_env_str(char environment) } static void print_country(const uint8_t type, uint8_t len, const uint8_t *data, - const struct print_ies_data *ie_buffer) + const struct ieee80211_elems *elems) { printf(" %.*s", 2, data); @@ -716,21 +711,21 @@ static void print_country(const uint8_t type, uint8_t len, const uint8_t *data, static void print_powerconstraint(const uint8_t type, uint8_t len, const uint8_t *data, - const struct print_ies_data *ie_buffer) + const struct ieee80211_elems *elems) { printf(" %d dB\n", data[0]); } static void print_tpcreport(const uint8_t type, uint8_t len, const uint8_t *data, - const struct print_ies_data *ie_buffer) + const struct ieee80211_elems *elems) { printf(" TX power: %d dBm\n", data[0]); /* printf(" Link Margin (%d dB) is reserved in Beacons\n", data[1]); */ } static void print_erp(const uint8_t type, uint8_t len, const uint8_t *data, - const struct print_ies_data *ie_buffer) + const struct ieee80211_elems *elems) { if (data[0] == 0x00) printf(" "); @@ -744,7 +739,7 @@ static void print_erp(const uint8_t type, uint8_t len, const uint8_t *data, } static void print_ap_channel_report(const uint8_t type, uint8_t len, const uint8_t *data, - const struct print_ies_data *ie_buffer) + const struct ieee80211_elems *elems) { uint8_t oper_class = data[0]; int i; @@ -1084,13 +1079,13 @@ static void print_osen_ie(const char *defcipher, const char *defauth, } static void print_rsn(const uint8_t type, uint8_t len, const uint8_t *data, - const struct print_ies_data *ie_buffer) + const struct ieee80211_elems *elems) { print_rsn_ie("CCMP", "IEEE 802.1X", len, data); } static void print_ht_capa(const uint8_t type, uint8_t len, const uint8_t *data, - const struct print_ies_data *ie_buffer) + const struct ieee80211_elems *elems) { printf("\n"); print_ht_capability(data[0] | (data[1] << 8)); @@ -1135,7 +1130,7 @@ static const char* vgroup_11u(uint8_t t) static void print_interworking(const uint8_t type, uint8_t len, const uint8_t *data, - const struct print_ies_data *ie_buffer) + const struct ieee80211_elems *elems) { /* See Section 7.3.2.92 in the 802.11u spec. */ printf("\n"); @@ -1168,7 +1163,7 @@ static void print_interworking(const uint8_t type, uint8_t len, static void print_11u_advert(const uint8_t type, uint8_t len, const uint8_t *data, - const struct print_ies_data *ie_buffer) + const struct ieee80211_elems *elems) { /* See Section 7.3.2.93 in the 802.11u spec. */ /* TODO: This code below does not decode private protocol IDs */ @@ -1201,7 +1196,7 @@ static void print_11u_advert(const uint8_t type, uint8_t len, } static void print_11u_rcon(const uint8_t type, uint8_t len, const uint8_t *data, - const struct print_ies_data *ie_buffer) + const struct ieee80211_elems *elems) { /* See Section 7.3.2.96 in the 802.11u spec. */ int idx = 0; @@ -1254,7 +1249,7 @@ static void print_11u_rcon(const uint8_t type, uint8_t len, const uint8_t *data, static void print_tx_power_envelope(const uint8_t type, uint8_t len, const uint8_t *data, - const struct print_ies_data *ie_buffer) + const struct ieee80211_elems *elems) { const uint8_t local_max_tx_power_count = data[0] & 7; const uint8_t local_max_tx_power_unit_interp = (data[0] >> 3) & 7; @@ -1290,7 +1285,7 @@ static const char *ht_secondary_offset[4] = { }; static void print_ht_op(const uint8_t type, uint8_t len, const uint8_t *data, - const struct print_ies_data *ie_buffer) + const struct ieee80211_elems *elems) { static const char *protection[4] = { "no", @@ -1322,21 +1317,11 @@ static void print_ht_op(const uint8_t type, uint8_t len, const uint8_t *data, static void print_capabilities(const uint8_t type, uint8_t len, const uint8_t *data, - const struct print_ies_data *ie_buffer) + const struct ieee80211_elems *elems) { int i, base, bit, si_duration = 0, max_amsdu = 0; - bool s_psmp_support = false, is_vht_cap = false; - unsigned char *ie = ie_buffer->ie; - int ielen = ie_buffer->ielen; - - while (ielen >= 2 && ielen >= ie[1]) { - if (ie[0] == 191) { - is_vht_cap = true; - break; - } - ielen -= ie[1] + 2; - ie += ie[1] + 2; - } + bool is_vht_cap = (elems->lengths[EID_VHT_CAPABILITY] > 0); + bool s_psmp_support = false; for (i = 0; i < len; i++) { base = i * 8; @@ -1486,7 +1471,7 @@ static void print_capabilities(const uint8_t type, uint8_t len, } static void print_tim(const uint8_t type, uint8_t len, const uint8_t *data, - const struct print_ies_data *ie_buffer) + const struct ieee80211_elems *elems) { printf(" DTIM Count %u DTIM Period %u Bitmap Control 0x%x " "Bitmap[0] 0x%x", @@ -1497,13 +1482,13 @@ static void print_tim(const uint8_t type, uint8_t len, const uint8_t *data, } static void print_ibssatim(const uint8_t type, uint8_t len, const uint8_t *data, - const struct print_ies_data *ie_buffer) + const struct ieee80211_elems *elems) { printf(" %d TUs\n", (data[1] << 8) + data[0]); } static void print_vht_capa(const uint8_t type, uint8_t len, const uint8_t *data, - const struct print_ies_data *ie_buffer) + const struct ieee80211_elems *elems) { printf("\n"); print_vht_info((__u32) data[0] | ((__u32)data[1] << 8) | @@ -1512,7 +1497,7 @@ static void print_vht_capa(const uint8_t type, uint8_t len, const uint8_t *data, } static void print_vht_oper(const uint8_t type, uint8_t len, const uint8_t *data, - const struct print_ies_data *ie_buffer) + const struct ieee80211_elems *elems) { const char *chandwidths[] = { [0] = "20 or 40 MHz", @@ -1531,7 +1516,7 @@ static void print_vht_oper(const uint8_t type, uint8_t len, const uint8_t *data, static void print_supp_op_classes(const uint8_t type, uint8_t len, const uint8_t *data, - const struct print_ies_data *ie_buffer) + const struct ieee80211_elems *elems) { uint8_t *p = (uint8_t*) data; const uint8_t *next_data = p + len; @@ -1565,7 +1550,7 @@ static void print_supp_op_classes(const uint8_t type, uint8_t len, static void print_measurement_pilot_tx(const uint8_t type, uint8_t len, const uint8_t *data, - const struct print_ies_data *ie_buffer) + const struct ieee80211_elems *elems) { uint8_t *p, len_remaining; @@ -1614,7 +1599,7 @@ static void print_measurement_pilot_tx(const uint8_t type, uint8_t len, static void print_obss_scan_params(const uint8_t type, uint8_t len, const uint8_t *data, - const struct print_ies_data *ie_buffer) + const struct ieee80211_elems *elems) { printf("\n"); printf("\t\t * passive dwell: %d TUs\n", (data[1] << 8) | data[0]); @@ -1629,7 +1614,7 @@ static void print_obss_scan_params(const uint8_t type, uint8_t len, static void print_secchan_offs(const uint8_t type, uint8_t len, const uint8_t *data, - const struct print_ies_data *ie_buffer) + const struct ieee80211_elems *elems) { if (data[0] < ARRAY_SIZE(ht_secondary_offset)) printf(" %s (%d)\n", ht_secondary_offset[data[0]], data[0]); @@ -1638,7 +1623,7 @@ static void print_secchan_offs(const uint8_t type, uint8_t len, } static void print_bss_load(const uint8_t type, uint8_t len, const uint8_t *data, - const struct print_ies_data *ie_buffer) + const struct ieee80211_elems *elems) { printf("\n"); printf("\t\t * station count: %d\n", (data[1] << 8) | data[0]); @@ -1648,7 +1633,7 @@ static void print_bss_load(const uint8_t type, uint8_t len, const uint8_t *data, static void print_mesh_conf(const uint8_t type, uint8_t len, const uint8_t *data, - const struct print_ies_data *ie_buffer) + const struct ieee80211_elems *elems) { printf("\n"); printf("\t\t * Active Path Selection Protocol ID: %d\n", data[0]); @@ -1681,7 +1666,7 @@ static void print_mesh_conf(const uint8_t type, uint8_t len, static void print_s1g_capa(const uint8_t type, uint8_t len, const uint8_t *data, - const struct print_ies_data *ie_buffer) + const struct ieee80211_elems *elems) { printf("\n"); print_s1g_capability(data); @@ -1689,14 +1674,14 @@ static void print_s1g_capa(const uint8_t type, uint8_t len, static void print_short_beacon_int(const uint8_t type, uint8_t len, const uint8_t *data, - const struct print_ies_data *ie_buffer) + const struct ieee80211_elems *elems) { printf(" %d\n", (data[1] << 8) | data[0]); } static void print_s1g_oper(const uint8_t type, uint8_t len, const uint8_t *data, - const struct print_ies_data *ie_buffer) + const struct ieee80211_elems *elems) { int oper_ch_width, prim_ch_width; int prim_ch_width_subfield = data[0] & 0x1; @@ -1777,7 +1762,7 @@ static void print_s1g_oper(const uint8_t type, uint8_t len, struct ie_print { const char *name; void (*print)(const uint8_t type, uint8_t len, const uint8_t *data, - const struct print_ies_data *ie_buffer); + const struct ieee80211_elems *elems); uint8_t minlen, maxlen; uint8_t flags; }; @@ -1790,7 +1775,7 @@ struct element { static void print_ie(const struct ie_print *p, const uint8_t type, uint8_t len, const uint8_t *data, - const struct print_ies_data *ie_buffer) + const struct ieee80211_elems *elems) { int i; @@ -1811,7 +1796,7 @@ static void print_ie(const struct ie_print *p, const uint8_t type, uint8_t len, return; } - p->print(type, len, data, ie_buffer); + p->print(type, len, data, elems); } #define PRINT_IGN { \ @@ -1873,14 +1858,14 @@ static const struct ie_print ieprinters[] = { }; static void print_wifi_wpa(const uint8_t type, uint8_t len, const uint8_t *data, - const struct print_ies_data *ie_buffer) + const struct ieee80211_elems *elems) { print_rsn_ie("TKIP", "IEEE 802.1X", len, data); } static void print_wifi_osen(const uint8_t type, uint8_t len, const uint8_t *data, - const struct print_ies_data *ie_buffer) + const struct ieee80211_elems *elems) { print_osen_ie("OSEN", "OSEN", len, data); } @@ -1928,7 +1913,7 @@ static bool print_wifi_wmm_param(const uint8_t *data, uint8_t len) } static void print_wifi_wmm(const uint8_t type, uint8_t len, const uint8_t *data, - const struct print_ies_data *ie_buffer) + const struct ieee80211_elems *elems) { int i; @@ -1971,7 +1956,7 @@ static const char * wifi_wps_dev_passwd_id(uint16_t id) } static void print_wifi_wps(const uint8_t type, uint8_t len, const uint8_t *data, - const struct print_ies_data *ie_buffer) + const struct ieee80211_elems *elems) { bool first = true; __u16 subtype, sublen; @@ -2211,7 +2196,7 @@ static const struct ie_print wifiprinters[] = { static inline void print_p2p(const uint8_t type, uint8_t len, const uint8_t *data, - const struct print_ies_data *ie_buffer) + const struct ieee80211_elems *elems) { bool first = true; __u8 subtype; @@ -2293,7 +2278,7 @@ static inline void print_p2p(const uint8_t type, uint8_t len, static inline void print_hs20_ind(const uint8_t type, uint8_t len, const uint8_t *data, - const struct print_ies_data *ie_buffer) + const struct ieee80211_elems *elems) { /* I can't find the spec for this...just going off what wireshark uses. */ printf("\n"); @@ -2305,7 +2290,7 @@ static inline void print_hs20_ind(const uint8_t type, uint8_t len, static void print_wifi_owe_tarns(const uint8_t type, uint8_t len, const uint8_t *data, - const struct print_ies_data *ie_buffer) + const struct ieee80211_elems *elems) { char mac_addr[20]; int ssid_len; @@ -2398,7 +2383,7 @@ static void print_vendor(unsigned char len, const unsigned char *data, } static void print_he_capa(const uint8_t type, uint8_t len, const uint8_t *data, - const struct print_ies_data *ie_buffer) + const struct ieee80211_elems *elems) { printf("\n"); print_he_capability(data, len); @@ -2495,9 +2480,6 @@ static int parse_ies(unsigned char *ie, int ielen, bool unknown, void print_ies(unsigned char *ie, int ielen, bool unknown, enum print_ie_type ptype) { - struct print_ies_data ie_buffer = { - .ie = ie, - .ielen = ielen }; struct ieee80211_elems elems = { }; unsigned i; @@ -2513,7 +2495,7 @@ void print_ies(unsigned char *ie, int ielen, bool unknown, ieprinters[i].flags & BIT(ptype) && elems.lengths[i] > 0) { print_ie(&ieprinters[i], i, elems.lengths[i], - elems.ies[i], &ie_buffer); + elems.ies[i], &elems); } else if (i == EID_VENDOR) { print_vendor(elems.lengths[i], elems.ies[i],