| #include <errno.h> |
| |
| #include "nl80211.h" |
| #include "iw.h" |
| |
| |
| static int handle_bitrates(struct nl80211_state *state, |
| struct nl_cb *cb, |
| struct nl_msg *msg, |
| int argc, char **argv) |
| { |
| struct nlattr *nl_rates, *nl_band; |
| int i; |
| bool have_legacy_24 = false, have_legacy_5 = false; |
| uint8_t legacy_24[32], legacy_5[32]; |
| int n_legacy_24 = 0, n_legacy_5 = 0; |
| uint8_t *legacy = NULL; |
| int *n_legacy = NULL; |
| bool have_mcs_24 = false, have_mcs_5 = false; |
| #ifdef NL80211_TXRATE_MCS |
| uint8_t mcs_24[77], mcs_5[77]; |
| int n_mcs_24 = 0, n_mcs_5 = 0; |
| uint8_t *mcs = NULL; |
| int *n_mcs = NULL; |
| #endif |
| enum { |
| S_NONE, |
| S_LEGACY, |
| S_MCS, |
| } parser_state = S_NONE; |
| |
| for (i = 0; i < argc; i++) { |
| char *end; |
| double tmpd; |
| #ifdef NL80211_TXRATE_MCS |
| long tmpl; |
| #endif |
| |
| if (strcmp(argv[i], "legacy-2.4") == 0) { |
| if (have_legacy_24) |
| return 1; |
| parser_state = S_LEGACY; |
| legacy = legacy_24; |
| n_legacy = &n_legacy_24; |
| have_legacy_24 = true; |
| } else if (strcmp(argv[i], "legacy-5") == 0) { |
| if (have_legacy_5) |
| return 1; |
| parser_state = S_LEGACY; |
| legacy = legacy_5; |
| n_legacy = &n_legacy_5; |
| have_legacy_5 = true; |
| } |
| #ifdef NL80211_TXRATE_MCS |
| else if (strcmp(argv[i], "mcs-2.4") == 0) { |
| if (have_mcs_24) |
| return 1; |
| parser_state = S_MCS; |
| mcs = mcs_24; |
| n_mcs = &n_mcs_24; |
| have_mcs_24 = true; |
| } else if (strcmp(argv[i], "mcs-5") == 0) { |
| if (have_mcs_5) |
| return 1; |
| parser_state = S_MCS; |
| mcs = mcs_5; |
| n_mcs = &n_mcs_5; |
| have_mcs_5 = true; |
| } |
| #endif |
| else switch (parser_state) { |
| case S_LEGACY: |
| tmpd = strtod(argv[i], &end); |
| if (*end != '\0') |
| return 1; |
| if (tmpd < 1 || tmpd > 255 * 2) |
| return 1; |
| legacy[(*n_legacy)++] = tmpd * 2; |
| break; |
| case S_MCS: |
| #ifdef NL80211_TXRATE_MCS |
| tmpl = strtol(argv[i], &end, 0); |
| if (*end != '\0') |
| return 1; |
| if (tmpl < 0 || tmpl > 255) |
| return 1; |
| mcs[(*n_mcs)++] = tmpl; |
| break; |
| #endif |
| default: |
| return 1; |
| } |
| } |
| |
| nl_rates = nla_nest_start(msg, NL80211_ATTR_TX_RATES); |
| if (!nl_rates) |
| goto nla_put_failure; |
| |
| if (have_legacy_24 || have_mcs_24) { |
| nl_band = nla_nest_start(msg, NL80211_BAND_2GHZ); |
| if (!nl_band) |
| goto nla_put_failure; |
| if (have_legacy_24) |
| nla_put(msg, NL80211_TXRATE_LEGACY, n_legacy_24, legacy_24); |
| #ifdef NL80211_TXRATE_MCS |
| if (have_mcs_24) |
| nla_put(msg, NL80211_TXRATE_MCS, n_mcs_24, mcs_24); |
| #endif |
| nla_nest_end(msg, nl_band); |
| } |
| |
| if (have_legacy_5 || have_mcs_5) { |
| nl_band = nla_nest_start(msg, NL80211_BAND_5GHZ); |
| if (!nl_band) |
| goto nla_put_failure; |
| if (have_legacy_5) |
| nla_put(msg, NL80211_TXRATE_LEGACY, n_legacy_5, legacy_5); |
| #ifdef NL80211_TXRATE_MCS |
| if (have_mcs_5) |
| nla_put(msg, NL80211_TXRATE_MCS, n_mcs_5, mcs_5); |
| #endif |
| nla_nest_end(msg, nl_band); |
| } |
| |
| nla_nest_end(msg, nl_rates); |
| |
| return 0; |
| nla_put_failure: |
| return -ENOBUFS; |
| } |
| |
| #define DESCR_LEGACY "[legacy-<2.4|5> <legacy rate in Mbps>*]" |
| #ifdef NL80211_TXRATE_MCS |
| #define DESCR DESCR_LEGACY " [mcs-<2.4|5> <MCS index>*]" |
| #else |
| #define DESCR DESCR_LEGACY |
| #endif |
| |
| COMMAND(set, bitrates, DESCR, NL80211_CMD_SET_TX_BITRATE_MASK, 0, CIB_NETDEV, |
| handle_bitrates, |
| "Sets up the specified rate masks.\n" |
| "Not passing any arguments would clear the existing mask (if any)."); |