Commit Graph

23 Commits

Author SHA1 Message Date
James Prestwood 98cf2bf3ec frame-xchg: refactor to use wiphy work queue
In order to first integrate frame-xchg some refactoring needed to
be done. First it is useful to allow queueing frames up rather than
requiring the module (p2p, anqp etc) to wait for the last frame to
finish. This can be aided by radio management but frame-xchg needed
some refactoring as well.

First was getting rid of this fx pointer re-use. It looks like this
was done to save a bit of memory but things get pretty complex
needed to check if the pointer is stale or has been reset. Instead
of this we now just allocate a new pointer each frame-xchg. This
allows for the module to queue multiple requests as well as removes
the complexity of needed to check if the fx pointer is stale.

Next was adding the ability to track frame-xchgs by ID. If a module
can queue up multiple requests it also needs to be able to cancel
them individually vs per-wdev. This comes free with the wiphy work
queue since it returns an ID which can be given directly to the
caller.

Then radio management was simply piped in by adding the
insert/done APIs.
2020-07-09 09:58:16 -05:00
James Prestwood 05ad0120a8 frame-xchg: add destroy function to start() APIs
This makes things more consistent with other IWD APIs as well as
prepares for unifying frame-xchg and scanning.
2020-06-23 10:45:31 -05:00
James Prestwood 6c9c65a5de frame-xchg: fix incorrect length check
frame_xchg_startv was using sizeof(mmpdu) to check the minimum length
for a frame. Instead mmpdu_header_len should be used since this checks
fc.order and returns either 24 or 28 bytes, not 28 bytes always.

This change adds the requirement that the first iovec in the array
must contain at least the first 2 bytes (mmpdu_fc) of the header.
This really shouldn't be a problem since all current users of
frame-xchg put the entire header (or entire frame) into the first
iovec in the array.
2020-06-22 10:27:59 -05:00
James Prestwood 8b1161ec8e frame-xchg: fix bug when starting new xchg from callback
This bug is caused by the following behavior:

 1. Start a frame-xchg, wait for callback
 2. From callback start a new frame-xchg, same prefix.

The new frame-xchg request will detect that there is a duplicate watch,
which is correct behavior. It will then remove this duplicate from the
watchlist. The issue here is that we are in the watchlist notify loop
from the original xchg. This causes that loop to read from the now
freed watchlist item, causing an invalid read.

Instead of freeing the item immediately, check if the notify loop is in
progress and only set 'id' to zero and 'stale_items' to true. This will
allow the notify loop to finish, then the watchlist code will prune out
any stale items. If not in the notify loop the item can be freed as it
was before.
2020-06-04 09:36:42 -05:00
Andrew Zaborowski 1e10d13645 frame-xchg: Use frame_watch_group_match in frame_watch_group_get 2020-06-04 09:14:21 -05:00
Andrew Zaborowski d012a7f2ac frame-xchg: Fix frame_watch_remove_by_handler for group 0
Don't match the default group's (group_id 0) wdev_id against the
provided wdev_id because the default group can be used on all wdevs and
its wdev_id is 0.  Also match individual item's wdev_id in the group to
make up for this although it normally wouldn't matter.
2020-06-04 09:13:47 -05:00
Fabrice Fontaine c352714e61 frame-xchg.c: fix build with glibc < 2.24
SOL_NETLINK is used since commit
87a198111a resulting in the following
build failure with glibc < 2.24:

src/frame-xchg.c: In function 'frame_watch_group_io_read':
src/frame-xchg.c:328:27: error: 'SOL_NETLINK' undeclared (first use in this function)
   if (cmsg->cmsg_level != SOL_NETLINK)
                           ^

This failure is due to glibc that doesn't support SOL_NETLINK before
version 2.24 and
f9b437d5ef

Fixes:
 - http://autobuild.buildroot.org/results/3485088b84111c271bbcfaf025aa4103c6452072
2020-04-22 10:38:51 -05:00
Andrew Zaborowski 59a7f2e681 frame-xchg: Drop l_io read destroy handler
This function was intended to catch socket errors and destroy the group
but it would leak the l_io object if that happened, and if called on
ordinary shutdown it could cause a crash.  Since we're now assuming
that the netlink socket operations never fail just remove it.
2020-03-20 10:47:53 -05:00
Andrew Zaborowski e7e597c876 frame-xchg: Add frame_xchg_start 2020-03-20 10:15:50 -05:00
Andrew Zaborowski e6de4b10ad frame-xchg: Add facility to keep retransmitting after ACK
In some cases a P2P peer will ACK our frame but not reply on the first
attempt, and other implementations seem to handle this by going back to
retransmitting the frame at a high rate until it gets ACKed again, at
which point they will again give the peer a longer time to tx the
response frame.  Implement the same logic here by adding a
retries_on_ack parameter that takes the number of additional times we
want to restart the normal retransmit counter after we received no
response frame on the first attempt.  So passing 0 maintains the
current behaviour, 1 for 1 extra attempt, etc.

