2010-08-16 19:06:31

by Christopher Piggott

[permalink] [raw]
Subject: nl80211 scanning from userspace

Hi,

I'm trying to figure out how to use nl80211 to scan. ?The "iw" example
has been somewhat helpful, though the userspace header file nl80211
and /usr/include/netlink/*.h have been helpful. ?I'm on an ubuntu
system, and I'm sorry to say that the libnl1-doc package has some
doxygen files in it that don't agree with the actual headers (function
prototypes differ, etc.) but it's enough to get at least some picture
of what's going on.

Here's what I have put together so far, in snippets:

Register callbacks for all messages:
?? ?callbacks = nl_cb_alloc(NL_CB_DEFAULT);
?? ?nl_cb_set_all(callbacks, ?NL_CB_CUSTOM, rx, NULL);

Create a socket, allocate a cache. ?I do error checking on each of
these calls to make sure they succeed, but I'm eliminating that here
for brevity:
?? ?genl_connect(sock);
?? ?cache = genl_ctrl_alloc_cache(sock);
?? ?nl80211 = genl_ctrl_search_by_name(cache, cacheName); ? /*
cacheName is "nl80211" */

Start building the message. ?First build an SSID list with one entry
in it (empty string)
?? ?struct nl_msg *ssids?= nlmsg_alloc();
?? ?nla_put_string(ssids, 0, "");

Next build the scan request message:
?? ?struct nl_msg *msg = nlmsg_alloc();
?? ?int flags = 0;
?? ?int cmd = NL80211_CMD_TRIGGER_SCAN;
?? ?genlmsg_put(msg, 0, 0, genl_family_get_id(nl80211), 0,?flags, cmd, 0);
?? ?/* append our ssid list to this message as a nested message */
?? ?nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids)

Finally I send the request:
?? ?int rc = nl_send_auto_complete(sock, msg);

>From this I found out that 32 bytes were sent (seems reasonable).
Unfortunately, what I get back is this:
??[HEADER] 16 octets
?? ?.nlmsg_len = 52
?? ?.nlmsg_type = 2 <ERROR>
?? ?.nlmsg_flags = 0 <>
?? ?.nlmsg_seq = 1282012377
?? ?.nlmsg_pid = 30415
??[ERRORMSG] 20 octets
?? ?.error = -22 "Invalid argument"
??[ORIGINAL MESSAGE] 16 octets
?? ?.nlmsg_len = 16
?? ?.nlmsg_type = 23 <0x17>
?? ?.nlmsg_flags = 5 <REQUEST,ACK>
?? ?.nlmsg_seq = 1282012377
?? ?.nlmsg_pid = 30415

so, even following what iw's "scan.c" does I have somehow pieced the
request together incorrectly.

Questions:
1. Am I doing something obviously wrong?
2. Is this even the interface I should be using to do this? ?(I need
to scan for all access points on a specific "hidden" SSID to retrieve
some information about their SNR. ?It's a type of "site survey"
application for building contour maps of coverage).

I'm not sure what I'm doing next makes sense, either. ?After I send
the scan request I wait 3 seconds then start reading like this:
?? ?while(nl_recvmsgs(sock, callbacks) != 0)
?? ?{
?? ? ? ?printf("processed a result\n");
?? ?}

I have registered my callback earlier; this seems to work because I
get the message (above) plus later an "Operation Not Supported"
message. ?The operation is indeed supported, as it works with the
iwlist and iw command line tools.

--Chris


2010-08-16 19:13:49

by Johannes Berg

[permalink] [raw]
Subject: Re: nl80211 scanning from userspace

On Mon, 2010-08-16 at 15:06 -0400, Christopher Piggott wrote:

> Start building the message. First build an SSID list with one entry
> in it (empty string)
> struct nl_msg *ssids = nlmsg_alloc();
> nla_put_string(ssids, 0, "");

I think that has to be a 1 instead of 0, but I'm not entirely sure.

> Next build the scan request message:
> struct nl_msg *msg = nlmsg_alloc();
> int flags = 0;
> int cmd = NL80211_CMD_TRIGGER_SCAN;
> genlmsg_put(msg, 0, 0, genl_family_get_id(nl80211), 0, flags, cmd, 0);
> /* append our ssid list to this message as a nested message */
> nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids)

You're not telling it which interface should scan, this is handled
generically in iw.c, look for
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, devidx);

> Finally I send the request:
> int rc = nl_send_auto_complete(sock, msg);
>
> From this I found out that 32 bytes were sent (seems reasonable).
> Unfortunately, what I get back is this:
> [HEADER] 16 octets
> .nlmsg_len = 52
> .nlmsg_type = 2 <ERROR>
> .nlmsg_flags = 0 <>
> .nlmsg_seq = 1282012377
> .nlmsg_pid = 30415
> [ERRORMSG] 20 octets
> .error = -22 "Invalid argument"
> [ORIGINAL MESSAGE] 16 octets
> .nlmsg_len = 16
> .nlmsg_type = 23 <0x17>
> .nlmsg_flags = 5 <REQUEST,ACK>
> .nlmsg_seq = 1282012377
> .nlmsg_pid = 30415
>
> so, even following what iw's "scan.c" does I have somehow pieced the
> request together incorrectly.
>
> Questions:
> 1. Am I doing something obviously wrong?

You're also missing the interface as above.

> 2. Is this even the interface I should be using to do this? (I need
> to scan for all access points on a specific "hidden" SSID to retrieve
> some information about their SNR. It's a type of "site survey"
> application for building contour maps of coverage).

Yes, it does make sense.

> I'm not sure what I'm doing next makes sense, either. After I send
> the scan request I wait 3 seconds then start reading like this:
> while(nl_recvmsgs(sock, callbacks) != 0)
> {
> printf("processed a result\n");
> }
>
> I have registered my callback earlier; this seems to work because I
> get the message (above) plus later an "Operation Not Supported"
> message. The operation is indeed supported, as it works with the
> iwlist and iw command line tools.

Maybe you should look at wpa_supplicant either for doing your thing, or
for the driver_nl80211.c code in it, which is more explicit than iw.

johannes


2010-08-21 15:39:26

by Bob Copeland

[permalink] [raw]
Subject: Re: nl80211 scanning from userspace

On Fri, Aug 20, 2010 at 7:42 PM, Christopher Piggott <[email protected]> wrote:
> I'm sorry ... I hit REPLY again to Johannes personally rather than to
> the list. ?I don't know what it is about this list server that makes
> me do it ... maybe there's no Reply-To.

Tip: for most Linux-related mailing lists, simply use reply-to-all.

http://www.unicom.com/pw/reply-to-harmful.html

--
Bob Copeland %% http://www.bobcopeland.com