All of lore.kernel.org
 help / color / mirror / Atom feed
From: Benjamin Berg <benjamin@sipsolutions.net>
To: Johannes Berg <johannes@sipsolutions.net>
Cc: linux-wireless@vger.kernel.org, sw@simonwunderlich.de,
	Benjamin Berg <benjamin.berg@open-mesh.com>
Subject: [PATCH 1/8] util: Add generic frequency/channel command line handler
Date: Mon,  7 Nov 2016 15:59:36 +0100	[thread overview]
Message-ID: <20161107145943.16761-2-benjamin@sipsolutions.net> (raw)
In-Reply-To: <20161107145943.16761-1-benjamin@sipsolutions.net>

From: Benjamin Berg <benjamin.berg@open-mesh.com>

The ability to parse channel definitions is required in a lot of places
inside iw. However, right now each of these duplicates a lot of code to
handle it.

So add a new helper which can be used everywhere.

Signed-off-by: Benjamin Berg <benjamin.berg@open-mesh.com>
---
 iw.h   |  10 +++
 util.c | 239 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 249 insertions(+)

diff --git a/iw.h b/iw.h
index 2837bd3..7d56391 100644
--- a/iw.h
+++ b/iw.h
@@ -70,6 +70,14 @@ struct chanmode {
 	int chantype; /* for older kernel */
 };
 
+struct chandef {
+	enum nl80211_chan_width width;
+
+	unsigned int control_freq;
+	unsigned int center_freq1;
+	unsigned int center_freq2;
+};
+
 #define ARRAY_SIZE(ar) (sizeof(ar)/sizeof(ar[0]))
 #define DIV_ROUND_UP(x, y) (((x) + (y - 1)) / (y))
 
@@ -150,6 +158,8 @@ int parse_hex_mask(char *hexmask, unsigned char **result, size_t *result_len,
 unsigned char *parse_hex(char *hex, size_t *outlen);
 
 int parse_keys(struct nl_msg *msg, char **argv, int argc);
+int parse_freqchan(struct chandef *chandef, bool chan, int argc, char **argv, int *parsed);
+int put_chandef(struct nl_msg *msg, struct chandef *chandef);
 
 void print_ht_mcs(const __u8 *mcs);
 void print_ampdu_length(__u8 exponent);
diff --git a/util.c b/util.c
index a338464..833b1ce 100644
--- a/util.c
+++ b/util.c
@@ -469,6 +469,245 @@ int parse_keys(struct nl_msg *msg, char **argv, int argc)
 	return 2;
 }
 
