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>
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_FREQUENCY_OFFSET
] = { .type
= NLA_U32
},
33 [NL80211_BSS_BSSID
] = { },
34 [NL80211_BSS_BEACON_INTERVAL
] = { .type
= NLA_U16
},
35 [NL80211_BSS_CAPABILITY
] = { .type
= NLA_U16
},
36 [NL80211_BSS_INFORMATION_ELEMENTS
] = { },
37 [NL80211_BSS_SIGNAL_MBM
] = { .type
= NLA_U32
},
38 [NL80211_BSS_SIGNAL_UNSPEC
] = { .type
= NLA_U8
},
39 [NL80211_BSS_STATUS
] = { .type
= NLA_U32
},
41 struct link_result
*result
= arg
;
42 char mac_addr
[20], dev
[20], link_addr
[20];
44 const char *indent
= "\t";
47 nla_parse(tb
, NL80211_ATTR_MAX
, genlmsg_attrdata(gnlh
, 0),
48 genlmsg_attrlen(gnlh
, 0), NULL
);
50 if (!tb
[NL80211_ATTR_BSS
]) {
51 fprintf(stderr
, "bss info missing!\n");
54 if (nla_parse_nested(bss
, NL80211_BSS_MAX
,
57 fprintf(stderr
, "failed to parse nested attributes!\n");
61 if (!bss
[NL80211_BSS_BSSID
])
64 if (!bss
[NL80211_BSS_STATUS
])
67 mac_addr_n2a(mac_addr
, nla_data(bss
[NL80211_BSS_BSSID
]));
68 if_indextoname(nla_get_u32(tb
[NL80211_ATTR_IFINDEX
]), dev
);
70 if (bss
[NL80211_BSS_MLO_LINK_ID
])
71 link_id
= nla_get_u8(bss
[NL80211_BSS_MLO_LINK_ID
]);
73 if (bss
[NL80211_BSS_MLD_ADDR
]) {
74 mac_addr_n2a(link_addr
, nla_data(bss
[NL80211_BSS_BSSID
]));
78 if (memcmp(result
->sta_addr
,
79 nla_data(bss
[NL80211_BSS_MLD_ADDR
]), 6)) {
80 mac_addr_n2a(mac_addr
, nla_data(bss
[NL80211_BSS_MLD_ADDR
]));
81 printf("!! inconsistent MLD address information (%s)\n",
85 mac_addr_n2a(mac_addr
, nla_data(bss
[NL80211_BSS_MLD_ADDR
]));
87 memcpy(result
->sta_addr
,
88 nla_data(bss
[NL80211_BSS_MLD_ADDR
]), 6);
89 if (nla_get_u32(bss
[NL80211_BSS_STATUS
]) == NL80211_BSS_STATUS_ASSOCIATED
) {
90 printf("Connected to %s (on %s)\n", mac_addr
, dev
);
93 if (bss
[NL80211_BSS_INFORMATION_ELEMENTS
])
94 print_ies(nla_data(bss
[NL80211_BSS_INFORMATION_ELEMENTS
]),
95 nla_len(bss
[NL80211_BSS_INFORMATION_ELEMENTS
]),
96 false, PRINT_LINK_MLO_MLD
);
99 memcpy(result
->sta_addr
, nla_data(bss
[NL80211_BSS_BSSID
]), 6);
102 switch (nla_get_u32(bss
[NL80211_BSS_STATUS
])) {
103 case NL80211_BSS_STATUS_ASSOCIATED
:
105 printf("\tLink %d BSSID %s\n", link_id
, link_addr
);
107 printf("Connected to %s (on %s)\n", mac_addr
, dev
);
109 case NL80211_BSS_STATUS_AUTHENTICATED
:
110 printf("Authenticated with %s (on %s)\n", mac_addr
, dev
);
112 case NL80211_BSS_STATUS_IBSS_JOINED
:
113 printf("Joined IBSS %s (on %s)\n", mac_addr
, dev
);
119 result
->anything_found
= true;
121 if (bss
[NL80211_BSS_INFORMATION_ELEMENTS
])
122 print_ies(nla_data(bss
[NL80211_BSS_INFORMATION_ELEMENTS
]),
123 nla_len(bss
[NL80211_BSS_INFORMATION_ELEMENTS
]),
124 false, result
->mld
? PRINT_LINK_MLO_LINK
: PRINT_LINK
);
126 if (bss
[NL80211_BSS_FREQUENCY_OFFSET
])
127 freq_offset
= nla_get_u32(bss
[NL80211_BSS_FREQUENCY_OFFSET
]);
129 if (bss
[NL80211_BSS_FREQUENCY
])
130 printf("%sfreq: %d.%d\n", indent
,
131 nla_get_u32(bss
[NL80211_BSS_FREQUENCY
]), freq_offset
);
133 if (nla_get_u32(bss
[NL80211_BSS_STATUS
]) != NL80211_BSS_STATUS_ASSOCIATED
)
136 /* only in the assoc case do we want more info from station get */
137 result
->link_found
= true;
141 static int handle_scan_for_link(struct nl80211_state
*state
,
143 int argc
, char **argv
,
149 register_handler(link_bss_handler
, &lr
);
153 static int print_link_sta(struct nl_msg
*msg
, void *arg
)
155 struct nlattr
*tb
[NL80211_ATTR_MAX
+ 1];
156 struct genlmsghdr
*gnlh
= nlmsg_data(nlmsg_hdr(msg
));
157 struct nlattr
*sinfo
[NL80211_STA_INFO_MAX
+ 1];
158 struct nlattr
*binfo
[NL80211_STA_BSS_PARAM_MAX
+ 1];
159 static struct nla_policy stats_policy
[NL80211_STA_INFO_MAX
+ 1] = {
160 [NL80211_STA_INFO_INACTIVE_TIME
] = { .type
= NLA_U32
},
161 [NL80211_STA_INFO_RX_BYTES
] = { .type
= NLA_U32
},
162 [NL80211_STA_INFO_TX_BYTES
] = { .type
= NLA_U32
},
163 [NL80211_STA_INFO_RX_PACKETS
] = { .type
= NLA_U32
},
164 [NL80211_STA_INFO_TX_PACKETS
] = { .type
= NLA_U32
},
165 [NL80211_STA_INFO_SIGNAL
] = { .type
= NLA_U8
},
166 [NL80211_STA_INFO_RX_BITRATE
] = { .type
= NLA_NESTED
},
167 [NL80211_STA_INFO_TX_BITRATE
] = { .type
= NLA_NESTED
},
168 [NL80211_STA_INFO_LLID
] = { .type
= NLA_U16
},
169 [NL80211_STA_INFO_PLID
] = { .type
= NLA_U16
},
170 [NL80211_STA_INFO_PLINK_STATE
] = { .type
= NLA_U8
},
172 static struct nla_policy bss_policy
[NL80211_STA_BSS_PARAM_MAX
+ 1] = {
173 [NL80211_STA_BSS_PARAM_CTS_PROT
] = { .type
= NLA_FLAG
},
174 [NL80211_STA_BSS_PARAM_SHORT_PREAMBLE
] = { .type
= NLA_FLAG
},
175 [NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME
] = { .type
= NLA_FLAG
},
176 [NL80211_STA_BSS_PARAM_DTIM_PERIOD
] = { .type
= NLA_U8
},
177 [NL80211_STA_BSS_PARAM_BEACON_INTERVAL
] = { .type
= NLA_U16
},
180 nla_parse(tb
, NL80211_ATTR_MAX
, genlmsg_attrdata(gnlh
, 0),
181 genlmsg_attrlen(gnlh
, 0), NULL
);
183 if (!tb
[NL80211_ATTR_STA_INFO
]) {
184 fprintf(stderr
, "sta stats missing!\n");
187 if (nla_parse_nested(sinfo
, NL80211_STA_INFO_MAX
,
188 tb
[NL80211_ATTR_STA_INFO
],
190 fprintf(stderr
, "failed to parse nested attributes!\n");
194 if (sinfo
[NL80211_STA_INFO_RX_BYTES
] && sinfo
[NL80211_STA_INFO_RX_PACKETS
])
195 printf("\tRX: %u bytes (%u packets)\n",
196 nla_get_u32(sinfo
[NL80211_STA_INFO_RX_BYTES
]),
197 nla_get_u32(sinfo
[NL80211_STA_INFO_RX_PACKETS
]));
198 if (sinfo
[NL80211_STA_INFO_TX_BYTES
] && sinfo
[NL80211_STA_INFO_TX_PACKETS
])
199 printf("\tTX: %u bytes (%u packets)\n",
200 nla_get_u32(sinfo
[NL80211_STA_INFO_TX_BYTES
]),
201 nla_get_u32(sinfo
[NL80211_STA_INFO_TX_PACKETS
]));
202 if (sinfo
[NL80211_STA_INFO_SIGNAL
])
203 printf("\tsignal: %d dBm\n",
204 (int8_t)nla_get_u8(sinfo
[NL80211_STA_INFO_SIGNAL
]));
206 if (sinfo
[NL80211_STA_INFO_RX_BITRATE
]) {
209 parse_bitrate(sinfo
[NL80211_STA_INFO_RX_BITRATE
], buf
, sizeof(buf
));
210 printf("\trx bitrate: %s\n", buf
);
212 if (sinfo
[NL80211_STA_INFO_TX_BITRATE
]) {
215 parse_bitrate(sinfo
[NL80211_STA_INFO_TX_BITRATE
], buf
, sizeof(buf
));
216 printf("\ttx bitrate: %s\n", buf
);
219 if (sinfo
[NL80211_STA_INFO_BSS_PARAM
]) {
220 if (nla_parse_nested(binfo
, NL80211_STA_BSS_PARAM_MAX
,
221 sinfo
[NL80211_STA_INFO_BSS_PARAM
],
223 fprintf(stderr
, "failed to parse nested bss parameters!\n");
226 printf("\tbss flags: ");
227 if (binfo
[NL80211_STA_BSS_PARAM_CTS_PROT
]) {
228 printf("CTS-protection");
231 if (binfo
[NL80211_STA_BSS_PARAM_SHORT_PREAMBLE
]) {
232 printf("%sshort-preamble", delim
);
235 if (binfo
[NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME
])
236 printf("%sshort-slot-time", delim
);
237 printf("\n\tdtim period: %d",
238 nla_get_u8(binfo
[NL80211_STA_BSS_PARAM_DTIM_PERIOD
]));
239 printf("\n\tbeacon int: %d",
240 nla_get_u16(binfo
[NL80211_STA_BSS_PARAM_BEACON_INTERVAL
]));
248 static int handle_link_sta(struct nl80211_state
*state
,
250 int argc
, char **argv
,
253 unsigned char mac_addr
[ETH_ALEN
];
258 if (mac_addr_a2n(mac_addr
, argv
[0])) {
259 fprintf(stderr
, "invalid mac address\n");
269 NLA_PUT(msg
, NL80211_ATTR_MAC
, ETH_ALEN
, mac_addr
);
271 register_handler(print_link_sta
, NULL
);
278 static int handle_link(struct nl80211_state
*state
,
279 struct nl_msg
*msg
, int argc
, char **argv
,
282 char *link_argv
[] = {
288 char *station_argv
[] = {
298 link_argv
[0] = argv
[0];
299 err
= handle_cmd(state
, id
, 3, link_argv
);
303 if (!lr
.link_found
) {
304 if (!lr
.anything_found
)
305 printf("Not connected.\n");
309 mac_addr_n2a(addr_buf
, lr
.sta_addr
);
313 printf("MLD %s stats:\n", addr_buf
);
315 station_argv
[0] = argv
[0];
316 station_argv
[3] = addr_buf
;
317 return handle_cmd(state
, id
, 4, station_argv
);
319 TOPLEVEL(link
, NULL
, 0, 0, CIB_NETDEV
, handle_link
,
320 "Print information about the current connection, if any.");
321 HIDDEN(link
, get_sta
, "<mac-addr>", NL80211_CMD_GET_STATION
, 0,
322 CIB_NETDEV
, handle_link_sta
);
323 HIDDEN(link
, get_bss
, NULL
, NL80211_CMD_GET_SCAN
, NLM_F_DUMP
,
324 CIB_NETDEV
, handle_scan_for_link
);