]> git.ipfire.org Git - thirdparty/iw.git/commitdiff
iw: add TID specific configuration command
authorSergey Matyukevich <sergey.matyukevich.os@quantenna.com>
Fri, 24 Apr 2020 11:29:05 +0000 (14:29 +0300)
committerJohannes Berg <johannes.berg@intel.com>
Tue, 26 May 2020 12:46:10 +0000 (14:46 +0200)
Use command NL80211_CMD_SET_TID_CONFIG to perform per-node TID specific
configuration. If peer is not specified, then configuration is applied
to all the peers. Currently kernel supports configuration of the
following parameters:
- short/long retry
- mpdu/msdu aggregation on/off
- rts/cts on/off
- noack on/off

Examples:
Apply configuration for specific peer and TIDs:
$ iw dev wlan0 set tidconf peer 1:2:3:4:5:6 tids 0x3 ampdu off tids 0x2 sretry 10 lretry 100
$ iw dev wlan0 set tidconf peer 1:2:3:4:5:6 tids 0x1 override ampdu off amsdu off

Apply configuration for all peers and all TIDs:
$ iw dev wlan0 set tidconf tids 0xff ampdu off amsdu off sretry 10 lretry 100 noack off

Apply configuration for all peers and specific TIDs:
$ iw dev wlan0 set tidconf peer 0xff:0xff:0xff:0xff:0xff:0xff tids 0x1 ampdu off amsdu off

Signed-off-by: Sergey Matyukevich <sergey.matyukevich.os@quantenna.com>
Link: https://lore.kernel.org/r/20200424112905.26770-6-sergey.matyukevich.os@quantenna.com
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
interface.c

index 6a44304628c2cf631ab3fa176fb41590a14b624b..df96bede165d5042242f4af14445a7453409b20d 100644 (file)
@@ -727,3 +727,232 @@ COMMAND(switch, freq,
        "Switch the operating channel by sending a channel switch announcement (CSA).");
 COMMAND(switch, channel, "<channel> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz] [beacons <count>] [block-tx]",
        NL80211_CMD_CHANNEL_SWITCH, 0, CIB_NETDEV, handle_chan, NULL);
