From patchwork Wed Apr 24 19:03:17 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matthias Schiffer X-Patchwork-Id: 1090335 X-Patchwork-Delegate: mschiffer@universe-factory.net Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=lists.openwrt.org (client-ip=2607:7c80:54:e::133; helo=bombadil.infradead.org; envelope-from=openwrt-devel-bounces+incoming=patchwork.ozlabs.org@lists.openwrt.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=universe-factory.net Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="YPVVb7o3"; dkim-atps=neutral Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:e::133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 44q8qq6qW2z9s3q for ; Thu, 25 Apr 2019 05:04:07 +1000 (AEST) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:Subject:MIME-Version:Message-Id:Date:To :From:Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References: List-Owner; bh=+RxKN5JcKXwfVDRhTyfl5m193PRoMlP2VBgfTd4ldh8=; b=YPVVb7o3gv+FTQ BCFSXe1GqFpaq1//UC73DNTWUB/rwGH9aq/w7bi7AnKddghKTfoTC+SIO1AkYergiVGf0RWDJ04CO g5XsiQ51c1DxKb2DR14opjw0a0f3HltfQRCObNlWFft98zwKlSjVrbhy9VgjJvunXaUzJs9Ap00Y9 XPPxmhLnZK8+UZZdyXIFDD+53LKDPR9QdhanRFkHCDvFAIFlsXWAY53aKItKCVAuxOW1hytn2Jxcy 4hlxkiilRrHuchcC5PIAhg1FKkMv2HFcR4jbgrfE5oTeBkB9iQQjKaNqpwvo0VcuhZlACXmt30boU /EPqEIDv5LoOQEpnIh1g==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1hJNBR-0004tS-8k; Wed, 24 Apr 2019 19:03:53 +0000 Received: from orthanc.universe-factory.net ([104.238.176.138]) by bombadil.infradead.org with esmtps (Exim 4.90_1 #2 (Red Hat Linux)) id 1hJNBH-0004k7-A3 for openwrt-devel@lists.openwrt.org; Wed, 24 Apr 2019 19:03:45 +0000 Received: from localhost.localdomain (unknown [IPv6:2001:19f0:6c01:100::2]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by orthanc.universe-factory.net (Postfix) with ESMTPSA id 0917D1F416; Wed, 24 Apr 2019 21:03:37 +0200 (CEST) From: Matthias Schiffer To: openwrt-devel@lists.openwrt.org, jo@mein.io Date: Wed, 24 Apr 2019 21:03:17 +0200 Message-Id: <72d19000530fe2b51b5a59c8ccda4d6c51c3f8ba.1556132277.git.mschiffer@universe-factory.net> X-Mailer: git-send-email 2.21.0 MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20190424_120343_645325_23160A28 X-CRM114-Status: GOOD ( 16.87 ) X-Spam-Score: -0.0 (/) X-Spam-Report: SpamAssassin version 3.4.2 on bombadil.infradead.org summary: Content analysis details: (-0.0 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 SPF_HELO_PASS SPF: HELO matches SPF record -0.0 SPF_PASS SPF: sender matches SPF record Subject: [OpenWrt-Devel] [PATCH iwinfo 1/2] Add support for regulatory rules X-BeenThere: openwrt-devel@lists.openwrt.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Matthias Schiffer Sender: "openwrt-devel" Errors-To: openwrt-devel-bounces+incoming=patchwork.ozlabs.org@lists.openwrt.org The new regrulelist operation returns the list of regulatory rules, similar to the `iw reg get` command. The passed ifname must either refer to a PHY, or be NULL to retrieve the rules for the global regdomain. The new operation is implemented for nl80211 only. Signed-off-by: Matthias Schiffer --- include/iwinfo.h | 27 ++++++++++ iwinfo_nl80211.c | 126 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 153 insertions(+) Usecase: In Gluon we would like to use the regulatory data to filter the channel list for channels that are valid for indoor / outdoor use. diff --git a/include/iwinfo.h b/include/iwinfo.h index 9b2ffd1ea111..f7e53c599e5f 100644 --- a/include/iwinfo.h +++ b/include/iwinfo.h @@ -57,6 +57,22 @@ #define IWINFO_FREQ_NO_160MHZ (1 << 5) #define IWINFO_FREQ_NO_2160MHZ (1 << 6) +#define IWINFO_REGRULE_NO_OFDM (1 << 0) +#define IWINFO_REGRULE_NO_CCK (1 << 1) +#define IWINFO_REGRULE_NO_INDOOR (1 << 2) +#define IWINFO_REGRULE_NO_OUTDOOR (1 << 3) +#define IWINFO_REGRULE_DFS (1 << 4) +#define IWINFO_REGRULE_PTP_ONLY (1 << 5) +#define IWINFO_REGRULE_AUTO_BW (1 << 6) +#define IWINFO_REGRULE_IR_CONCURRENT (1 << 7) +#define IWINFO_REGRULE_NO_HT40MINUS (1 << 8) +#define IWINFO_REGRULE_NO_HT40PLUS (1 << 9) +#define IWINFO_REGRULE_NO_80MHZ (1 << 10) +#define IWINFO_REGRULE_NO_160MHZ (1 << 11) +#define IWINFO_REGRULE_NO_IR (1 << 12) +#define IWINFO_REGRULE_PASSIVE_SCAN (1 << 13) +#define IWINFO_REGRULE_NO_IBSS (1 << 14) + extern const char *IWINFO_CIPHER_NAMES[IWINFO_CIPHER_COUNT]; extern const char *IWINFO_KMGMT_NAMES[IWINFO_KMGMT_COUNT]; extern const char *IWINFO_AUTH_NAMES[IWINFO_AUTH_COUNT]; @@ -183,6 +199,16 @@ struct iwinfo_country_entry { char ccode[4]; }; +struct iwinfo_regrule_entry { + uint32_t start_freq_khz; + uint32_t end_freq_khz; + uint32_t max_bw_khz; + uint32_t max_ant_gain_mbi; + uint32_t max_eirp_mbm; + uint32_t dfs_cac_time_ms; + uint32_t flags; +}; + struct iwinfo_iso3166_label { uint16_t iso3166; char name[28]; @@ -242,6 +268,7 @@ struct iwinfo_ops { int (*freqlist)(const char *, char *, int *); int (*countrylist)(const char *, char *, int *); int (*survey)(const char *, char *, int *); + int (*regrulelist)(const char *, char *, int *); int (*lookup_phy)(const char *, char *); void (*close)(void); }; diff --git a/iwinfo_nl80211.c b/iwinfo_nl80211.c index 200be28d9a44..9b1efea2f4b5 100644 --- a/iwinfo_nl80211.c +++ b/iwinfo_nl80211.c @@ -2732,6 +2732,131 @@ static int nl80211_get_countrylist(const char *ifname, char *buf, int *len) return 0; } +static int nl80211_get_regrulelist_cb(struct nl_msg *msg, void *arg) { + struct nl80211_array_buf *arr = arg; + struct iwinfo_regrule_entry *e; + const char *const end = (char *)arr->buf + IWINFO_BUFSIZE; + + uint32_t flags; + int rule_rem; + + struct nlattr **attr = nl80211_parse(msg); + struct nlattr *rule; + struct nlattr *rule_attr[NL80211_REG_RULE_ATTR_MAX + 1]; + + e = arr->buf; + e += arr->count; + + if (!attr[NL80211_ATTR_REG_RULES]) + return NL_SKIP; + + nla_for_each_nested(rule, attr[NL80211_ATTR_REG_RULES], rule_rem) + { + if ((char *)(e+1) > end) + break; // We're out of buffer space... + + nla_parse(rule_attr, NL80211_REG_RULE_ATTR_MAX, nla_data(rule), nla_len(rule), NULL); + + if ( + !rule_attr[NL80211_ATTR_REG_RULE_FLAGS] || + !rule_attr[NL80211_ATTR_FREQ_RANGE_START] || + !rule_attr[NL80211_ATTR_FREQ_RANGE_END] || + !rule_attr[NL80211_ATTR_FREQ_RANGE_MAX_BW] || + !rule_attr[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN] || + !rule_attr[NL80211_ATTR_POWER_RULE_MAX_EIRP] + ) + continue; + + flags = nla_get_u32(rule_attr[NL80211_ATTR_REG_RULE_FLAGS]); + + e->flags = 0; + e->start_freq_khz = nla_get_u32(rule_attr[NL80211_ATTR_FREQ_RANGE_START]); + e->end_freq_khz = nla_get_u32(rule_attr[NL80211_ATTR_FREQ_RANGE_END]); + e->max_bw_khz = nla_get_u32(rule_attr[NL80211_ATTR_FREQ_RANGE_MAX_BW]); + e->max_ant_gain_mbi = nla_get_u32(rule_attr[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN]); + e->max_eirp_mbm = nla_get_u32(rule_attr[NL80211_ATTR_POWER_RULE_MAX_EIRP]); + + if ((flags & NL80211_RRF_DFS) && rule_attr[NL80211_ATTR_DFS_CAC_TIME]) { + e->dfs_cac_time_ms = nla_get_u32(rule_attr[NL80211_ATTR_DFS_CAC_TIME]); + } + +#define HANDLE_FLAG(flag) \ + do { \ + if (flags & NL80211_RRF_##flag) \ + e->flags |= IWINFO_REGRULE_##flag; \ + } while (0) + + HANDLE_FLAG(NO_OFDM); + HANDLE_FLAG(NO_CCK); + HANDLE_FLAG(NO_INDOOR); + HANDLE_FLAG(NO_OUTDOOR); + HANDLE_FLAG(DFS); + HANDLE_FLAG(PTP_ONLY); + HANDLE_FLAG(AUTO_BW); + HANDLE_FLAG(IR_CONCURRENT); + HANDLE_FLAG(NO_HT40MINUS); + HANDLE_FLAG(NO_HT40PLUS); + HANDLE_FLAG(NO_80MHZ); + HANDLE_FLAG(NO_160MHZ); + + /* Logic taken from iw */ + if ((flags & NL80211_RRF_NO_IR) && (flags & __NL80211_RRF_NO_IBSS)) { + e->flags |= IWINFO_REGRULE_NO_IR; + } else { + HANDLE_FLAG(PASSIVE_SCAN); + + if (flags & __NL80211_RRF_NO_IBSS) + e->flags |= IWINFO_REGRULE_NO_IBSS; + } + +#undef HANDLE_FLAG + + e++; + arr->count++; + } + + return NL_SKIP; +} + +static int nl80211_get_regrulelist(const char *ifname, char *buf, int *len) +{ + struct nl80211_msg_conveyor *cv; + struct nl80211_array_buf arr = { .buf = buf, .count = 0 }; + int phyidx = -1; + + if (nl80211_init() < 0) + goto out; + + if (ifname) { + if (!strncmp(ifname, "phy", 3)) + phyidx = atoi(&ifname[3]); + else if (!strncmp(ifname, "radio", 5)) + phyidx = nl80211_phy_idx_from_uci(ifname); + + if (phyidx < 0) + goto out; + } + + cv = nl80211_new(nls->nl80211, NL80211_CMD_GET_REG, 0); + if (!cv) + goto out; + + if (ifname) + NLA_PUT_U32(cv->msg, NL80211_ATTR_WIPHY, phyidx); + + if (nl80211_send(cv, nl80211_get_regrulelist_cb, &arr)) + goto out; + + *len = arr.count * sizeof(struct iwinfo_regrule_entry); + return 0; + +nla_put_failure: + nl80211_free(cv); +out: + *len = 0; + return -1; +} + struct nl80211_modes { @@ -3045,6 +3170,7 @@ const struct iwinfo_ops nl80211_ops = { .freqlist = nl80211_get_freqlist, .countrylist = nl80211_get_countrylist, .survey = nl80211_get_survey, + .regrulelist = nl80211_get_regrulelist, .lookup_phy = nl80211_lookup_phyname, .close = nl80211_close };