Merge Official Source

Signed-off-by: Tianling Shen <cnsztl@immortalwrt.org>
This commit is contained in:
Tianling Shen 2025-05-12 19:54:59 +08:00
commit c2b634f5e9
No known key found for this signature in database
GPG Key ID: 6850B6345C862176
23 changed files with 2322 additions and 78 deletions

View File

@ -3,11 +3,11 @@ include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=nat46
PKG_MIRROR_HASH:=09b93f31d10030d3b4f326066b544b70b1f60236d0482f27c384ed93b298c0a6
PKG_MIRROR_HASH:=35d7987eed7f05e5f7d1d2e111a8c9f5d019ccf11eb839dfe0bd2e2c46b6199a
PKG_SOURCE_URL:=https://github.com/ayourtch/nat46.git
PKG_SOURCE_DATE:=2022-09-19
PKG_SOURCE_DATE:=2025-04-23
PKG_SOURCE_PROTO:=git
PKG_SOURCE_VERSION:=4c5beee236841724219598fabb1edc93d4f08ce5
PKG_SOURCE_VERSION:=04923c51039e8ca270c6f1dde3f04f3b36958089
PKG_MAINTAINER:=Hans Dedecker <dedeckeh@gmail.com>
PKG_LICENSE:=GPL-2.0

View File

@ -5,7 +5,7 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=hostapd
PKG_RELEASE:=1
PKG_RELEASE:=2
PKG_SOURCE_URL:=https://w1.fi/hostap.git
PKG_SOURCE_PROTO:=git
@ -110,7 +110,7 @@ ifeq ($(SSL_VARIANT),openssl)
DRIVER_MAKEOPTS += CONFIG_AP=y CONFIG_MESH=y
endif
ifeq ($(LOCAL_VARIANT),full)
DRIVER_MAKEOPTS += CONFIG_OWE=y CONFIG_SUITEB192=y CONFIG_AP=y CONFIG_MESH=y CONFIG_EAP_PWD=y
DRIVER_MAKEOPTS += CONFIG_OWE=y CONFIG_SUITEB192=y CONFIG_AP=y CONFIG_MESH=y CONFIG_EAP_PWD=y CONFIG_DPP=y CONFIG_DPP2=y
endif
endif
@ -140,7 +140,7 @@ ifeq ($(SSL_VARIANT),mbedtls)
DRIVER_MAKEOPTS += CONFIG_AP=y CONFIG_MESH=y CONFIG_WPS_NFC=1
endif
ifeq ($(LOCAL_VARIANT),full)
DRIVER_MAKEOPTS += CONFIG_OWE=y CONFIG_SUITEB192=y CONFIG_AP=y CONFIG_MESH=y CONFIG_WPS_NFC=1 CONFIG_EAP_PWD=y
DRIVER_MAKEOPTS += CONFIG_OWE=y CONFIG_SUITEB192=y CONFIG_AP=y CONFIG_MESH=y CONFIG_WPS_NFC=1 CONFIG_EAP_PWD=y CONFIG_DPP=y CONFIG_DPP2=y
endif
endif

View File

@ -46,6 +46,15 @@ function network_socket_close(data)
data.socket.close();
}
function network_rx_cleanup_state(name)
{
for (let name, sub in core.remote_subscribe)
delete sub[name];
for (let name, sub in core.remote_publish)
delete sub[name];
}
function network_rx_socket_close(data)
{
if (!data)
@ -53,14 +62,10 @@ function network_rx_socket_close(data)
core.dbg(`Incoming connection from ${data.name} closed\n`);
let net = networks[data.network];
if (net && net.rx_channels[data.name] == data)
if (net && net.rx_channels[data.name] != data) {
delete net.rx_channels[data.name];
for (let name, sub in core.remote_subscribe)
delete sub[data.name];
for (let name, sub in core.remote_publish)
delete sub[data.name];
network_rx_cleanup_state(data.name);
}
network_socket_close(data);
}
@ -189,10 +194,21 @@ function network_check_auth(sock_data, info)
if (sock_data.timer)
sock_data.timer.cancel();
sock_data.auth = true;
network_rx_cleanup_state(sock_data.name);
net.rx_channels[sock_data.name] = sock_data;
core.dbg(`Incoming connection from ${sock_data.name} established\n`);
if (!net.tx_channels[sock_data.name])
let chan = net.tx_channels[sock_data.name];
if (!chan) {
net.timer.set(100);
return;
}
chan.channel.request({
method: "ping",
data: {},
return: "ignore",
});
}
function network_accept(net, sock, addr)
@ -337,6 +353,10 @@ function network_open_channel(net, name, peer)
delete net.tx_channels[sock_data.name];
network_tx_socket_close(sock_data);
if (net.timer.remaining() > 0)
return;
net.timer.set(sock_data.auth ? 100 : 10000);
};
sock_data.socket = sock;

View File

@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=iw
PKG_VERSION:=6.9
PKG_RELEASE:=3
PKG_RELEASE:=4
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
PKG_SOURCE_URL:=@KERNEL/software/network/iw

View File