+
+
+static int toggle_tid_param(const char *argv0, const char *argv1,
+                           struct nl_msg *msg, uint32_t attr)
+{
+       uint8_t val;
+
+       if (strcmp(argv1, "on") == 0) {
+               val = NL80211_TID_CONFIG_ENABLE;
+       } else if (strcmp(argv1, "off") == 0) {
+               val = NL80211_TID_CONFIG_DISABLE;
+       } else {
+               fprintf(stderr, "Invalid %s parameter: %s\n", argv0, argv1);
+               return 2;
+       }
+
+       NLA_PUT_U8(msg, attr, val);
+       return 0;
+
+ nla_put_failure:
+       return -ENOBUFS;
+}
+
+static int handle_tid_config(struct nl80211_state *state,
+                            struct nl_msg *msg,
+                            int argc, char **argv,
+                            enum id_input id)
+{
+       struct nlattr *tids_array = NULL;
+       struct nlattr *tids_entry = NULL;
+       unsigned char peer[ETH_ALEN];
+       int tids_num = 0;
+       char *end;
+       int ret;
+       enum {
+               PS_ADDR,
+               PS_TIDS,
+               PS_CONF,
+       } parse_state = PS_ADDR;
+
+       while (argc) {
+               switch (parse_state) {
+               case PS_ADDR:
+                       if (strcmp(argv[0], "peer") == 0) {
+                               if (argc < 2) {
+                                       fprintf(stderr, "Not enough args for %s\n", argv[0]);
+                                       return HANDLER_RET_USAGE;
+                               }
+
+                               if (mac_addr_a2n(peer, argv[1])) {
+                                       fprintf(stderr, "Invalid MAC address\n");
+                                       return 2;
+                               }
+
+                               NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, peer);
+
+                               argc -= 2;
+                               argv += 2;
+                               parse_state = PS_TIDS;
+
+                       } else if (strcmp(argv[0], "tids") == 0) {
+                               parse_state = PS_TIDS;
+                       } else {
+                               fprintf(stderr, "Peer MAC address expected\n");
+                               return HANDLER_RET_USAGE;
+                       }
+
+                       break;
+               case PS_TIDS:
+                       if (strcmp(argv[0], "tids") == 0) {
+                               if (argc < 2) {
+                                       fprintf(stderr, "not enough args for %s\n", argv[0]);
+                                       return HANDLER_RET_USAGE;
+                               }
+
+                               if (!tids_array) {
+                                       tids_array = nla_nest_start(msg, NL80211_ATTR_TID_CONFIG);
+                                       if (!tids_array)
+                                               return -ENOBUFS;
+                               }
+
+                               if (tids_entry) {
+                                       nla_nest_end(msg, tids_entry);
+                                       tids_num++;
+                               }
+
+                               tids_entry = nla_nest_start(msg, tids_num);
+                               if (!tids_entry)
+                                       return -ENOBUFS;
+
+                               NLA_PUT_U16(msg, NL80211_TID_CONFIG_ATTR_TIDS, strtol(argv[1], &end, 0));
+                               if (*end) {
+                                       fprintf(stderr, "Invalid TID mask value: %s\n", argv[1]);
+                                       return 2;
+                               }
+
+                               argc -= 2;
+                               argv += 2;
+                               parse_state = PS_CONF;
+                       } else {
+                               fprintf(stderr, "TID mask expected\n");
+                               return HANDLER_RET_USAGE;
+                       }
+
+                       break;
+               case PS_CONF:
+                       if (strcmp(argv[0], "tids") == 0) {
+                               parse_state = PS_TIDS;
+                       } else if (strcmp(argv[0], "override") == 0) {
+                               NLA_PUT_FLAG(msg, NL80211_TID_CONFIG_ATTR_OVERRIDE);
+
+                               argc -= 1;
+                               argv += 1;
+                       } else if (strcmp(argv[0], "ampdu") == 0) {
+                               if (argc < 2) {
+                                       fprintf(stderr, "not enough args for %s\n", argv[0]);
+                                       return HANDLER_RET_USAGE;
+                               }
+
+                               ret = toggle_tid_param(argv[0], argv[1], msg,
+                                                      NL80211_TID_CONFIG_ATTR_AMPDU_CTRL);
+                               if (ret)
+                                       return ret;
+
+                               argc -= 2;
+                               argv += 2;
+                       } else if (strcmp(argv[0], "amsdu") == 0) {
+                               if (argc < 2) {
+                                       fprintf(stderr, "not enough args for %s\n", argv[0]);
+                                       return HANDLER_RET_USAGE;
+                               }
+
+                               ret = toggle_tid_param(argv[0], argv[1], msg,
+                                                      NL80211_TID_CONFIG_ATTR_AMSDU_CTRL);
+                               if (ret)
+                                       return ret;
+
+                               argc -= 2;
+                               argv += 2;
+                       } else if (strcmp(argv[0], "noack") == 0) {
+                               if (argc < 2) {
+                                       fprintf(stderr, "not enough args for %s\n", argv[0]);
+                                       return HANDLER_RET_USAGE;
+                               }
+
+                               ret = toggle_tid_param(argv[0], argv[1], msg,
+                                                      NL80211_TID_CONFIG_ATTR_NOACK);
+                               if (ret)
+                                       return ret;
+
+                               argc -= 2;
+                               argv += 2;
+                       } else if (strcmp(argv[0], "rtscts") == 0) {
+                               if (argc < 2) {
+                                       fprintf(stderr, "not enough args for %s\n", argv[0]);
+                                       return HANDLER_RET_USAGE;
+                               }
+
+                               ret = toggle_tid_param(argv[0], argv[1], msg,
+                                                      NL80211_TID_CONFIG_ATTR_RTSCTS_CTRL);
+                               if (ret)
+                                       return ret;
+
+                               argc -= 2;
+                               argv += 2;
+                       } else if (strcmp(argv[0], "sretry") == 0) {
+                               if (argc < 2) {
+                                       fprintf(stderr, "not enough args for %s\n", argv[0]);
+                                       return HANDLER_RET_USAGE;
+                               }
+
+                               NLA_PUT_U8(msg, NL80211_TID_CONFIG_ATTR_RETRY_SHORT, strtol(argv[1], &end, 0));
+                               if (*end) {
+                                       fprintf(stderr, "Invalid short_retry value: %s\n", argv[1]);
+                                       return 2;
+                               }
+
+                               argc -= 2;
+                               argv += 2;
+                       } else if (strcmp(argv[0], "lretry") == 0) {
+                               if (argc < 2) {
+                                       fprintf(stderr, "not enough args for %s\n", argv[0]);
+                                       return HANDLER_RET_USAGE;
+                               }
+
+                               NLA_PUT_U8(msg, NL80211_TID_CONFIG_ATTR_RETRY_LONG, strtol(argv[1], &end, 0));
+                               if (*end) {
+                                       fprintf(stderr, "Invalid long_retry value: %s\n", argv[1]);
+                                       return 2;
+                               }
+
+                               argc -= 2;
+                               argv += 2;
+                       } else {
+                               fprintf(stderr, "Unknown parameter: %s\n", argv[0]);
+                               return HANDLER_RET_USAGE;
+                       }
+
+                       break;
+               default:
+                       fprintf(stderr, "Failed to parse: internal failure\n");
+                       return HANDLER_RET_USAGE;
+               }
+       }
+
+       if (tids_entry)
+               nla_nest_end(msg, tids_entry);
+
+       if (tids_array)
+               nla_nest_end(msg, tids_array);
+
+       return 0;
+
+nla_put_failure:
+       return -ENOBUFS;
+}
+
+COMMAND(set, tidconf, "[peer <MAC address>] tids <mask> [override] [sretry <num>] [lretry <num>] "
+       "[ampdu [on|off]] [amsdu [on|off]] [noack [on|off]] [rtscts [on|off]]",
+       NL80211_CMD_SET_TID_CONFIG, 0, CIB_NETDEV, handle_tid_config,
+       "Setup per-node TID specific configuration for TIDs selected by bitmask.\n"
+       "If MAC address is not specified, then supplied TID configuration\n"
+       "applied to all the peers.\n"
+       "Examples:\n"
+       "  $ iw dev wlan0 tids 0x1 ampdu off\n"
+       "  $ iw dev wlan0 tids 0x5 ampdu off amsdu off rtscts on\n"
+       "  $ iw dev wlan0 tids 0x3 override ampdu on noack on rtscts on\n"
+       "  $ iw dev wlan0 peer xx:xx:xx:xx:xx:xx tids 0x1 ampdu off tids 0x3 amsdu off rtscts on\n"
+       );