7 #include <netlink/genl/genl.h>
8 #include <netlink/genl/family.h>
9 #include <netlink/genl/ctrl.h>
10 #include <netlink/msg.h>
11 #include <netlink/attr.h>
22 static struct link_result lr
= { .link_found
= false };
24 static int link_bss_handler(struct nl_msg
*msg
, void *arg
)
26 struct nlattr
*tb
[NL80211_ATTR_MAX
+ 1];
27 struct genlmsghdr
*gnlh
= nlmsg_data(nlmsg_hdr(msg
));
28 struct nlattr
*bss
[NL80211_BSS_MAX
+ 1];
29 static struct nla_policy bss_policy
[NL80211_BSS_MAX
+ 1] = {
30 [NL80211_BSS_TSF
] = { .type
= NLA_U64
},
31 [NL80211_BSS_FREQUENCY
] = { .type
= NLA_U32
},
32 [NL80211_BSS_BSSID
] = { },
33 [NL80211_BSS_BEACON_INTERVAL
] = { .type
= NLA_U16
},
34 [NL80211_BSS_CAPABILITY
] = { .type
= NLA_U16
},
35 [NL80211_BSS_INFORMATION_ELEMENTS
] = { },
36 [NL80211_BSS_SIGNAL_MBM
] = { .type
= NLA_U32
},
37 [NL80211_BSS_SIGNAL_UNSPEC
] = { .type
= NLA_U8
},
38 [NL80211_BSS_STATUS
] = { .type
= NLA_U32
},
40 struct link_result
*result
= arg
;
41 char mac_addr
[20], dev
[20];
43 nla_parse(tb
, NL80211_ATTR_MAX
, genlmsg_attrdata(gnlh
, 0),
44 genlmsg_attrlen(gnlh
, 0), NULL
);
46 if (!tb
[NL80211_ATTR_BSS
]) {
47 fprintf(stderr
, "bss info missing!\n");
50 if (nla_parse_nested(bss
, NL80211_BSS_MAX
,
53 fprintf(stderr
, "failed to parse nested attributes!\n");
57 if (!bss
[NL80211_BSS_BSSID
])
60 if (!bss
[NL80211_BSS_STATUS
])
63 mac_addr_n2a(mac_addr
, nla_data(bss
[NL80211_BSS_BSSID
]));
64 if_indextoname(nla_get_u32(tb
[NL80211_ATTR_IFINDEX
]), dev
);
66 switch (nla_get_u32(bss
[NL80211_BSS_STATUS
])) {
67 case NL80211_BSS_STATUS_ASSOCIATED
:
68 printf("Connected to %s (on %s)\n", mac_addr
, dev
);
70 case NL80211_BSS_STATUS_AUTHENTICATED
:
71 printf("Authenticated with %s (on %s)\n", mac_addr
, dev
);
73 case NL80211_BSS_STATUS_IBSS_JOINED
:
74 printf("Joined IBSS %s (on %s)\n", mac_addr
, dev
);
80 result
->anything_found
= true;
82 if (bss
[NL80211_BSS_INFORMATION_ELEMENTS
])
83 print_ies(nla_data(bss
[NL80211_BSS_INFORMATION_ELEMENTS
]),
84 nla_len(bss
[NL80211_BSS_INFORMATION_ELEMENTS
]),
87 if (bss
[NL80211_BSS_FREQUENCY
])
88 printf("\tfreq: %d\n",
89 nla_get_u32(bss
[NL80211_BSS_FREQUENCY
]));
91 if (nla_get_u32(bss
[NL80211_BSS_STATUS
]) != NL80211_BSS_STATUS_ASSOCIATED
)
94 /* only in the assoc case do we want more info from station get */
95 result
->link_found
= true;
96 memcpy(result
->bssid
, nla_data(bss
[NL80211_BSS_BSSID
]), 6);
100 static int handle_scan_for_link(struct nl80211_state
*state
,
103 int argc
, char **argv
,
109 nl_cb_set(cb
, NL_CB_VALID
, NL_CB_CUSTOM
, link_bss_handler
, &lr
);
113 static int print_link_sta(struct nl_msg
*msg
, void *arg
)
115 struct nlattr
*tb
[NL80211_ATTR_MAX
+ 1];
116 struct genlmsghdr
*gnlh
= nlmsg_data(nlmsg_hdr(msg
));
117 struct nlattr
*sinfo
[NL80211_STA_INFO_MAX
+ 1];
118 struct nlattr
*rinfo
[NL80211_RATE_INFO_MAX
+ 1];
119 struct nlattr
*binfo
[NL80211_STA_BSS_PARAM_MAX
+ 1];
120 static struct nla_policy stats_policy
[NL80211_STA_INFO_MAX
+ 1] = {
121 [NL80211_STA_INFO_INACTIVE_TIME
] = { .type
= NLA_U32
},
122 [NL80211_STA_INFO_RX_BYTES
] = { .type
= NLA_U32
},
123 [NL80211_STA_INFO_TX_BYTES
] = { .type
= NLA_U32
},
124 [NL80211_STA_INFO_RX_PACKETS
] = { .type
= NLA_U32
},
125 [NL80211_STA_INFO_TX_PACKETS
] = { .type
= NLA_U32
},
126 [NL80211_STA_INFO_SIGNAL
] = { .type
= NLA_U8
},
127 [NL80211_STA_INFO_TX_BITRATE
] = { .type
= NLA_NESTED
},
128 [NL80211_STA_INFO_LLID
] = { .type
= NLA_U16
},
129 [NL80211_STA_INFO_PLID
] = { .type
= NLA_U16
},
130 [NL80211_STA_INFO_PLINK_STATE
] = { .type
= NLA_U8
},
133 static struct nla_policy rate_policy
[NL80211_RATE_INFO_MAX
+ 1] = {
134 [NL80211_RATE_INFO_BITRATE
] = { .type
= NLA_U16
},
135 [NL80211_RATE_INFO_BITRATE32
] = { .type
= NLA_U32
},
136 [NL80211_RATE_INFO_MCS
] = { .type
= NLA_U8
},
137 [NL80211_RATE_INFO_40_MHZ_WIDTH
] = { .type
= NLA_FLAG
},
138 [NL80211_RATE_INFO_SHORT_GI
] = { .type
= NLA_FLAG
},
140 static struct nla_policy bss_policy
[NL80211_STA_BSS_PARAM_MAX
+ 1] = {
141 [NL80211_STA_BSS_PARAM_CTS_PROT
] = { .type
= NLA_FLAG
},
142 [NL80211_STA_BSS_PARAM_SHORT_PREAMBLE
] = { .type
= NLA_FLAG
},
143 [NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME
] = { .type
= NLA_FLAG
},
144 [NL80211_STA_BSS_PARAM_DTIM_PERIOD
] = { .type
= NLA_U8
},
145 [NL80211_STA_BSS_PARAM_BEACON_INTERVAL
] = { .type
= NLA_U16
},
148 nla_parse(tb
, NL80211_ATTR_MAX
, genlmsg_attrdata(gnlh
, 0),
149 genlmsg_attrlen(gnlh
, 0), NULL
);
151 if (!tb
[NL80211_ATTR_STA_INFO
]) {
152 fprintf(stderr
, "sta stats missing!\n");
155 if (nla_parse_nested(sinfo
, NL80211_STA_INFO_MAX
,
156 tb
[NL80211_ATTR_STA_INFO
],
158 fprintf(stderr
, "failed to parse nested attributes!\n");
162 if (sinfo
[NL80211_STA_INFO_RX_BYTES
] && sinfo
[NL80211_STA_INFO_RX_PACKETS
])
163 printf("\tRX: %u bytes (%u packets)\n",
164 nla_get_u32(sinfo
[NL80211_STA_INFO_RX_BYTES
]),
165 nla_get_u32(sinfo
[NL80211_STA_INFO_RX_PACKETS
]));
166 if (sinfo
[NL80211_STA_INFO_TX_BYTES
] && sinfo
[NL80211_STA_INFO_TX_PACKETS
])
167 printf("\tTX: %u bytes (%u packets)\n",
168 nla_get_u32(sinfo
[NL80211_STA_INFO_TX_BYTES
]),
169 nla_get_u32(sinfo
[NL80211_STA_INFO_TX_PACKETS
]));
170 if (sinfo
[NL80211_STA_INFO_SIGNAL
])
171 printf("\tsignal: %d dBm\n",
172 (int8_t)nla_get_u8(sinfo
[NL80211_STA_INFO_SIGNAL
]));
174 if (sinfo
[NL80211_STA_INFO_TX_BITRATE
]) {
175 if (nla_parse_nested(rinfo
, NL80211_RATE_INFO_MAX
,
176 sinfo
[NL80211_STA_INFO_TX_BITRATE
], rate_policy
)) {
177 fprintf(stderr
, "failed to parse nested rate attributes!\n");
180 printf("\ttx bitrate: ");
181 if (rinfo
[NL80211_RATE_INFO_BITRATE32
])
182 rate
= nla_get_u32(rinfo
[NL80211_RATE_INFO_BITRATE32
]);
183 else if (rinfo
[NL80211_RATE_INFO_BITRATE
])
184 rate
= nla_get_u16(rinfo
[NL80211_RATE_INFO_BITRATE
]);
186 printf("%d.%d MBit/s", rate
/ 10, rate
% 10);
188 if (rinfo
[NL80211_RATE_INFO_MCS
])
189 printf(" MCS %d", nla_get_u8(rinfo
[NL80211_RATE_INFO_MCS
]));
190 if (rinfo
[NL80211_RATE_INFO_40_MHZ_WIDTH
])
192 if (rinfo
[NL80211_RATE_INFO_SHORT_GI
])
198 if (sinfo
[NL80211_STA_INFO_BSS_PARAM
]) {
199 if (nla_parse_nested(binfo
, NL80211_STA_BSS_PARAM_MAX
,
200 sinfo
[NL80211_STA_INFO_BSS_PARAM
],
202 fprintf(stderr
, "failed to parse nested bss parameters!\n");
205 printf("\n\tbss flags:\t");
206 if (binfo
[NL80211_STA_BSS_PARAM_CTS_PROT
]) {
207 printf("CTS-protection");
210 if (binfo
[NL80211_STA_BSS_PARAM_SHORT_PREAMBLE
]) {
211 printf("%sshort-preamble", delim
);
214 if (binfo
[NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME
])
215 printf("%sshort-slot-time", delim
);
216 printf("\n\tdtim period:\t%d",
217 nla_get_u8(binfo
[NL80211_STA_BSS_PARAM_DTIM_PERIOD
]));
218 printf("\n\tbeacon int:\t%d",
219 nla_get_u16(binfo
[NL80211_STA_BSS_PARAM_BEACON_INTERVAL
]));
227 static int handle_link_sta(struct nl80211_state
*state
,
230 int argc
, char **argv
,
233 unsigned char mac_addr
[ETH_ALEN
];
238 if (mac_addr_a2n(mac_addr
, argv
[0])) {
239 fprintf(stderr
, "invalid mac address\n");
249 NLA_PUT(msg
, NL80211_ATTR_MAC
, ETH_ALEN
, mac_addr
);
251 nl_cb_set(cb
, NL_CB_VALID
, NL_CB_CUSTOM
, print_link_sta
, NULL
);
258 static int handle_link(struct nl80211_state
*state
, struct nl_cb
*cb
,
259 struct nl_msg
*msg
, int argc
, char **argv
,
262 char *link_argv
[] = {
268 char *station_argv
[] = {
278 link_argv
[0] = argv
[0];
279 err
= handle_cmd(state
, id
, 3, link_argv
);
283 if (!lr
.link_found
) {
284 if (!lr
.anything_found
)
285 printf("Not connected.\n");
289 mac_addr_n2a(bssid_buf
, lr
.bssid
);
290 bssid_buf
[17] = '\0';
292 station_argv
[0] = argv
[0];
293 station_argv
[3] = bssid_buf
;
294 return handle_cmd(state
, id
, 4, station_argv
);
296 TOPLEVEL(link
, NULL
, 0, 0, CIB_NETDEV
, handle_link
,
297 "Print information about the current link, if any.");
298 HIDDEN(link
, get_sta
, "", NL80211_CMD_GET_STATION
, 0,
299 CIB_NETDEV
, handle_link_sta
);
300 HIDDEN(link
, get_bss
, NULL
, NL80211_CMD_GET_SCAN
, NLM_F_DUMP
,
301 CIB_NETDEV
, handle_scan_for_link
);