]> git.ipfire.org Git - thirdparty/iw.git/blob - station.c
move over station handling
[thirdparty/iw.git] / station.c
1 #include <linux/nl80211.h>
2 #include <net/if.h>
3 #include <errno.h>
4 #include <string.h>
5
6 #include <netlink/genl/genl.h>
7 #include <netlink/genl/family.h>
8 #include <netlink/genl/ctrl.h>
9 #include <netlink/msg.h>
10 #include <netlink/attr.h>
11
12 #include "iw.h"
13
14 enum plink_state {
15 LISTEN,
16 OPN_SNT,
17 OPN_RCVD,
18 CNF_RCVD,
19 ESTAB,
20 HOLDING,
21 BLOCKED
22 };
23
24 enum plink_actions {
25 PLINK_ACTION_UNDEFINED,
26 PLINK_ACTION_OPEN,
27 PLINK_ACTION_BLOCK,
28 };
29
30
31 static int wait_handler(struct nl_msg *msg, void *arg)
32 {
33 int *finished = arg;
34
35 *finished = 1;
36 return NL_STOP;
37 }
38
39 static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
40 void *arg)
41 {
42 fprintf(stderr, "nl80211 error %d\n", err->error);
43 exit(err->error);
44 }
45
46 static int print_sta_handler(struct nl_msg *msg, void *arg)
47 {
48 struct nlattr *tb[NL80211_ATTR_MAX + 1];
49 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
50 struct nlattr *sinfo[NL80211_STA_INFO_MAX + 1];
51 char mac_addr[20], state_name[10], dev[20];
52 static struct nla_policy stats_policy[NL80211_STA_INFO_MAX + 1] = {
53 [NL80211_STA_INFO_INACTIVE_TIME] = { .type = NLA_U32 },
54 [NL80211_STA_INFO_RX_BYTES] = { .type = NLA_U32 },
55 [NL80211_STA_INFO_TX_BYTES] = { .type = NLA_U32 },
56 [NL80211_STA_INFO_LLID] = { .type = NLA_U16 },
57 [NL80211_STA_INFO_PLID] = { .type = NLA_U16 },
58 [NL80211_STA_INFO_PLINK_STATE] = { .type = NLA_U8 },
59 };
60
61 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
62 genlmsg_attrlen(gnlh, 0), NULL);
63
64 /*
65 * TODO: validate the interface and mac address!
66 * Otherwise, there's a race condition as soon as
67 * the kernel starts sending station notifications.
68 */
69
70 if (!tb[NL80211_ATTR_STA_INFO]) {
71 fprintf(stderr, "sta stats missing!");
72 return NL_SKIP;
73 }
74 if (nla_parse_nested(sinfo, NL80211_STA_INFO_MAX,
75 tb[NL80211_ATTR_STA_INFO],
76 stats_policy)) {
77 fprintf(stderr, "failed to parse nested attributes!");
78 return NL_SKIP;
79 }
80
81 mac_addr_n2a(mac_addr, nla_data(tb[NL80211_ATTR_MAC]));
82 if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), dev);
83 printf("Station %s (on %s)", mac_addr, dev);
84
85 if (sinfo[NL80211_STA_INFO_INACTIVE_TIME])
86 printf("\n\tinactive time:\t%d ms",
87 nla_get_u32(sinfo[NL80211_STA_INFO_INACTIVE_TIME]));
88 if (sinfo[NL80211_STA_INFO_RX_BYTES])
89 printf("\n\trx bytes:\t%d",
90 nla_get_u32(sinfo[NL80211_STA_INFO_RX_BYTES]));
91 if (sinfo[NL80211_STA_INFO_TX_BYTES])
92 printf("\n\ttx bytes:\t%d",
93 nla_get_u32(sinfo[NL80211_STA_INFO_TX_BYTES]));
94 if (sinfo[NL80211_STA_INFO_LLID])
95 printf("\n\tmesh llid:\t%d",
96 nla_get_u16(sinfo[NL80211_STA_INFO_LLID]));
97 if (sinfo[NL80211_STA_INFO_PLID])
98 printf("\n\tmesh plid:\t%d",
99 nla_get_u16(sinfo[NL80211_STA_INFO_PLID]));
100 if (sinfo[NL80211_STA_INFO_PLINK_STATE]) {
101 switch (nla_get_u16(sinfo[NL80211_STA_INFO_PLINK_STATE])) {
102 case LISTEN:
103 strcpy(state_name, "LISTEN");
104 break;
105 case OPN_SNT:
106 strcpy(state_name, "OPN_SNT");
107 break;
108 case OPN_RCVD:
109 strcpy(state_name, "OPN_RCVD");
110 break;
111 case CNF_RCVD:
112 strcpy(state_name, "CNF_RCVD");
113 break;
114 case ESTAB:
115 strcpy(state_name, "ESTAB");
116 break;
117 case HOLDING:
118 strcpy(state_name, "HOLDING");
119 break;
120 case BLOCKED:
121 strcpy(state_name, "BLOCKED");
122 break;
123 default:
124 strcpy(state_name, "UNKNOWN");
125 break;
126 }
127 printf("\n\tmesh plink:\t%s", state_name);
128 }
129
130 printf("\n");
131 return NL_SKIP;
132 }
133
134 static int handle_station_get(struct nl80211_state *state,
135 struct nl_msg *msg,
136 int argc, char **argv)
137 {
138 struct nl_cb *cb = NULL;
139 int ret = 1;
140 int err;
141 int finished = 0;
142 unsigned char mac_addr[ETH_ALEN];
143
144 if (argc < 1)
145 return -1;
146
147 if (mac_addr_a2n(mac_addr, argv[0])) {
148 fprintf(stderr, "invalid mac address\n");
149 return 1;
150 }
151
152 argc--;
153 argv++;
154
155 if (argc)
156 return -1;
157
158 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr);
159
160 cb = nl_cb_alloc(NL_CB_CUSTOM);
161 if (!cb)
162 goto out;
163
164 if (nl_send_auto_complete(state->nl_handle, msg) < 0)
165 goto out;
166
167 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_sta_handler, NULL);
168 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, wait_handler, &finished);
169 nl_cb_err(cb, NL_CB_CUSTOM, error_handler, NULL);
170
171 err = nl_recvmsgs(state->nl_handle, cb);
172
173 if (!finished)
174 err = nl_wait_for_ack(state->nl_handle);
175
176 if (err < 0)
177 goto out;
178
179 ret = 0;
180
181 out:
182 nl_cb_put(cb);
183 nla_put_failure:
184 return ret;
185 }
186 COMMAND(station, get, "<MAC address>",
187 NL80211_CMD_GET_STATION, 0, CIB_NETDEV, handle_station_get);
188 COMMAND(station, del, "<MAC address>",
189 NL80211_CMD_DEL_STATION, 0, CIB_NETDEV, handle_station_get);
190
191 static int handle_station_set(struct nl80211_state *state,
192 struct nl_msg *msg,
193 int argc, char **argv)
194 {
195 struct nl_cb *cb = NULL;
196 int ret = 1;
197 int err;
198 int finished = 0;
199 unsigned char plink_action;
200 unsigned char mac_addr[ETH_ALEN];
201
202 if (argc < 3)
203 return -1;
204
205 if (mac_addr_a2n(mac_addr, argv[0])) {
206 fprintf(stderr, "invalid mac address\n");
207 return 1;
208 }
209 argc--;
210 argv++;
211
212 if (strcmp("plink_action", argv[0]) != 0)
213 return 1;
214 argc--;
215 argv++;
216
217 if (strcmp("open", argv[0]) == 0)
218 plink_action = PLINK_ACTION_OPEN;
219 else if (strcmp("block", argv[0]) == 0)
220 plink_action = PLINK_ACTION_BLOCK;
221 else {
222 fprintf(stderr, "plink action not supported\n");
223 return 1;
224 }
225 argc--;
226 argv++;
227
228 if (argc)
229 return -1;
230
231 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr);
232 NLA_PUT_U8(msg, NL80211_ATTR_STA_PLINK_ACTION, plink_action);
233
234 cb = nl_cb_alloc(NL_CB_CUSTOM);
235 if (!cb)
236 goto out;
237
238 if (nl_send_auto_complete(state->nl_handle, msg) < 0)
239 goto out;
240
241 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_sta_handler, NULL);
242 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, wait_handler, &finished);
243 nl_cb_err(cb, NL_CB_CUSTOM, error_handler, NULL);
244
245 err = nl_recvmsgs(state->nl_handle, cb);
246
247 if (!finished)
248 err = nl_wait_for_ack(state->nl_handle);
249
250 if (err < 0)
251 goto out;
252
253 ret = 0;
254
255 out:
256 nl_cb_put(cb);
257 nla_put_failure:
258 return ret;
259 }
260 COMMAND(station, set, "<MAC address> plink_action <open|block>",
261 NL80211_CMD_SET_STATION, 0, CIB_NETDEV, handle_station_set);
262
263 static int handle_station_dump(struct nl80211_state *state,
264 struct nl_msg *msg,
265 int argc, char **argv)
266 {
267 struct nl_cb *cb = NULL;
268 int ret = 1;
269 int err;
270 int finished = 0;
271
272 if (argc)
273 return -1;
274
275 cb = nl_cb_alloc(NL_CB_CUSTOM);
276 if (!cb)
277 goto out;
278
279 if (nl_send_auto_complete(state->nl_handle, msg) < 0)
280 goto out;
281
282 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_sta_handler, NULL);
283 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, wait_handler, &finished);
284
285 err = nl_recvmsgs(state->nl_handle, cb);
286
287 if (err < 0)
288 goto out;
289
290 ret = 0;
291
292 out:
293 nl_cb_put(cb);
294 return ret;
295 }
296 COMMAND(station, dump, NULL,
297 NL80211_CMD_SET_STATION, NLM_F_DUMP, CIB_NETDEV, handle_station_dump);