5 #include <netlink/genl/genl.h>
6 #include <netlink/genl/family.h>
7 #include <netlink/genl/ctrl.h>
8 #include <netlink/msg.h>
9 #include <netlink/attr.h>
27 PLINK_ACTION_UNDEFINED
,
33 static int print_sta_handler(struct nl_msg
*msg
, void *arg
)
35 struct nlattr
*tb
[NL80211_ATTR_MAX
+ 1];
36 struct genlmsghdr
*gnlh
= nlmsg_data(nlmsg_hdr(msg
));
37 struct nlattr
*sinfo
[NL80211_STA_INFO_MAX
+ 1];
38 struct nlattr
*rinfo
[NL80211_RATE_INFO_MAX
+ 1];
39 char mac_addr
[20], state_name
[10], dev
[20];
40 struct nl80211_sta_flag_update
*sta_flags
;
41 static struct nla_policy stats_policy
[NL80211_STA_INFO_MAX
+ 1] = {
42 [NL80211_STA_INFO_INACTIVE_TIME
] = { .type
= NLA_U32
},
43 [NL80211_STA_INFO_RX_BYTES
] = { .type
= NLA_U32
},
44 [NL80211_STA_INFO_TX_BYTES
] = { .type
= NLA_U32
},
45 [NL80211_STA_INFO_RX_PACKETS
] = { .type
= NLA_U32
},
46 [NL80211_STA_INFO_TX_PACKETS
] = { .type
= NLA_U32
},
47 [NL80211_STA_INFO_SIGNAL
] = { .type
= NLA_U8
},
48 [NL80211_STA_INFO_T_OFFSET
] = { .type
= NLA_U64
},
49 [NL80211_STA_INFO_TX_BITRATE
] = { .type
= NLA_NESTED
},
50 [NL80211_STA_INFO_LLID
] = { .type
= NLA_U16
},
51 [NL80211_STA_INFO_PLID
] = { .type
= NLA_U16
},
52 [NL80211_STA_INFO_PLINK_STATE
] = { .type
= NLA_U8
},
53 [NL80211_STA_INFO_TX_RETRIES
] = { .type
= NLA_U32
},
54 [NL80211_STA_INFO_TX_FAILED
] = { .type
= NLA_U32
},
55 [NL80211_STA_INFO_STA_FLAGS
] =
56 { .minlen
= sizeof(struct nl80211_sta_flag_update
) },
59 static struct nla_policy rate_policy
[NL80211_RATE_INFO_MAX
+ 1] = {
60 [NL80211_RATE_INFO_BITRATE
] = { .type
= NLA_U16
},
61 [NL80211_RATE_INFO_MCS
] = { .type
= NLA_U8
},
62 [NL80211_RATE_INFO_40_MHZ_WIDTH
] = { .type
= NLA_FLAG
},
63 [NL80211_RATE_INFO_SHORT_GI
] = { .type
= NLA_FLAG
},
66 nla_parse(tb
, NL80211_ATTR_MAX
, genlmsg_attrdata(gnlh
, 0),
67 genlmsg_attrlen(gnlh
, 0), NULL
);
70 * TODO: validate the interface and mac address!
71 * Otherwise, there's a race condition as soon as
72 * the kernel starts sending station notifications.
75 if (!tb
[NL80211_ATTR_STA_INFO
]) {
76 fprintf(stderr
, "sta stats missing!\n");
79 if (nla_parse_nested(sinfo
, NL80211_STA_INFO_MAX
,
80 tb
[NL80211_ATTR_STA_INFO
],
82 fprintf(stderr
, "failed to parse nested attributes!\n");
86 mac_addr_n2a(mac_addr
, nla_data(tb
[NL80211_ATTR_MAC
]));
87 if_indextoname(nla_get_u32(tb
[NL80211_ATTR_IFINDEX
]), dev
);
88 printf("Station %s (on %s)", mac_addr
, dev
);
90 if (sinfo
[NL80211_STA_INFO_INACTIVE_TIME
])
91 printf("\n\tinactive time:\t%u ms",
92 nla_get_u32(sinfo
[NL80211_STA_INFO_INACTIVE_TIME
]));
93 if (sinfo
[NL80211_STA_INFO_RX_BYTES
])
94 printf("\n\trx bytes:\t%u",
95 nla_get_u32(sinfo
[NL80211_STA_INFO_RX_BYTES
]));
96 if (sinfo
[NL80211_STA_INFO_RX_PACKETS
])
97 printf("\n\trx packets:\t%u",
98 nla_get_u32(sinfo
[NL80211_STA_INFO_RX_PACKETS
]));
99 if (sinfo
[NL80211_STA_INFO_TX_BYTES
])
100 printf("\n\ttx bytes:\t%u",
101 nla_get_u32(sinfo
[NL80211_STA_INFO_TX_BYTES
]));
102 if (sinfo
[NL80211_STA_INFO_TX_PACKETS
])
103 printf("\n\ttx packets:\t%u",
104 nla_get_u32(sinfo
[NL80211_STA_INFO_TX_PACKETS
]));
105 if (sinfo
[NL80211_STA_INFO_TX_RETRIES
])
106 printf("\n\ttx retries:\t%u",
107 nla_get_u32(sinfo
[NL80211_STA_INFO_TX_RETRIES
]));
108 if (sinfo
[NL80211_STA_INFO_TX_FAILED
])
109 printf("\n\ttx failed:\t%u",
110 nla_get_u32(sinfo
[NL80211_STA_INFO_TX_FAILED
]));
111 if (sinfo
[NL80211_STA_INFO_SIGNAL
])
112 printf("\n\tsignal: \t%d dBm",
113 (int8_t)nla_get_u8(sinfo
[NL80211_STA_INFO_SIGNAL
]));
114 if (sinfo
[NL80211_STA_INFO_SIGNAL_AVG
])
115 printf("\n\tsignal avg:\t%d dBm",
116 (int8_t)nla_get_u8(sinfo
[NL80211_STA_INFO_SIGNAL_AVG
]));
117 if (sinfo
[NL80211_STA_INFO_T_OFFSET
])
118 printf("\n\tToffset:\t%lld us",
119 (unsigned long long)nla_get_u64(sinfo
[NL80211_STA_INFO_T_OFFSET
]));
121 if (sinfo
[NL80211_STA_INFO_TX_BITRATE
]) {
122 if (nla_parse_nested(rinfo
, NL80211_RATE_INFO_MAX
,
123 sinfo
[NL80211_STA_INFO_TX_BITRATE
], rate_policy
)) {
124 fprintf(stderr
, "failed to parse nested rate attributes!\n");
126 printf("\n\ttx bitrate:\t");
127 if (rinfo
[NL80211_RATE_INFO_BITRATE
]) {
128 int rate
= nla_get_u16(rinfo
[NL80211_RATE_INFO_BITRATE
]);
129 printf("%d.%d MBit/s", rate
/ 10, rate
% 10);
132 if (rinfo
[NL80211_RATE_INFO_MCS
])
133 printf(" MCS %d", nla_get_u8(rinfo
[NL80211_RATE_INFO_MCS
]));
134 if (rinfo
[NL80211_RATE_INFO_40_MHZ_WIDTH
])
136 if (rinfo
[NL80211_RATE_INFO_SHORT_GI
])
141 if (sinfo
[NL80211_STA_INFO_LLID
])
142 printf("\n\tmesh llid:\t%d",
143 nla_get_u16(sinfo
[NL80211_STA_INFO_LLID
]));
144 if (sinfo
[NL80211_STA_INFO_PLID
])
145 printf("\n\tmesh plid:\t%d",
146 nla_get_u16(sinfo
[NL80211_STA_INFO_PLID
]));
147 if (sinfo
[NL80211_STA_INFO_PLINK_STATE
]) {
148 switch (nla_get_u8(sinfo
[NL80211_STA_INFO_PLINK_STATE
])) {
150 strcpy(state_name
, "LISTEN");
153 strcpy(state_name
, "OPN_SNT");
156 strcpy(state_name
, "OPN_RCVD");
159 strcpy(state_name
, "CNF_RCVD");
162 strcpy(state_name
, "ESTAB");
165 strcpy(state_name
, "HOLDING");
168 strcpy(state_name
, "BLOCKED");
171 strcpy(state_name
, "UNKNOWN");
174 printf("\n\tmesh plink:\t%s", state_name
);
177 if (sinfo
[NL80211_STA_INFO_STA_FLAGS
]) {
178 sta_flags
= (struct nl80211_sta_flag_update
*)
179 nla_data(sinfo
[NL80211_STA_INFO_STA_FLAGS
]);
181 if (sta_flags
->mask
& BIT(NL80211_STA_FLAG_AUTHORIZED
)) {
182 printf("\n\tauthorized:\t");
183 if (sta_flags
->set
& BIT(NL80211_STA_FLAG_AUTHORIZED
))
189 if (sta_flags
->mask
& BIT(NL80211_STA_FLAG_AUTHENTICATED
)) {
190 printf("\n\tauthenticated:\t");
191 if (sta_flags
->set
& BIT(NL80211_STA_FLAG_AUTHENTICATED
))
197 if (sta_flags
->mask
& BIT(NL80211_STA_FLAG_SHORT_PREAMBLE
)) {
198 printf("\n\tpreamble:\t");
199 if (sta_flags
->set
& BIT(NL80211_STA_FLAG_SHORT_PREAMBLE
))
205 if (sta_flags
->mask
& BIT(NL80211_STA_FLAG_WME
)) {
206 printf("\n\tWMM/WME:\t");
207 if (sta_flags
->set
& BIT(NL80211_STA_FLAG_WME
))
213 if (sta_flags
->mask
& BIT(NL80211_STA_FLAG_MFP
)) {
214 printf("\n\tMFP:\t\t");
215 if (sta_flags
->set
& BIT(NL80211_STA_FLAG_MFP
))
221 if (sta_flags
->mask
& BIT(NL80211_STA_FLAG_TDLS_PEER
)) {
222 printf("\n\tTDLS peer:\t\t");
223 if (sta_flags
->set
& BIT(NL80211_STA_FLAG_TDLS_PEER
))
234 static int handle_station_get(struct nl80211_state
*state
,
237 int argc
, char **argv
)
239 unsigned char mac_addr
[ETH_ALEN
];
244 if (mac_addr_a2n(mac_addr
, argv
[0])) {
245 fprintf(stderr
, "invalid mac address\n");
255 NLA_PUT(msg
, NL80211_ATTR_MAC
, ETH_ALEN
, mac_addr
);
257 nl_cb_set(cb
, NL_CB_VALID
, NL_CB_CUSTOM
, print_sta_handler
, NULL
);
263 COMMAND(station
, get
, "<MAC address>",
264 NL80211_CMD_GET_STATION
, 0, CIB_NETDEV
, handle_station_get
,
265 "Get information for a specific station.");
266 COMMAND(station
, del
, "<MAC address>",
267 NL80211_CMD_DEL_STATION
, 0, CIB_NETDEV
, handle_station_get
,
268 "Remove the given station entry (use with caution!)");
270 static const struct cmd
*station_set_plink
;
271 static const struct cmd
*station_set_vlan
;
273 static const struct cmd
*select_station_cmd(int argc
, char **argv
)
277 if (strcmp(argv
[1], "plink_action") == 0)
278 return station_set_plink
;
279 if (strcmp(argv
[1], "vlan") == 0)
280 return station_set_vlan
;
284 static int handle_station_set_plink(struct nl80211_state
*state
,
287 int argc
, char **argv
)
289 unsigned char plink_action
;
290 unsigned char mac_addr
[ETH_ALEN
];
295 if (mac_addr_a2n(mac_addr
, argv
[0])) {
296 fprintf(stderr
, "invalid mac address\n");
302 if (strcmp("plink_action", argv
[0]) != 0)
307 if (strcmp("open", argv
[0]) == 0)
308 plink_action
= PLINK_ACTION_OPEN
;
309 else if (strcmp("block", argv
[0]) == 0)
310 plink_action
= PLINK_ACTION_BLOCK
;
312 fprintf(stderr
, "plink action not supported\n");
321 NLA_PUT(msg
, NL80211_ATTR_MAC
, ETH_ALEN
, mac_addr
);
322 NLA_PUT_U8(msg
, NL80211_ATTR_STA_PLINK_ACTION
, plink_action
);
328 COMMAND_ALIAS(station
, set
, "<MAC address> plink_action <open|block>",
329 NL80211_CMD_SET_STATION
, 0, CIB_NETDEV
, handle_station_set_plink
,
330 "Set mesh peer link action for this station (peer).",
331 select_station_cmd
, station_set_plink
);
333 static int handle_station_set_vlan(struct nl80211_state
*state
,
336 int argc
, char **argv
)
338 unsigned char mac_addr
[ETH_ALEN
];
339 unsigned long sta_vlan
= 0;
345 if (mac_addr_a2n(mac_addr
, argv
[0])) {
346 fprintf(stderr
, "invalid mac address\n");
352 if (strcmp("vlan", argv
[0]) != 0)
357 sta_vlan
= strtoul(argv
[0], &err
, 0);
359 fprintf(stderr
, "invalid vlan id\n");
368 NLA_PUT(msg
, NL80211_ATTR_MAC
, ETH_ALEN
, mac_addr
);
369 NLA_PUT_U32(msg
, NL80211_ATTR_STA_VLAN
, sta_vlan
);
375 COMMAND_ALIAS(station
, set
, "<MAC address> vlan <ifindex>",
376 NL80211_CMD_SET_STATION
, 0, CIB_NETDEV
, handle_station_set_vlan
,
377 "Set an AP VLAN for this station.",
378 select_station_cmd
, station_set_vlan
);
381 static int handle_station_dump(struct nl80211_state
*state
,
384 int argc
, char **argv
)
386 nl_cb_set(cb
, NL_CB_VALID
, NL_CB_CUSTOM
, print_sta_handler
, NULL
);
389 COMMAND(station
, dump
, NULL
,
390 NL80211_CMD_GET_STATION
, NLM_F_DUMP
, CIB_NETDEV
, handle_station_dump
,
391 "List all stations known, e.g. the AP on managed interfaces");