@ -0,0 +1,170 @@
From 966c590bc4dcbd9a69fdf8fe9f41cec00e72e376 Mon Sep 17 00:00:00 2001
From: Dylan Eskew <dylan.eskew@candelatech.com>
Date: Mon, 30 Sep 2024 11:11:43 -0700
Subject: [PATCH] iw: scan: add enum for element IDs
Formerly, element IDs were hardcoded. Improve readability by using
element ID names.
Signed-off-by: Dylan Eskew <dylan.eskew@candelatech.com>
Link: https://patch.msgid.link/20240930181145.1043048-2-dylan.eskew@candelatech.com
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
ieee80211.h | 43 +++++++++++++++++++++++++++
scan.c | 86 +++++++++++++++++++++++++++++++----------------------
2 files changed, 93 insertions(+), 36 deletions(-)
--- a/ieee80211.h
+++ b/ieee80211.h
@@ -58,6 +58,49 @@ struct ieee80211_vht_cap {
struct ieee80211_vht_mcs_info mcs;
} __attribute__ ((packed));
+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,
+ EID_EXT_HE_OPERATION = 36,
+};
+
#define SUITE(oui, id) (((oui) << 8) | (id))
/* cipher suite selectors */
--- a/scan.c
+++ b/scan.c
@@ -1816,40 +1816,54 @@ static void print_ie(const struct ie_pri
}
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,
@@ -2392,8 +2406,8 @@ static void print_he_oper(const uint8_t
}
static const struct ie_print ext_printers[] = {
- [35] = { "HE capabilities", print_he_capa, 21, 54, BIT(PRINT_SCAN), },
- [36] = { "HE Operation", print_he_oper, 6, 15, BIT(PRINT_SCAN), },
+ [EID_EXT_HE_CAPABILITY] = { "HE capabilities", print_he_capa, 21, 54, BIT(PRINT_SCAN), },
+ [EID_EXT_HE_OPERATION] = { "HE Operation", print_he_oper, 6, 15, BIT(PRINT_SCAN), },
};
static void print_extension(unsigned char len, unsigned char *ie,

View File

@ -0,0 +1,482 @@
From a0a7ddef29fc412cee7e3ca027905218b145a40f Mon Sep 17 00:00:00 2001
From: Dylan Eskew <dylan.eskew@candelatech.com>
Date: Fri, 22 Nov 2024 08:18:51 -0800
Subject: [PATCH] iw: scan: replace passed ie buffer with ie context
Since some ies require references to other ies, parse
the ie list once before to create a context and prevent
parsing more than the two times required.
Signed-off-by: Dylan Eskew <dylan.eskew@candelatech.com>
Link: https://patch.msgid.link/20241122161851.647214-1-dylan.eskew@candelatech.com
[cleanups]
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
scan.c | 141 +++++++++++++++++++++++++++++++--------------------------
1 file changed, 76 insertions(+), 65 deletions(-)
--- a/scan.c
+++ b/scan.c
@@ -554,13 +554,12 @@ static void tab_on_first(bool *first)
*first = false;
}
-struct print_ies_data {
- unsigned char *ie;
- int ielen;
+struct ie_context {
+ bool is_vht_cap;
};
static void print_ssid(const uint8_t type, uint8_t len, const uint8_t *data,
- const struct print_ies_data *ie_buffer)
+ const struct ie_context *ctx)
{
printf(" ");
print_ssid_escaped(len, data);
@@ -572,7 +571,7 @@ static void print_ssid(const uint8_t typ
static void print_supprates(const uint8_t type, uint8_t len,
const uint8_t *data,
- const struct print_ies_data *ie_buffer)
+ const struct ie_context *ctx)
{
int i;
@@ -595,7 +594,7 @@ static void print_supprates(const uint8_
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 ie_context *ctx)
{
__u64 capa = ((__u64) data[0]) |
((__u64) data[1]) << 8 |
@@ -649,7 +648,7 @@ static void print_rm_enabled_capabilitie
}
static void print_ds(const uint8_t type, uint8_t len, const uint8_t *data,
- const struct print_ies_data *ie_buffer)
+ const struct ie_context *ctx)
{
printf(" channel %d\n", data[0]);
}
@@ -669,7 +668,7 @@ static const char *country_env_str(char
}
static void print_country(const uint8_t type, uint8_t len, const uint8_t *data,
- const struct print_ies_data *ie_buffer)
+ const struct ie_context *ctx)
{
printf(" %.*s", 2, data);
@@ -716,21 +715,21 @@ static void print_country(const uint8_t
static void print_powerconstraint(const uint8_t type, uint8_t len,
const uint8_t *data,
- const struct print_ies_data *ie_buffer)
+ const struct ie_context *ctx)
{
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 ie_context *ctx)
{
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 ie_context *ctx)
{
if (data[0] == 0x00)
printf(" <no flags>");
@@ -744,7 +743,7 @@ static void print_erp(const uint8_t type
}
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 ie_context *ctx)
{
uint8_t oper_class = data[0];
int i;
@@ -1084,13 +1083,13 @@ static void print_osen_ie(const char *de
}
static void print_rsn(const uint8_t type, uint8_t len, const uint8_t *data,
- const struct print_ies_data *ie_buffer)
+ const struct ie_context *ctx)
{
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 ie_context *ctx)
{
printf("\n");
print_ht_capability(data[0] | (data[1] << 8));
@@ -1135,7 +1134,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 ie_context *ctx)
{
/* See Section 7.3.2.92 in the 802.11u spec. */
printf("\n");
@@ -1168,7 +1167,7 @@ static void print_interworking(const uin
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 ie_context *ctx)
{
/* See Section 7.3.2.93 in the 802.11u spec. */
/* TODO: This code below does not decode private protocol IDs */
@@ -1201,7 +1200,7 @@ static void print_11u_advert(const uint8
}
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 ie_context *ctx)
{
/* See Section 7.3.2.96 in the 802.11u spec. */
int idx = 0;
@@ -1254,7 +1253,7 @@ static void print_11u_rcon(const uint8_t
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 ie_context *ctx)
{
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 +1289,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 ie_context *ctx)
{
static const char *protection[4] = {
"no",
@@ -1322,21 +1321,10 @@ static void print_ht_op(const uint8_t ty
static void print_capabilities(const uint8_t type, uint8_t len,
const uint8_t *data,
- const struct print_ies_data *ie_buffer)
+ const struct ie_context *ctx)
{
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 s_psmp_support = false;
for (i = 0; i < len; i++) {
base = i * 8;
@@ -1432,8 +1420,8 @@ static void print_capabilities(const uin
CAPA(61, "TDLS Wider Bandwidth");
CAPA(62, "Operating Mode Notification");
- ADD_BIT_VAL(63, is_vht_cap, max_amsdu, 1);
- ADD_BIT_VAL(64, is_vht_cap, max_amsdu, 2);
+ ADD_BIT_VAL(63, ctx->is_vht_cap, max_amsdu, 1);
+ ADD_BIT_VAL(64, ctx->is_vht_cap, max_amsdu, 2);
CAPA(65, "Channel Schedule Management");
CAPA(66, "Geodatabase Inband Enabling Signal");
@@ -1462,7 +1450,7 @@ static void print_capabilities(const uin
printf("\n\t\t * Service Interval Granularity is %d ms",
(si_duration + 1) * 5);
- if (is_vht_cap) {
+ if (ctx->is_vht_cap) {
printf("\n\t\t * Max Number Of MSDUs In A-MSDU is ");
switch (max_amsdu) {
case 0:
@@ -1486,7 +1474,7 @@ static void print_capabilities(const uin
}
static void print_tim(const uint8_t type, uint8_t len, const uint8_t *data,
- const struct print_ies_data *ie_buffer)
+ const struct ie_context *ctx)
{
printf(" DTIM Count %u DTIM Period %u Bitmap Control 0x%x "
"Bitmap[0] 0x%x",
@@ -1497,13 +1485,13 @@ static void print_tim(const uint8_t type
}
static void print_ibssatim(const uint8_t type, uint8_t len, const uint8_t *data,
- const struct print_ies_data *ie_buffer)
+ const struct ie_context *ctx)
{
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 ie_context *ctx)
{
printf("\n");
print_vht_info((__u32) data[0] | ((__u32)data[1] << 8) |
@@ -1512,7 +1500,7 @@ static void print_vht_capa(const uint8_t
}
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 ie_context *ctx)
{
const char *chandwidths[] = {
[0] = "20 or 40 MHz",
@@ -1531,7 +1519,7 @@ static void print_vht_oper(const uint8_t
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 ie_context *ctx)
{
uint8_t *p = (uint8_t*) data;
const uint8_t *next_data = p + len;
@@ -1565,7 +1553,7 @@ static void print_supp_op_classes(const
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 ie_context *ctx)
{
uint8_t *p, len_remaining;
@@ -1614,7 +1602,7 @@ static void print_measurement_pilot_tx(c
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 ie_context *ctx)
{
printf("\n");
printf("\t\t * passive dwell: %d TUs\n", (data[1] << 8) | data[0]);
@@ -1629,7 +1617,7 @@ static void print_obss_scan_params(const
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 ie_context *ctx)
{
if (data[0] < ARRAY_SIZE(ht_secondary_offset))
printf(" %s (%d)\n", ht_secondary_offset[data[0]], data[0]);
@@ -1638,7 +1626,7 @@ static void print_secchan_offs(const uin
}
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 ie_context *ctx)
{
printf("\n");
printf("\t\t * station count: %d\n", (data[1] << 8) | data[0]);
@@ -1648,7 +1636,7 @@ static void print_bss_load(const uint8_t
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 ie_context *ctx)
{
printf("\n");
printf("\t\t * Active Path Selection Protocol ID: %d\n", data[0]);
@@ -1681,7 +1669,7 @@ static void print_mesh_conf(const uint8_
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 ie_context *ctx)
{
printf("\n");
print_s1g_capability(data);
@@ -1689,14 +1677,14 @@ static void print_s1g_capa(const uint8_t
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 ie_context *ctx)
{
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 ie_context *ctx)
{
int oper_ch_width, prim_ch_width;
int prim_ch_width_subfield = data[0] & 0x1;
@@ -1777,14 +1765,14 @@ static void print_s1g_oper(const uint8_t
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 ie_context *ctx);
uint8_t minlen, maxlen;
uint8_t flags;
};
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 ie_context *ctx)
{
int i;
@@ -1805,7 +1793,7 @@ static void print_ie(const struct ie_pri
return;
}
- p->print(type, len, data, ie_buffer);
+ p->print(type, len, data, ctx);
}
#define PRINT_IGN { \
@@ -1867,14 +1855,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 ie_context *ctx)
{
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 ie_context *ctx)
{
print_osen_ie("OSEN", "OSEN", len, data);
}
@@ -1922,7 +1910,7 @@ static bool print_wifi_wmm_param(const u
}
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 ie_context *ctx)
{
int i;
@@ -1965,7 +1953,7 @@ static const char * wifi_wps_dev_passwd_
}
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 ie_context *ctx)
{
bool first = true;
__u16 subtype, sublen;
@@ -2205,7 +2193,7 @@ static const struct ie_print wifiprinter
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 ie_context *ctx)
{
bool first = true;
__u8 subtype;
@@ -2287,7 +2275,7 @@ static inline void print_p2p(const uint8
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 ie_context *ctx)
{
/* I can't find the spec for this...just going off what wireshark uses. */
printf("\n");
@@ -2299,7 +2287,7 @@ static inline void print_hs20_ind(const
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 ie_context *ctx)
{
char mac_addr[20];
int ssid_len;
@@ -2392,14 +2380,14 @@ static void print_vendor(unsigned char l
}
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 ie_context *ctx)
{
printf("\n");
print_he_capability(data, len);
}
static void print_he_oper(const uint8_t type, uint8_t len, const uint8_t *data,
- const struct print_ies_data *ie_buffer)
+ const struct ie_context *ctx)
{
printf("\n");
print_he_operation(data, len);
@@ -2437,23 +2425,46 @@ static void print_extension(unsigned cha
}
}
+static void init_context(struct ie_context *ctx,
+ unsigned char *ie, int ielen)
+{
+ unsigned char *pos = ie;
+ int remaining = ielen;
+
+ memset(ctx, 0, sizeof(*ctx));
+
+ if (!ie || !ielen)
+ return;
+
+ while (remaining >= 2 && remaining - 2 >= pos[1]) {
+ switch (pos[0]) {
+ case EID_VHT_CAPABILITY:
+ ctx->is_vht_cap = true;
+ break;
+ }
+
+ remaining -= pos[1] + 2;
+ pos += pos[1] + 2;
+ }
+}
+
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 ie_context ctx;
- if (ie == NULL || ielen < 0)
+ if (!ie)
return;
+ init_context(&ctx, ie, ielen);
+
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);
+ ie[0], ie[1], ie + 2, &ctx);
} else if (ie[0] == 221 /* vendor */) {
print_vendor(ie[1], ie + 2, unknown, ptype);
} else if (ie[0] == 255 /* extension */) {

View File

@ -0,0 +1,207 @@
From 4c859917316b69e66ba241d85b4da6ee01292a11 Mon Sep 17 00:00:00 2001
From: Dylan Eskew <dylan.eskew@candelatech.com>
Date: Wed, 19 Mar 2025 11:39:17 -0700
Subject: [PATCH] iw: util: update and clean up eht capa printing
A number of fields were either missing or incorrect, so
update to more aligned with 802.11be spec. Also clean up
printout formatting.
Signed-off-by: Dylan Eskew <dylan.eskew@candelatech.com>
Link: https://patch.msgid.link/20250319183918.1215853-2-dylan.eskew@candelatech.com
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
iw.h | 2 +
util.c | 124 ++++++++++++++++++++++++++++++++++++++++++++-------------
2 files changed, 99 insertions(+), 27 deletions(-)
--- a/iw.h
+++ b/iw.h
@@ -224,6 +224,8 @@ void print_vht_info(__u32 capa, const __
void print_he_capability(const uint8_t *ie, int len);
void print_he_operation(const uint8_t *ie, int len);
void print_he_info(struct nlattr *nl_iftype);
+void print_eht_capability(const uint8_t *ie, int len, const uint8_t *he_cap,
+ bool from_ap);
void print_eht_info(struct nlattr *nl_iftype, int band);
void print_s1g_capability(const uint8_t *caps);
--- a/util.c
+++ b/util.c
@@ -1515,11 +1515,11 @@ static void __print_eht_capa(int band,
const __u8 *mcs_set, size_t mcs_len,
const __u8 *ppet, size_t ppet_len,
const __u16 *he_phy_cap,
+ bool from_ap,
bool indent)
{
unsigned int i;
const char *pre = indent ? "\t" : "";
- const char *mcs[] = { "0-7", "8-9", "10-11", "12-13"};
#define PRINT_EHT_CAP(_var, _idx, _bit, _str) \
do { \
@@ -1534,6 +1534,7 @@ static void __print_eht_capa(int band,
} while (0)
#define PRINT_EHT_MAC_CAP(...) PRINT_EHT_CAP(mac_cap, __VA_ARGS__)
+ #define PRINT_EHT_MAC_CAP_MASK(...) PRINT_EHT_CAP_MASK(mac_cap, __VA_ARGS__)
#define PRINT_EHT_PHY_CAP(...) PRINT_EHT_CAP(phy_cap, __VA_ARGS__)
#define PRINT_EHT_PHY_CAP_MASK(...) PRINT_EHT_CAP_MASK(phy_cap, __VA_ARGS__)
@@ -1542,13 +1543,22 @@ static void __print_eht_capa(int band,
printf("%02x", mac_cap[i]);
printf("):\n");
- PRINT_EHT_MAC_CAP(0, 0, "NSEP priority access Supported");
+ PRINT_EHT_MAC_CAP(0, 0, "EPCS Priority Access Supported");
PRINT_EHT_MAC_CAP(0, 1, "EHT OM Control Supported");
- PRINT_EHT_MAC_CAP(0, 2, "Triggered TXOP Sharing Supported");
- PRINT_EHT_MAC_CAP(0, 3, "ARR Supported");
+ PRINT_EHT_MAC_CAP(0, 2, "Triggered TXOP Sharing Mode 1 Supported");
+ PRINT_EHT_MAC_CAP(0, 3, "Triggered TXOP Sharing Mode 2 Supported");
+ PRINT_EHT_MAC_CAP(0, 4, "Restricted TWP Supported");
+ PRINT_EHT_MAC_CAP(0, 5, "SCS Traffic Description Supported");
+ PRINT_EHT_MAC_CAP_MASK(0, 6, 0x3, "Maximum MPDU Length");
+
+ PRINT_EHT_MAC_CAP(1, 1, "Maximum A_MPDU Length Exponent Extension");
+ PRINT_EHT_MAC_CAP(1, 2, "EHT TRS Supported");
+ PRINT_EHT_MAC_CAP(1, 3, "TXOP Return In TXOP Sharing Mode 2 Supported");
+ PRINT_EHT_MAC_CAP(1, 4, "Two BQRs Supported");
+ PRINT_EHT_MAC_CAP_MASK(1, 5, 0x3, "EHT Link Adaptation Supported");
- printf("%s\t\tEHT PHY Capabilities: (0x", pre);
- for (i = 0; i < 8; i++)
+ printf("%s\t\tEHT PHY Capabilities (0x", pre);
+ for (i = 0; i < 9; i++)
printf("%02x", ((__u8 *)phy_cap)[i]);
printf("):\n");
@@ -1594,39 +1604,77 @@ static void __print_eht_capa(int band,
PRINT_EHT_PHY_CAP(1, 28, "MU Beamformer (80MHz)");
PRINT_EHT_PHY_CAP(1, 29, "MU Beamformer (160MHz)");
PRINT_EHT_PHY_CAP(1, 30, "MU Beamformer (320MHz)");
+ PRINT_EHT_PHY_CAP(1, 31, "TB Sounding Feedback Rate Limit");
- printf("%s\t\tEHT MCS/NSS: (0x", pre);
- for (i = 0; i < mcs_len; i++)
- printf("%02x", ((__u8 *)mcs_set)[i]);
- printf("):\n");
+ PRINT_EHT_PHY_CAP(2, 0, "Rx 1024-QAM In Wider Bandwidth DL OFDMA Supported");
+ PRINT_EHT_PHY_CAP(2, 1, "Rx 4096-QAM In Wider Bandwidth DL OFDMA Supported");
- if (!(he_phy_cap[0] & ((BIT(2) | BIT(3) | BIT(4)) << 8))){
- for (i = 0; i < 4; i++)
- printf("%s\t\tEHT bw=20 MHz, max NSS for MCS %s: Rx=%u, Tx=%u\n",
- pre, mcs[i],
- mcs_set[i] & 0xf, mcs_set[i] >> 4);
+ if (!from_ap &&
+ !(he_phy_cap[0] & ((BIT(1) | BIT(2) | BIT(3) | BIT(4)) << 8))) {
+ static const char * const mcs[] = { "0-7", "8-9", "10-11", "12-13" };
+
+ printf("%s\t\tEHT-MCS Map (20 Mhz Non-AP STA) (0x", pre);
+ for (i = 0; i < mcs_len; i++)
+ printf("%02x", ((__u8 *)mcs_set)[i]);
+ printf("):\n");
+
+ for (i = 0; i < 4; i++) {
+ printf("%s\t\t\tRx Max NSS for MCS %s: %u\n",
+ pre, mcs[i], mcs_set[i] & 0xf);
+ printf("%s\t\t\tTx Max NSS for MCS %s: %u\n",
+ pre, mcs[i], mcs_set[i] >> 4);
+ }
} else {
- if (he_phy_cap[0] & (BIT(2) << 8)) {
+ static const char * const mcs[] = { "0-9", "10-11", "12-13"};
+
+ /* Bit 1 corresponds to 2.4Ghz 40Mhz support
+ * Bit 2 corresponds to 5/6Ghz 40 and 80Mhz support
+ * If no Channel Width bits are set, but we are an AP, we use
+ * this MCS logic also.
+ */
+ if (he_phy_cap[0] & ((BIT(1) | BIT(2)) << 8) ||
+ (from_ap && !(he_phy_cap[0] & ((BIT(1) | BIT(2) | BIT(3) | BIT(4)) << 8)))) {
+ printf("%s\t\tEHT-MCS Map (BW <= 80) (0x", pre);
for (i = 0; i < 3; i++)
- printf("%s\t\tEHT bw <= 80 MHz, max NSS for MCS %s: Rx=%u, Tx=%u\n",
- pre, mcs[i + 1],
- mcs_set[i] & 0xf, mcs_set[i] >> 4);
+ printf("%02x", ((__u8 *)mcs_set)[i]);
+ printf("):\n");
+
+ for (i = 0; i < 3; i++) {
+ printf("%s\t\t\tRx Max NSS for MCS %s: %u\n",
+ pre, mcs[i], mcs_set[i] & 0xf);
+ printf("%s\t\t\tTx Max NSS for MCS %s: %u\n",
+ pre, mcs[i], mcs_set[i] >> 4);
+ }
}
mcs_set += 3;
if (he_phy_cap[0] & (BIT(3) << 8)) {
+ printf("%s\t\tEHT-MCS Map (BW = 160) (0x", pre);
for (i = 0; i < 3; i++)
- printf("%s\t\tEHT bw=160 MHz, max NSS for MCS %s: Rx=%u, Tx=%u\n",
- pre, mcs[i + 1],
- mcs_set[i] & 0xf, mcs_set[i] >> 4);
+ printf("%02x", ((__u8 *)mcs_set)[i]);
+ printf("):\n");
+
+ for (i = 0; i < 3; i++) {
+ printf("%s\t\t\tRx Max NSS for MCS %s: %u\n",
+ pre, mcs[i], mcs_set[i] & 0xf);
+ printf("%s\t\t\tTx Max NSS for MCS %s: %u\n",
+ pre, mcs[i], mcs_set[i] >> 4);
+ }
}
mcs_set += 3;
if (band == NL80211_BAND_6GHZ && (phy_cap[0] & BIT(1))) {
+ printf("%s\t\tEHT-MCS Map (BW = 320) (0x", pre);
for (i = 0; i < 3; i++)
- printf("%s\t\tEHT bw=320 MHz, max NSS for MCS %s: Rx=%u, Tx=%u\n",
- pre, mcs[i + 1],
- mcs_set[i] & 0xf, mcs_set[i] >> 4);
+ printf("%02x", ((__u8 *)mcs_set)[i]);
+ printf("):\n");
+
+ for (i = 0; i < 3; i++) {
+ printf("%s\t\t\tRx Max NSS for MCS %s: %u\n",
+ pre, mcs[i], mcs_set[i] & 0xf);
+ printf("%s\t\t\tTx Max NSS for MCS %s: %u\n",
+ pre, mcs[i], mcs_set[i] >> 4);
+ }
}
}
@@ -1713,7 +1761,29 @@ void print_eht_info(struct nlattr *nl_if
}
__print_eht_capa(band, mac_cap, phy_cap, mcs_set, mcs_len, ppet, ppet_len,
- he_phy_cap, true);
+ he_phy_cap, false, true);
+}
+
+void print_eht_capability(const uint8_t *ie, int len, const uint8_t *he_cap,
+ bool from_ap)
+{
+ const void *mac_cap, *phy_cap, *mcs_set, *he_phy_cap;
+ int mcs_len;
+ int i = 0;
+
+ mac_cap = &ie[i];
+ i += 2;
+
+ phy_cap = &ie[i];
+ i += 9;
+
+ mcs_set = &ie[i];
+ mcs_len = len - i;
+
+ he_phy_cap = &he_cap[6];
+
+ __print_eht_capa(NL80211_BAND_6GHZ, mac_cap, phy_cap, mcs_set, mcs_len,
+ NULL, 0, he_phy_cap - 1, from_ap, false);
}
void print_he_capability(const uint8_t *ie, int len)

View File

@ -0,0 +1,175 @@
From a6ad3f11ead18d1812c7d3759991dc22b20d90da Mon Sep 17 00:00:00 2001
From: Dylan Eskew <dylan.eskew@candelatech.com>
Date: Wed, 19 Mar 2025 11:39:18 -0700
Subject: [PATCH] iw: scan: add eht capability parsing
Add ability to print out EHT capabilities from
AP beacons.
Signed-off-by: Dylan Eskew <dylan.eskew@candelatech.com>
Link: https://patch.msgid.link/20250319183918.1215853-3-dylan.eskew@candelatech.com
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
ieee80211.h | 1 +
iw.h | 2 +-
link.c | 5 +++--
scan.c | 34 +++++++++++++++++++++++++++-------
4 files changed, 32 insertions(+), 10 deletions(-)
--- a/ieee80211.h
+++ b/ieee80211.h
@@ -99,6 +99,7 @@ enum elem_id {
enum elem_id_ext {
EID_EXT_HE_CAPABILITY = 35,
EID_EXT_HE_OPERATION = 36,
+ EID_EXT_EHT_CAPABILITY = 108,
};
#define SUITE(oui, id) (((oui) << 8) | (id))
--- a/iw.h
+++ b/iw.h
@@ -256,7 +256,7 @@ enum print_ie_type {
#define BIT(x) (1ULL<<(x))
void print_ies(unsigned char *ie, int ielen, bool unknown,
- enum print_ie_type ptype);
+ enum print_ie_type ptype, bool from_ap);
void parse_bitrate(struct nlattr *bitrate_attr, char *buf, int buflen);
void iw_hexdump(const char *prefix, const __u8 *data, size_t len);
--- a/link.c
+++ b/link.c
@@ -93,7 +93,7 @@ static int link_bss_handler(struct nl_ms
if (bss[NL80211_BSS_INFORMATION_ELEMENTS])
print_ies(nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]),
nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]),
- false, PRINT_LINK_MLO_MLD);
+ false, PRINT_LINK_MLO_MLD, false);
}
} else {
memcpy(result->sta_addr, nla_data(bss[NL80211_BSS_BSSID]), 6);
@@ -121,7 +121,8 @@ static int link_bss_handler(struct nl_ms
if (bss[NL80211_BSS_INFORMATION_ELEMENTS])
print_ies(nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]),
nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]),
- false, result->mld ? PRINT_LINK_MLO_LINK : PRINT_LINK);
+ false, result->mld ? PRINT_LINK_MLO_LINK : PRINT_LINK,
+ false);
if (bss[NL80211_BSS_FREQUENCY_OFFSET])
freq_offset = nla_get_u32(bss[NL80211_BSS_FREQUENCY_OFFSET]);
--- a/scan.c
+++ b/scan.c
@@ -555,7 +555,9 @@ static void tab_on_first(bool *first)
}
struct ie_context {
+ bool from_ap;
bool is_vht_cap;
+ const uint8_t *he_cap;
};
static void print_ssid(const uint8_t type, uint8_t len, const uint8_t *data,
@@ -2393,12 +2395,21 @@ static void print_he_oper(const uint8_t
print_he_operation(data, len);
}
+static void print_eht_capa(const uint8_t type, uint8_t len,
+ const uint8_t *data, const struct ie_context *ctx)
+{
+ printf("\n");
+ print_eht_capability(data, len, ctx->he_cap, ctx->from_ap);
+}
+
static const struct ie_print ext_printers[] = {
[EID_EXT_HE_CAPABILITY] = { "HE capabilities", print_he_capa, 21, 54, BIT(PRINT_SCAN), },
[EID_EXT_HE_OPERATION] = { "HE Operation", print_he_oper, 6, 15, BIT(PRINT_SCAN), },
+ [EID_EXT_EHT_CAPABILITY] = { "EHT capabilities", print_eht_capa, 13, 30, BIT(PRINT_SCAN), },
};
static void print_extension(unsigned char len, unsigned char *ie,
+ const struct ie_context *ctx,
bool unknown, enum print_ie_type ptype)
{
unsigned char tag;
@@ -2411,7 +2422,7 @@ static void print_extension(unsigned cha
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);
+ print_ie(&ext_printers[tag], tag, len - 1, ie + 1, ctx);
return;
}
@@ -2426,7 +2437,7 @@ static void print_extension(unsigned cha
}
static void init_context(struct ie_context *ctx,
- unsigned char *ie, int ielen)
+ unsigned char *ie, int ielen, bool from_ap)
{
unsigned char *pos = ie;
int remaining = ielen;
@@ -2436,11 +2447,20 @@ static void init_context(struct ie_conte
if (!ie || !ielen)
return;
+ ctx->from_ap = from_ap;
+
while (remaining >= 2 && remaining - 2 >= pos[1]) {
switch (pos[0]) {
case EID_VHT_CAPABILITY:
ctx->is_vht_cap = true;
break;
+ case EID_EXTENSION:
+ switch (pos[2]) {
+ case EID_EXT_HE_CAPABILITY:
+ ctx->he_cap = pos + 3;
+ break;
+ }
+ break;
}
remaining -= pos[1] + 2;
@@ -2449,14 +2469,14 @@ static void init_context(struct ie_conte
}
void print_ies(unsigned char *ie, int ielen, bool unknown,
- enum print_ie_type ptype)
+ enum print_ie_type ptype, bool from_ap)
{
struct ie_context ctx;
if (!ie)
return;
- init_context(&ctx, ie, ielen);
+ init_context(&ctx, ie, ielen, from_ap);
while (ielen >= 2 && ielen - 2 >= ie[1]) {
if (ie[0] < ARRAY_SIZE(ieprinters) &&
@@ -2468,7 +2488,7 @@ void print_ies(unsigned char *ie, int ie
} 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);
+ print_extension(ie[1], ie + 2, &ctx, unknown, ptype);
} else if (unknown) {
int i;
@@ -2673,13 +2693,13 @@ static int print_bss_handler(struct nl_m
printf("\tInformation elements from Probe Response "
"frame:\n");
print_ies(nla_data(ies), nla_len(ies),
- params->unknown, params->type);
+ params->unknown, params->type, true);
}
if (bss[NL80211_BSS_BEACON_IES] && show--) {
printf("\tInformation elements from Beacon frame:\n");
print_ies(nla_data(bss[NL80211_BSS_BEACON_IES]),
nla_len(bss[NL80211_BSS_BEACON_IES]),
- params->unknown, params->type);
+ params->unknown, params->type, true);
}
return NL_SKIP;

View File

@ -0,0 +1,107 @@
From 59660a349cf35903e951f99bdd8a74df063c912e Mon Sep 17 00:00:00 2001
From: Aleksander Jan Bajkowski <olek2@wp.pl>
Date: Fri, 2 May 2025 21:44:05 +0200
Subject: [PATCH] iw: fix EHT capabilities on Big Endian platforms
IE fields are encoded in Little Endian and are not correctly
printed on Big Endian platforms.
Fixes: 5a71b722270c ("iw: Print local EHT capabilities")
Signed-off-by: Aleksander Jan Bajkowski <olek2@wp.pl>
Link: https://patch.msgid.link/20250502194405.3489240-1-olek2@wp.pl
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
util.c | 40 +++++++++++++++++++++++++---------------
1 file changed, 25 insertions(+), 15 deletions(-)
--- a/util.c
+++ b/util.c
@@ -1521,22 +1521,31 @@ static void __print_eht_capa(int band,
unsigned int i;
const char *pre = indent ? "\t" : "";
- #define PRINT_EHT_CAP(_var, _idx, _bit, _str) \
+ #define PRINT_EHT_MAC_CAP(_idx, _bit, _str) \
do { \
- if (_var[_idx] & BIT(_bit)) \
+ if (mac_cap[_idx] & BIT(_bit)) \
printf("%s\t\t\t" _str "\n", pre); \
} while (0)
- #define PRINT_EHT_CAP_MASK(_var, _idx, _shift, _mask, _str) \
+ #define PRINT_EHT_MAC_CAP_MASK(_idx, _shift, _mask, _str) \
do { \
- if ((_var[_idx] >> _shift) & _mask) \
- printf("%s\t\t\t" _str ": %d\n", pre, (_var[_idx] >> _shift) & _mask); \
+ if ((mac_cap[_idx] >> _shift) & _mask) \
+ printf("%s\t\t\t" _str ": %d\n", pre, \
+ (mac_cap[_idx] >> _shift) & _mask); \
} while (0)
- #define PRINT_EHT_MAC_CAP(...) PRINT_EHT_CAP(mac_cap, __VA_ARGS__)
- #define PRINT_EHT_MAC_CAP_MASK(...) PRINT_EHT_CAP_MASK(mac_cap, __VA_ARGS__)
- #define PRINT_EHT_PHY_CAP(...) PRINT_EHT_CAP(phy_cap, __VA_ARGS__)
- #define PRINT_EHT_PHY_CAP_MASK(...) PRINT_EHT_CAP_MASK(phy_cap, __VA_ARGS__)
+ #define PRINT_EHT_PHY_CAP(_idx, _bit, _str) \
+ do { \
+ if (le32toh(phy_cap[_idx]) & BIT(_bit)) \
+ printf("%s\t\t\t" _str "\n", pre); \
+ } while (0)
+
+ #define PRINT_EHT_PHY_CAP_MASK(_idx, _shift, _mask, _str) \
+ do { \
+ if ((le32toh(phy_cap[_idx]) >> _shift) & _mask) \
+ printf("%s\t\t\t" _str ": %d\n", pre, \
+ (le32toh(phy_cap[_idx]) >> _shift) & _mask); \
+ } while (0)
printf("%s\t\tEHT MAC Capabilities (0x", pre);
for (i = 0; i < 2; i++)
@@ -1610,7 +1619,7 @@ static void __print_eht_capa(int band,
PRINT_EHT_PHY_CAP(2, 1, "Rx 4096-QAM In Wider Bandwidth DL OFDMA Supported");
if (!from_ap &&
- !(he_phy_cap[0] & ((BIT(1) | BIT(2) | BIT(3) | BIT(4)) << 8))) {
+ !(le16toh(he_phy_cap[0]) & ((BIT(1) | BIT(2) | BIT(3) | BIT(4)) << 8))) {
static const char * const mcs[] = { "0-7", "8-9", "10-11", "12-13" };
printf("%s\t\tEHT-MCS Map (20 Mhz Non-AP STA) (0x", pre);
@@ -1632,8 +1641,9 @@ static void __print_eht_capa(int band,
* If no Channel Width bits are set, but we are an AP, we use
* this MCS logic also.
*/
- if (he_phy_cap[0] & ((BIT(1) | BIT(2)) << 8) ||
- (from_ap && !(he_phy_cap[0] & ((BIT(1) | BIT(2) | BIT(3) | BIT(4)) << 8)))) {
+ if (le16toh(he_phy_cap[0]) & ((BIT(1) | BIT(2)) << 8) ||
+ (from_ap && !(le16toh(he_phy_cap[0]) &
+ ((BIT(1) | BIT(2) | BIT(3) | BIT(4)) << 8)))) {
printf("%s\t\tEHT-MCS Map (BW <= 80) (0x", pre);
for (i = 0; i < 3; i++)
printf("%02x", ((__u8 *)mcs_set)[i]);
@@ -1648,7 +1658,7 @@ static void __print_eht_capa(int band,
}
mcs_set += 3;
- if (he_phy_cap[0] & (BIT(3) << 8)) {
+ if (le16toh(he_phy_cap[0]) & (BIT(3) << 8)) {
printf("%s\t\tEHT-MCS Map (BW = 160) (0x", pre);
for (i = 0; i < 3; i++)
printf("%02x", ((__u8 *)mcs_set)[i]);
@@ -1663,7 +1673,7 @@ static void __print_eht_capa(int band,
}
mcs_set += 3;
- if (band == NL80211_BAND_6GHZ && (phy_cap[0] & BIT(1))) {
+ if (band == NL80211_BAND_6GHZ && (le32toh(phy_cap[0]) & BIT(1))) {
printf("%s\t\tEHT-MCS Map (BW = 320) (0x", pre);
for (i = 0; i < 3; i++)
printf("%02x", ((__u8 *)mcs_set)[i]);
@@ -1678,7 +1688,7 @@ static void __print_eht_capa(int band,
}
}
- if (ppet && ppet_len && (phy_cap[1] & BIT(11))) {
+ if (ppet && ppet_len && (le32toh(phy_cap[1]) & BIT(11))) {
printf("%s\t\tEHT PPE Thresholds ", pre);
for (i = 0; i < ppet_len; i++)
if (ppet[i])

View File

@ -0,0 +1,131 @@
From 8ea80d378ce5f727e69493533a666278c6a568a7 Mon Sep 17 00:00:00 2001
From: Aleksander Jan Bajkowski <olek2@wp.pl>
Date: Fri, 2 May 2025 12:03:53 +0200
Subject: [PATCH] iw: scan: Add printing of EHT Operation Element
Add ability to print out EHT capabilities from AP beacons.
Signed-off-by: Aleksander Jan Bajkowski <olek2@wp.pl>
Link: https://patch.msgid.link/20250502100353.3149470-1-olek2@wp.pl
[add default case to bandwidth switch]
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
ieee80211.h | 1 +
iw.h | 1 +
scan.c | 8 +++++++
util.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 73 insertions(+)
--- a/ieee80211.h
+++ b/ieee80211.h
@@ -99,6 +99,7 @@ enum elem_id {
enum elem_id_ext {
EID_EXT_HE_CAPABILITY = 35,
EID_EXT_HE_OPERATION = 36,
+ EID_EXT_EHT_OPERATION = 106,
EID_EXT_EHT_CAPABILITY = 108,
};
--- a/iw.h
+++ b/iw.h
@@ -226,6 +226,7 @@ void print_he_operation(const uint8_t *i
void print_he_info(struct nlattr *nl_iftype);
void print_eht_capability(const uint8_t *ie, int len, const uint8_t *he_cap,
bool from_ap);
+void print_eht_operation(const uint8_t *ie, int len);
void print_eht_info(struct nlattr *nl_iftype, int band);
void print_s1g_capability(const uint8_t *caps);
--- a/scan.c
+++ b/scan.c
@@ -2402,10 +2402,18 @@ static void print_eht_capa(const uint8_t
print_eht_capability(data, len, ctx->he_cap, ctx->from_ap);
}
+static void print_eht_oper(const uint8_t type, uint8_t len, const uint8_t *data,
+ const struct ie_context *ctx)
+{
+ printf("\n");
+ print_eht_operation(data, len);
+}
+
static const struct ie_print ext_printers[] = {
[EID_EXT_HE_CAPABILITY] = { "HE capabilities", print_he_capa, 21, 54, BIT(PRINT_SCAN), },
[EID_EXT_HE_OPERATION] = { "HE Operation", print_he_oper, 6, 15, BIT(PRINT_SCAN), },
[EID_EXT_EHT_CAPABILITY] = { "EHT capabilities", print_eht_capa, 13, 30, BIT(PRINT_SCAN), },
+ [EID_EXT_EHT_OPERATION] = { "EHT Operation", print_eht_oper, 5, 10, BIT(PRINT_SCAN), },
};
static void print_extension(unsigned char len, unsigned char *ie,
--- a/util.c
+++ b/util.c
@@ -1917,6 +1917,69 @@ void print_he_operation(const uint8_t *i
}
}
+void print_eht_operation(const uint8_t *ie, int len)
+{
+ uint8_t oper_parameters = ie[0];
+ uint8_t disabled_subchannel_info_present = oper_parameters & 0x02;
+ uint8_t eht_operation_info_present = oper_parameters & 0x01;
+
+ printf("\t\tEHT Operation Parameters: (0x%02x)\n",
+ oper_parameters);
+
+ if (oper_parameters & 0x04)
+ printf("\t\t\tEHT Default PE Duration\n");
+
+ if (oper_parameters & 0x08)
+ printf("\t\t\tGroup Addressed BU Indication Limit\n");
+
+ printf("\t\t\tGroup Addressed BU Indication Exponent: 0x%01x\n",
+ (oper_parameters >> 4 & 3));
+
+ printf("\t\tBasic EHT-MCS And Nss Set: 0x");
+ for (uint8_t i = 0; i < 4; i++)
+ printf("%02x", ie[1 + i]);
+
+ printf("\n");
+
+ if (eht_operation_info_present) {
+ uint8_t offset = 5;
+ const uint8_t control = ie[offset];
+ uint8_t eht_operation_info_len = 3;
+
+ if (disabled_subchannel_info_present)
+ eht_operation_info_len += 2;
+
+ if (len - offset < eht_operation_info_len) {
+ printf("\t\tEHT Operation Info: Invalid\n");
+ return;
+ }
+
+ printf("\t\tEHT Operation Info: 0x");
+ for (uint8_t i = 0; i < eht_operation_info_len; i++)
+ printf("%02x", ie[offset + i]);
+
+ printf("\n");
+ printf("\t\t\tChannel Width: ");
+ switch (control & 0x7) {
+ case 0: printf("20 MHz\n"); break;
+ case 1: printf("40 MHz\n"); break;
+ case 2: printf("80 MHz\n"); break;
+ case 3: printf("160 MHz\n"); break;
+ case 4: printf("320 MHz\n"); break;
+ default: printf("invalid bandwidth (%d)\n", control & 0x7); break;
+ }
+
+ printf("\t\t\tCenter Frequency Segment 0: %hhu\n",
+ ie[offset + 1]);
+ printf("\t\t\tCenter Frequency Segment 1: %hhu\n",
+ ie[offset + 2]);
+
+ if (disabled_subchannel_info_present)
+ printf("\t\t\tDisabled Subchannel Bitmap: 0x%02x%02x\n",
+ ie[offset + 3], ie[offset + 4]);
+ }
+}
+
void iw_hexdump(const char *prefix, const __u8 *buf, size_t size)
{
size_t i;

View File

@ -132,7 +132,7 @@
{
--- a/scan.c
+++ b/scan.c
@@ -1308,6 +1308,9 @@ static void print_ht_op(const uint8_t ty
@@ -1309,6 +1309,9 @@ static void print_ht_op(const uint8_t ty
printf("\t\t * secondary channel offset: %s\n",
ht_secondary_offset[data[1] & 0x3]);
printf("\t\t * STA channel width: %s\n", sta_chan_width[(data[1] & 0x4)>>2]);
@ -142,55 +142,62 @@
printf("\t\t * RIFS: %d\n", (data[1] & 0x8)>>3);
printf("\t\t * HT protection: %s\n", protection[data[2] & 0x3]);
printf("\t\t * non-GF present: %d\n", (data[2] & 0x4) >> 2);
@@ -1818,30 +1821,31 @@ static void print_ie(const struct ie_pri
@@ -1808,17 +1811,25 @@ static void print_ie(const struct ie_pri
static const struct ie_print ieprinters[] = {
[0] = { "SSID", print_ssid, 0, 32,
BIT(PRINT_SCAN) | BIT(PRINT_LINK) | BIT(PRINT_LINK_MLO_MLD), },
+ [11] = { "BSS Load", print_bss_load, 5, 5, BIT(PRINT_SCAN), },
+ [45] = { "HT capabilities", print_ht_capa, 26, 26, BIT(PRINT_SCAN), },
+ [48] = { "RSN", print_rsn, 2, 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), },
+ [114] = { "MESH ID", print_ssid, 0, 32, BIT(PRINT_SCAN) | BIT(PRINT_LINK), },
+ [191] = { "VHT capabilities", print_vht_capa, 12, 255, BIT(PRINT_SCAN), },
+ [192] = { "VHT operation", print_vht_oper, 5, 255, BIT(PRINT_SCAN), },
[EID_SSID] = { "SSID", print_ssid, 0, 32,
BIT(PRINT_SCAN) | BIT(PRINT_LINK) | BIT(PRINT_LINK_MLO_MLD), },
+ [EID_BSS_LOAD] = { "BSS Load", print_bss_load, 5, 5, BIT(PRINT_SCAN), },
+ [EID_HT_CAPABILITY] = { "HT capabilities", print_ht_capa, 26, 26, BIT(PRINT_SCAN), },
+ [EID_RSN] = { "RSN", print_rsn, 2, 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_MESH_ID] = { "MESH ID", print_ssid, 0, 32, BIT(PRINT_SCAN) | BIT(PRINT_LINK), },
+ [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), },
+#ifdef IW_FULL
[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), },
@@ -1850,6 +1854,7 @@ static const struct ie_print ieprinters[
[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_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), },
@@ -1828,18 +1839,11 @@ static const struct ie_print ieprinters[
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,
@@ -1854,6 +1858,7 @@ static const struct ie_print ieprinters[
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), },
+#endif
};
static void print_wifi_wpa(const uint8_t type, uint8_t len, const uint8_t *data,
@@ -2185,8 +2190,10 @@ static void print_wifi_wps(const uint8_t
@@ -2189,8 +2194,10 @@ static void print_wifi_wps(const uint8_t
static const struct ie_print wifiprinters[] = {
[1] = { "WPA", print_wifi_wpa, 2, 255, BIT(PRINT_SCAN), },
@ -201,7 +208,7 @@
};
static inline void print_p2p(const uint8_t type, uint8_t len,
@@ -2349,6 +2356,10 @@ static void print_vendor(unsigned char l
@@ -2353,6 +2360,10 @@ static void print_vendor(unsigned char l
return;
}
@ -212,7 +219,7 @@
if (len >= 4 && memcmp(data, wfa_oui, 3) == 0) {
if (data[3] < ARRAY_SIZE(wfa_printers) &&
wfa_printers[data[3]].name &&
@@ -2491,6 +2502,7 @@ static void print_capa_non_dmg(__u16 cap
@@ -2544,6 +2555,7 @@ static void print_capa_non_dmg(__u16 cap
printf(" ESS");
if (capa & WLAN_CAPABILITY_IBSS)
printf(" IBSS");
@ -220,7 +227,7 @@
if (capa & WLAN_CAPABILITY_CF_POLLABLE)
printf(" CfPollable");
if (capa & WLAN_CAPABILITY_CF_POLL_REQUEST)
@@ -2519,6 +2531,7 @@ static void print_capa_non_dmg(__u16 cap
@@ -2572,6 +2584,7 @@ static void print_capa_non_dmg(__u16 cap
printf(" DelayedBACK");
if (capa & WLAN_CAPABILITY_IMM_BACK)
printf(" ImmediateBACK");
@ -228,7 +235,7 @@
}
static int print_bss_handler(struct nl_msg *msg, void *arg)
@@ -2609,8 +2622,10 @@ static int print_bss_handler(struct nl_m
@@ -2662,8 +2675,10 @@ static int print_bss_handler(struct nl_m
else
printf("\tfreq: %d\n", freq);
@ -239,7 +246,7 @@
}
if (bss[NL80211_BSS_BEACON_INTERVAL])
printf("\tbeacon interval: %d TUs\n",
@@ -2804,6 +2819,7 @@ static int handle_stop_sched_scan(struct
@@ -2857,6 +2872,7 @@ static int handle_stop_sched_scan(struct
return 0;
}
@ -247,7 +254,7 @@
COMMAND(scan, sched_start,
SCHED_SCAN_OPTIONS,
NL80211_CMD_START_SCHED_SCAN, 0, CIB_NETDEV, handle_start_sched_scan,
@@ -2814,3 +2830,4 @@ COMMAND(scan, sched_start,
@@ -2867,3 +2883,4 @@ COMMAND(scan, sched_start,
COMMAND(scan, sched_stop, "",
NL80211_CMD_STOP_SCHED_SCAN, 0, CIB_NETDEV, handle_stop_sched_scan,
"Stop an ongoing scheduled scan.");

View File

@ -12,9 +12,9 @@ PKG_RELEASE:=1
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL=https://github.com/jow-/ucode.git
PKG_SOURCE_DATE:=2025-03-24
PKG_SOURCE_VERSION:=b27d70c977ab4381f4094a0b1208e2a13fc5123f
PKG_MIRROR_HASH:=30a19d71a55ac320c92879beaed18a2f8da7b3b523eb7effa34ad3c4f9e1e50d
PKG_SOURCE_DATE:=2025-05-11
PKG_SOURCE_VERSION:=d5b3a9dc1091dd28cf6f0f60cd34fc322ef27717
PKG_MIRROR_HASH:=cd8af9d5ac28e2530b56015a3f2fcf6f36062546cac8b23a5f7b75b367209b54
PKG_MAINTAINER:=Jo-Philipp Wich <jo@mein.io>
PKG_LICENSE:=ISC

View File

@ -0,0 +1,27 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Mon, 12 May 2025 12:43:44 +0200
Subject: [PATCH] ubus: fix use-after-free on deferred request reply() method
Hold a reference to the defer resource as long as it is still needed
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/lib/ubus.c
+++ b/lib/ubus.c
@@ -636,6 +636,7 @@ uc_ubus_call_user_cb(uc_ubus_deferred_t
uc_value_t *this, *func;
request_reg_get(defer->vm, defer->registry_index, &this, &func, NULL, NULL);
+ ucv_get(this);
if (ucv_is_callable(func)) {
uc_vm_stack_push(defer->vm, ucv_get(this));
@@ -648,6 +649,7 @@ uc_ubus_call_user_cb(uc_ubus_deferred_t
}
request_reg_clear(defer->vm, defer->registry_index);
+ ucv_put(this);
}
static void

View File

@ -79,14 +79,14 @@
#address-cells = <1>;
#size-cells = <0>;
led-1 {
led@1 {
reg = <1>;
color = <LED_COLOR_ID_GREEN>;
function = LED_FUNCTION_LAN;
};
led-2 {
led@2 {
reg = <2>;
color = <LED_COLOR_ID_AMBER>;
function = LED_FUNCTION_LAN;
@ -101,14 +101,14 @@
#address-cells = <1>;
#size-cells = <0>;
led-1 {
led@1 {
reg = <1>;
color = <LED_COLOR_ID_GREEN>;
function = LED_FUNCTION_LAN;
};
led-2 {
led@2 {
reg = <2>;
color = <LED_COLOR_ID_AMBER>;
function = LED_FUNCTION_LAN;

View File

@ -38,10 +38,10 @@ define Device/tplink_tdw8980
$(Device/lantiqTpLink)
DEVICE_MODEL := TD-W8980
DEVICE_VARIANT := v1
DEVICE_ALT0_VENDOR := TP-LINK
DEVICE_ALT0_VENDOR := TP-Link
DEVICE_ALT0_MODEL := TD-W9980
DEVICE_ALT0_VARIANT := v1
DEVICE_ALT1_VENDOR := TP-LINK
DEVICE_ALT1_VENDOR := TP-Link
DEVICE_ALT1_MODEL := TD-W9980B
DEVICE_ALT1_VARIANT := v1
TPLINK_FLASHLAYOUT := 8Mltq

View File

@ -0,0 +1,203 @@
// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
#include "mt7621.dtsi"
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/input/input.h>
#include <dt-bindings/leds/common.h>
/ {
compatible = "cudy,r700", "mediatek,mt7621-soc";
model = "Cudy R700";
aliases {
led-boot = &led_internet_blue;
led-failsafe = &led_internet_blue;
led-running = &led_internet_blue;
led-upgrade = &led_internet_blue;
label-mac-device = &gmac0;
};
chosen {
bootargs = "console=ttyS0,115200";
};
keys {
compatible = "gpio-keys";
reset {
label = "reset";
gpios = <&gpio 8 GPIO_ACTIVE_LOW>;
linux,code = <KEY_RESTART>;
};
};
leds {
compatible = "gpio-leds";
led_internet_blue: internet_blue {
label = "blue:internet";
gpios = <&gpio 4 GPIO_ACTIVE_LOW>;
};
internet_red {
label = "red:internet";
gpios = <&gpio 3 GPIO_ACTIVE_LOW>;
};
wan {
function = LED_FUNCTION_WAN;
color = <LED_COLOR_ID_GREEN>;
gpios = <&gpio 13 GPIO_ACTIVE_LOW>;
};
lan1 {
label = "green:lan1";
gpios = <&gpio 14 GPIO_ACTIVE_LOW>;
};
lan2 {
label = "green:lan2";
gpios = <&gpio 18 GPIO_ACTIVE_LOW>;
};
lan3 {
label = "green:lan3";
gpios = <&gpio 16 GPIO_ACTIVE_LOW>;
};
lan4 {
label = "green:lan4";
gpios = <&gpio 15 GPIO_ACTIVE_LOW>;
};
};
};
&gmac0 {
nvmem-cells = <&macaddr_bdinfo_de00 0>;
nvmem-cell-names = "mac-address";
};
&spi0 {
status = "okay";
flash@0 {
compatible = "jedec,spi-nor";
reg = <0>;
spi-max-frequency = <50000000>;
partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
partition@0 {
label = "u-boot";
reg = <0x0 0x30000>;
read-only;
};
partition@30000 {
label = "u-boot-env";
reg = <0x30000 0x10000>;
read-only;
};
partition@40000 {
label = "factory";
reg = <0x40000 0x10000>;
read-only;
nvmem-layout {
compatible = "fixed-layout";
#address-cells = <1>;
#size-cells = <1>;
eeprom_factory_0: eeprom@0 {
reg = <0x0 0x400>;
};
eeprom_factory_8000: eeprom@8000 {
reg = <0x8000 0x4da8>;
};
};
};
partition@50000 {
compatible = "denx,uimage";
label = "firmware";
reg = <0x50000 0xf80000>;
};
partition@fd0000 {
label = "debug";
reg = <0xfd0000 0x10000>;
read-only;
};
partition@fe0000 {
label = "backup";
reg = <0xfe0000 0x10000>;
read-only;
};
partition@ff0000 {
label = "bdinfo";
reg = <0xff0000 0x10000>;
read-only;
nvmem-layout {
compatible = "fixed-layout";
#address-cells = <1>;
#size-cells = <1>;
macaddr_bdinfo_de00: macaddr@de00 {
compatible = "mac-base";
reg = <0xde00 0x6>;
#nvmem-cell-cells = <1>;
};
};
};
};
};
};
&state_default {
gpio {
groups = "i2c", "jtag", "uart3", "wdt";
function = "gpio";
};
};
&gmac1 {
status = "okay";
label = "wan";
phy-handle = <&ethphy4>;
nvmem-cells = <&macaddr_bdinfo_de00 1>;
nvmem-cell-names = "mac-address";
};
&switch0 {
ports {
port@0 {
status = "okay";
label = "lan1";
};
port@1 {
status = "okay";
label = "lan2";
};
port@2 {
status = "okay";
label = "lan3";
};
port@3 {
status = "okay";
label = "lan4";
};
};
};

View File

@ -41,6 +41,18 @@
gpios = <&gpio 11 GPIO_ACTIVE_HIGH>;
};
};
i2c_gpio: i2c-gpio {
compatible = "i2c-gpio";
sda-gpios = <&gpio 3 GPIO_ACTIVE_HIGH>;
scl-gpios = <&gpio 4 GPIO_ACTIVE_HIGH>;
i2c-gpio,delay-us = <50>;
i2c-gpio,timeout-ms = <100>;
/* Semtech SX9512 */
};
};
&pcie {
@ -92,7 +104,8 @@
};
&i2c {
status = "okay";
/* Uses i2c-gpio */
status = "disabled";
};
&ethphy0 {
@ -101,7 +114,7 @@
&state_default {
gpio {
groups = "uart2", "uart3";
groups = "i2c", "uart2", "uart3";
function = "gpio";
};
};

View File

@ -4,7 +4,7 @@
/ {
compatible = "genexis,pulse-ex400", "mediatek,mt7621-soc";
model = "Genexis/Inteno Pulse EX400";
model = "Genexis Pulse EX400";
aliases {
led-boot = &led_status_red;
@ -21,3 +21,83 @@
gpios = <&gpio 12 GPIO_ACTIVE_LOW>;
};
};
&i2c_gpio {
touch@2b {
compatible = "semtech,sx9512";
reg = <0x2b>;
#address-cells = <1>;
#size-cells = <0>;
poll-interval = <150>;
/* Touch area 2.4 GHz */
channel@1 {
reg = <1>;
semtech,cin-delta = <0x3>;
semtech,sense-threshold = <0x04>;
linux,keycodes = <KEY_A>;
};
/* Touch area 5 GHz */
channel@2 {
reg = <2>;
semtech,cin-delta = <0x3>;
semtech,sense-threshold = <0x04>;
linux,keycodes = <KEY_B>;
};
/* Touch area WPS */
channel@3 {
reg = <3>;
semtech,cin-delta = <0x3>;
semtech,sense-threshold = <0x04>;
linux,keycodes = <KEY_WPS_BUTTON>;
};
channel@4 {
reg = <4>;
led {
color = <LED_COLOR_ID_RED>;
function = LED_FUNCTION_WAN;
};
};
channel@5 {
reg = <5>;
led {
color = <LED_COLOR_ID_GREEN>;
function = LED_FUNCTION_WAN;
};
};
channel@6 {
reg = <6>;
led {
color = <LED_COLOR_ID_GREEN>;
function = LED_FUNCTION_WLAN_5GHZ;
linux,default-trigger = "phy1tpt";
};
};
channel@7 {
reg = <7>;
led {
color = <LED_COLOR_ID_GREEN>;
function = LED_FUNCTION_WLAN_2GHZ;
linux,default-trigger = "phy0tpt";
};
};
};
};

View File

@ -769,6 +769,16 @@ define Device/cudy_wr2100
endef
TARGET_DEVICES += cudy_wr2100
define Device/cudy_r700
$(Device/dsa-migration)
DEVICE_VENDOR := Cudy
DEVICE_MODEL := R700
IMAGE_SIZE := 15872k
UIMAGE_NAME := R29
DEVICE_PACKAGES := -uboot-envtools
endef
TARGET_DEVICES += cudy_r700
define Device/cudy_x6-v1
$(Device/dsa-migration)
IMAGE_SIZE := 32256k
@ -1413,7 +1423,7 @@ endif
IMAGE/sysupgrade.bin := append-kernel | inteno-bootfs | \
sysupgrade-tar kernel=$$$$@ | check-size | append-metadata
DEVICE_IMG_NAME = $$(DEVICE_IMG_PREFIX)-$$(2)
DEVICE_PACKAGES := kmod-mt7603 kmod-mt7615-firmware kmod-usb3
DEVICE_PACKAGES := kmod-mt7603 kmod-mt7615-firmware kmod-usb3 kmod-keyboard-sx951x kmod-button-hotplug
endef
define Device/genexis_pulse-ex400

View File

@ -152,3 +152,21 @@ define KernelPackage/sound-mt7620/description
endef
$(eval $(call KernelPackage,sound-mt7620))
define KernelPackage/keyboard-sx951x
SUBMENU:=Other modules
TITLE:=Semtech SX9512/SX9513
DEPENDS:=@TARGET_ramips_mt7621 +kmod-input-core
KCONFIG:= \
CONFIG_KEYBOARD_SX951X \
CONFIG_INPUT_KEYBOARD=y
FILES:=$(LINUX_DIR)/drivers/input/keyboard/sx951x.ko
AUTOLOAD:=$(call AutoProbe,sx951x)
endef
define KernelPackage/keyboard-sx951x/description
Enable support for SX9512/SX9513 capacitive touch controllers
endef
$(eval $(call KernelPackage,keyboard-sx951x))

View File

@ -59,9 +59,11 @@ belkin,rt1800)
ucidef_set_led_netdev "wan" "wan" "white:wan" "wan"
;;
confiabits,mt7621-v1|\
genexis,pulse-ex400|\
netis,n6)
ucidef_set_led_netdev "wan" "wan" "green:wan" "wan" "link tx rx"
;;
cudy,r700|\
cudy,wr2100)
ucidef_set_led_netdev "lan1" "lan1" "green:lan1" "lan1"
ucidef_set_led_netdev "lan2" "lan2" "green:lan2" "lan2"

View File

@ -0,0 +1,560 @@
From ba92c0187006e2a6eae9573a569d275b0bd31732 Mon Sep 17 00:00:00 2001
From: David Bauer <mail@david-bauer.net>
Date: Fri, 2 May 2025 23:04:27 +0200
Subject: [PATCH] Input sx951x: add Semtech SX9512/SX9513 driver
The Semtech SX9512/SX9513 is a family of capacitive touch-keyboard
controllers.
All chips offer 8 channel touch sensitive inputs with one LED driver per
output channel.
The also SX9512 supports proximity detection which is currently not
supported with the driver.
This chip can be found on the Genexis Pulse EX400 repeater platform.
Link: https://www.mouser.com/datasheet/2/761/SEMTS05226_1-2575172.pdf
Link: https://www.spinics.net/lists/kernel/msg5669349.html
Signed-off-by: David Bauer <mail@david-bauer.net>
---
drivers/input/keyboard/Kconfig | 11 +
drivers/input/keyboard/Makefile | 1 +
drivers/input/keyboard/sx951x.c | 490 ++++++++++++++++++++++++++++++++
3 files changed, 502 insertions(+)
create mode 100644 drivers/input/keyboard/sx951x.c
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index 1d0c5f4c0f99..6dc397389c64 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -616,6 +616,17 @@ config KEYBOARD_SUNKBD
To compile this driver as a module, choose M here: the
module will be called sunkbd.
+config KEYBOARD_SX951X
+ tristate "Semtech SX951X capacitive touch controller"
+ depends on OF && I2C
+ select REGMAP_I2C
+ help
+ Say Y here to enable the Semtech SX9512/SX9153 capacitive
+ touch controller driver.
+
+ To compile this driver as a module, choose M here: the
+ module will be called sx951x.
+
config KEYBOARD_SH_KEYSC
tristate "SuperH KEYSC keypad support"
depends on ARCH_SHMOBILE || COMPILE_TEST
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index aecef00c5d09..e59ca83c30ec 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -66,6 +66,7 @@ obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o
obj-$(CONFIG_KEYBOARD_ST_KEYSCAN) += st-keyscan.o
obj-$(CONFIG_KEYBOARD_SUN4I_LRADC) += sun4i-lradc-keys.o
obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o
+obj-$(CONFIG_KEYBOARD_SX951X) += sx951x.o
obj-$(CONFIG_KEYBOARD_TC3589X) += tc3589x-keypad.o
obj-$(CONFIG_KEYBOARD_TEGRA) += tegra-kbc.o
obj-$(CONFIG_KEYBOARD_TM2_TOUCHKEY) += tm2-touchkey.o
diff --git a/drivers/input/keyboard/sx951x.c b/drivers/input/keyboard/sx951x.c
new file mode 100644
index 000000000000..66355036aa95
--- /dev/null
+++ b/drivers/input/keyboard/sx951x.c
@@ -0,0 +1,490 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Input driver for Semtech SX9512/SX9513 capacitive touch sensors.
+ *
+ * The difference between SX9512 and SX9513 is the presence of proximity
+ * sensing capabilities on the SX9512.
+ *
+ * SX951xB is the identical chip but with a different I2C address.
+ *
+ * (c) 2025 David Bauer <mail@david-bauer.net>
+ */
+
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+ #include <linux/input.h>
+ #include <linux/leds.h>
+ #include <linux/of.h>
+ #include <linux/regmap.h>
+ #include <linux/i2c.h>
+ #include <linux/gpio/consumer.h>
+ #include <linux/bitfield.h>
+
+ /* Generic properties */
+#define SX951X_I2C_ADDRESS 0x2b
+#define SX951XB_I2C_ADDRESS_ 0x2d
+#define SX951X_NUM_CHANNELS 8
+#define SX951X_POLL_INTERVAL 100
+
+/* Registers*/
+#define SX951X_REG_IRQ_SRC 0x00
+#define SX951X_REG_TOUCH_STATUS 0x01
+#define SX951X_REG_PROXIMITY_STATUS 0x02
+#define SX951X_REG_COMPENSATION_STATUS 0x03
+#define SX951X_REG_IRQ_NVM_CTRL 0x04
+#define SX951X_REG_SPO2_MODE_CTRL 0x07
+#define SX951X_REG_PWR_KEY_CTRL 0x08
+#define SX951X_REG_IRQ_MASK 0x09
+
+/* LED registers */
+#define SX951X_REG_LED_MAP_ENG1 0x0c
+#define SX951X_REG_LED_MAP_ENG2 0x0d
+#define SX951X_REG_LED_PWM_FREQ 0x0e
+#define SX951X_REG_LED_MODE 0x0f
+#define SX951X_REG_LED_IDLE 0x10
+#define SX951X_REG_LED_OFF_DELAY 0x11
+#define SX951X_REG_LED_ON_ENG1 0x12
+#define SX951X_REG_LED_FADE_ENG1 0x13
+#define SX951X_REG_LED_ON_ENG2 0x14
+#define SX951X_REG_LED_FADE_ENG2 0x15
+#define SX951X_REG_LED_POWER_IDLE 0x16
+#define SX951X_REG_LED_POWER_ON 0x17
+#define SX951X_REG_LED_POWER_OFF 0x18
+#define SX951X_REG_LED_POWER_FADE 0x19
+#define SX951X_REG_LED_POWER_ON_PULSE 0x1a
+#define SX951X_REG_LED_POWER_MODE 0x1b
+
+/* Capacitive touch sensing registers*/
+#define SX951X_REG_CAP_SENSE_ENABLE 0x1e
+
+#define SX951X_REG_CAP_SENSE_RANGE(x) (0x1f + (x))
+#define SX951X_REG_CAP_SENSE_RANGE_CIN_DELTA_MASK GENMASK(1, 0)
+
+#define SX951X_REG_CAP_SENSE_THRESH(x) (0x28 + (x))
+#define SX951X_REG_CAP_SENSE_THRESH_ALL 0x30
+
+#define SX951X_REG_CAP_SENSE_OP 0x31
+#define SX951X_REG_CAP_SENSE_MODE 0x32
+#define SX951X_REG_CAP_SENSE_DEBOUNCE 0x33
+
+/* Reset register*/
+#define SX951X_REG_SOFT_RESET 0xff
+
+/* Default properties (keys)*/
+#define SX951X_KEY_DEFAULT_CIN_DELTA 0x03
+#define SX951X_KEY_DEFAULT_SENSE_THRESHOLD 0x04
+
+struct sx951x_key_data {
+ u32 cin_delta;
+ u32 sense_threshold;
+};
+
+struct sx951x_led {
+#ifdef CONFIG_LEDS_CLASS
+ struct led_classdev cdev;
+ struct sx951x_priv *priv;
+
+ u32 reg;
+ bool registered;
+#endif
+};
+
+struct sx951x_priv {
+ struct regmap *regmap;
+ struct device *dev;
+ struct input_dev *idev;
+ const struct sx951x_hw_data *hw;
+
+ struct sx951x_led leds[SX951X_NUM_CHANNELS];
+
+ /* device-config */
+ u32 poll_interval;
+
+ /* key-config */
+ u32 keycodes[SX951X_NUM_CHANNELS];
+ struct sx951x_key_data key_data[SX951X_NUM_CHANNELS];
+};
+
+struct sx951x_hw_data {
+ bool has_proximity_sensing;
+};
+
+static const struct reg_default sx951x_reg_defaults[] = {
+ { SX951X_REG_LED_MAP_ENG1, 0x00 },
+ { SX951X_REG_LED_MAP_ENG2, 0x00 },
+ { SX951X_REG_LED_PWM_FREQ, 0x10 },
+ { SX951X_REG_LED_IDLE, 0xff },
+ { SX951X_REG_LED_ON_ENG1, 0xff },
+ { SX951X_REG_LED_ON_ENG2, 0xff },
+ { SX951X_REG_LED_POWER_IDLE, 0xff },
+ { SX951X_REG_LED_POWER_ON, 0xff },
+ { SX951X_REG_CAP_SENSE_ENABLE, 0x00 },
+ { SX951X_REG_CAP_SENSE_RANGE(0), 0x40 },
+ { SX951X_REG_CAP_SENSE_RANGE(1), 0x40 },
+ { SX951X_REG_CAP_SENSE_RANGE(2), 0x40 },
+ { SX951X_REG_CAP_SENSE_RANGE(3), 0x40 },
+ { SX951X_REG_CAP_SENSE_RANGE(4), 0x40 },
+ { SX951X_REG_CAP_SENSE_RANGE(5), 0x40 },
+ { SX951X_REG_CAP_SENSE_RANGE(6), 0x40 },
+ { SX951X_REG_CAP_SENSE_RANGE(7), 0x40 },
+ { SX951X_REG_CAP_SENSE_THRESH(0), 0x0f },
+ { SX951X_REG_CAP_SENSE_THRESH(1), 0x0f },
+ { SX951X_REG_CAP_SENSE_THRESH(2), 0x0f },
+ { SX951X_REG_CAP_SENSE_THRESH(3), 0x0f },
+ { SX951X_REG_CAP_SENSE_THRESH(4), 0x0f },
+ { SX951X_REG_CAP_SENSE_THRESH(5), 0x0f },
+ { SX951X_REG_CAP_SENSE_THRESH(6), 0x0f },
+ { SX951X_REG_CAP_SENSE_THRESH(7), 0x0f },
+ { SX951X_REG_CAP_SENSE_THRESH_ALL, 0x0f },
+ { SX951X_REG_CAP_SENSE_OP, 0x14 },
+ { SX951X_REG_CAP_SENSE_MODE, 0x70 },
+ { SX951X_REG_CAP_SENSE_DEBOUNCE, 0xff },
+};
+
+static bool sx951x_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case SX951X_REG_TOUCH_STATUS:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct regmap_config sx951x_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .max_register = SX951X_REG_SOFT_RESET,
+
+ .reg_defaults = sx951x_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(sx951x_reg_defaults),
+
+ .cache_type = REGCACHE_MAPLE,
+ .volatile_reg = sx951x_volatile_reg,
+};
+
+#ifdef CONFIG_LEDS_CLASS
+static int sx951x_led_set(struct led_classdev *cdev, enum led_brightness value)
+{
+ struct sx951x_led *led = container_of(cdev, struct sx951x_led, cdev);
+ struct sx951x_priv *priv = led->priv;
+
+ return regmap_update_bits(priv->regmap,
+ SX951X_REG_LED_MAP_ENG2,
+ BIT(led->reg),
+ value ? BIT(led->reg) : 0);
+}
+
+static int sx951x_led_init(struct sx951x_priv *priv,
+ struct device_node *channel_node, u32 reg)
+{
+ struct device_node *led_node;
+ struct sx951x_led *led = &priv->leds[reg];
+ struct led_init_data init_data = {};
+ int error;
+
+ if (led->registered) {
+ dev_err(priv->dev,
+ "LED %d already registered\n", reg);
+ return -EINVAL;
+ }
+
+ led_node = of_get_child_by_name(channel_node, "led");
+ if (!led_node) {
+ /* No LED */
+ return 0;
+ }
+
+ led->cdev.flags = 0;
+ led->cdev.brightness_set_blocking = sx951x_led_set;
+ led->cdev.max_brightness = 1;
+ led->cdev.brightness = LED_OFF;
+
+ init_data.default_label = of_get_property(led_node, "label", NULL);
+ init_data.fwnode = of_fwnode_handle(led_node);
+
+ led->reg = reg;
+ led->priv = priv;
+
+ error = devm_led_classdev_register_ext(priv->dev, &led->cdev, &init_data);
+ if (error)
+ return error;
+
+ return 0;
+}
+#endif
+
+static void sx951x_poll(struct input_dev *input)
+{
+ struct sx951x_priv *priv = input_get_drvdata(input);
+ struct device *dev = priv->dev;
+ unsigned int val;
+ int error;
+ int i;
+
+ error = regmap_read(priv->regmap, SX951X_REG_TOUCH_STATUS, &val);
+ if (error) {
+ dev_err(dev, "Failed to read touch status: %d\n", error);
+ return;
+ }
+
+ for (i = 0; i < SX951X_NUM_CHANNELS; i++) {
+ if (priv->keycodes[i] == KEY_RESERVED)
+ continue;
+
+ input_report_key(input, priv->keycodes[i], !!(val & BIT(i)));
+ input_sync(input);
+ }
+}
+
+static int sx951x_channel_init(struct sx951x_priv *priv, struct device_node *of_node,
+ u32 chan_idx)
+{
+ struct sx951x_key_data *key_data;
+ struct device *dev = priv->dev;
+ int error;
+
+ key_data = &priv->key_data[chan_idx];
+
+ /* Defaults */
+ key_data->cin_delta = SX951X_KEY_DEFAULT_CIN_DELTA;
+ key_data->sense_threshold = SX951X_KEY_DEFAULT_SENSE_THRESHOLD;
+
+ error = of_property_read_u32(of_node, "linux,keycodes",
+ &priv->keycodes[chan_idx]);
+ if (error) {
+ /* Not configured */
+ return 0;
+ }
+
+ error = of_property_read_u32(of_node, "semtech,cin-delta",
+ &key_data->cin_delta);
+ if (key_data->cin_delta > 0x03) {
+ dev_err(dev, "Failed to read cin-delta for channel %d: %d\n",
+ chan_idx, error);
+ return error;
+ }
+
+ error = of_property_read_u32(of_node, "semtech,sense-threshold",
+ &key_data->sense_threshold);
+ if (key_data->sense_threshold > 0xff) {
+ dev_err(dev, "Failed to read sense-threshold for channel %d: %d\n",
+ chan_idx, error);
+ return error;
+ }
+
+ error = regmap_update_bits(priv->regmap,
+ SX951X_REG_CAP_SENSE_RANGE(chan_idx),
+ SX951X_REG_CAP_SENSE_RANGE_CIN_DELTA_MASK,
+ key_data->cin_delta);
+
+ if (error) {
+ dev_err(dev, "Failed to set cin-delta for channel %d: %d\n",
+ chan_idx, error);
+ return error;
+ }
+
+ error = regmap_write(priv->regmap,
+ SX951X_REG_CAP_SENSE_THRESH(chan_idx),
+ key_data->sense_threshold);
+ if (error) {
+ dev_err(dev, "Failed to set sense-threshold for channel %d: %d\n",
+ chan_idx, error);
+ return error;
+ }
+
+ return 0;
+}
+
+static int sx951x_channels_init(struct sx951x_priv *priv)
+{
+ struct device *dev = priv->dev;
+ unsigned int channels = 0;
+ int error;
+ u32 reg;
+
+ for_each_child_of_node_scoped(dev->of_node, child) {
+ error = of_property_read_u32(child, "reg", &reg);
+ if (error != 0 || reg >= SX951X_NUM_CHANNELS) {
+ dev_err(dev, "Invalid channel %d\n", reg);
+ return -EINVAL;
+ }
+
+ priv->keycodes[reg] = KEY_RESERVED;
+
+ error = sx951x_channel_init(priv, child, reg);
+ if (error) {
+ dev_err(dev, "Failed to initialize channel %d: %d\n",
+ reg, error);
+ return error;
+ }
+
+ if (priv->keycodes[reg] != KEY_RESERVED)
+ channels |= BIT(reg);
+
+#ifdef CONFIG_LEDS_CLASS
+ error = sx951x_led_init(priv, child, reg);
+ if (error) {
+ dev_err(dev, "Failed to initialize LED %d: %d\n",
+ reg, error);
+ return error;
+ }
+#endif
+ }
+
+ /* Enable sensing on channels with keycode configured */
+ error = regmap_write(priv->regmap,
+ SX951X_REG_CAP_SENSE_ENABLE,
+ channels);
+
+ return 0;
+}
+
+static int sx951x_input_init(struct sx951x_priv *priv)
+{
+ struct device *dev = priv->dev;
+ int i, error;
+
+ priv->idev = devm_input_allocate_device(dev);
+ if (!priv->idev)
+ return -ENOMEM;
+
+ priv->idev->name = "SX9512/SX9513 capacitive touch sensor";
+ priv->idev->id.bustype = BUS_I2C;
+ __set_bit(EV_KEY, priv->idev->evbit);
+
+ for (i = 0; i < SX951X_NUM_CHANNELS; i++)
+ __set_bit(priv->keycodes[i], priv->idev->keybit);
+
+ __clear_bit(KEY_RESERVED, priv->idev->keybit);
+
+ priv->idev->keycode = priv->keycodes;
+ priv->idev->keycodesize = sizeof(priv->keycodes[0]);
+ priv->idev->keycodemax = SX951X_NUM_CHANNELS;
+
+ input_set_drvdata(priv->idev, priv);
+
+ error = input_setup_polling(priv->idev, sx951x_poll);
+ if (error) {
+ dev_err(dev, "Unable to set up polling: %d\n", error);
+ return error;
+ }
+
+ input_set_poll_interval(priv->idev, priv->poll_interval);
+
+ error = input_register_device(priv->idev);
+ if (error) {
+ dev_err(dev, "Unable to register polled device: %d\n",
+ error);
+ return error;
+ }
+
+ return 0;
+}
+
+static int sx951x_probe(struct i2c_client *i2c_client)
+{
+ const struct i2c_device_id *id;
+ const struct sx951x_hw_data *hw;
+ struct device *dev = &i2c_client->dev;
+ struct sx951x_priv *priv;
+ int error;
+
+ if (i2c_client->addr != SX951X_I2C_ADDRESS &&
+ i2c_client->addr != SX951XB_I2C_ADDRESS_) {
+ dev_err(dev, "Invalid I2C address: 0x%02x\n",
+ i2c_client->addr);
+ return -ENODEV;
+ }
+
+ id = i2c_client_get_device_id(i2c_client);
+ hw = i2c_get_match_data(i2c_client);
+ if (!id || !hw) {
+ dev_err(dev, "Invalid device configuration\n");
+ return -EINVAL;
+ }
+
+ priv = devm_kzalloc(dev,
+ sizeof(struct sx951x_priv),
+ GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->dev = dev;
+ priv->hw = hw;
+
+ priv->regmap = devm_regmap_init_i2c(i2c_client, &sx951x_regmap_config);
+ if (IS_ERR(priv->regmap))
+ return PTR_ERR(priv->regmap);
+
+ /* Parse device configuration */
+ if (of_property_read_u32(dev->of_node, "poll-interval",
+ &priv->poll_interval))
+ priv->poll_interval = SX951X_POLL_INTERVAL;
+
+ /* Register LED and input channels */
+ error = sx951x_channels_init(priv);
+ if (error) {
+ dev_err(dev, "Failed to initialize channels: %d\n", error);
+ return error;
+ }
+
+ /* Register input device */
+ error = sx951x_input_init(priv);
+ if (error) {
+ dev_err(dev, "Failed to register input device: %d\n", error);
+ return error;
+ }
+
+ return 0;
+}
+
+static void sx951x_remove(struct i2c_client *i2c_client)
+{
+ struct sx951x_priv *priv = i2c_get_clientdata(i2c_client);
+
+ /* Disable sensing */
+ regmap_write(priv->regmap, SX951X_REG_CAP_SENSE_ENABLE, 0x00);
+
+ /* Turn off all LEDs */
+ regmap_write(priv->regmap, SX951X_REG_LED_MAP_ENG2, 0x00);
+}
+
+static const struct sx951x_hw_data sx9512_hw_data = {
+ .has_proximity_sensing = true,
+};
+
+static const struct sx951x_hw_data sx9513_hw_data = {
+ .has_proximity_sensing = false,
+};
+
+static const struct of_device_id sx951x_dt_ids[] = {
+ { .compatible = "semtech,sx9512", .data = &sx9512_hw_data },
+ { .compatible = "semtech,sx9513", .data = &sx9513_hw_data },
+ { }
+};
+MODULE_DEVICE_TABLE(of, sx951x_dt_ids);
+
+static const struct i2c_device_id sx951x_i2c_ids[] = {
+ { "sx9512", (kernel_ulong_t)&sx9512_hw_data },
+ { "sx9513", (kernel_ulong_t)&sx9513_hw_data },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, sx951x_i2c_ids);
+
+static struct i2c_driver sx951x_i2c_driver = {
+ .driver = {
+ .name = "sx951x",
+ .of_match_table = sx951x_dt_ids,
+ },
+ .id_table = sx951x_i2c_ids,
+ .probe = sx951x_probe,
+ .remove = sx951x_remove,
+};
+
+module_i2c_driver(sx951x_i2c_driver);
+
+MODULE_DESCRIPTION("Semtech SX9512/SX9513 driver");
+MODULE_AUTHOR("David Bauer <mail@david-bauer.net>");
+MODULE_LICENSE("GPL");
--
2.47.2

View File

@ -0,0 +1,32 @@
libatomic: Do not enforce march on aarch64
Inspired by The Yocto Project [1].
[1] https://github.com/yoctoproject/poky/blob/51192a79f1717786dda42776f916c3d97ada7971/meta/recipes-devtools/gcc/gcc/0022-libatomic-Do-not-enforce-march-on-aarch64.patch
Signed-off-by: Konstantin Demin <rockdrilla@gmail.com>
libatomic/Makefile.am | 1 -
libatomic/Makefile.in | 1 -
2 files changed, 2 deletions(-)
--- a/libatomic/Makefile.am
+++ b/libatomic/Makefile.am
@@ -130,7 +130,6 @@ libatomic_la_LIBADD = $(foreach s,$(SIZES),$(addsuffix _$(s)_.lo,$(SIZEOBJS)))
## On a target-specific basis, include alternates to be selected by IFUNC.
if HAVE_IFUNC
if ARCH_AARCH64_LINUX
-IFUNC_OPTIONS = -march=armv8-a+lse
libatomic_la_LIBADD += $(foreach s,$(SIZES),$(addsuffix _$(s)_1_.lo,$(SIZEOBJS)))
endif
--- a/libatomic/Makefile.in
+++ b/libatomic/Makefile.in
@@ -452,7 +452,6 @@ M_SRC = $(firstword $(filter %/$(M_FILE), $(all_c_files)))
libatomic_la_LIBADD = $(foreach s,$(SIZES),$(addsuffix \
_$(s)_.lo,$(SIZEOBJS))) $(am__append_1) $(am__append_2) \
$(am__append_3) $(am__append_4)
-@ARCH_AARCH64_LINUX_TRUE@@HAVE_IFUNC_TRUE@IFUNC_OPTIONS = -march=armv8-a+lse
@ARCH_ARM_LINUX_TRUE@@HAVE_IFUNC_TRUE@IFUNC_OPTIONS = -march=armv7-a+fp -DHAVE_KERNEL64
@ARCH_I386_TRUE@@HAVE_IFUNC_TRUE@IFUNC_OPTIONS = -march=i586
@ARCH_X86_64_TRUE@@HAVE_IFUNC_TRUE@IFUNC_OPTIONS = -mcx16 -mcx16