[OpenWrt-Devel] [PATCH iwinfo 1/2] Add support for regulatory rules
Matthias Schiffer
mschiffer at universe-factory.net
Wed Apr 24 19:29:23 EDT 2019
On 4/24/19 9:03 PM, Matthias Schiffer wrote:
> 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 <mschiffer at universe-factory.net>
> ---
> 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.
It seems we have found a simpler solution for Gluon (country3 option in
hostapd.conf). So unless someone else considers this a useful feature for
libiwinfo, this patch can be rejected.
>
>
> 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
> };
>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: OpenPGP digital signature
URL: <http://lists.infradead.org/pipermail/openwrt-devel/attachments/20190425/87e93088/attachment.sig>
-------------- next part --------------
_______________________________________________
openwrt-devel mailing list
openwrt-devel at lists.openwrt.org
https://lists.openwrt.org/mailman/listinfo/openwrt-devel
More information about the openwrt-devel
mailing list