+
+static int handle_fragmentation(struct nl80211_state *state,
+ struct nl_msg *msg,
+ int argc, char **argv,
+ enum id_input id)
+{
+ unsigned int frag;
+
+ if (argc != 1)
+ return 1;
+
+ if (strcmp("off", argv[0]) == 0)
+ frag = -1;
+ else {
+ char *end;
+
+ if (!*argv[0])
+ return 1;
+ frag = strtoul(argv[0], &end, 10);
+ if (*end != '\0')
+ return 1;
+ }
+
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, frag);
+
+ return 0;
+ nla_put_failure:
+ return -ENOBUFS;
+}
+COMMAND(set, frag, "<fragmentation threshold|off>",
+ NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_fragmentation,
+ "Set fragmentation threshold.");
+
+static int handle_rts(struct nl80211_state *state,
+ struct nl_msg *msg,
+ int argc, char **argv,
+ enum id_input id)
+{
+ unsigned int rts;
+
+ if (argc != 1)
+ return 1;
+
+ if (strcmp("off", argv[0]) == 0)
+ rts = -1;
+ else {
+ char *end;
+
+ if (!*argv[0])
+ return 1;
+ rts = strtoul(argv[0], &end, 10);
+ if (*end != '\0')
+ return 1;
+ }
+
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, rts);
+
+ return 0;
+ nla_put_failure:
+ return -ENOBUFS;
+}
+COMMAND(set, rts, "<rts threshold|off>",
+ NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_rts,
+ "Set rts threshold.");
+
+static int handle_retry(struct nl80211_state *state,
+ struct nl_msg *msg,
+ int argc, char **argv, enum id_input id)
+{
+ unsigned int retry_short = 0, retry_long = 0;
+ bool have_retry_s = false, have_retry_l = false;
+ int i;
+ enum {
+ S_NONE,
+ S_SHORT,
+ S_LONG,
+ } parser_state = S_NONE;
+
+ if (!argc || (argc != 2 && argc != 4))
+ return 1;
+
+ for (i = 0; i < argc; i++) {
+ char *end;
+ unsigned int tmpul;
+
+ if (strcmp(argv[i], "short") == 0) {
+ if (have_retry_s)
+ return 1;
+ parser_state = S_SHORT;
+ have_retry_s = true;
+ } else if (strcmp(argv[i], "long") == 0) {
+ if (have_retry_l)
+ return 1;
+ parser_state = S_LONG;
+ have_retry_l = true;
+ } else {
+ tmpul = strtoul(argv[i], &end, 10);
+ if (*end != '\0')
+ return 1;
+ if (!tmpul || tmpul > 255)
+ return -EINVAL;
+ switch (parser_state) {
+ case S_SHORT:
+ retry_short = tmpul;
+ break;
+ case S_LONG:
+ retry_long = tmpul;
+ break;
+ default:
+ return 1;
+ }
+ }
+ }
+
+ if (!have_retry_s && !have_retry_l)
+ return 1;
+ if (have_retry_s)
+ NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_RETRY_SHORT, retry_short);
+ if (have_retry_l)
+ NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_RETRY_LONG, retry_long);
+
+ return 0;
+ nla_put_failure:
+ return -ENOBUFS;
+}
+COMMAND(set, retry, "[short <limit>] [long <limit>]",
+ NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_retry,
+ "Set retry limit.");
+
+#ifndef NETNS_RUN_DIR
+#define NETNS_RUN_DIR "/var/run/netns"
+#endif
+static int netns_get_fd(const char *name)
+{
+ char pathbuf[MAXPATHLEN];
+ const char *path, *ptr;
+
+ path = name;
+ ptr = strchr(name, '/');
+ if (!ptr) {
+ snprintf(pathbuf, sizeof(pathbuf), "%s/%s",
+ NETNS_RUN_DIR, name );
+ path = pathbuf;
+ }
+ return open(path, O_RDONLY);
+}
+
+static int handle_netns(struct nl80211_state *state,
+ struct nl_msg *msg,
+ int argc, char **argv,
+ enum id_input id)
+{
+ char *end;
+ int fd;
+
+ if (argc < 1 || !*argv[0])
+ return 1;
+
+ if (argc == 1) {
+ NLA_PUT_U32(msg, NL80211_ATTR_PID,
+ strtoul(argv[0], &end, 10));
+ if (*end != '\0') {
+ printf("Invalid parameter: pid(%s)\n", argv[0]);
+ return 1;
+ }
+ return 0;
+ }
+
+ if (argc != 2 || strcmp(argv[0], "name"))
+ return 1;
+
+ if ((fd = netns_get_fd(argv[1])) >= 0) {
+ NLA_PUT_U32(msg, NL80211_ATTR_NETNS_FD, fd);
+ return 0;
+ } else {
+ printf("Invalid parameter: nsname(%s)\n", argv[0]);
+ }
+
+ return 1;
+
+ nla_put_failure:
+ return -ENOBUFS;
+}
+COMMAND(set, netns, "{ <pid> | name <nsname> }",
+ NL80211_CMD_SET_WIPHY_NETNS, 0, CIB_PHY, handle_netns,
+ "Put this wireless device into a different network namespace:\n"
+ " <pid> - change network namespace by process id\n"
+ " <nsname> - change network namespace by name from "NETNS_RUN_DIR"\n"
+ " or by absolute path (man ip-netns)\n");
+
+static int handle_coverage(struct nl80211_state *state,
+ struct nl_msg *msg,
+ int argc, char **argv,
+ enum id_input id)
+{
+ char *end;
+ unsigned int coverage;
+
+ if (argc != 1)
+ return 1;
+
+ if (!*argv[0])
+ return 1;
+ coverage = strtoul(argv[0], &end, 10);
+ if (coverage > 255)
+ return 1;
+
+ if (*end)
+ return 1;
+
+ NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS, coverage);
+
+ return 0;
+ nla_put_failure:
+ return -ENOBUFS;
+}
+COMMAND(set, coverage, "<coverage class>",
+ NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_coverage,
+ "Set coverage class (1 for every 3 usec of air propagation time).\n"
+ "Valid values: 0 - 255.");
+
+static int handle_distance(struct nl80211_state *state,
+ struct nl_msg *msg,
+ int argc, char **argv,
+ enum id_input id)
+{
+ if (argc != 1)
+ return 1;
+
+ if (!*argv[0])
+ return 1;
+
+ if (strcmp("auto", argv[0]) == 0) {
+ NLA_PUT_FLAG(msg, NL80211_ATTR_WIPHY_DYN_ACK);
+ } else {
+ char *end;
+ unsigned int distance, coverage;
+
+ distance = strtoul(argv[0], &end, 10);
+
+ if (*end)
+ return 1;
+
+ /*
+ * Divide double the distance by the speed of light
+ * in m/usec (300) to get round-trip time in microseconds
+ * and then divide the result by three to get coverage class
+ * as specified in IEEE 802.11-2007 table 7-27.
+ * Values are rounded upwards.
+ */
+ coverage = (distance + 449) / 450;
+ if (coverage > 255)
+ return 1;
+
+ NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS, coverage);
+ }
+
+ return 0;
+ nla_put_failure:
+ return -ENOBUFS;
+}
+COMMAND(set, distance, "<auto|distance>",
+ NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_distance,
+ "Enable ACK timeout estimation algorithm (dynack) or set appropriate\n"
+ "coverage class for given link distance in meters.\n"
+ "To disable dynack set valid value for coverage class.\n"
+ "Valid values: 0 - 114750");
+
+static int handle_txpower(struct nl80211_state *state,
+ struct nl_msg *msg,
+ int argc, char **argv,
+ enum id_input id)
+{
+ enum nl80211_tx_power_setting type;
+ int mbm;
+
+ /* get the required args */
+ if (argc != 1 && argc != 2)
+ return 1;
+
+ if (!strcmp(argv[0], "auto"))
+ type = NL80211_TX_POWER_AUTOMATIC;
+ else if (!strcmp(argv[0], "fixed"))
+ type = NL80211_TX_POWER_FIXED;
+ else if (!strcmp(argv[0], "limit"))
+ type = NL80211_TX_POWER_LIMITED;
+ else {
+ printf("Invalid parameter: %s\n", argv[0]);
+ return 2;
+ }
+
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_TX_POWER_SETTING, type);
+
+ if (type != NL80211_TX_POWER_AUTOMATIC) {
+ char *endptr;
+ if (argc != 2) {
+ printf("Missing TX power level argument.\n");
+ return 2;
+ }
+
+ mbm = strtol(argv[1], &endptr, 10);
+ if (*endptr)
+ return 2;
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_TX_POWER_LEVEL, mbm);
+ } else if (argc != 1)
+ return 1;
+
+ return 0;
+
+ nla_put_failure:
+ return -ENOBUFS;
+}
+COMMAND(set, txpower, "<auto|fixed|limit> [<tx power in mBm>]",
+ NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_txpower,
+ "Specify transmit power level and setting type.");
+COMMAND(set, txpower, "<auto|fixed|limit> [<tx power in mBm>]",
+ NL80211_CMD_SET_WIPHY, 0, CIB_NETDEV, handle_txpower,
+ "Specify transmit power level and setting type.");
+
+static int handle_antenna(struct nl80211_state *state,
+ struct nl_msg *msg,
+ int argc, char **argv,
+ enum id_input id)
+{
+ char *end;
+ uint32_t tx_ant = 0, rx_ant = 0;
+
+ if (argc == 1 && strcmp(argv[0], "all") == 0) {
+ tx_ant = 0xffffffff;
+ rx_ant = 0xffffffff;
+ } else if (argc == 1) {
+ tx_ant = rx_ant = strtoul(argv[0], &end, 0);
+ if (*end)
+ return 1;
+ }
+ else if (argc == 2) {
+ tx_ant = strtoul(argv[0], &end, 0);
+ if (*end)
+ return 1;
+ rx_ant = strtoul(argv[1], &end, 0);
+ if (*end)
+ return 1;
+ } else
+ return 1;
+
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_ANTENNA_TX, tx_ant);
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_ANTENNA_RX, rx_ant);
+
+ return 0;
+
+ nla_put_failure:
+ return -ENOBUFS;
+}
+COMMAND(set, antenna, "<bitmap> | all | <tx bitmap> <rx bitmap>",
+ NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_antenna,
+ "Set a bitmap of allowed antennas to use for TX and RX.\n"
+ "The driver may reject antenna configurations it cannot support.");