1 #include <linux/nl80211.h>
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>
25 PLINK_ACTION_UNDEFINED
,
31 static int wait_handler(struct nl_msg
*msg
, void *arg
)
39 static int error_handler(struct sockaddr_nl
*nla
, struct nlmsgerr
*err
,
42 fprintf(stderr
, "nl80211 error %d\n", err
->error
);
46 static int print_sta_handler(struct nl_msg
*msg
, void *arg
)
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
},
61 nla_parse(tb
, NL80211_ATTR_MAX
, genlmsg_attrdata(gnlh
, 0),
62 genlmsg_attrlen(gnlh
, 0), NULL
);
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.
70 if (!tb
[NL80211_ATTR_STA_INFO
]) {
71 fprintf(stderr
, "sta stats missing!");
74 if (nla_parse_nested(sinfo
, NL80211_STA_INFO_MAX
,
75 tb
[NL80211_ATTR_STA_INFO
],
77 fprintf(stderr
, "failed to parse nested attributes!");
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
);
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
])) {
103 strcpy(state_name
, "LISTEN");
106 strcpy(state_name
, "OPN_SNT");
109 strcpy(state_name
, "OPN_RCVD");
112 strcpy(state_name
, "CNF_RCVD");
115 strcpy(state_name
, "ESTAB");
118 strcpy(state_name
, "HOLDING");
121 strcpy(state_name
, "BLOCKED");
124 strcpy(state_name
, "UNKNOWN");
127 printf("\n\tmesh plink:\t%s", state_name
);
134 static int handle_station_get(struct nl80211_state
*state
,
135 char *dev
, int argc
, char **argv
)
138 struct nl_cb
*cb
= NULL
;
142 unsigned char mac_addr
[ETH_ALEN
];
145 fprintf(stderr
, "not enough arguments\n");
149 if (mac_addr_a2n(mac_addr
, argv
[0])) {
150 fprintf(stderr
, "invalid mac address\n");
158 fprintf(stderr
, "too many arguments\n");
166 genlmsg_put(msg
, 0, 0, genl_family_get_id(state
->nl80211
), 0,
167 0, NL80211_CMD_GET_STATION
, 0);
169 NLA_PUT(msg
, NL80211_ATTR_MAC
, ETH_ALEN
, mac_addr
);
170 NLA_PUT_U32(msg
, NL80211_ATTR_IFINDEX
, if_nametoindex(dev
));
172 cb
= nl_cb_alloc(NL_CB_CUSTOM
);
176 if (nl_send_auto_complete(state
->nl_handle
, msg
) < 0)
179 nl_cb_set(cb
, NL_CB_VALID
, NL_CB_CUSTOM
, print_sta_handler
, NULL
);
180 nl_cb_set(cb
, NL_CB_ACK
, NL_CB_CUSTOM
, wait_handler
, &finished
);
181 nl_cb_err(cb
, NL_CB_CUSTOM
, error_handler
, NULL
);
183 err
= nl_recvmsgs(state
->nl_handle
, cb
);
186 err
= nl_wait_for_ack(state
->nl_handle
);
200 static int handle_station_set(struct nl80211_state
*state
,
201 char *dev
, int argc
, char **argv
)
204 struct nl_cb
*cb
= NULL
;
208 unsigned char plink_action
;
209 unsigned char mac_addr
[ETH_ALEN
];
212 fprintf(stderr
, "not enough arguments\n");
216 if (mac_addr_a2n(mac_addr
, argv
[0])) {
217 fprintf(stderr
, "invalid mac address\n");
223 if (strcmp("plink_action", argv
[0]) != 0) {
224 fprintf(stderr
, "parameter not supported\n");
230 if (strcmp("open", argv
[0]) == 0)
231 plink_action
= PLINK_ACTION_OPEN
;
232 else if (strcmp("block", argv
[0]) == 0)
233 plink_action
= PLINK_ACTION_BLOCK
;
235 fprintf(stderr
, "plink action not supported\n");
242 fprintf(stderr
, "too many arguments\n");
250 genlmsg_put(msg
, 0, 0, genl_family_get_id(state
->nl80211
), 0,
251 0, NL80211_CMD_SET_STATION
, 0);
253 NLA_PUT(msg
, NL80211_ATTR_MAC
, ETH_ALEN
, mac_addr
);
254 NLA_PUT_U32(msg
, NL80211_ATTR_IFINDEX
, if_nametoindex(dev
));
255 NLA_PUT_U8(msg
, NL80211_ATTR_STA_PLINK_ACTION
, plink_action
);
257 cb
= nl_cb_alloc(NL_CB_CUSTOM
);
261 if (nl_send_auto_complete(state
->nl_handle
, msg
) < 0)
264 nl_cb_set(cb
, NL_CB_VALID
, NL_CB_CUSTOM
, print_sta_handler
, NULL
);
265 nl_cb_set(cb
, NL_CB_ACK
, NL_CB_CUSTOM
, wait_handler
, &finished
);
266 nl_cb_err(cb
, NL_CB_CUSTOM
, error_handler
, NULL
);
268 err
= nl_recvmsgs(state
->nl_handle
, cb
);
271 err
= nl_wait_for_ack(state
->nl_handle
);
284 static int handle_station_dump(struct nl80211_state
*state
,
285 char *dev
, int argc
, char **argv
)
288 struct nl_cb
*cb
= NULL
;
294 fprintf(stderr
, "too many arguments\n");
302 genlmsg_put(msg
, 0, 0, genl_family_get_id(state
->nl80211
), 0,
303 NLM_F_DUMP
, NL80211_CMD_GET_STATION
, 0);
305 NLA_PUT_U32(msg
, NL80211_ATTR_IFINDEX
, if_nametoindex(dev
));
307 cb
= nl_cb_alloc(NL_CB_CUSTOM
);
311 if (nl_send_auto_complete(state
->nl_handle
, msg
) < 0)
314 nl_cb_set(cb
, NL_CB_VALID
, NL_CB_CUSTOM
, print_sta_handler
, NULL
);
315 nl_cb_set(cb
, NL_CB_FINISH
, NL_CB_CUSTOM
, wait_handler
, &finished
);
317 err
= nl_recvmsgs(state
->nl_handle
, cb
);
331 static int handle_station_del(struct nl80211_state
*state
,
332 char *dev
, int argc
, char **argv
)
335 struct nl_cb
*cb
= NULL
;
339 unsigned char mac
[ETH_ALEN
];
342 fprintf(stderr
, "too many arguments\n");
346 if (argc
&& mac_addr_a2n(mac
, argv
[0])) {
347 fprintf(stderr
, "invalid mac address\n");
355 genlmsg_put(msg
, 0, 0, genl_family_get_id(state
->nl80211
), 0, 0,
356 NL80211_CMD_DEL_STATION
, 0);
358 NLA_PUT_U32(msg
, NL80211_ATTR_IFINDEX
, if_nametoindex(dev
));
360 NLA_PUT(msg
, NL80211_ATTR_MAC
, ETH_ALEN
, mac
);
362 cb
= nl_cb_alloc(NL_CB_CUSTOM
);
366 if (nl_send_auto_complete(state
->nl_handle
, msg
) < 0)
369 nl_cb_set(cb
, NL_CB_VALID
, NL_CB_CUSTOM
, print_sta_handler
, NULL
);
370 nl_cb_set(cb
, NL_CB_ACK
, NL_CB_CUSTOM
, wait_handler
, &finished
);
371 nl_cb_err(cb
, NL_CB_CUSTOM
, error_handler
, NULL
);
373 err
= nl_recvmsgs(state
->nl_handle
, cb
);
376 err
= nl_wait_for_ack(state
->nl_handle
);
390 int handle_station(struct nl80211_state
*state
,
391 char *dev
, int argc
, char **argv
)
396 fprintf(stderr
, "you must specify an station command\n");
403 if (strcmp(cmd
, "del") == 0)
404 return handle_station_del(state
, dev
, argc
, argv
);
405 if (strcmp(cmd
, "get") == 0)
406 return handle_station_get(state
, dev
, argc
, argv
);
407 if (strcmp(cmd
, "set") == 0)
408 return handle_station_set(state
, dev
, argc
, argv
);
409 if (strcmp(cmd
, "dump") == 0)
410 return handle_station_dump(state
, dev
, argc
, argv
);
412 printf("invalid interface command %s\n", cmd
);