The 802.11-2012 specification notes that a subset of IEs should be present
in IBSS probe requests. This is what (initially) allows nodes to discover
that other nodes are 11n capable. Notably - HTCAP, but not HTINFO.
This isn't everything required to reliably enable 11n between net80211
peers; there's more work to come.
Tested:
* AR9380, IBSS+11n mode
Do not try to pass such frames; a correct frame cannot be smaller than
(the corresponding) header size.
(for wpi(4) an additional check was added in r289012).
PR: 144987
Remove 'if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);' from raw xmit
and apbridge path; it will be incremented by ieee80211_tx_complete()
after packet transmission.
Noticed by: Imre Vadasz <imre@vdsz.com>
again hopefully.
Rather than blindly removing a supposedly unused variable as reported by
the Clang Static Analyzer, inspect the code and hide them with proper
#ifdefs as they are used in certain conditional parts of the code.
Hide subtype mask/shift (which is used for index calculation
in ieee80211_mgt_subtype_name[] array) in function call.
Tested with RTL8188CUS, STA mode.
Reviewed by: adrian
Differential Revision: https://reviews.freebsd.org/D5369
le*dec / le*enc functions.
Replace net80211 specific macros with system-wide bytestream
encoding/decoding functions:
- LE_READ_2 -> le16dec
- LE_READ_4 -> le32dec
- LE_WRITE_2 -> le16enc
- LE_WRITE_4 -> le32enc
+ drop ieee80211_input.h include, where it was included for these
operations only.
Reviewed by: adrian
Differential Revision: https://reviews.freebsd.org/D6030
A-MSDU is another 11n aggregation mechanism where multiple ethernet
frames get LLC encapsulated (so they have a length field), padded,
and put in a single MPDU (802.11 MAC frame.) This means it gets sent
out as a single frame, with a single seqno, it's acked as one frame, etc.
It turns out that, hah, atheros fast frames is almost but not quite
like this, so I'm reusing all of the current superg/fast-frames stuff
in order to actually transmit A-MSDU. Yes, this means that A-MSDU
frames are also only aggregated two at a time, so it's not necessarily
a huge win, but it's better than nothing.
This doesn't do anything by default - the driver needs to say it does
A-MSDU as well as set the AMSDU software TX capability so this code path
gets exercised.
For now, the only driver that enables this is urtwn. I'll enable it
for rsu at some point soon.
Tested:
* Add an amsdu encap path to aggregate two frames, same as the
fast-frames path.
* Always do the superg init/teardown and node init/teardown stuff,
regardless of whether the nodes are doing fast-frames (the ATH
capability stuff.) That way we can reuse it for amsdu.
* Don't do AMSDU for multicast/broadcast and EAPOL frames.
* If we're doing A-MPDU, then don't bother doing FF/A-MSDU.
We can likely do both together, but I don't want to change
behaviour.
* Teach the fast frames approx txtime logic to support the 11n
rates. But, since we don't currently have a full "current rate"
support, assume it's HT20, long-gi, etc. That way we overshoot
on the TX time estimation, so we're always inside the requirements.
(And we only aggregate two frames for now, so we're not really
going to exceed that.)
* Drop the maximum FF age default down to 2ms, otherwise we end up
with some very annoyingly large latencies.
TODO:
* We only aggregate two ethernet frames, so I'm not checking the max
A-MSDU size. But when it comes time to support >2 frames, we should
obey that.
Tested:
* urtwn(4)
transmitted
- Use M_TXCB mechanism to report about null data frame transmission.
- Increase timeout from 1 to 10 ms (the previous one may be not enough
for non-empty queue).
Tested with:
* Intel 3945BG, STA mode.
* RTL8188CUS, STA mode.
Approved by: adrian (mentor)
Differential Revision: https://reviews.freebsd.org/D5147
This doesn't free the mbuf upon error; the driver ic_raw_xmit method is still
doing that.
Submitted by: <s3erios@gmail.com>
Differential Revision: https://reviews.freebsd.org/D3774
Move error handling into ieee80211_parent_xmitpkt() instead of spreading it
between functions.
Submitted by: <s3erios@gmail.com>
Differential Revision: https://reviews.freebsd.org/D3772
* Create ieee80211_free_mbuf() which frees a list of mbufs.
* Use it in the fragment transmit path and ath / uath transmit paths.
* Call it in xmit_pkt() if the transmission fails; otherwise fragments
may be leaked.
This should be a big no-op.
Submitted by: <s3erios@gmail.com>
Differential Revision: https://reviews.freebsd.org/D3769
connectivity interact with the net80211 stack.
Historical background: originally wireless devices created an interface,
just like Ethernet devices do. Name of an interface matched the name of
the driver that created. Later, wlan(4) layer was introduced, and the
wlanX interfaces become the actual interface, leaving original ones as
"a parent interface" of wlanX. Kernelwise, the KPI between net80211 layer
and a driver became a mix of methods that pass a pointer to struct ifnet
as identifier and methods that pass pointer to struct ieee80211com. From
user point of view, the parent interface just hangs on in the ifconfig
list, and user can't do anything useful with it.
Now, the struct ifnet goes away. The struct ieee80211com is the only
KPI between a device driver and net80211. Details:
- The struct ieee80211com is embedded into drivers softc.
- Packets are sent via new ic_transmit method, which is very much like
the previous if_transmit.
- Bringing parent up/down is done via new ic_parent method, which notifies
driver about any changes: number of wlan(4) interfaces, number of them
in promisc or allmulti state.
- Device specific ioctls (if any) are received on new ic_ioctl method.
- Packets/errors accounting are done by the stack. In certain cases, when
driver experiences errors and can not attribute them to any specific
interface, driver updates ic_oerrors or ic_ierrors counters.
Details on interface configuration with new world order:
- A sequence of commands needed to bring up wireless DOESN"T change.
- /etc/rc.conf parameters DON'T change.
- List of devices that can be used to create wlan(4) interfaces is
now provided by net.wlan.devices sysctl.
Most drivers in this change were converted by me, except of wpi(4),
that was done by Andriy Voskoboinyk. Big thanks to Kevin Lo for testing
changes to at least 8 drivers. Thanks to pluknet@, Oliver Hartmann,
Olivier Cochard, gjb@, mmoll@, op@ and lev@, who also participated in
testing.
Reviewed by: adrian
Sponsored by: Netflix
Sponsored by: Nginx, Inc.
* 286410
* 286413
* 286416
The initial commit broke a variety of debug and features that aren't
in the GENERIC kernels but are enabled in other platforms.
with the net80211 stack.
Historical background: originally wireless devices created an interface,
just like Ethernet devices do. Name of an interface matched the name of
the driver that created. Later, wlan(4) layer was introduced, and the
wlanX interfaces become the actual interface, leaving original ones as
"a parent interface" of wlanX. Kernelwise, the KPI between net80211 layer
and a driver became a mix of methods that pass a pointer to struct ifnet
as identifier and methods that pass pointer to struct ieee80211com. From
user point of view, the parent interface just hangs on in the ifconfig
list, and user can't do anything useful with it.
Now, the struct ifnet goes away. The struct ieee80211com is the only
KPI between a device driver and net80211. Details:
- The struct ieee80211com is embedded into drivers softc.
- Packets are sent via new ic_transmit method, which is very much like
the previous if_transmit.
- Bringing parent up/down is done via new ic_parent method, which notifies
driver about any changes: number of wlan(4) interfaces, number of them
in promisc or allmulti state.
- Device specific ioctls (if any) are received on new ic_ioctl method.
- Packets/errors accounting are done by the stack. In certain cases, when
driver experiences errors and can not attribute them to any specific
interface, driver updates ic_oerrors or ic_ierrors counters.
Details on interface configuration with new world order:
- A sequence of commands needed to bring up wireless DOESN"T change.
- /etc/rc.conf parameters DON'T change.
- List of devices that can be used to create wlan(4) interfaces is
now provided by net.wlan.devices sysctl.
Most drivers in this change were converted by me, except of wpi(4),
that was done by Andriy Voskoboinyk. Big thanks to Kevin Lo for testing
changes to at least 8 drivers. Thanks to Olivier Cochard, gjb@, mmoll@,
op@ and lev@, who also participated in testing. Details here:
https://wiki.freebsd.org/projects/ifnet/net80211
Still, drivers: ndis, wtap, mwl, ipw, bwn, wi, upgt, uath were not
tested. Changes to mwl, ipw, bwn, wi, upgt are trivial and chances
of problems are low. The wtap wasn't compilable even before this change.
But the ndis driver is complex, and it is likely to be broken with this
commit. Help with testing and debugging it is appreciated.
Differential Revision: D2655, D2740
Sponsored by: Nginx, Inc.
Sponsored by: Netflix
with the transmit params.
This allows raw 802.11 frames to be queued in the driver if necessary,
rather than requiring it to be direct-dispatched into the hardware.
Tested:
* ath(4), STA mode
* iwn(4), STA mode
MFC after: 2 weeks
Sponsored by: Norse Corp, Inc.
DragonflyBSD uses the FreeBSD wireless stack and drivers. Their malloc()
API is named differently, so they don't have userland/kernel symbol
clashes like we do (think libuinet.)
So, to make it easier for them and to port to other BSDs/other operating
systems, start hiding the malloc specific bits behind defines in
ieee80211_freebsd.h.
DragonflyBSD can now put these portability defines in their local
ieee80211_dragonflybsd.h.
This should be a great big no-op for everyone running wifi.
TODO:
* kill M_WAITOK - some platforms just don't want you to use it
* .. and/or handle it returning NULL rather than waiting forever.
* MALLOC_DEFINE() ?
* Migrate the well-known malloc names (eg M_TEMP) to net80211
namespace defines.
ieee80211_pwrsave() can fail due to queue overflow, check its return code
and increment oerrors counter when it fails. Also handle more error cases
and update oerrors counter when we don't send mbuf due to some errors.
Return ENETDOWN when parent interface isn't ready. Update obytes and omcasts
counters in corresponding places.
PR: 184626
Differential Revision: https://reviews.freebsd.org/D2621
Reviewed by: adrian
MFC after: 1 week
frames to 0
From IEEE Std. 802.11-2012, 8.3.2.1 "Data frame format", p. 415 (513):
"The Sequence Control field for QoS (+)Null frames is ignored by the receiver
upon reception."
At this moment, any <mode>_input() function interprets them as regular QoS data
frames with TID = 0. As a result, stations, that use another TX sequence for
QoS Null frames (e.g. wpi(4), where (QoS) Null frames are generated by the
firmware), may experience significant packet loss with any other NIC in hostap
mode.
Tested:
* wpi(4) (author)
* iwn(4) - Intel 5100, STA mode (me)
PR: kern/200128
Submitted by: Andriy Voskoboinyk <s3erios@gmail.com>
configured as 11b.
This came up when debugging other issues surrounding scanning and
channel modes.
What's going on:
* The VAP comes up as an 11b VAP, but on an 11n capable NIC;
* .. it announces HTINFO and MCS rates;
* The AP thinks it's an 11n capable device and transmits 11n frames
to the STA;
* But the STA is in 11b mode, and thus doesn't receive/ACK the frames.
It didn't happen for the ath(4) devices as the AR5416/AR9300 HALs
unconditionally enable MCS frame reception, even if the channel
mode is not 11n. But the Intel NICs are configured in 11b/11a/11g
modes when doing those, even if 11n is enabled and available.
So, don't announce 11n capabilities if the VAP isn't on an 11n
channel when sending management assocation request / reassociation
request frames.
TODO:
* Lots more testing - 11n should be "upgraded" after association,
and I just want to make sure I haven't broken 11n upgrade.
I shouldn't have - this is only happening for /sending/ association
requests, which APs aren't doing.
Tested:
* ath(4) APs (AR9331, AR7161+AR9280, AR934x)
* AR5416, STA mode
* Intel 5100, STA mode
PR: kern/196290
Frames transmitted during SLEEP state should be queued in the
power save queue before waking the unit up. Otherwise DHCP
requests and such will be dropped if the NIC is asleep - the
NIC will wake up but not transmit the frame.
The origin of WEP comes from IEEE Std 802.11-1997 where it defines
whether the frame body of MAC frame has been encrypted using WEP
algorithm or not.
IEEE Std. 802.11-2007 changes WEP to Protected Frame, indicates
whether the frame is protected by a cryptographic encapsulation
algorithm.
Reviewed by: adrian, rpaulo
to this event, adding if_var.h to files that do need it. Also, include
all includes that now are included due to implicit pollution via if_var.h
Sponsored by: Netflix
Sponsored by: Nginx, Inc.
from a management frame transmission.
This bug is a bit loopy, so here goes.
The underlying cause is pretty easy to understand - the node isn't
referenced before passing into the callout, so if the node is deleted
before the callout fires, it'll dereference free'd memory.
The code path however is slightly more convoluted.
The functions _say_ mgt_tx - ie management transmit - which is partially
true. Yes, that callback is attached to the mbuf for some management
frames. However, it's only for frames relating to scanning and
authentication attempts. It helpfully drives the VAP state back to
"SCAN" if the transmission fails _OR_ (as I subsequently found out!)
if the transmission succeeds but the state machine doesn't make progress
towards being authenticated and active.
Now, the code itself isn't terribly clear about this.
It _looks_ like it's just handling the transmit failure case.
However, when you look at what goes on in the transmit success case, it's
moving the VAP state back to SCAN if it hasn't changed state since
the time the callback was scheduled. Ie, if it's in ASSOC or AUTH still,
it'll go back to SCAN. But if it has transitioned to the RUN state,
the comparison will fail and it'll not transition things back to the
SCAN state.
So, to fix this, I decided to leave everything the way it is and merely
fix the locking and remove the node reference.
The _better_ fix would be to turn this callout into a "assoc/auth request"
timeout callback and make the callout locked, thus eliminating all races.
However, until all the drivers have been fixed so that transmit completions
occur outside of any locking that's going on, it's going to be impossible
to do this without introducing LORs. So, I leave some of the evilness
in there.
Tested:
* AR5212, ath(4), STA mode
* 5100 and 4965 wifi, iwn(4), STA mode
The aim of this function is to eventually be the completion entry point
for all 802.11 encapsulated mbufs. All the wifi drivers end up doing
what is in this function so it's an easy win to turn it into a net80211
method and abstract out this code.
Ideally the drivers will all eventually be modified to queue up completed
mbufs and call this function with all the driver locks not held.
This will allow for some much more interesting software queue handling
in the future (like net80211 based A-MSDU, fast-frames, A-MPDU aggregation
and retransmission.)
Tested:
* ath(4), iwn(4)
upper layer(s).
This eliminates the if_snd queue from net80211. Yay!
This unfortunately has a few side effects:
* It breaks ALTQ to net80211 for now - sorry everyone, but fixing
parallelism and eliminating the if_snd queue is more important
than supporting this broken traffic scheduling model. :-)
* There's no VAP and IC flush methods just yet - I think I'll add
some NULL methods for now just as placeholders.
* It reduces throughput a little because now net80211 will drop packets
rather than buffer them if the driver doesn't do its own buffering.
This will be addressed in the future as I implement per-node software
queues.
Tested:
* ath(4) and iwn(4) in STA operation
the normal and the mesh transmit paths can use.
The API is a bit horrible because it both consumes the mbuf and frees
the node reference regardless of whether it succeeds or not.
It's a hold-over from how the code behaves; it'd be nice to have it
not free the node reference / mbuf if TX fails and let the caller
decide what to do.
When creating fragment frames, the header length should honour the
DATAPAD flag.
This fixes the fragments that are queued to the ath(4) driver but it
doesn't yet fix fragment transmission. That requires further changes
to the ath(4) transmit path. Well, strictly speaking, it requires
further changes to _all_ wifi driver transmit paths, but this is at least
a start.
Tested:
* AR5416, STA mode, w/ fragthreshold set to 256.
This patchset implements a new TX lock, covering both the per-VAP (and
thus per-node) TX locking and the serialisation through to the underlying
physical device.
This implements the hard requirement that frames to the underlying physical
device are scheduled to the underlying device in the same order that they
are processed at the VAP layer. This includes adding extra encapsulation
state (such as sequence numbers and CCMP IV numbers.) Any order mismatch
here will result in dropped packets at the receiver.
There are multiple transmit contexts from the upper protocol layers as well
as the "raw" interface via the management and BPF transmit paths.
All of these need to be correctly serialised or bad behaviour will result
under load.
The specifics:
* add a new TX IC lock - it will eventually just be used for serialisation
to the underlying physical device but for now it's used for both the
VAP encapsulation/serialisation and the physical device dispatch.
This lock is specifically non-recursive.
* Methodize the parent transmit, vap transmit and ic_raw_xmit function
pointers; use lock assertions in the parent/vap transmit routines.
* Add a lock assertion in ieee80211_encap() - the TX lock must be held
here to guarantee sensible behaviour.
* Refactor out the packet sending code from ieee80211_start() - now
ieee80211_start() is just a loop over the ifnet queue and it dispatches
each VAP packet send through ieee80211_start_pkt().
Yes, I will likely rename ieee80211_start_pkt() to something that
better reflects its status as a VAP packet transmit path. More on
that later.
* Add locking around the management and BAR TX sending - to ensure that
encapsulation and TX are done hand-in-hand.
* Add locking in the mesh code - again, to ensure that encapsulation
and mesh transmit are done hand-in-hand.
* Add locking around the power save queue and ageq handling, when
dispatching to the parent interface.
* Add locking around the WDS handoff.
* Add a note in the mesh dispatch code that the TX path needs to be
re-thought-out - right now it's doing a direct parent device transmit
rather than going via the vap layer. It may "work", but it's likely
incorrect (as it bypasses any possible per-node power save and
aggregation handling.)
Why not a per-VAP or per-node lock?
Because in order to ensure per-VAP ordering, we'd have to hold the
VAP lock across parent->if_transmit(). There are a few problems
with this:
* There's some state being setup during each driver transmit - specifically,
the encryption encap / CCMP IV setup. That should eventually be dragged
back into the encapsulation phase but for now it lives in the driver TX path.
This should be locked.
* Two drivers (ath, iwn) re-use the node->ni_txseqs array in order to
allocate sequence numbers when doing transmit aggregation. This should
also be locked.
* Drivers may have multiple frames queued already - so when one calls
if_transmit(), it may end up dispatching multiple frames for different
VAPs/nodes, each needing a different lock when handling that particular
end destination.
So to be "correct" locking-wise, we'd end up needing to grab a VAP or
node lock inside the driver TX path when setting up crypto / AMPDU sequence
numbers, and we may already _have_ a TX lock held - mostly for the same
destination vap/node, but sometimes it'll be for others. That could lead
to LORs and thus deadlocks.
So for now, I'm sticking with an IC TX lock. It has the advantage of
papering over the above and it also has the added advantage that I can
assert that it's being held when doing a parent device transmit.
I'll look at splitting the locks out a bit more later on.
General outstanding net80211 TX path issues / TODO:
* Look into separating out the VAP serialisation and the IC handoff.
It's going to be tricky as parent->if_transmit() doesn't give me the
opportunity to split queuing from driver dispatch. See above.
* Work with monthadar to fix up the mesh transmit path so it doesn't go via
the parent interface when retransmitting frames.
* Push the encryption handling back into the driver, if it's at all
architectually sane to do so. I know it's possible - it's what mac80211
in Linux does.
* Make ieee80211_raw_xmit() queue a frame into VAP or parent queue rather
than doing a short-cut direct into the driver. There are QoS issues
here - you do want your management frames to be encapsulated and pushed
onto the stack sooner than the (large, bursty) amount of data frames
that are queued. But there has to be a saner way to do this.
* Fragments are still broken - drivers need to be upgraded to an if_transmit()
implementation and then fragmentation handling needs to be properly fixed.
Tested:
* STA - AR5416, AR9280, Intel 5300 abgn wifi
* Hostap - AR5416, AR9160, AR9280
* Mesh - some testing by monthadar@, more to come.