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
,
136 int argc
, char **argv
)
138 struct nl_cb
*cb
= NULL
;
141 unsigned char mac_addr
[ETH_ALEN
];
146 if (mac_addr_a2n(mac_addr
, argv
[0])) {
147 fprintf(stderr
, "invalid mac address\n");
157 NLA_PUT(msg
, NL80211_ATTR_MAC
, ETH_ALEN
, mac_addr
);
159 cb
= nl_cb_alloc(NL_CB_CUSTOM
);
163 if (nl_send_auto_complete(state
->nl_handle
, msg
) < 0)
166 nl_cb_set(cb
, NL_CB_VALID
, NL_CB_CUSTOM
, print_sta_handler
, NULL
);
167 nl_cb_set(cb
, NL_CB_ACK
, NL_CB_CUSTOM
, wait_handler
, &finished
);
168 nl_cb_err(cb
, NL_CB_CUSTOM
, error_handler
, NULL
);
170 nl_recvmsgs(state
->nl_handle
, cb
);
174 err
= nl_wait_for_ack(state
->nl_handle
);
181 COMMAND(station
, get
, "<MAC address>",
182 NL80211_CMD_GET_STATION
, 0, CIB_NETDEV
, handle_station_get
);
183 COMMAND(station
, del
, "<MAC address>",
184 NL80211_CMD_DEL_STATION
, 0, CIB_NETDEV
, handle_station_get
);
186 static int handle_station_set(struct nl80211_state
*state
,
188 int argc
, char **argv
)
190 struct nl_cb
*cb
= NULL
;
193 unsigned char plink_action
;
194 unsigned char mac_addr
[ETH_ALEN
];
199 if (mac_addr_a2n(mac_addr
, argv
[0])) {
200 fprintf(stderr
, "invalid mac address\n");
206 if (strcmp("plink_action", argv
[0]) != 0)
211 if (strcmp("open", argv
[0]) == 0)
212 plink_action
= PLINK_ACTION_OPEN
;
213 else if (strcmp("block", argv
[0]) == 0)
214 plink_action
= PLINK_ACTION_BLOCK
;
216 fprintf(stderr
, "plink action not supported\n");
225 NLA_PUT(msg
, NL80211_ATTR_MAC
, ETH_ALEN
, mac_addr
);
226 NLA_PUT_U8(msg
, NL80211_ATTR_STA_PLINK_ACTION
, plink_action
);
228 cb
= nl_cb_alloc(NL_CB_CUSTOM
);
232 if ((err
= nl_send_auto_complete(state
->nl_handle
, msg
)) < 0)
235 nl_cb_set(cb
, NL_CB_VALID
, NL_CB_CUSTOM
, print_sta_handler
, NULL
);
236 nl_cb_set(cb
, NL_CB_ACK
, NL_CB_CUSTOM
, wait_handler
, &finished
);
237 nl_cb_err(cb
, NL_CB_CUSTOM
, error_handler
, NULL
);
239 nl_recvmsgs(state
->nl_handle
, cb
);
243 err
= nl_wait_for_ack(state
->nl_handle
);
250 COMMAND(station
, set
, "<MAC address> plink_action <open|block>",
251 NL80211_CMD_SET_STATION
, 0, CIB_NETDEV
, handle_station_set
);
253 static int handle_station_dump(struct nl80211_state
*state
,
255 int argc
, char **argv
)
257 struct nl_cb
*cb
= NULL
;
264 cb
= nl_cb_alloc(NL_CB_CUSTOM
);
268 if ((err
= nl_send_auto_complete(state
->nl_handle
, msg
)) < 0)
271 nl_cb_set(cb
, NL_CB_VALID
, NL_CB_CUSTOM
, print_sta_handler
, NULL
);
272 nl_cb_set(cb
, NL_CB_FINISH
, NL_CB_CUSTOM
, wait_handler
, &finished
);
274 nl_recvmsgs(state
->nl_handle
, cb
);
278 err
= nl_wait_for_ack(state
->nl_handle
);
284 COMMAND(station
, dump
, NULL
,
285 NL80211_CMD_SET_STATION
, NLM_F_DUMP
, CIB_NETDEV
, handle_station_dump
);