In effect we may retransmit a frame about 15 * (retry_on_ack + 1) *
<in-kernel retransmit limit> times.  The kernel/driver retransmits a
frame a number of times if there's no ACK (I've seen about 20 normally)
at a high frequency, if that fails we retry the whole process 15 times
inside frame-xchg.c and if we still get no ACK at any point, we give up.
If we do get an ACK, we wait for a response frame and if we don't get
that we will optionally reset the retry counter and restart the whole
thing retry_on_ack times.
2020-03-20 10:13:42 -05:00
Andrew Zaborowski 22d7a3c629 frame-xchg: Optimize frame_watch_remove_by_handler scenarios
Since frame_watch_remove_by_handler only forgets a given function +
user data pointers, and doesn't remove the frame prefixes added in the
kernel, we can avoid later re-registering those prefixes with the
kernel by keeping them in our local watchlist, and only replacing the
handler pointer with a dummy function.
2020-03-18 13:49:42 -05:00
Andrew Zaborowski 60bb42087a frame-xchg: Allow frame_xchg_stop calls inside frame callbacks
Make sure a frame callback is free to call frame_xchg_stop without
causing a crash.  Frame callback here means the one that gets
called if our tx frame was ACKed and triggered a respone frame that
matched one of the provided prefixes, within the given time.

All in all a frame callback is allowed to call either
frame_xchg_stop or frame_xchg_startv or neither.  Same applies to
the final callback (called when no matching responses received).
2020-03-17 15:45:07 -05:00
Andrew Zaborowski f1aa208edf frame-xchg: Allow calling frame_xchg_stop from the callback
Don't crash if the user calls frame_xchg_stop(wdev) from inside the
frame exchange's final callback.  That call is going to be redundant but
it's convenient to do this inside a cleanup function for a given wdev
without having to check whether any frame exchange was actually running.
2020-03-17 15:44:56 -05:00
Andrew Zaborowski 9147a6b726 frame-xchg: Fix frame_watch_item_remove_by_handler 2020-03-17 15:44:22 -05:00
Andrew Zaborowski a18c75d375 frame-xchg: Actually free duplicate watches
Fix a potential leak when we need to drop an existing watch because it's
being replaced with a new one.
2020-03-17 15:44:10 -05:00
Andrew Zaborowski 87a198111a frame-xchg: Don't use l_genl for additional nl80211 sockets
For nl80211 sockets other than our main l_genl object use socket io
directly, to avoid creating many instances of l_genl.  The only reason
we use multiple sockets is to work around an nl80211 design quirk that
requires closing the socket to unregister management frame watches.
Normally there should not be a need to create multiple sockets in a
program.
2020-02-17 12:23:13 -06:00
Andrew Zaborowski 0d62b5a2fc frame-xchg: Add a frame exchange API
Add a little state machine and a related API, to simplify sending out a
frame, receiving the Ack / No-ack status and (if acked) waiting for a
response frame from the target device, one of a list of possible
frame prefixes.  The nl80211 API for this makes it complicated
enough that this new API seems to be justified, on top of that there's a
quirk when using the brcmfmac driver where the nl80211 response
(containing the operation's cookie), the Tx Status event and the response
Frame event are received from nl80211 in reverse order (not seen with
other drivers so far), further complicating what should be a pretty
simple task.
2020-02-17 10:45:40 -06:00
Andrew Zaborowski ff7abdb89d frame-xchg: Try to call a handler only once per frame
Try to better deduplicate the frame watches.  Until now we'd check if
we'd already registered a given frame body prefix with the kernel, or a
matching more general prefix (shorter).  Now also try to check if we
have already have a watch with the same callback pointer and user_data
value, and:

 * an identical or shorter (more general) prefix, in that case ignore
   the new watch completely.

 * a longer (more specific) prefix, in that case forget the existing
   watch.

The use case for this is when we have a single callback for multiple
watches and multiple frame types, and inside that callback we're looking
at the frame body again and matching it to frame types.  In that case
we don't want that function to be called multiple times for one frame
event.
2020-02-17 10:42:55 -06:00
Andrew Zaborowski 1896ac2d73 frame-xchg: Use both group_id and wdev_id when removing group
In frame_watch_group_remove I forgot to actually match the group to be
removed by both wdev_id and group_id.  group_ids are unique only in the
scope of one wdev.
2020-02-07 15:41:14 -06:00
Andrew Zaborowski 053c1ca2a2 frame-xchg: Add new groups to watch_groups list
I forgot to actually add new groups being created in
frame_watch_group_get to the watch_groups queue, meaning that we'd
re-create the group every time a new watch was added to the group.
2020-02-07 15:34:14 -06:00
Andrew Zaborowski fff6c97e99 frame-watch: Fix an l_queue_foreach_remove call
A pointer to the wdev_id is expected in this call inside
frame_watch_group_remove_wdev instead of a pointer to the pointer.
2020-02-04 10:46:57 -06:00
Andrew Zaborowski 1df4cb5be7 frame-watch: Actually unregister removed groups
Actually close the sockets for removed groups an free resources
2020-02-04 10:46:32 -06:00
Andrew Zaborowski 6484b7dbb6 Add a new frame watch API
This new API is independent of netdev.c and allows actually
unregistering from receiving notifications of frames, although with some
quirks.  The current API only allowed the callback for a registration to
be forgotten but our process and/or the kernel would still be woken up
when matching frames were received because the kernel had no frame
unregister call.  In the new API you can supply a group-id paramter when
registering frames.  If it is non-zero the frame_watch_group_remove() call
can be used to remove all frame registrations that had a given group-id
by closing the netlink socket on which the notifications would be
received.  This means though that it's a slightly costly operation.

The file is named frame-xchg.c because I'm thinking of also adding
utilities for sending frames and waiting for one of a number of replies
and handling the acked/un-acked information.
2020-01-13 11:49:08 -06:00