+static int parse_freqs(struct chandef *chandef, int argc, char **argv,
+		       int *parsed)
+{
+	static const struct {
+		const char *name;
+		unsigned int val;
+	} bwmap[] = {
+		{ .name = "5", .val = NL80211_CHAN_WIDTH_5, },
+		{ .name = "10", .val = NL80211_CHAN_WIDTH_10, },
+		{ .name = "20", .val = NL80211_CHAN_WIDTH_20, },
+		{ .name = "40", .val = NL80211_CHAN_WIDTH_40, },
+		{ .name = "80", .val = NL80211_CHAN_WIDTH_80, },
+		{ .name = "80+80", .val = NL80211_CHAN_WIDTH_80P80, },
+		{ .name = "160", .val = NL80211_CHAN_WIDTH_160, },
+	};
+	uint32_t freq;
+	unsigned int i, bwval = NL80211_CHAN_WIDTH_20_NOHT;
+	char *end;
+
+	if (argc < 1)
+		return 0;
+
+	for (i = 0; i < ARRAY_SIZE(bwmap); i++) {
+		if (strcasecmp(bwmap[i].name, argv[0]) == 0) {
+			bwval = bwmap[i].val;
+			*parsed += 1;
+			break;
+		}
+	}
+	chandef->width = bwval;
+
+	/* First argument was not understood, give up gracefully. */
+	if (bwval == NL80211_CHAN_WIDTH_20_NOHT)
+		return 0;
+
+	if (argc < 2)
+		return 0;
+
+	/* center freq 1 */
+	if (!*argv[1])
+		return 0;
+	freq = strtoul(argv[1], &end, 10);
+	if (*end)
+		return 0;
+	*parsed += 1;
+
+	chandef->center_freq1 = freq;
+
+	if (argc < 3)
+		return 0;
+
+	/* center freq 2 */
+	if (!*argv[2])
+		return 0;
+	freq = strtoul(argv[2], &end, 10);
+	if (*end)
+		return 0;
+	chandef->center_freq2 = freq;
+
+	*parsed += 1;
+
+	return 0;
+}
+
+
+/**
+ * parse_freqchan - Parse frequency or channel definition
+ *
+ * @chandef: chandef structure to be filled in
+ * @chan: Boolean whether to parse a channel or frequency based specifier
+ * @argc: Number of arguments
+ * @argv: Array of string arguments
+ * @parsed: Pointer to return the number of used arguments, or NULL to error
+ *          out if any argument is left unused.
+ *
+ * The given chandef structure will be filled in from the command line
+ * arguments. argc/argv will be updated so that further arguments from the
+ * command line can be parsed.
+ *
+ * Note that no integer argument may follow a frequency definition to allow the
+ * user to skip the center frequency definition(s).
+ *
+ * The working specifier if chan is set are:
+ *   <channel> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz]
+ *
+ * And if frequency is set:
+ *   <freq> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz]
+ *   <control freq> [5|10|20|40|80|80+80|160] [<center1_freq> [<center2_freq>]]
+ *
+ * If the mode/channel width is not given the NOHT is assumed.
+ *
+ * Return: Number of used arguments, zero or negative error number otherwise
+ */
+int parse_freqchan(struct chandef *chandef, bool chan, int argc, char **argv,
+		   int *parsed)
+{
+	char *end;
+	static const struct chanmode chanmode[] = {
+		{ .name = "HT20",
+		  .width = NL80211_CHAN_WIDTH_20,
+		  .freq1_diff = 0,
+		  .chantype = NL80211_CHAN_HT20 },
+		{ .name = "HT40+",
+		  .width = NL80211_CHAN_WIDTH_40,
+		  .freq1_diff = 10,
+		  .chantype = NL80211_CHAN_HT40PLUS },
+		{ .name = "HT40-",
+		  .width = NL80211_CHAN_WIDTH_40,
+		  .freq1_diff = -10,
+		  .chantype = NL80211_CHAN_HT40MINUS },
+		{ .name = "NOHT",
+		  .width = NL80211_CHAN_WIDTH_20_NOHT,
+		  .freq1_diff = 0,
+		  .chantype = NL80211_CHAN_NO_HT },
+		{ .name = "5MHz",
+		  .width = NL80211_CHAN_WIDTH_5,
+		  .freq1_diff = 0,
+		  .chantype = -1 },
+		{ .name = "10MHz",
+		  .width = NL80211_CHAN_WIDTH_10,
+		  .freq1_diff = 0,
+		  .chantype = -1 },
+		{ .name = "80MHz",
+		  .width = NL80211_CHAN_WIDTH_80,
+		  .freq1_diff = 0,
+		  .chantype = -1 },
+	};
+	const struct chanmode *chanmode_selected = NULL;
+	unsigned int freq;
+	unsigned int i;
+	int _parsed = 0;
+	int res = 0;
+
+	if (argc < 1)
+		return 1;
+
+	if (!argv[0])
+		goto out;
+	freq = strtoul(argv[0], &end, 10);
+	if (*end) {
+		res = 1;
+		goto out;
+	}
+
+	_parsed += 1;
+
+	memset(chandef, 0, sizeof(struct chandef));
+
+	if (chan) {
+		enum nl80211_band band;
+
+		band = freq <= 14 ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ;
+		freq = ieee80211_channel_to_frequency(freq, band);
+	}
+	chandef->control_freq = freq;
+	/* Assume 20MHz NOHT channel for now. */
+	chandef->center_freq1 = freq;
+
+	/* Try to parse HT mode definitions */
+	if (argc > 1) {
+		for (i = 0; i < ARRAY_SIZE(chanmode); i++) {
+			if (strcasecmp(chanmode[i].name, argv[1]) == 0) {
+				chanmode_selected = &chanmode[i];
+				_parsed += 1;
+				break;
+			}
+		}
+	}
+
+	/* channel mode given, use it and return. */
+	if (chanmode_selected) {
+		chandef->center_freq1 = get_cf1(chanmode_selected, freq);
+		chandef->width = chanmode_selected->width;
+		goto out;
+	}
+
+	/* This was a only a channel definition, nothing further may follow. */
+	if (chan)
+		goto out;
+
+	res = parse_freqs(chandef, argc - 1, argv + 1, &_parsed);
+
+ out:
+	/* Error out if parsed is NULL. */
+	if (!parsed && _parsed != argc)
+		return 1;
+
+	if (parsed)
+		*parsed = _parsed;
+
+	return res;
+}
+
+int put_chandef(struct nl_msg *msg, struct chandef *chandef)
+{
+	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, chandef->control_freq);
+	NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH, chandef->width);
+
+	switch (chandef->width) {
+	case NL80211_CHAN_WIDTH_20_NOHT:
+		NLA_PUT_U32(msg,
+			    NL80211_ATTR_WIPHY_CHANNEL_TYPE,
+			    NL80211_CHAN_NO_HT);
+		break;
+	case NL80211_CHAN_WIDTH_20:
+		NLA_PUT_U32(msg,
+			    NL80211_ATTR_WIPHY_CHANNEL_TYPE,
+			    NL80211_CHAN_HT20);
+		break;
+	case NL80211_CHAN_WIDTH_40:
+		if (chandef->control_freq > chandef->center_freq1)
+			NLA_PUT_U32(msg,
+				    NL80211_ATTR_WIPHY_CHANNEL_TYPE,
+				    NL80211_CHAN_HT40MINUS);
+		else
+			NLA_PUT_U32(msg,
+				    NL80211_ATTR_WIPHY_CHANNEL_TYPE,
+				    NL80211_CHAN_HT40PLUS);
+		break;
+	default:
+		break;
+	}
+
+	if (chandef->center_freq1)
+		NLA_PUT_U32(msg,
+			    NL80211_ATTR_CENTER_FREQ1,
+			    chandef->center_freq1);
+
+	if (chandef->center_freq2)
+		NLA_PUT_U32(msg,
+			    NL80211_ATTR_CENTER_FREQ2,
+			    chandef->center_freq2);
+
+	return 0;
+
+ nla_put_failure:
+	return -ENOBUFS;
+}
+
 static void print_mcs_index(const __u8 *mcs)
 {
 	int mcs_bit, prev_bit = -2, prev_cont = 0;
-- 
2.10.2

  reply	other threads:[~2016-11-07 14:59 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-11-07 14:59 [PATCH 0/8] iw: Add common chandef parser and new DFS related commands Benjamin Berg
2016-11-07 14:59 ` Benjamin Berg [this message]
2016-11-07 14:59 ` [PATCH 2/8] phy: Use common freqchan helper for setting the operating channel Benjamin Berg
2016-11-07 14:59 ` [PATCH 3/8] ibss: Use common freqchan helper for joining an ibss Benjamin Berg
2016-11-07 14:59 ` [PATCH 4/8] mesh: Use common freqchan helper for joining a mesh Benjamin Berg
2016-11-07 14:59 ` [PATCH 5/8] Add cac command to allow clearing channels Benjamin Berg
2016-11-07 14:59 ` [PATCH 6/8] Add commands to send CSA Benjamin Berg
2016-11-07 14:59 ` [PATCH 7/8] Add flag for DFS handling in IBSS Benjamin Berg
2016-11-07 14:59 ` [PATCH 8/8] Print frequency of radar events Benjamin Berg
2016-11-17 17:21   ` Henrik Eriksson
2016-11-17 17:25     ` Benjamin Berg
2016-11-16 12:41 ` [PATCH 0/8] iw: Add common chandef parser and new DFS related commands Johannes Berg

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20161107145943.16761-2-benjamin@sipsolutions.net \
    --to=benjamin@sipsolutions.net \
    --cc=benjamin.berg@open-mesh.com \
    --cc=johannes@sipsolutions.net \
    --cc=linux-wireless@vger.kernel.org \
    --cc=sw@simonwunderlich.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.