X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=station.c;h=247f44588aeb0c9af5f00cc301c5f50ca6a7d6a6;hb=8d5d7ba796bf89c1efd3be3fbed5d1c7bd40dec7;hp=055de0404fffa88ae6f7022a3657d0fa30f4281e;hpb=b1ca19a8519e275cf46317d07fc981d88256a485;p=thirdparty%2Fiw.git diff --git a/station.c b/station.c index 055de04..247f445 100644 --- a/station.c +++ b/station.c @@ -1,4 +1,3 @@ -#include #include #include #include @@ -9,8 +8,11 @@ #include #include +#include "nl80211.h" #include "iw.h" +SECTION(station); + enum plink_state { LISTEN, OPN_SNT, @@ -28,34 +30,38 @@ enum plink_actions { }; -static int wait_handler(struct nl_msg *msg, void *arg) -{ - int *finished = arg; - - *finished = 1; - return NL_STOP; -} - -static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, - void *arg) -{ - fprintf(stderr, "nl80211 error %d\n", err->error); - exit(err->error); -} - static int print_sta_handler(struct nl_msg *msg, void *arg) { struct nlattr *tb[NL80211_ATTR_MAX + 1]; struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); struct nlattr *sinfo[NL80211_STA_INFO_MAX + 1]; + struct nlattr *rinfo[NL80211_RATE_INFO_MAX + 1]; char mac_addr[20], state_name[10], dev[20]; + struct nl80211_sta_flag_update *sta_flags; static struct nla_policy stats_policy[NL80211_STA_INFO_MAX + 1] = { [NL80211_STA_INFO_INACTIVE_TIME] = { .type = NLA_U32 }, [NL80211_STA_INFO_RX_BYTES] = { .type = NLA_U32 }, [NL80211_STA_INFO_TX_BYTES] = { .type = NLA_U32 }, + [NL80211_STA_INFO_RX_PACKETS] = { .type = NLA_U32 }, + [NL80211_STA_INFO_TX_PACKETS] = { .type = NLA_U32 }, + [NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 }, + [NL80211_STA_INFO_T_OFFSET] = { .type = NLA_U64 }, + [NL80211_STA_INFO_TX_BITRATE] = { .type = NLA_NESTED }, [NL80211_STA_INFO_LLID] = { .type = NLA_U16 }, [NL80211_STA_INFO_PLID] = { .type = NLA_U16 }, [NL80211_STA_INFO_PLINK_STATE] = { .type = NLA_U8 }, + [NL80211_STA_INFO_TX_RETRIES] = { .type = NLA_U32 }, + [NL80211_STA_INFO_TX_FAILED] = { .type = NLA_U32 }, + [NL80211_STA_INFO_STA_FLAGS] = + { .minlen = sizeof(struct nl80211_sta_flag_update) }, + }; + + static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = { + [NL80211_RATE_INFO_BITRATE] = { .type = NLA_U16 }, + [NL80211_RATE_INFO_BITRATE32] = { .type = NLA_U32 }, + [NL80211_RATE_INFO_MCS] = { .type = NLA_U8 }, + [NL80211_RATE_INFO_40_MHZ_WIDTH] = { .type = NLA_FLAG }, + [NL80211_RATE_INFO_SHORT_GI] = { .type = NLA_FLAG }, }; nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), @@ -68,13 +74,13 @@ static int print_sta_handler(struct nl_msg *msg, void *arg) */ if (!tb[NL80211_ATTR_STA_INFO]) { - fprintf(stderr, "sta stats missing!"); + fprintf(stderr, "sta stats missing!\n"); return NL_SKIP; } if (nla_parse_nested(sinfo, NL80211_STA_INFO_MAX, tb[NL80211_ATTR_STA_INFO], stats_policy)) { - fprintf(stderr, "failed to parse nested attributes!"); + fprintf(stderr, "failed to parse nested attributes!\n"); return NL_SKIP; } @@ -83,14 +89,59 @@ static int print_sta_handler(struct nl_msg *msg, void *arg) printf("Station %s (on %s)", mac_addr, dev); if (sinfo[NL80211_STA_INFO_INACTIVE_TIME]) - printf("\n\tinactive time:\t%d ms", + printf("\n\tinactive time:\t%u ms", nla_get_u32(sinfo[NL80211_STA_INFO_INACTIVE_TIME])); if (sinfo[NL80211_STA_INFO_RX_BYTES]) - printf("\n\trx bytes:\t%d", + printf("\n\trx bytes:\t%u", nla_get_u32(sinfo[NL80211_STA_INFO_RX_BYTES])); + if (sinfo[NL80211_STA_INFO_RX_PACKETS]) + printf("\n\trx packets:\t%u", + nla_get_u32(sinfo[NL80211_STA_INFO_RX_PACKETS])); if (sinfo[NL80211_STA_INFO_TX_BYTES]) - printf("\n\ttx bytes:\t%d", + printf("\n\ttx bytes:\t%u", nla_get_u32(sinfo[NL80211_STA_INFO_TX_BYTES])); + if (sinfo[NL80211_STA_INFO_TX_PACKETS]) + printf("\n\ttx packets:\t%u", + nla_get_u32(sinfo[NL80211_STA_INFO_TX_PACKETS])); + if (sinfo[NL80211_STA_INFO_TX_RETRIES]) + printf("\n\ttx retries:\t%u", + nla_get_u32(sinfo[NL80211_STA_INFO_TX_RETRIES])); + if (sinfo[NL80211_STA_INFO_TX_FAILED]) + printf("\n\ttx failed:\t%u", + nla_get_u32(sinfo[NL80211_STA_INFO_TX_FAILED])); + if (sinfo[NL80211_STA_INFO_SIGNAL]) + printf("\n\tsignal: \t%d dBm", + (int8_t)nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL])); + if (sinfo[NL80211_STA_INFO_SIGNAL_AVG]) + printf("\n\tsignal avg:\t%d dBm", + (int8_t)nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL_AVG])); + if (sinfo[NL80211_STA_INFO_T_OFFSET]) + printf("\n\tToffset:\t%lld us", + (unsigned long long)nla_get_u64(sinfo[NL80211_STA_INFO_T_OFFSET])); + + if (sinfo[NL80211_STA_INFO_TX_BITRATE]) { + if (nla_parse_nested(rinfo, NL80211_RATE_INFO_MAX, + sinfo[NL80211_STA_INFO_TX_BITRATE], rate_policy)) { + fprintf(stderr, "failed to parse nested rate attributes!\n"); + } else { + int rate = 0; + printf("\n\ttx bitrate:\t"); + if (rinfo[NL80211_RATE_INFO_BITRATE32]) + rate = nla_get_u32(rinfo[NL80211_RATE_INFO_BITRATE32]); + else if (rinfo[NL80211_RATE_INFO_BITRATE]) + rate = nla_get_u16(rinfo[NL80211_RATE_INFO_BITRATE]); + if (rate > 0) + printf("%d.%d MBit/s", rate / 10, rate % 10); + + if (rinfo[NL80211_RATE_INFO_MCS]) + printf(" MCS %d", nla_get_u8(rinfo[NL80211_RATE_INFO_MCS])); + if (rinfo[NL80211_RATE_INFO_40_MHZ_WIDTH]) + printf(" 40Mhz"); + if (rinfo[NL80211_RATE_INFO_SHORT_GI]) + printf(" short GI"); + } + } + if (sinfo[NL80211_STA_INFO_LLID]) printf("\n\tmesh llid:\t%d", nla_get_u16(sinfo[NL80211_STA_INFO_LLID])); @@ -98,7 +149,7 @@ static int print_sta_handler(struct nl_msg *msg, void *arg) printf("\n\tmesh plid:\t%d", nla_get_u16(sinfo[NL80211_STA_INFO_PLID])); if (sinfo[NL80211_STA_INFO_PLINK_STATE]) { - switch (nla_get_u16(sinfo[NL80211_STA_INFO_PLINK_STATE])) { + switch (nla_get_u8(sinfo[NL80211_STA_INFO_PLINK_STATE])) { case LISTEN: strcpy(state_name, "LISTEN"); break; @@ -127,84 +178,129 @@ static int print_sta_handler(struct nl_msg *msg, void *arg) printf("\n\tmesh plink:\t%s", state_name); } + if (sinfo[NL80211_STA_INFO_STA_FLAGS]) { + sta_flags = (struct nl80211_sta_flag_update *) + nla_data(sinfo[NL80211_STA_INFO_STA_FLAGS]); + + if (sta_flags->mask & BIT(NL80211_STA_FLAG_AUTHORIZED)) { + printf("\n\tauthorized:\t"); + if (sta_flags->set & BIT(NL80211_STA_FLAG_AUTHORIZED)) + printf("yes"); + else + printf("no"); + } + + if (sta_flags->mask & BIT(NL80211_STA_FLAG_AUTHENTICATED)) { + printf("\n\tauthenticated:\t"); + if (sta_flags->set & BIT(NL80211_STA_FLAG_AUTHENTICATED)) + printf("yes"); + else + printf("no"); + } + + if (sta_flags->mask & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) { + printf("\n\tpreamble:\t"); + if (sta_flags->set & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) + printf("short"); + else + printf("long"); + } + + if (sta_flags->mask & BIT(NL80211_STA_FLAG_WME)) { + printf("\n\tWMM/WME:\t"); + if (sta_flags->set & BIT(NL80211_STA_FLAG_WME)) + printf("yes"); + else + printf("no"); + } + + if (sta_flags->mask & BIT(NL80211_STA_FLAG_MFP)) { + printf("\n\tMFP:\t\t"); + if (sta_flags->set & BIT(NL80211_STA_FLAG_MFP)) + printf("yes"); + else + printf("no"); + } + + if (sta_flags->mask & BIT(NL80211_STA_FLAG_TDLS_PEER)) { + printf("\n\tTDLS peer:\t\t"); + if (sta_flags->set & BIT(NL80211_STA_FLAG_TDLS_PEER)) + printf("yes"); + else + printf("no"); + } + } + printf("\n"); return NL_SKIP; } static int handle_station_get(struct nl80211_state *state, + struct nl_cb *cb, struct nl_msg *msg, - int argc, char **argv) + int argc, char **argv, + enum id_input id) { - struct nl_cb *cb = NULL; - int ret = 1; - int err; - int finished = 0; unsigned char mac_addr[ETH_ALEN]; if (argc < 1) - return -1; + return 1; if (mac_addr_a2n(mac_addr, argv[0])) { fprintf(stderr, "invalid mac address\n"); - return 1; + return 2; } argc--; argv++; if (argc) - return -1; + return 1; NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); - cb = nl_cb_alloc(NL_CB_CUSTOM); - if (!cb) - goto out; - - if (nl_send_auto_complete(state->nl_handle, msg) < 0) - goto out; - nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_sta_handler, NULL); - nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, wait_handler, &finished); - nl_cb_err(cb, NL_CB_CUSTOM, error_handler, NULL); - - err = nl_recvmsgs(state->nl_handle, cb); - - if (!finished) - err = nl_wait_for_ack(state->nl_handle); - if (err < 0) - goto out; - - ret = 0; - - out: - nl_cb_put(cb); + return 0; nla_put_failure: - return ret; + return -ENOBUFS; } COMMAND(station, get, "", - NL80211_CMD_GET_STATION, 0, CIB_NETDEV, handle_station_get); + NL80211_CMD_GET_STATION, 0, CIB_NETDEV, handle_station_get, + "Get information for a specific station."); COMMAND(station, del, "", - NL80211_CMD_DEL_STATION, 0, CIB_NETDEV, handle_station_get); + NL80211_CMD_DEL_STATION, 0, CIB_NETDEV, handle_station_get, + "Remove the given station entry (use with caution!)"); -static int handle_station_set(struct nl80211_state *state, +static const struct cmd *station_set_plink; +static const struct cmd *station_set_vlan; + +static const struct cmd *select_station_cmd(int argc, char **argv) +{ + if (argc < 2) + return NULL; + if (strcmp(argv[1], "plink_action") == 0) + return station_set_plink; + if (strcmp(argv[1], "vlan") == 0) + return station_set_vlan; + return NULL; +} + +static int handle_station_set_plink(struct nl80211_state *state, + struct nl_cb *cb, struct nl_msg *msg, - int argc, char **argv) + int argc, char **argv, + enum id_input id) { - struct nl_cb *cb = NULL; - int ret = 1; - int err; - int finished = 0; unsigned char plink_action; unsigned char mac_addr[ETH_ALEN]; if (argc < 3) - return -1; + return 1; if (mac_addr_a2n(mac_addr, argv[0])) { fprintf(stderr, "invalid mac address\n"); - return 1; + return 2; } argc--; argv++; @@ -220,78 +316,84 @@ static int handle_station_set(struct nl80211_state *state, plink_action = PLINK_ACTION_BLOCK; else { fprintf(stderr, "plink action not supported\n"); - return 1; + return 2; } argc--; argv++; if (argc) - return -1; + return 1; NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); NLA_PUT_U8(msg, NL80211_ATTR_STA_PLINK_ACTION, plink_action); - cb = nl_cb_alloc(NL_CB_CUSTOM); - if (!cb) - goto out; + return 0; + nla_put_failure: + return -ENOBUFS; +} +COMMAND_ALIAS(station, set, " plink_action ", + NL80211_CMD_SET_STATION, 0, CIB_NETDEV, handle_station_set_plink, + "Set mesh peer link action for this station (peer).", + select_station_cmd, station_set_plink); + +static int handle_station_set_vlan(struct nl80211_state *state, + struct nl_cb *cb, + struct nl_msg *msg, + int argc, char **argv, + enum id_input id) +{ + unsigned char mac_addr[ETH_ALEN]; + unsigned long sta_vlan = 0; + char *err = NULL; - if (nl_send_auto_complete(state->nl_handle, msg) < 0) - goto out; + if (argc < 3) + return 1; - nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_sta_handler, NULL); - nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, wait_handler, &finished); - nl_cb_err(cb, NL_CB_CUSTOM, error_handler, NULL); + if (mac_addr_a2n(mac_addr, argv[0])) { + fprintf(stderr, "invalid mac address\n"); + return 2; + } + argc--; + argv++; - err = nl_recvmsgs(state->nl_handle, cb); + if (strcmp("vlan", argv[0]) != 0) + return 1; + argc--; + argv++; - if (!finished) - err = nl_wait_for_ack(state->nl_handle); + sta_vlan = strtoul(argv[0], &err, 0); + if (err && *err) { + fprintf(stderr, "invalid vlan id\n"); + return 2; + } + argc--; + argv++; - if (err < 0) - goto out; + if (argc) + return 1; - ret = 0; + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); + NLA_PUT_U32(msg, NL80211_ATTR_STA_VLAN, sta_vlan); - out: - nl_cb_put(cb); + return 0; nla_put_failure: - return ret; + return -ENOBUFS; } -COMMAND(station, set, " plink_action ", - NL80211_CMD_SET_STATION, 0, CIB_NETDEV, handle_station_set); +COMMAND_ALIAS(station, set, " vlan ", + NL80211_CMD_SET_STATION, 0, CIB_NETDEV, handle_station_set_vlan, + "Set an AP VLAN for this station.", + select_station_cmd, station_set_vlan); + static int handle_station_dump(struct nl80211_state *state, + struct nl_cb *cb, struct nl_msg *msg, - int argc, char **argv) + int argc, char **argv, + enum id_input id) { - struct nl_cb *cb = NULL; - int ret = 1; - int err; - int finished = 0; - - if (argc) - return -1; - - cb = nl_cb_alloc(NL_CB_CUSTOM); - if (!cb) - goto out; - - if (nl_send_auto_complete(state->nl_handle, msg) < 0) - goto out; - nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_sta_handler, NULL); - nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, wait_handler, &finished); - - err = nl_recvmsgs(state->nl_handle, cb); - - if (err < 0) - goto out; - - ret = 0; - - out: - nl_cb_put(cb); - return ret; + return 0; } COMMAND(station, dump, NULL, - NL80211_CMD_SET_STATION, NLM_F_DUMP, CIB_NETDEV, handle_station_dump); + NL80211_CMD_GET_STATION, NLM_F_DUMP, CIB_NETDEV, handle_station_dump, + "List all stations known, e.g. the AP on managed interfaces");