1 #include <linux/nl80211.h>
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>
24 PLINK_ACTION_UNDEFINED
,
30 static int wait_handler(struct nl_msg
*msg
, void *arg
)
38 static int error_handler(struct sockaddr_nl
*nla
, struct nlmsgerr
*err
,
41 fprintf(stderr
, "nl80211 error %d\n", err
->error
);
45 static int print_sta_handler(struct nl_msg
*msg
, void *arg
)
47 struct nlattr
*tb
[NL80211_ATTR_MAX
+ 1];
48 struct genlmsghdr
*gnlh
= nlmsg_data(nlmsg_hdr(msg
));
49 struct nlattr
*sinfo
[NL80211_STA_INFO_MAX
+ 1];
50 char mac_addr
[20], state_name
[10], dev
[20];
51 static struct nla_policy stats_policy
[NL80211_STA_INFO_MAX
+ 1] = {
52 [NL80211_STA_INFO_INACTIVE_TIME
] = { .type
= NLA_U32
},
53 [NL80211_STA_INFO_RX_BYTES
] = { .type
= NLA_U32
},
54 [NL80211_STA_INFO_TX_BYTES
] = { .type
= NLA_U32
},
55 [NL80211_STA_INFO_LLID
] = { .type
= NLA_U16
},
56 [NL80211_STA_INFO_PLID
] = { .type
= NLA_U16
},
57 [NL80211_STA_INFO_PLINK_STATE
] = { .type
= NLA_U8
},
60 nla_parse(tb
, NL80211_ATTR_MAX
, genlmsg_attrdata(gnlh
, 0),
61 genlmsg_attrlen(gnlh
, 0), NULL
);
64 * TODO: validate the interface and mac address!
65 * Otherwise, there's a race condition as soon as
66 * the kernel starts sending station notifications.
69 if (!tb
[NL80211_ATTR_STA_INFO
]) {
70 fprintf(stderr
, "sta stats missing!");
73 if (nla_parse_nested(sinfo
, NL80211_STA_INFO_MAX
,
74 tb
[NL80211_ATTR_STA_INFO
],
76 fprintf(stderr
, "failed to parse nested attributes!");
80 mac_addr_n2a(mac_addr
, nla_data(tb
[NL80211_ATTR_MAC
]));
81 if_indextoname(nla_get_u32(tb
[NL80211_ATTR_IFINDEX
]), dev
);
82 printf("Station %s (on %s)", mac_addr
, dev
);
84 if (sinfo
[NL80211_STA_INFO_INACTIVE_TIME
])
85 printf("\n\tinactive time:\t%d ms",
86 nla_get_u32(sinfo
[NL80211_STA_INFO_INACTIVE_TIME
]));
87 if (sinfo
[NL80211_STA_INFO_RX_BYTES
])
88 printf("\n\trx bytes:\t%d",
89 nla_get_u32(sinfo
[NL80211_STA_INFO_RX_BYTES
]));
90 if (sinfo
[NL80211_STA_INFO_TX_BYTES
])
91 printf("\n\ttx bytes:\t%d",
92 nla_get_u32(sinfo
[NL80211_STA_INFO_TX_BYTES
]));
93 if (sinfo
[NL80211_STA_INFO_LLID
])
94 printf("\n\tmesh llid:\t%d",
95 nla_get_u16(sinfo
[NL80211_STA_INFO_LLID
]));
96 if (sinfo
[NL80211_STA_INFO_PLID
])
97 printf("\n\tmesh plid:\t%d",
98 nla_get_u16(sinfo
[NL80211_STA_INFO_PLID
]));
99 if (sinfo
[NL80211_STA_INFO_PLINK_STATE
]) {
100 switch (nla_get_u16(sinfo
[NL80211_STA_INFO_PLINK_STATE
])) {
102 strcpy(state_name
, "LISTEN");
105 strcpy(state_name
, "OPN_SNT");
108 strcpy(state_name
, "OPN_RCVD");
111 strcpy(state_name
, "CNF_RCVD");
114 strcpy(state_name
, "ESTAB");
117 strcpy(state_name
, "HOLDING");
120 strcpy(state_name
, "BLOCKED");
123 strcpy(state_name
, "UNKNOWN");
126 printf("\n\tmesh plink:\t%s", state_name
);
133 static int handle_station_get(struct nl80211_state
*state
,
134 char *dev
, int argc
, char **argv
)
137 struct nl_cb
*cb
= NULL
;
141 unsigned char mac_addr
[ETH_ALEN
];
144 fprintf(stderr
, "not enough arguments\n");
148 if (mac_addr_a2n(mac_addr
, argv
[0])) {
149 fprintf(stderr
, "invalid mac address\n");
157 fprintf(stderr
, "too many arguments\n");
165 genlmsg_put(msg
, 0, 0, genl_family_get_id(state
->nl80211
), 0,
166 0, NL80211_CMD_GET_STATION
, 0);
168 NLA_PUT(msg
, NL80211_ATTR_MAC
, ETH_ALEN
, mac_addr
);
169 NLA_PUT_U32(msg
, NL80211_ATTR_IFINDEX
, if_nametoindex(dev
));
171 cb
= nl_cb_alloc(NL_CB_CUSTOM
);
175 if (nl_send_auto_complete(state
->nl_handle
, msg
) < 0)
178 nl_cb_set(cb
, NL_CB_VALID
, NL_CB_CUSTOM
, print_sta_handler
, NULL
);
179 nl_cb_set(cb
, NL_CB_ACK
, NL_CB_CUSTOM
, wait_handler
, &finished
);
180 nl_cb_err(cb
, NL_CB_CUSTOM
, error_handler
, NULL
);
182 err
= nl_recvmsgs(state
->nl_handle
, cb
);
185 err
= nl_wait_for_ack(state
->nl_handle
);
199 static int handle_station_set(struct nl80211_state
*state
,
200 char *dev
, int argc
, char **argv
)
203 struct nl_cb
*cb
= NULL
;
207 unsigned char plink_action
;
208 unsigned char mac_addr
[ETH_ALEN
];
211 fprintf(stderr
, "not enough arguments\n");
215 if (mac_addr_a2n(mac_addr
, argv
[0])) {
216 fprintf(stderr
, "invalid mac address\n");
222 if (strcmp("plink_action", argv
[0]) != 0) {
223 fprintf(stderr
, "parameter not supported\n");
229 if (strcmp("open", argv
[0]) == 0)
230 plink_action
= PLINK_ACTION_OPEN
;
231 else if (strcmp("block", argv
[0]) == 0)
232 plink_action
= PLINK_ACTION_BLOCK
;
234 fprintf(stderr
, "plink action not supported\n");
241 fprintf(stderr
, "too many arguments\n");
249 genlmsg_put(msg
, 0, 0, genl_family_get_id(state
->nl80211
), 0,
250 0, NL80211_CMD_SET_STATION
, 0);
252 NLA_PUT(msg
, NL80211_ATTR_MAC
, ETH_ALEN
, mac_addr
);
253 NLA_PUT_U32(msg
, NL80211_ATTR_IFINDEX
, if_nametoindex(dev
));
254 NLA_PUT_U8(msg
, NL80211_ATTR_STA_PLINK_ACTION
, plink_action
);
256 cb
= nl_cb_alloc(NL_CB_CUSTOM
);
260 if (nl_send_auto_complete(state
->nl_handle
, msg
) < 0)
263 nl_cb_set(cb
, NL_CB_VALID
, NL_CB_CUSTOM
, print_sta_handler
, NULL
);
264 nl_cb_set(cb
, NL_CB_ACK
, NL_CB_CUSTOM
, wait_handler
, &finished
);
265 nl_cb_err(cb
, NL_CB_CUSTOM
, error_handler
, NULL
);
267 err
= nl_recvmsgs(state
->nl_handle
, cb
);
270 err
= nl_wait_for_ack(state
->nl_handle
);
283 static int handle_station_dump(struct nl80211_state
*state
,
284 char *dev
, int argc
, char **argv
)
287 struct nl_cb
*cb
= NULL
;
293 fprintf(stderr
, "too many arguments\n");
301 genlmsg_put(msg
, 0, 0, genl_family_get_id(state
->nl80211
), 0,
302 NLM_F_DUMP
, NL80211_CMD_GET_STATION
, 0);
304 NLA_PUT_U32(msg
, NL80211_ATTR_IFINDEX
, if_nametoindex(dev
));
306 cb
= nl_cb_alloc(NL_CB_CUSTOM
);
310 if (nl_send_auto_complete(state
->nl_handle
, msg
) < 0)
313 nl_cb_set(cb
, NL_CB_VALID
, NL_CB_CUSTOM
, print_sta_handler
, NULL
);
314 nl_cb_set(cb
, NL_CB_FINISH
, NL_CB_CUSTOM
, wait_handler
, &finished
);
316 err
= nl_recvmsgs(state
->nl_handle
, cb
);
330 static int handle_station_del(struct nl80211_state
*state
,
331 char *dev
, int argc
, char **argv
)
334 struct nl_cb
*cb
= NULL
;
338 unsigned char mac
[ETH_ALEN
];
341 fprintf(stderr
, "too many arguments\n");
345 if (argc
&& mac_addr_a2n(mac
, argv
[0])) {
346 fprintf(stderr
, "invalid mac address\n");
354 genlmsg_put(msg
, 0, 0, genl_family_get_id(state
->nl80211
), 0, 0,
355 NL80211_CMD_DEL_STATION
, 0);
357 NLA_PUT_U32(msg
, NL80211_ATTR_IFINDEX
, if_nametoindex(dev
));
359 NLA_PUT(msg
, NL80211_ATTR_MAC
, ETH_ALEN
, mac
);
361 cb
= nl_cb_alloc(NL_CB_CUSTOM
);
365 if (nl_send_auto_complete(state
->nl_handle
, msg
) < 0)
368 nl_cb_set(cb
, NL_CB_VALID
, NL_CB_CUSTOM
, print_sta_handler
, NULL
);
369 nl_cb_set(cb
, NL_CB_ACK
, NL_CB_CUSTOM
, wait_handler
, &finished
);
370 nl_cb_err(cb
, NL_CB_CUSTOM
, error_handler
, NULL
);
372 err
= nl_recvmsgs(state
->nl_handle
, cb
);
375 err
= nl_wait_for_ack(state
->nl_handle
);
389 int handle_station(struct nl80211_state
*state
,
390 char *dev
, int argc
, char **argv
)
395 fprintf(stderr
, "you must specify an station command\n");
402 if (strcmp(cmd
, "del") == 0)
403 return handle_station_del(state
, dev
, argc
, argv
);
404 if (strcmp(cmd
, "get") == 0)
405 return handle_station_get(state
, dev
, argc
, argv
);
406 if (strcmp(cmd
, "set") == 0)
407 return handle_station_set(state
, dev
, argc
, argv
);
408 if (strcmp(cmd
, "dump") == 0)
409 return handle_station_dump(state
, dev
, argc
, argv
);
411 printf("invalid interface command %s\n", cmd
);