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>
20 static int handle_scan(struct nl80211_state
*state
,
23 int argc
, char **argv
)
25 struct nl_msg
*ssids
= NULL
;
28 ssids
= nlmsg_alloc();
31 NLA_PUT(ssids
, 1, 0, "");
32 nla_put_nested(msg
, NL80211_ATTR_SCAN_SSIDS
, ssids
);
39 COMMAND(scan
, trigger
, NULL
,
40 NL80211_CMD_TRIGGER_SCAN
, 0, CIB_NETDEV
, handle_scan
);
42 typedef void (*printfn
)(unsigned char type
, unsigned char len
, unsigned char *data
);
44 static void print_ssid(unsigned char type
, unsigned char len
, unsigned char *data
)
48 for (i
=0; i
<len
; i
++) {
50 printf("%c", data
[i
]);
52 printf("\\x%.2x", data
[i
]);
57 static void print_supprates(unsigned char type
, unsigned char len
, unsigned char *data
)
62 printf("\tSupported rates: ");
64 printf("\tExtended supported rates: ");
66 for (i
=0; i
<len
; i
++) {
67 int r
= data
[i
] & 0x7f;
68 printf("%d.%d%s ", r
/2, 5*(r
&1), data
[i
] & 0x80 ? "*":"");
73 static void print_ds(unsigned char type
, unsigned char len
, unsigned char *data
)
75 printf("\tDS Parameter set: channel %d\n", data
[0]);
78 static void print_ign(unsigned char type
, unsigned char len
, unsigned char *data
)
80 /* ignore for now, not too useful */
83 static const printfn ieprinters
[] = {
85 [1] = print_supprates
,
88 [50] = print_supprates
,
91 static void print_vendor(unsigned char len
, unsigned char *data
,
92 struct scan_params
*params
)
97 printf("\tVendor specific: <too short> data:\n");
98 for(i
= 0; i
< len
; i
++)
99 printf(" %.02x", data
[i
]);
104 /* currently _all_ vendor IEs are unknown (not parsed) */
105 if (!params
->unknown
)
108 printf("\tVendor specific: OUI %.2x:%.2x:%.2x, data:",
109 data
[0], data
[1], data
[2]);
110 for (i
= 3; i
< len
; i
++)
111 printf(" %.2x", data
[i
]);
115 static void print_ies(unsigned char *ie
, int ielen
, struct scan_params
*params
)
117 while (ielen
>= 2 && ielen
>= ie
[1]) {
118 if (ie
[0] < ARRAY_SIZE(ieprinters
) && ieprinters
[ie
[0]]) {
119 ieprinters
[ie
[0]](ie
[0], ie
[1], ie
+ 2);
120 } else if (ie
[0] == 221 /* vendor */) {
121 print_vendor(ie
[1], ie
+ 2, params
);
122 } else if (params
->unknown
) {
125 printf("\tUnknown IE (%d):", ie
[0]);
126 for (i
=0; i
<ie
[1]; i
++)
127 printf(" %.2x", ie
[2+i
]);
135 static int print_bss_handler(struct nl_msg
*msg
, void *arg
)
137 struct nlattr
*tb
[NL80211_ATTR_MAX
+ 1];
138 struct genlmsghdr
*gnlh
= nlmsg_data(nlmsg_hdr(msg
));
139 struct nlattr
*bss
[NL80211_BSS_MAX
+ 1];
140 char mac_addr
[20], dev
[20];
141 static struct nla_policy bss_policy
[NL80211_BSS_MAX
+ 1] = {
142 [NL80211_BSS_TSF
] = { .type
= NLA_U64
},
143 [NL80211_BSS_FREQUENCY
] = { .type
= NLA_U32
},
144 [NL80211_BSS_BSSID
] = { },
145 [NL80211_BSS_BEACON_INTERVAL
] = { .type
= NLA_U16
},
146 [NL80211_BSS_CAPABILITY
] = { .type
= NLA_U16
},
147 [NL80211_BSS_INFORMATION_ELEMENTS
] = { },
148 [NL80211_BSS_SIGNAL_MBM
] = { .type
= NLA_U32
},
149 [NL80211_BSS_SIGNAL_UNSPEC
] = { .type
= NLA_U8
},
152 nla_parse(tb
, NL80211_ATTR_MAX
, genlmsg_attrdata(gnlh
, 0),
153 genlmsg_attrlen(gnlh
, 0), NULL
);
155 if (!tb
[NL80211_ATTR_BSS
]) {
156 fprintf(stderr
, "bss info missing!");
159 if (nla_parse_nested(bss
, NL80211_BSS_MAX
,
160 tb
[NL80211_ATTR_BSS
],
162 fprintf(stderr
, "failed to parse nested attributes!");
166 if (!bss
[NL80211_BSS_BSSID
])
169 mac_addr_n2a(mac_addr
, nla_data(bss
[NL80211_BSS_BSSID
]));
170 if_indextoname(nla_get_u32(tb
[NL80211_ATTR_IFINDEX
]), dev
);
171 printf("BSS %s (on %s)\n", mac_addr
, dev
);
173 if (bss
[NL80211_BSS_TSF
]) {
174 unsigned long long tsf
;
175 tsf
= (unsigned long long)nla_get_u64(bss
[NL80211_BSS_TSF
]);
176 printf("\tTSF: %llu usec (%llud, %.2lld:%.2llu:%.2llu)\n",
177 tsf
, tsf
/1000/1000/60/60/24, (tsf
/1000/1000/60/60) % 24,
178 (tsf
/1000/1000/60) % 60, (tsf
/1000/1000) % 60);
180 if (bss
[NL80211_BSS_FREQUENCY
])
181 printf("\tfreq: %d\n",
182 nla_get_u32(bss
[NL80211_BSS_FREQUENCY
]));
183 if (bss
[NL80211_BSS_BEACON_INTERVAL
])
184 printf("\tbeacon interval: %d\n",
185 nla_get_u16(bss
[NL80211_BSS_BEACON_INTERVAL
]));
186 if (bss
[NL80211_BSS_CAPABILITY
])
187 printf("\tcapability: 0x%.4x\n",
188 nla_get_u16(bss
[NL80211_BSS_CAPABILITY
]));
189 if (bss
[NL80211_BSS_SIGNAL_MBM
]) {
190 int s
= nla_get_u32(bss
[NL80211_BSS_SIGNAL_MBM
]);
191 printf("\tsignal: %d.%.2d dBm\n", s
/100, s
%100);
193 if (bss
[NL80211_BSS_SIGNAL_UNSPEC
]) {
194 unsigned char s
= nla_get_u8(bss
[NL80211_BSS_SIGNAL_UNSPEC
]);
195 printf("\tsignal: %d/100\n", s
);
197 if (bss
[NL80211_BSS_INFORMATION_ELEMENTS
])
198 print_ies(nla_data(bss
[NL80211_BSS_INFORMATION_ELEMENTS
]),
199 nla_len(bss
[NL80211_BSS_INFORMATION_ELEMENTS
]),
205 static struct scan_params scan_params
;
207 static int handle_scan_dump(struct nl80211_state
*state
,
210 int argc
, char **argv
)
215 scan_params
.unknown
= false;
216 if (argc
== 1 && !strcmp(argv
[0], "-u"))
217 scan_params
.unknown
= true;
219 nl_cb_set(cb
, NL_CB_VALID
, NL_CB_CUSTOM
, print_bss_handler
,
223 COMMAND(scan
, dump
, "[-u]",
224 NL80211_CMD_GET_SCAN
, NLM_F_DUMP
, CIB_NETDEV
, handle_scan_dump
);
226 static int handle_scan_combined(struct nl80211_state
*state
,
229 int argc
, char **argv
)
231 static char *trig_argv
[] = {
236 static char *dump_argv
[] = {
241 static const __u32 cmds
[] = {
242 NL80211_CMD_NEW_SCAN_RESULTS
,
243 NL80211_CMD_SCAN_ABORTED
,
247 trig_argv
[0] = argv
[0];
248 err
= handle_cmd(state
, II_NETDEV
, ARRAY_SIZE(trig_argv
), trig_argv
);
253 * WARNING: DO NOT COPY THIS CODE INTO YOUR APPLICATION
255 * This code has a bug, which requires creating a separate
256 * nl80211 socket to fix:
257 * It is possible for a NL80211_CMD_NEW_SCAN_RESULTS or
258 * NL80211_CMD_SCAN_ABORTED message to be sent by the kernel
259 * before (!) we listen to it, because we only start listening
260 * after we send our scan request.
262 * Doing it the other way around has a race condition as well,
263 * if you first open the events socket you may get a notification
264 * for a previous scan.
266 * The only proper way to fix this would be to listen to events
267 * before sending the command, and for the kernel to send the
268 * scan request along with the event, so that you can match up
269 * whether the scan you requested was finished or aborted (this
270 * may result in processing a scan that another application
271 * requested, but that doesn't seem to be a problem).
273 * Alas, the kernel doesn't do that (yet).
276 if (listen_events(state
, ARRAY_SIZE(cmds
), cmds
) ==
277 NL80211_CMD_SCAN_ABORTED
) {
278 printf("scan aborted!\n");
282 dump_argv
[0] = argv
[0];
283 return handle_cmd(state
, II_NETDEV
, ARRAY_SIZE(dump_argv
), dump_argv
);
285 TOPLEVEL(scan
, NULL
, 0, 0, CIB_NETDEV
, handle_scan_combined
);