Expanded Nak packet contains (possibly multiple) 8 byte chunks that
contain the type (1 byte, always '254') vendor-id (3 bytes) and
vendor-type (4) bytes.
Unfortunately the current logic was reading the vendor-id at the wrong
offset (0 instead of 1) and so the extracted vendor-type was incorrect.
Fixes: 17c569ba4c ("eap: Add authenticator method logic and API")
If we received a Nak or an Expanded Nak packet, the intent was to print
our own method type. Instead we tried to print the Nak type contents.
Fix that by always passing in our method info to eap_type_to_str.
Fixes: 17c569ba4c ("eap: Add authenticator method logic and API")
The '__' prefix is meant for private, semi-private,
inner implementation or otherwise special APIs that
are typically exposed in a header. In the case of watchlist, these
functions were static and do not fit the above description. Remove the
__ prefix accordingly.
When using iwd.conf:[General].EnableNetworkConfiguration=true, it is not
possible to configure systemd.network:[Network].MulticastDNS= as
systemd-networkd considers the link to be unmanaged. This patch allows
iwd to configure that setting on systemd-resolved directly.
If the extended feature for CQM levels was not supported no CQM
registration would happen, not even for a single level. This
caused IWD to completely lose the ability to roam since it would
only get notified when the kernel was disconnecting, around -90
dBm, not giving IWD enough time to roam.
Instead if the extended feature is not supported we can still
register for the event, just without multiple signal levels.
There is no functional change here but checking the return
value makes static analysis much happier. Checking the
return and setting the default inside the if clause is also
consistent with how IWD does it many other places.
Handle situations where the BSS we're trying to connect to is no longer
in the kernel scan result cache. Normally, the kernel will re-scan the
target frequency if this happens on the CMD_CONNECT path, and retry the
connection.
Unfortunately, CMD_AUTHENTICATE path used for WPA3, OWE and FILS does
not have this scanning behavior. CMD_AUTHENTICATE simply fails with
a -ENOENT error. Work around this by trying a limited scan of the
target frequency and re-trying CMD_AUTHENTICATE once.
An earlier patch fixed a problem where a queued quick scan would
be triggered and fail once already connected, resulting in a state
transition from connected --> autoconnect_full. This fixed the
Connect() path but this could also happen via autoconnect. Starting
from a connected state, the sequence goes:
- DBus scan is triggered
- AP disconnects IWD
- State transition from disconnected --> autoconnect_quick
- Queue quick scan
- DBus scan results come in and used to autoconnect
- A connect work item is inserted ahead of all others, transition
from autoconnect_quick --> connecting.
- Connect completes, transition from connecting --> connected
- Quick scan can finally get triggered, which the kernel fails to
do since IWD is connected, transition from connected -->
autoconnect_full.
This can be fixed by checking for a pending quick scan in the
autoconnect path.
Commit eac2410c83 ("station: Take scanned frequencies into account")
has made it unnecessary to explicitly invoke station_set_scan_results
with the expire to true in case a dbus scan finished prematurely or a
subset was not able to be started. Remove this no-longer needed logic.
Fixes: eac2410c83 ("station: Take scanned frequencies into account")
The diagnostic interface returns an error anyways if station is
not connected so it makes more sense to only bring the interface
up when its actually usable. This also removes the interface
when station disconnects, which was never done before (the
interface stayed up indefinitely due to a forgotten remove call).
When we're auto-connecting and have hidden networks configured, use
active scans regardless of whether we see any hidden BSSes in our
existing scan results.
This allows us to more effectively see/connect to hidden networks
when first powering up or after suspend.
Kernel might report hidden BSSes that are reported from beacon frames
separately than ones reported due to probe responses. This may confuse
the station network collation logic since the scan_bss generated by the
probe response might be removed erroneously when processing the scan_bss
that was generated due to a beacon.
Make sure that bss_match also takes the SSID into account and only
matches scan_bss structures that have the same BSSID and SSID contents.
Instead of manually managing whether to expire BSSes or not, use the
scanned frequency set instead. This makes the API slightly easier to
understand (dropping two boolean arguments in a row) and also a bit more
future-proof.
Commit d372d59bea checks whether a hidden network had a previous
connection attempt and re-tries. However, it inadvertently dropped
handling of a condition where a non-hidden network SSID is provided to
ConnectHiddenNetwork. Fix that.
Fixes: d372d59bea ("station: Allow ConnectHiddenNetwork to be retried")
The diagnostic interface serves no purpose until the AP has
been started. Any calls on it will return an error so instead
it makes more sense to bring it up when the AP is started, and
down when the AP is stopped.
Its useful being able to refer to the network Name/SSID once
an AP is started. For example opening an iwctl session with an
already started AP provides no way of obtaining the SSID.
In some cases the AP can send a deauthenticate frame right after
accepting our authentication. In this case the kernel never properly
sends a CMD_CONNECT event with a failure, even though CMD_COONNECT was
used to initiate the connection. Try to work around that by detecting
that a Deauthenticate event arrives prior to any Associte or Connect
events and handle this case as a connect failure.
Now that ConnectHiddenNetwork can be invoked while we're connected, set
the mac randomization hint parameter properly. The kernel will reject
requests if randomization is enabled while we're connected to a network.
If we forget a hidden network, then make sure to remove it from the
network list completely. Otherwise it would be possible to still
issue a Network.Connect to that particular object, but the fact that the
network is hidden would be lost.
==17639== 72 (16 direct, 56 indirect) bytes in 1 blocks are definitely
lost in loss record 3 of 3
==17639== at 0x4C2F0CF: malloc (vg_replace_malloc.c:299)
==17639== by 0x4670AD: l_malloc (util.c:61)
==17639== by 0x4215AA: scan_freq_set_new (scan.c:1906)
==17639== by 0x412A9C: parse_neighbor_report (station.c:1910)
==17639== by 0x407335: netdev_neighbor_report_frame_event
(netdev.c:3522)
==17639== by 0x44BBE6: frame_watch_unicast_notify (frame-xchg.c:233)
==17639== by 0x470C04: dispatch_unicast_watches (genl.c:961)
==17639== by 0x470C04: process_unicast (genl.c:980)
==17639== by 0x470C04: received_data (genl.c:1101)
==17639== by 0x46D9DB: io_callback (io.c:118)
==17639== by 0x46CC0C: l_main_iterate (main.c:477)
==17639== by 0x46CCDB: l_main_run (main.c:524)
==17639== by 0x46CF01: l_main_run_with_signal (main.c:656)
==17639== by 0x403EDE: main (main.c:490)
In the case that ConnectHiddenNetwork scans successfully, but fails for
some other reason, the network object is left in the scan results until
it expires. This will prevent subsequent attempts to use
ConnectHiddenNetwork with a .NotHidden error. Fix that by checking
whether a found network is hidden, and if so, allow the request to
proceed.
Rework the logic slightly so that this function returns an error message
on error and NULL on success, just like other D-Bus method
implementations. This also simplifies the code slightly.
We used to not allow to connect to a different network while already
connected. One had to disconnect first. This also applied to
ConnectHiddenNetwork calls.
This restriction can be dropped now. station will intelligently
disconnect from the current AP when a station_connect_network() is
issued.
If the disconnect fails and station_disconnect_onconnect_cb is called
with an error, we reply to the original message accordingly.
Unfortunately pending_connect is not unrefed or cleared in this case.
Fix that.
Fixes: d0ee923dda ("station: Disconnect, if needed, on a new connection attempt")
An invalid known_network.freq file containing several UUID
groups which have the same 'name' key results in memory leaks
in IWD. This is because the file is loaded and the group's
are iterated without detecting duplicates. This leads to the
same network_info's known_frequencies being set/overridden
multiple times.
To fix this we just check if the network_info already has a
UUID set. If so remove the stale entry.
There may be other old, invalid, or stale entries from previous
versions of IWD, or a user misconfiguring the file. These will
now also be removed during load.
netdev_shutdown calls queue_destroy on the netdev_list, which in turn
calls netdev_free. netdev_free invokes the watches to notify them about
the netdev being removed. Those clients, or anything downstream can
still invoke netdev_find. Unfortunately queue_destroy is not re-entrant
safe, so netdev_find might return stale data. Fix that by using
l_queue_peek_head / l_queue_pop_head instead.
src/station.c:station_enter_state() Old State: connecting, new state:
connected
^CTerminate
src/netdev.c:netdev_free() Freeing netdev wlan1[6]
src/device.c:device_free()
Removing scan context for wdev 100000001
src/scan.c:scan_context_free() sc: 0x4ae9ca0
src/netdev.c:netdev_free() Freeing netdev wlan0[48]
src/device.c:device_free()
src/station.c:station_free()
src/netconfig.c:netconfig_destroy()
==103174== Invalid read of size 8
==103174== at 0x467AA9: l_queue_find (queue.c:346)
==103174== by 0x43ACFF: netconfig_reset (netconfig.c:1027)
==103174== by 0x43AFFC: netconfig_destroy (netconfig.c:1123)
==103174== by 0x414379: station_free (station.c:3369)
==103174== by 0x414379: station_destroy_interface (station.c:3466)
==103174== by 0x47C80C: interface_instance_free (dbus-service.c:510)
==103174== by 0x47C80C: _dbus_object_tree_remove_interface
(dbus-service.c:1694)
==103174== by 0x47C99C: _dbus_object_tree_object_destroy
(dbus-service.c:795)
==103174== by 0x409A87: netdev_free (netdev.c:770)
==103174== by 0x4677AE: l_queue_clear (queue.c:107)
==103174== by 0x4677F8: l_queue_destroy (queue.c:82)
==103174== by 0x40CDC1: netdev_shutdown (netdev.c:5089)
==103174== by 0x404736: iwd_shutdown (main.c:78)
==103174== by 0x404736: iwd_shutdown (main.c:65)
==103174== by 0x46BD61: handle_callback (signal.c:78)
==103174== by 0x46BD61: signalfd_read_cb (signal.c:104)
In the case of module_init failing due to a module that comes after
netdev, the netdev module doesn't clean up netdev_list properly.
==6254== 24 bytes in 1 blocks are still reachable in loss record 1 of 1
==6254== at 0x483777F: malloc (in
/usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==6254== by 0x4675ED: l_malloc (util.c:61)
==6254== by 0x46909D: l_queue_new (queue.c:63)
==6254== by 0x406AE4: netdev_init (netdev.c:5038)
==6254== by 0x44A7B3: iwd_modules_init (module.c:152)
==6254== by 0x404713: nl80211_appeared (main.c:171)
==6254== by 0x4713DE: process_unicast (genl.c:993)
==6254== by 0x4713DE: received_data (genl.c:1101)
==6254== by 0x46E00B: io_callback (io.c:118)
==6254== by 0x46D20C: l_main_iterate (main.c:477)
==6254== by 0x46D2DB: l_main_run (main.c:524)
==6254== by 0x46D2DB: l_main_run (main.c:506)
==6254== by 0x46D502: l_main_run_with_signal (main.c:656)
==6254== by 0x403EDB: main (main.c:490)
Rather than the previous hack which disabled group traffic it
was found that the GTK RSC could be manually set to zero which
allows group traffic. This appears to fix AP mode on brcmfmac
along with the previous fixes. This is not documented in
nl80211, but appears to work with this driver.
This is how a fullmac card tells userspace that a station has
left. This fixes the issue where the same client cannot re-connect
to the same AP multiple times. ap_new_station was renamed to
ap_handle_new_station for consistency.
Some fullmac cards were found to be buggy with getting the GTK
where it returns a BIP key for the GTK index, even after creating
a GTK with NEW_KEY explicitly. In an effort to get these cards
semi-working we can treat this just as a warning and continue with
the handshake without a GTK set which disables group traffic. A
warning is printed in this case so the user is not completely in
the dark.
Fix an issue with the recent changes to signal monitoring from commit
f456501b ("station: retry roaming unless notified of a high RSSI"):
1. driver sends NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW
2. netdev->cur_rssi_low changes from FALSE to TRUE
3. netdev sends NETDEV_EVENT_RSSI_THRESHOLD_LOW to station
4. on roam reassociation, cur_rssi_low is reset to FALSE
5. station still assumes RSSI is low, periodically roams
until netdev sends NETDEV_EVENT_RSSI_THRESHOLD_HIGH
6. driver sends NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH
7. netdev->cur_rssi_low doesn't change (still FALSE)
8. netdev never sends NETDEV_EVENT_RSSI_THRESHOLD_HIGH
9. station remains stuck in an infinite roaming loop
The commit in question introduced the logic in (5). Previously the
assumption in station was - like in netdev - that if the signal was
still low, the driver would send a duplicate LOW event after
reassociation. This change makes netdev follow the same new logic as
station, i.e. assume the same signal state (LOW/HIGH) until told
otherwise by the driver.
Since fullmac cards handle auth/assoc in firmware IWD must
react differently while in AP mode just as it does in station.
For fullmac cards a NEW_STATION event is emitted post association
and from here the 4-way handshake can begin. In this NEW_STATION
handler a new sta_state is created and the needed members are
set in order to inject us back into the normal code execution
for softmac post association (i.e. creating group keys and
starting the 4-way handshake). From here everything works the
same as softmac.
At some point the non-interactive client tests began failing.
This was due to a bug in station where it would transition from
'connected' to 'autoconnect' due to a failed scan request. This
happened because a quick scan got scheduled during an ongoing
scan, then a Connect() gets issued. The work queue treats the
Connect as a priority so it delays the quick scan until after the
connection succeeds. This results in a failed quick scan which
IWD does not expect to happen when in a 'connected' state. This
failed scan actually triggers a state transition which then
gets IWD into a strange state where its connected from the
kernel point of view but does not think it is:
src/station.c:station_connect_cb() 13, result: 0
src/station.c:station_enter_state() Old State: connecting, new state: connected
src/wiphy.c:wiphy_radio_work_done() Work item 6 done
src/wiphy.c:wiphy_radio_work_next() Starting work item 5
src/station.c:station_quick_scan_triggered() Quick scan trigger failed: -95
src/station.c:station_enter_state() Old State: connected, new state: autoconnect_full
To fix this IWD should simply cancel any pending quick scans
if/when a Connect() call comes in.
Switch EAP-TLS-ClientCert and EAP-TLS-ClientKey to use
l_cert_load_container_file for file loading so that the file format is
autodetected. Add new setting EAP-TLS-ClientKeyBundle for loading both
the client certificate and private key from one file.
As requested move the client certificate and private key loading from
eap-tls-common.c to eap-tls.c. No man page change needed because those
two settings weren't documented in it in the first place.
This adds a new AccessPointDiagnostic interface. This interface
provides similar low level functionality as StationDiagnostic, but
for when IWD is in AP mode. This uses netdev_get_all_stations
which will dump all stations, parse, and return each station in
an individual callback. Once the dump is complete the destroy is
called and all data is packaged as an array of dictionaries.
AP mode will use the same structure for its diagnostic interface
and mostly the same dictionary keys. Apart from ConnectedBss and
Address being different, the remainder are the same so the
diagnostic_station_info to DBus dictionary conversion has been made
common so both station and AP can use it to build its diagnostic
dictionaries.
With AP now getting its own diagnostic interface it made sense
to move the netdev_station_info struct definition into its own
header which eventually can be accompanied by utilities in
diagnostic.c. These utilities can then be shared with AP and
station as needed.
systemd specifies a special passive target unit 'network-pre.target'
which may be pulled in by services that want to run before any network
interface is brought up or configured. Correspondingly, network
management services such as iwd and ead should specify
After=network-pre.target to ensure a proper ordering with respect to
this special target. For more information on network-pre.target, see
systemd.special(7).
Two examples to explain the rationale of this change:
1. On one of our embedded systems running iwd, a oneshot service is
run on startup to configure - among other things - the MAC address of
the wireless network interface based on some data in an EEPROM.
Following the systemd documentation, the oneshot service specifies:
Before=network-pre.target
Wants=network-pre.target
... to ensure that it is run before any network management software
starts. In practice, before this change, iwd was starting up and
connecting to an AP before the service had finished. iwd would then
get kicked off by the AP when the MAC address got changed. By
specifying After=network-pre.target, systemd will take care to avoid
this situation.
2. An administrator may wish to use network-pre.target to ensure
firewall rules are applied before any network management software is
started. This use-case is described in the systemd documentation[1].
Since iwd can be used for IP configuration, it should also respect
the After=network-pre.target convention.
Note that network-pre.target is a passive unit that is only pulled in if
another unit specifies e.g. Wants=network-pre.target. If no such unit
exists, this change will have no effect on the order in which systemd
starts iwd or ead.
[1] https://www.freedesktop.org/wiki/Software/systemd/NetworkTarget/
Following a successful roaming sequence, schedule another attempt unless
the driver has sent a high RSSI notification. This makes the behaviour
analogous to a failed roaming attempt where we remained connected to the
same BSS.
This makes iwd compatible with wireless drivers which do not necessarily
send out a duplicate low RSSI notification upon reassociation. Without
this change, iwd risks getting indefinitely stuck to a BSS with low
signal strength, even though a better BSS might later become available.
In the case of a high RSSI notification, the minimum roam time will also
be reset to zero. This preserves the original behaviour in the case
where a high RSSI notification is processed after station_roamed().
Doing so also gives a chance for faster roaming action in the following
example scenario:
1. RSSI LOW
2. schedule roam in 5 seconds
(5 seconds pass)
3. try roaming
4. roaming fails, same BSS
5. schedule roam in 60 seconds
(20 seconds pass)
6. RSSI HIGH
7. cancel scheduled roam
(20 seconds pass)
8. RSSI LOW
9. schedule roam in 5 seconds or 20 seconds?
By resetting the minimum roam time, we can avoid waiting 20 seconds when
the station may have moved considerably. And since the high/low RSSI
notifications are configured with a hysteresis, we should still be
protected against too frequent spurious roaming attempts.
This is a nl80211 dump version of netdev_get_station aimed at
AP mode. This will dump all stations, parse into
netdev_station_info structs, and call the callback for each
individual station found. Once the dump is completed the destroy
callback is called.
This adds a generalized API for GET_STATION. This API handles
calling and parsing the results into a new structure,
netdev_station_info. This results structure will hold any
data needed by consumers of netdev_get_station. A helper API
(netdev_get_current_station) was added as a convenience which
automatically passes handshake->aa as the MAC.
For now only the RSSI is parsed as this is already being
done for RSSI polling/events. Looking further more info will
be added such as rx/tx rates and estimated throughput.
Arrays of dictionaries are quite common, and for basic
types this API makes things much more convenient by
putting all the enter/append/leave calls in one place.
Add a parameter to station_set_scan_results to allow skipping the
removal of old BSSes. In the DBus-triggered scan only expire BSSes
after having gone through the full supported frequency set.
It should be safe to pass partial scan results to
station_set_scan_results() when not expiring BSSes so using this new
parameter I guess we could also call it for roam scan results.
A scan normally takes about 2 seconds on my dual-band wifi adapter when
connected. The drivers will normally probe on each supported channel in
some unspecified order and will have new partial results after each step
but the kernel sends NL80211_CMD_NEW_SCAN_RESULTS only when the full
scan request finishes, and for segmented scans we will wait for all
segments to finish before calling back from scan_active() or
scan_passive().
To improve user experience define our own channel order favouring the
2.4 channels 1, 6 and 11 and probe those as an individual scan request
so we can update most our DBus org.connman.iwd.Network objects more
quickly, before continuing with 5GHz band channels, updating DBus
objects again and finally the other 2.4GHz band channels.
The overall DBus-triggered scan on my wifi adapter takes about the same
time but my measurements were not very strict, and were not very
consistent with and without this change. With the change most Network
objects are updated after about 200ms though, meaning that I get most
of the network updates in the nm-applet UI 200ms from opening the
network list. The 5GHz band channels take another 1 to 1.5s to scan and
remaining 2.4GHz band channels another ~300ms.
Hopefully this is similar when using other drivers although I can easily
imagine a driver that parallelizes 2.4GHz and 5GHz channel probing using
two radios, or uses 2, 4 or another number of dual-band radios to probe
2, 4, ... channels simultanously. We'd then lose some of the
performance benefit. The faster scan results may be worth the longer
overall scan time anyway.
I'm also assuming that the wiphy's supported frequency list is exactly
what was scanned when we passed no frequency list to
NL80211_CMD_TRIGGER_SCAN and we won't get errors for passing some
frequency that shouldn't have been scanned.
When the IP is configured to be static we can now use ACD in
order to check that the IP is available and not already in
use. If a conflict is found netconfig will be reset and no IP
will be set on the interface. The ACD client is left with
the default 'defend once' policy, and probes are not turned
off. This will increase connection time, but for static IP's
it is the best approach.
The docs just specified what a IP prefix looks like, not an
actual example. Though its not recommended to just copy paste
blindly, its still useful to have some value in the man pages
that actually works if someone just wants to get a DHCP server
working.
In the strange case that the dns list or the domain list are empty and
openresolv is being used, delete the openresolv entry instance instead
of trying to set it to an empty value
Make sure to erase the network_info of a known network that has been
removed before disconnecting any stations connected to it. This fixes
the following warning observed when forgetting a connected network:
WARNING: ../git/src/network.c:network_rank_update() condition n < 0 failed
This also fixes a bug where such a forgotten network would incorrectly
appear as the first element in the response to GetOrderedNetworks(). By
clearing the network_info, network_rank_update() properly negates the
rank of the now-unknown network.
==5279== 104 bytes in 2 blocks are definitely lost in loss record 1 of 1
==5279== at 0x4C2F0CF: malloc (vg_replace_malloc.c:299)
==5279== by 0x4655CD: l_malloc (util.c:61)
==5279== by 0x47116B: l_rtnl_address_new (rtnl.c:136)
==5279== by 0x438F4B: netconfig_get_dhcp4_address (netconfig.c:429)
==5279== by 0x438F4B: netconfig_ipv4_dhcp_event_handler
(netconfig.c:735)
==5279== by 0x491C77: dhcp_client_event_notify (dhcp.c:332)
==5279== by 0x491C77: dhcp_client_rx_message (dhcp.c:810)
==5279== by 0x492A88: _dhcp_default_transport_read_handler
(dhcp-transport.c:151)
==5279== by 0x46BECB: io_callback (io.c:118)
==5279== by 0x46B10C: l_main_iterate (main.c:477)
==5279== by 0x46B1DB: l_main_run (main.c:524)
==5279== by 0x46B3EA: l_main_run_with_signal (main.c:646)
==5279== by 0x403ECE: main (main.c:490)
Fix the AlwaysRandomizeAddress setting name.
Add the stricter specification of the extension syntax.
Clarify that GTC and MD5 can't be used as outer EAP methods with wifi.
Tracking of addresses that weren't set by us seemed a bit questionable.
Take this out for now. If this is ever needed, then a queue with
l_rtnl_address objects should be used.
Introduce a new v4_address member which will hold the currently
configured IPV4 address (static or obtained via DHCP). Use the new
l_rtnl_address class for this.
As a side-effect, lease expiration will now properly remove the
configured address.
This patch converts the code to use the new l_rtnl_address class. The
settings parsing code will now return an l_rtnl_address object which
can be installed directly.
Also, address removal path for static addresses has been removed, since
netconfig_reset() sets disable_ipv6 setting to '1', which will remove
all IPV6 addresses for the interface.
This patch converts the code to use the new l_rtnl_route class instead
of using l_rtnl_route6* utilities. The settings parsing code will now
return an l_rtnl_route object which can be installed directly.
Also, the route removal path has been removed since netconfig_reset()
sets disable_ipv6 setting to '1' which will remove all IPV6 routes and
addresses for the interface.
This also changes the resolve API a little bit to act as a 'set' API
instead of an incremental 'add' API. This is actually easier to manage
in the resolve module since both systemd and resolvconf want changes
wholesale and not incrementally.
Waiting to request neighbor reports until we are in need of a roam
delays the roam time, and probably isn't as reliable since we are
most likely in a low RSSI state. Instead the neighbor report can
be requested immediately after connecting, saved, and used if/when
a roam is needed. The existing behavior is maintained if the early
neighbor report fails where a neighbor report is requested at the
time of the roam.
The code which parses the reports was factored out and shared
between the existing (late) neighbor report callback and the early
neighbor report callback.
handshake_state_set_authenticator_ie must be called to set group_cipher
in struct handshake_shake before handshake_set_gtk_state, otherwise
handshake_set_gtk_state is unable to determine the key length to set
handshake state gtk.
Fixes: 4bc20a0979 ("ap: Start EAP-WSC authentication with WSC enrollees")
For now the RA client is ran automatically when DHCPv6 client starts.
RA takes care of installing / deleting prefix routes and installing the
default gateway. If Router Advertisements indicate support DHCPv6, then
DHCPv6 transactions are kicked off and the address is set / removed
automatically.
Stateless configuration is not yet supported.
Modern kernels ~5.4+ have changed the way lost beacons are
reported and effectively make the lost beacon event useless
because it is immediately followed by a disconnect event. This
does not allow IWD enough time to do much of anything before
the disconnect comes in and we are forced to fully re-connect
to a different AP.
If EnableNetworkConfiguration was enabled ap.c required that
APRanges also be set. This prevents IWD from starting which
effects a perfectly valid station configuration. Instead if
APRanges is not provided IWD still allows ap_init to pass but
DHCP just will not be enabled.
Users can now supply an AP provisioning file containing an [IPv4]
section and define various DHCP settings:
[IPv4]
Address=<address>
Netmask=<netmask>
Gateway=<gateway>
IPRange=<start_address>,<end_address>
DNSList=<dns1>,<dns2>,...<dnsN>
LeaseTime=<lease_time>
There are a few notes/requirements to keep in mind when using a
provisioning file:
- All settings are optional but [IPv4].Address is required if the
interface does not already have an address set.
- If no [IPv4].Address is defined in the provisioning file and the AP
interface does not already have an address set, StartWithConfig()
will fail with -EINVAL.
- If a provisioning file is provided it will take precedence, and the
AP will not pull from the IP pool.
- A provisioning file containing an IPv4 section assumes DHCP is being
enabled and will override [General].EnableNetworkConfiguration.
- Any address that AP sets on the interface will be deleted when the AP
is stopped.
Users can now start an AP from settings based on a profile
on disk. The only argument is the SSID which will be used to
lookup the profile. If no profile is found a NotFound error
will be returned. Any invalid profiles will result in an
Invalid return.
This seems to happen occationally with testAP (potentially others).
The invalid read appears to happen when the frame_xchg_tx_cb detects
an early status and no ACK. In this particular case there is no
retry interval so we reach the retry limit and 'done' the frame.
This frees the 'fx' data all before the destroy callback can get
called. Once we finally return and the destroy callback is called
'fx' is freed and we see the invalid write.
==206== Memcheck, a memory error detector
==206== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==206== Using Valgrind-3.16.1 and LibVEX; rerun with -h for copyright info
==206== Command: iwd -p rad1,rad2,rad3,rad4 -d
==206== Parent PID: 140
==206==
==206== Invalid write of size 4
==206== at 0x4493A0: frame_xchg_tx_destroy (frame-xchg.c:941)
==206== by 0x46DAF6: destroy_request (genl.c:673)
==206== by 0x46DAF6: process_unicast (genl.c:1002)
==206== by 0x46DAF6: received_data (genl.c:1101)
==206== by 0x46AA4B: io_callback (io.c:118)
==206== by 0x469D6C: l_main_iterate (main.c:477)
==206== by 0x469E1B: l_main_run (main.c:524)
==206== by 0x469E1B: l_main_run (main.c:506)
==206== by 0x46A02B: l_main_run_with_signal (main.c:646)
==206== by 0x403E78: main (main.c:490)
==206== Address 0x4c59c6c is 172 bytes inside a block of size 176 free'd
==206== at 0x483B9F5: free (vg_replace_malloc.c:538)
==206== by 0x40F14C: destroy_work (wiphy.c:248)
==206== by 0x40F14C: wiphy_radio_work_done (wiphy.c:1578)
==206== by 0x44A916: frame_xchg_tx_cb (frame-xchg.c:930)
==206== by 0x46DAD9: process_unicast (genl.c:993)
==206== by 0x46DAD9: received_data (genl.c:1101)
==206== by 0x46AA4B: io_callback (io.c:118)
==206== by 0x469D6C: l_main_iterate (main.c:477)
==206== by 0x469E1B: l_main_run (main.c:524)
==206== by 0x469E1B: l_main_run (main.c:506)
==206== by 0x46A02B: l_main_run_with_signal (main.c:646)
==206== by 0x403E78: main (main.c:490)
==206== Block was alloc'd at
==206== at 0x483A809: malloc (vg_replace_malloc.c:307)
==206== by 0x4643CD: l_malloc (util.c:61)
==206== by 0x44AF8C: frame_xchg_startv (frame-xchg.c:1155)
==206== by 0x44B2A4: frame_xchg_start (frame-xchg.c:1108)
==206== by 0x42BC55: ap_send_mgmt_frame (ap.c:709)
==206== by 0x42F513: ap_probe_req_cb (ap.c:1869)
==206== by 0x449752: frame_watch_unicast_notify (frame-xchg.c:233)
==206== by 0x46DA2F: dispatch_unicast_watches (genl.c:961)
==206== by 0x46DA2F: process_unicast (genl.c:980)
==206== by 0x46DA2F: received_data (genl.c:1101)
==206== by 0x46AA4B: io_callback (io.c:118)
==206== by 0x469D6C: l_main_iterate (main.c:477)
==206== by 0x469E1B: l_main_run (main.c:524)
==206== by 0x469E1B: l_main_run (main.c:506)
==206== by 0x46A02B: l_main_run_with_signal (main.c:646)
==206==
The DHCP server can be enabled by enabling network configuration
with [General].EnableNetworkConfiguration. If an IP is not set
on the interface before the AP is started a valid IP range must
also be provided under [General].APRanges in IP prefix format e.g.
[General]
EnableNetworkConfiguration=true
APRanges=192.168.1.1/24
Each AP started will get assigned a new subnet within the range
specified by APRanges as to not conflict with other AP interfaces.
If there are no subnets left in the pool when an AP is started
it will fail with -EEXIST. Any AP's that are stopped will release
their subnet back into the pool to be used with other APs.
The DHCP IP pool will be automatically chosen by the ELL DHCP
implementation (+1 the AP's IP to *.254). The remaining DHCP
settings will be defaults chosen by ELL (DNS, lease time, etc).
periodic_scan_stop is called whenever we exit the autoscan state but a
periodic scan may not be running at the time. If we have a
user-triggered scan running, or the autoconnect_quick scan, and we reset
Scanning to false before that scan finished, a client could en up
calling GetOrderedNetwork too early and not receiving the scan results.
ConnectHiddenNetwork can be seen a triggering this sequence:
1. the active scan,
2. the optional agent request,
3. the Authentication/Association/4-Way Handshake/netconfig,
4. connected state
Currently Disconnect() interrupts 3 and 4, allow it to also interrupt
state 1. It's difficult to tell whether we're in state 2 from within
station.c.
Since our DBus API and our use cases only support initiating connections
and not accepting incoming connections we don't really need to reply to
Probe Requests on the P2P-Device interface. Start doing it firstly so
that we can test the scenario where we get discovered and pre-authorized
to connect in an autotest (wpa_supplicant doesn't seem to have a way to
authorize everyone, which is probably why most Wi-Fi Display dongles
don't do it and instead reply with "Fail: Information not available" and
then restart connection from their side) and secondly because the spec
wants us to do it.
Make sure dev->peer_list is non-NULL before using l_queue_push_tail()
same as we do when the peer info comes from a Probe Response (active
scan in Find Phase). Otherwise peers discovered through Probe Requests
before any Probe Responses are received will be lost.
The device type category array is indexed by the category ID so if we're
skipping i == 0 in the iteration, we should also skip the 0'th element
in device_type_categories.
The callback for the FRAME command was causing a crash in
wiphy_radio_work_done when not cancelled when the wiphy was being
removed from the system. This was likely to happen if this radio work
item was waiting for another item to finish. When the first one was
being cancelled due to the wiphy being removed, this one would be
started and immediately stopped by the radio work queue.
Now this crash could be fixed by dropping all frame exchange instances
on an interface that is being removed which is easy to do, but properly
cancelling the commands saves us the headache of analysing whether
there's a race condition in other situations where a frame exchange is
being aborted.
We want to use this flag only on the interfaces with one of the three
P2P iftypes so set the flag automatically depending on the iftype from
the last 'config' notification.
Convert ap_send_mgmt_frame() to use frame_xchg_start for sending frames,
this fixes among other things the ACK-received checks.
One side effect is that we're no longer sending Probe Responses with the
don't-wait-for-ack flag because frame-xchg doesn't support it, but other
AP implementations don't use that flag either.
Another side-effect is that we do use the no-cck-rate flag
unconditionally, something we may want to fix but would need to add
another parameter to frame-xchg.
Add a "psk" setting to allow the user to pass the binary PSK directly
instead of generating it from the passphrase and the SSID. In that case
we'll only send the PSK to WSC enrollees.
There has been a desire to remove the ELL plugin dependency from
IWD which is the only consumer of the plugin API. This removes
the dependency and prepares the tree for converting the existing
ofono plugin into a regular module.
sim_hardcoded was removed completely. This was originall implemented
before full ofono support purely to test the IWD side of EAP-SIM/AKA.
Since the ofono plugin (module-to-be) is now fully implemented there
really isn't a need for sim_hardcoded.
The Started property was being set in the Join IBSS callback which
isn't really when the IBSS has been started. The kernel automatically
scans for IBSS networks which takes some time. Its better to wait
on setting Started until we get the Join IBSS event.
Commit 1f910f84b4 ("eapol: Use eapol_start in authenticator mode too")
introduced the requirement that authentication eapol_sm objects also had
to be started via eapol_start. Adhoc was never updated to do that.
For multi-bss networks its nice to know which BSS is being connected
to. The ranking can hint at it, but blacklisting or network capabilities
could effect which network is actually chosen. An explicit debug print
makes debugging much easier.
Again the hs->support_ip_allocation flag is used for two purposes here,
first the user signals whether to support this mechanism through this
flag, then it reads the flag to find out if an IP was allocated.
Support IP allocation during the 4-Way Handshake as defined in the P2P
spec. This is the supplicant side implementation.
The API requires the user to set hs->support_ip_allocation true before
eapol_start(). On HANDSHAKE_EVENT_COMPLETE, if this same flag is still
set, we've received the IP lease, the netmask and the authenticator's
IP from the authenticator and there's no need to start DHCP. If the
flag is cleared, the user needs to use DHCP.
Allow the possibility of becoming the Group-owner when we parse the GO
Negotiation Request, build GO Negotiation Response and parse the GO
Negotiation Confirmation, i.e. if we're responding to a negotiation
initiated by the peer after it needed to request user action.
Until now the code assumed we can't become the GO or we'd report error.
Allow the possibility of becoming the Group-owner when we build the GO
Negotiation Request, parse GO Negotiation Response and build the GO
Negotiation Confirmation, i.e. if we're the initiator of the
negotiation.
Until now the code assumed we can't become the GO or we'd report error.
Add a utility to select random characters from the set defined in P2P
v1.7 Section 3.2.1. In this version the assumption is that we're only
actually using this for the two SSID characters.
explicit_bzero is used in src/ap.c since commit
d55e00b31d but src/missing.h is not
included, as a result build with uclibc fails on:
/srv/storage/autobuild/run/instance-1/output-1/host/lib/gcc/xtensa-buildroot-linux-uclibc/9.3.0/../../../../xtensa-buildroot-linux-uclibc/bin/ld: src/ap.o: in function `ap_probe_req_cb':
ap.c:(.text+0x23d8): undefined reference to `explicit_bzero'
Fixes:
- http://autobuild.buildroot.org/results/c7a0096a269bfc52bd8e23d453d36d5bfb61441d
Add the special case "DIRECT-" SSID, called the P2P Wildcard SSID, in
ap_probe_req_cb so as not to reject those Probe Requests on the basis of
ssid mismatch. I'd have preferred to keep all the P2P-specific bits in
p2p.c but in this case there's little point in adding a generic
config setting for SSID-matching quirks.
Prefix all the struct p2p_device members that are part of the connection
state with the "conn_" string for consistency. If we needed to support
multiple client connections, these members are the ones that would
probably land in a separate structure, without that prefix.
For WSC we should have been sending our probe requests from the same
address we're going to be doing EAP-WSC with the GO. Somehow I was able
to connect to most devices without that but other implementations seem
to use the Interface Address (the P2P-Client's MAC), not the Device
Address (P2P-Device's MAC). We could switch the order to first create
the new interface and scan from it is simpler to use the scan_context we
already have created on the device interface and set a different mac.
Check the conditions for PBC enrollee registration when we receive the
Association Request with WSC IE and indicate to the enrollee whether we
accept the association using a WSC IE in the Association Response.
After this, a NULL sta->assoc_rsne indicates that the station is not
establishing the RSNA and is a WSC enrollee.
Implement the caching of WSC probe requests -- when an Enrollee later
associates to start registration we need to have its Probe Request on
file. Also use this cache for PBC "Session Overlap" detection.
This adds the API for putting the AP in Push Button mode, which we'll
need to P2P GO side but may be useful on its own too. A WSC IE is added
to our beacons and probe responses indicating whether the PBC mode is
active.
On a new association or re-association, in addition to forgetting a
complete RSN Association, also stop the EAPoL SM to stop any ongoing
handshake.
Do this in a new function ap_stop_handshake that is now used in a few
places that had copies of the same few lines. I'll be adding some more
lines to this function for WSC support.
Reuse this flag on the authenticator side with a slightly different
meaning: when it's true we're forced to wait for the EAPoL-Start before
sending the first EAPoL-EAP frame to the supplicant, such as is required
in a WSC enrollee registration when the Association Request didn't have
a v2.0 WSC IE.
Add the wfa_build_authorized_macs function (wfa_ prefix following the
wfa_extract_ naming) and use it in wsc_build_probe_response. The logic
is changed slightly to treat the first 6-zeros address in the array as
the end of the array.
Setting 'match' false wouldn't do anything because it was already false.
If the frame is addressed to some other non-broadcast address ignore it
directly and exit ap_probe_req_cb.
To limit the number of ap_start parameters, group basic AP config
parameters in the ap_config struct that is passed as a pointer and owned
by the ap_state.
The intent was to read the UUID-E from the settings rather than generate
it from the enrollee's MAC because it needs to match the UUID-E from
enrolee's Probe Requests, fix this. The UUID-E supplied in the unit
test was being ignored but the test still passed because the supplied
UUID-E was generated the same way we generated it in eap-wsc.c.
When we're sending our probe response to the same peer that we're
currently connected or connecting to, use current WSC Configuration
Methods, UUID-E and WFD IE selected for this connection attempt, not the
ones we'd use when discovering peers or being discovered by peers.
In the case of the WFD IE, the "Available for WFD Session" flag is going
to differ between the two cases -- we may be unavailable for other peers
but we're still available for the peer we're trying to start the WFD
session with.
When we send our GO Negotiation Response, send the Configuration Method
selected for the current connection rather than the accepted methods mask
that we hold in dev->device_info.
When building the scan IEs for our provisioning scans, use the UUID-E
based on the Interface Address, not the Device Address, as that is what
wsc.c will be using to in the registration protocol.
Eventually we may have to base the UUID-E on the Device Address or
something else that is persistent, and pass the actual UUID-E to wsc.c,
as the Interface Address is randomly generated on every connect attempt.
IIRC the UUID-E is supposed to be persistent.
wsc_attr_builder_start_attr and wsc_attr_builder_free look at
builder->curlen to see whether the TLV's length needs to be updated to
include the previous attribute. If builder->curlen is 0
wsc_attr_builder_start_attr assumes there's no previous attribute and
starts writing at current builder->offset. If the previous attribute
length was 0 curlen would stay at 0 and that attribute would get
overwritten with the new one. To solve this add the 4 bytes of the T
and L to curlen as soon as a new attribute is started, and subtract
them when writing the L value. The alternative would be to set a flag
to say whether an attribute was started.
The spec explicitly allows 0-length attributes in section 12:
"The variable length string attributes, e.g., Device Name, are encoded
without null-termination, i.e., no 0x00 octets added to the end of the
value. If the string is empty, the attribute length is set to zero."
Add ability to populate search domains for resolvconf based systems.
Search domains are added using the 'search' directive and added using
the <ifname>.domain key into resolvconf.
Introduce a new resolvconf_invoke function that takes care of all the
details of invoking resolvconf and simplify the code a bit.
Introduce have_dns that tracks whether DNS servers were actually
provided. If no DNS info was provided, do not invoke resolvconf to
remove it.
Instead of interface index, resolvconf is now invoked with the printable
name of the interface and the dns entries are placed in the "dns"
protocol. This makes it a bit simpler to add additional info to
resolvconf instead of trying to generate a monolithic entry.
Resolve module does not currently track any state that has been set on
a per ifindex basis. This was okay while the set of information we
supported was quite small. However, with dhcpv6 support being prepared,
a more flexible framework is needed.
Change the resolve API to allocate and return an instance for a given
ifindex that has the ability to track information that was provided.
Found using lsan:
==29896==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 9 byte(s) in 1 object(s) allocated from:
#0 0x7fcd41e0c710 in __interceptor_malloc /var/tmp/portage/sys-devel/gcc-8.2.0-r6/work/gcc-8.2.0/libsanitizer/asan/asan_malloc_linux.cc:86
#1 0x606abd in l_malloc ell/util.c:62
#2 0x460230 in ie_tlv_vendor_ie_concat src/ie.c:140
#3 0x4605d1 in ie_tlv_extract_wfd_payload src/ie.c:216
#4 0x4a8773 in scan_parse_bss_information_elements src/scan.c:1105
#5 0x4a94a8 in scan_parse_attr_bss src/scan.c:1181
#6 0x4a99f8 in scan_parse_result src/scan.c:1238
#7 0x4abe4e in get_scan_callback src/scan.c:1451
#8 0x6442d9 in process_unicast ell/genl.c:979
#9 0x6453ff in received_data ell/genl.c:1087
#10 0x62e1a4 in io_callback ell/io.c:126
#11 0x628fca in l_main_iterate ell/main.c:473
#12 0x6294e8 in l_main_run ell/main.c:520
#13 0x629d8b in l_main_run_with_signal ell/main.c:642
#14 0x40681b in main src/main.c:505
#15 0x7fcd40a55bdd in __libc_start_main (/lib64/libc.so.6+0x21bdd)
This commit has all the changes to extend and generalise the current
eap-wsc.c code to handle both the Enrollee and Registrar side of the
protocol, reusing existing functions and structures.
Alongside the current EAP-WSC enrollee side support, add the initial
part of registrar side. In the same file, register a new method with
the name string of "WSC-R". In this patch only the load_settings
method is added. validate_identity and handle_response are added in
later patches.
Handle EAPoL-EAP frames using our eap.c methods in authenticator mode
same as we do on the supplicant side. The user (ap.c) will only need to
set a valid 8021x_settings in the handshake object, same as on the
supplicant side.
The goal is to add specifically EAP-WSC registrar side and it looks like
extending our EAP and EAPoL code to support both supplicant and
authenticator-side methods is simpler than adding just EAP-WSC as a
special case.
Since EAP-WSC always ends in an EAP failure, I haven't actually tested
the success path.
On the supplicant side eapol_register would only register the eapol_sm
on a given netdev to start receiving frames and an eapol_start call is
required for the state machine to start executing. On the authenticator
side we shouldn't have the "early frame" problem but there's no reason
for the semantics of the two methods to be different. Somehow we were
doing everything in eapol_register and not using eapol_start if
hs->authenticator was true, so bring this in line with the supplicant
side and require eapol_start to be called also from ap.c.
Move the update of station->networks_sorted order to before we set
station->connected_network NULL to avoid a crash when we attempt to
use the NULL pointer.
Besides being undefined behaviour, signed integer overflow can cause
unexpected comparison results. In the case of network_rank_compare(),
a connected network with rank INT_MAX would cause newly inserted
networks with negative rank to be inserted earlier in the ordered
network list. This is reflected in the GetOrderedMethods() DBus method
as can be seen in the following iwctl output:
[iwd]# station wlan0 get-networks
Network name Security Signal
----------------------------------------------------
BEOLAN 8021x **** }
BeoBlue psk *** } all unknown,
UI_Test_Network psk *** } hence assigned
deneb_2G psk *** } negative rank
BEOGUEST open **** }
> titan psk ****
Linksys05274_5GHz_dmt psk ****
Lyngby-4G-4 5GHz psk ****
Doing so ensures that the currently connected network is always at the
beginning of the list. Previously, the list would only get updated after
a scan.
This fixes the documented behaviour of GetOrderedNetworks() DBus method,
which states that the currently connected network is always at the
beginning of the returned array.
Fix a logic error which prevented iwd from using SAE/WPA3 when
attempting to connect to APs that are in transition mode. The SAE/WPA3
check incorrectly required mfpr bit to be set, which is true for
APs in WPA3-Personal only mode, but is set to 0 for APs in
WPA3-Personal transition mode.
This patch also adds a bit more diagnostic output to help diagnose
causes for connections where WPA3 is not attempted even when advertised
by the AP.
Replace the usage of eap_send_response() in the method implementations
with a new eap_method_respond that skips the redundant "type" parameter.
The new eap_send_packet is used inside eap_method_respond and will be
reused for sending request packets in authenticator side EAP methods.
Throughout the supplicant mode we'd use the eapol_sm_write wrapper but
in the authenticator mode we'd call __eapol_tx_packet directly. Adapt
eapol_sm_write to use the right destination address and use it
consistently.
sm->handshake already contains our RSN/WPA IE so there's no need to
rebuild it for msg 3/4, especially since we hardcode the fact that we
only support one pairwise cipher. If we start declaring more supported
ciphers and need to include a second RSNE we can first parse
sm->hs->authenticator_ie into a struct ir_rsn_info, overwrite the cipher
and rebuild it from that struct.
This way we duplicate less code and we hardcode fewer facts about the AP
in eapol.c which also helps in adding EAP-WSC.
In both FT or FILS EAPoL isn't used for the initial handshake and only
for the later re-keys. For FT we added the
eapol_sm_set_require_handshake mechanism to tell EAPoL to not require
the initial handshake and we can re-use it for FILS.
Currently an adversary can retransmit EAPOL Msg4/4 to make the AP
reinstall the PTK. Against older Linux kernels this can subsequently
be used to decrypt, replay, and possibly decrypt frames. See the
KRACK attacks research at krackattacks.com for attack scenarios.
In this case no machine-in-the-middle position is needed to trigger
the key reinstallation.
Fix this by using the ptk_complete boolean to track when the 4-way
handshake has completed (similar to its usage for clients). When
receiving a retransmitted Msg4/4 accept this frame but do not reinstall
the PTK.
Credits to Chris M. Stone, Sam Thomas, and Tom Chothia of Birmingham
University to help discover this issue.
Instead of creating the results->bss_list l_queue lazily, always create
one before sending the GET_SCAN command. This is to make sure that an
empty list is passed to the scan callback (e.g. in station.c) instead of
a NULL. Passing NULL has been causing difficult to debug crashes in
station.c, in fact I think I've been seeing them for over a year now
but can't be sure. station_set_scan_results has been taking ownership
of the new BSS list and, if station->connected_bss was not on the list,
it would try to add it not realizing that l_queue_push_tail() was doing
nothing. Always passing a valid list may help us prevent similar
problems in the future.
The crash might start with:
==120489== Invalid read of size 8
==120489== at 0x425D38: network_bss_select (network.c:709)
==120489== by 0x415BD1: station_try_next_bss (station.c:2263)
==120489== by 0x415E31: station_retry_with_status (station.c:2323)
==120489== by 0x415E31: station_connect_cb (station.c:2367)
==120489== by 0x407E66: netdev_connect_failed (netdev.c:569)
==120489== by 0x40B93D: netdev_connect_event (netdev.c:1801)
==120489== by 0x40B93D: netdev_mlme_notify (netdev.c:3678)
Incorporate the LGPL v2.1 licensed implementation of ARC4, taken from
the Nettle project (https://git.lysator.liu.se/nettle/nettle.git,
commit 3e7a480a1e351884), and tweak it a bit so we don't have to
operate on a skip buffer to fast forward the stream cipher, but can
simply invoke it with NULL dst or src arguments to achieve the same.
This removes the dependency [via libell] on the OS's implementation of
ecb(arc4), which may be going away, and which is not usually accelerated
in the first place.
Use a constant control flow in the derivation loop, avoiding leakage
in the iteration succesfuly converting the password.
Increase number of iterations (20 to 30) to avoid issues with
passwords needing more iterations.
With some devices the 10 seconds are not enough for the P2P Group Owner
to give us an address but I think we still want to use a timeout as
short as possible so that the user doesn't wait too long if the
connection isn't working.
p2p_connection_reset may be called as a result of a WFD service
unregistering and p2p_own_wfd is going to be NULL, don't update
p2p_own_wfd->available in this case.
With some WFD devices we occasionally get a Disconnect before or during
the DHCP setup on the first connection attempt to a newly formeg group,
with the reason code MMPDU_REASON_CODE_PREV_AUTH_NOT_VALID. Retrying a
a few times makes the connections consistently successful. Some
conditions are simplified/update in this patch because
conn_dhcp_timeout now implies conn_wsc_bss, and both imply
conn_retry_count.
In 98cf2bf3ec frame_xchg_stop was removed
and its use in p2p.c was changed to frame_xchg_cancel with the slight
complication that the ID returned by frame_xchg_start had do be stored.
Re-add frame_xchg_stop, (renamed as frame_xchg_stop_wdev) to simplify
this bit in p2p.c.
Since there may now be multiple frames-xchg record for each wdev, when
we receive the TX Status event, make sure we find the record who's radio
work has started, as indicated by fx->retry_cnt > 0. Otherwise we're
relying on the ordering of the frames in the "frame_xchgs" queue and
constant priority.
The BSSID (address_3) in response frames was being checked to be the
same as in the request frame, or all-zeros for faulty drivers. At least
one Wi-Fi Display device sends a GO Negotiation Response with the BSSID
different from its Device Address (by 1 bit) and I didn't see an easy
way to obtain that address beforhand so we can "whitelist" it for this
check, so just drop that check for now.
ANQP didn't have this check before it started using frame-xchg so it
shouldn't be critical.
When a frame registered in a given group Id triggers a callback and that
callback ends up calling frame_watch_group_remove for that group Id,
that call will happen inside WATCHLIST_NOTIFY_MATCHES and will free the
memory used by the watchlist. watchlist.h has protection against the
watchlist being "destroyed" inside WATCHLIST_NOTIFY_MATCHES, but not
against its memory being freed -- the memory where it stores the in_notify
and destroy_pending flags. Free the group immediately after
WATCHLIST_NOTIFY_MATCHES to avoid reads/writes to those flags triggering
valgrind warnings.
frame_xchg_destroy is passed as the wiphy radio work's destroy callback
to wiphy.c. If it's also called directly in frame_xchg_exit, there's
going to be a use-after-free when it's called again from wiphy_exit, so
instead use wiphy_radio_work_done which will call frame_xchg_destroy and
forget the frame_xchg record.
This patch lets us establish WFD connections by parsing, validating and
acting on WFD IEs in received frames, and adding our own WFD IEs in the
GO Negotiation and Association frames. Applications should assume that
any connection to a WFD-capable peer when we ourselves have a WFD
service registered, are WFD connections and should handle RTSP and
other IP-based protocols on those connections.
When connecting to a WFD-capable peer and when we have a WFD service
registered, the connection will fail if there are any conflicting or
invalid WFD parameters during GO Negotiation.
If anyone's registered as implementing the WFD service, add the
net.connman.iwd.p2p.Display DBus interface on peer objects that are
WFD-capable and are available for a WFD Session.
The net.connman.iwd.p2p.ServiceManager interface on the /net/connman/iwd
object lets user applications register/unregister the Wi-Fi Display
service. In this commit all it does is it adds local WFD information
as given by the app, to the frames we send out during discovery.
Instead of accepting raw WFD IE contents from the app and exposing
peers' raw WFD IEs to the app, we build the WFD IEs in our code based on
the few meaningful DBus properties that we support and using default
values for the rest. If an app ever needs any of the other WFD
capabilities more properties can be added.
The are useful for P2P service implementations to know unambiguously
which network interface a new P2P connection is on and the peer's IPv4
address if they need to initiate an IP connection or validate an
incoming connection's address from the peer.
This uses l_dhcp_lease_get_server_id to get the IP of the server that
offered us our current lease. l_dhcp_lease_get_server_id returns the
vaue of the L_DHCP_OPTION_SERVER_IDENTIFIER option, which is the address
that any unicast DHCP frames are supposed to be sent to so it seems to
be the best way to get the P2P group owner's IP address as a P2P-client.
peer->device_addr is a pointer to the Device Address contained in
one of two possible places in peer->bss. If during discovery we've
received a new beacon/probe response for an existing peer and we're
going to replace peer->bss, we also have to update peer->device_addr.
If we were in discovery only to be able to receive the target peer's
GO Negotiation Request (i.e. we have no users requesting discovery)
and we've received the frame and decided that the connection has
failed, exit discovery.
To use the wiphy radio work queue, scanning mostly remained the same.
start_next_scan_request was modified to be used as the work callback,
as well as not start the next scan if the current one was done
(since this is taken care of by wiphy work queue now). All
calls to start_next_scan_request were removed, and more or less
replaced with wiphy_radio_work_done.
scan_{suspend,resume} were both removed since radio management
priorities solve this for us. ANQP requests can be inserted ahead of
scan requests, which accomplishes the same thing.
Before connecting to a hidden network we must scan. During this scan
if another connection attempt comes in the expected behavior is to
abort the original connection. Rather than waiting for the scan to
complete, then canceling the original hidden connection we can just
cancel the hidden scan immediately, reply to dbus, and continue with
the new connection attempt.
The new frame-xchg module now handles a lot of what ANQP used to do. ANQP
now does not need to depend on nl80211/netdev for building and sending
frames. It also no longer needs any of the request lookups, frame watches
or to maintain a queue of requests because frame-xchg filters this for us.
From an API perspective:
- anqp_request() was changed to take the wdev_id rather than ifindex.
- anqp_cancel() was added so that station can properly clean up ANQP
requests if the device disappears.
During testing a bug was also fixed in station on the timeout path
where the request queue would get popped twice.
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.
These APIs will handle fairness and order in any operations which
radios can only do sequentially (offchannel, scanning, connection etc.).
Both scan and frame-xchg are complex modules (especially scanning)
which is why the radio management APIs were implemented generic enough
where the changes to both modules will be minimal. Any module that
requires this kind of work can push a work item into the radio
management work queue (wiphy_radio_work_insert) and when the work
is ready to be started radio management will call back into the module.
Once the work is completed (and this may be some time later e.g. in
scan results or a frame watch) the module can signal back that the
work is finished (wiphy_radio_work_done). Wiphy will then pop the
queue and continue with the next work item.
A concept of priority was added in order to allow important offchannel
operations (e.g. ANQP) to take priority over other work items. The
priority is an integer, where lower values are of a higher priority.
The concept of priority cleanly solves a lot of the complexity that
was added in order to support ANQP queries (suspending scanning and
waiting for ANQP to finish before connecting).
Instead ANQP queries can be queued at a higher priority than scanning
which removes the need for suspending scans. In addition we can treat
connections as radio management work and insert them at a lower
priority than ANQP, but higher than scanning. This forces the
connection to wait for ANQP without having to track any state.
When roaming, iwd tries to scan a limited number of frequencies to keep
the roaming latency down. Ideally the frequency list would come in from
a neighbor report, but if neighbor reports are not supported, we fall
back to our internal database for known frequencies of this network.
iwd tries to keep the number of scans down to a bare minimum, which
means that we might miss APs that are in range. This could happen
because the user might have moved physically and our frequency list is
no longer up to date, or if the AP frequencies have been reconfigured.
If a limited scan fails to find any good roaming candidates, re-attempt
a full scan right away.
If the roam failed and we are no longer connected, station_disassociated
is called which ends up calling station_roam_state_clear. Thus
resetting the variables is not needed. Reflow the logic to make this a
bit more explicit.
If the roam attempt fails, do not reset this to false. Generally this
is set by the fact that we lost beacon and to not attempt neighbor
reports, etc. This hint should be preserved across roam attempts.
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.
explicit_bzero is used in src/p2p.c since commit
1675c765a3 but src/missing.h is not
included, as a result build with uclibc fails on:
/home/naourr/work/instance-0/output-1/per-package/iwd/host/opt/ext-toolchain/bin/../lib/gcc/mips64el-buildroot-linux-uclibc/5.5.0/../../../../mips64el-buildroot-linux-uclibc/bin/ld: src/p2p.o: in function `p2p_connection_reset':
p2p.c:(.text+0x2cf4): undefined reference to `explicit_bzero'
/home/naourr/work/instance-0/output-1/per-package/iwd/host/opt/ext-toolchain/bin/../lib/gcc/mips64el-buildroot-linux-uclibc/5.5.0/../../../../mips64el-buildroot-linux-uclibc/bin/ld: p2p.c:(.text+0x2cfc): undefined reference to `explicit_bzero'
This logic was using l_hashmap_insert, which supports duplicates. Since
some entries were inserted multiple times, they ended up being printed
multiple times. Fix that by introducing a macro that uses
l_hashmap_replace instead.
Right now, if the connection fails, then network always thinks that the
password should be re-asked. Loosen this to only do so if the
connection failed at least in the handshake phase. If the connection
failed due to Association / Authentication timeout, it is likely that
something is wrong with the AP and it can't respond.
Using the new station ANQP watch network can delay the connection
request until after ANQP has finished. Since station may be
autoconnecting we must also add a check in network_autoconnect
which prevents it from autoconnecting if we have a pending Connect
request.
This is to allow network to watch for ANQP activity in order to
fix the race condition between scanning finishing and ANQP finishing.
Without this it is possible for a DBus Connect() to come in before
ANQP has completed and causing the network to return NotConfigured,
when its actually in the process of obtaining all the network info.
The watch was made globally in station due to network not having
a station object until each individual network is created. Adding a
watch during network creation would result in many watchers as well
as a lot of removal/addition as networks are found and lost.
Change signature of network_connect_new_hidden_network to take
reference to the caller's l_dbus_message struct. This allows to
set the caller's l_dbus_message struct to NULL after replying in
the case of a failure.
==201== at 0x467C15: l_dbus_message_unref (dbus-message.c:412)
==201== by 0x412A51: station_hidden_network_scan_results (station.c:2504)
==201== by 0x41EAEA: scan_finished (scan.c:1505)
==201== by 0x41EC10: get_scan_done (scan.c:1535)
==201== by 0x462592: destroy_request (genl.c:673)
==201== by 0x462987: process_unicast (genl.c:988)
==201== by 0x462987: received_data (genl.c:1087)
==201== by 0x45F5A2: io_callback (io.c:126)
==201== by 0x45E8FD: l_main_iterate (main.c:474)
==201== by 0x45E9BB: l_main_run (main.c:521)
==201== by 0x45EBCA: l_main_run_with_signal (main.c:643)
==201== by 0x403B15: main (main.c:512)
Introduce hidden_pending to keep reference to the dbus message object
while we wait for the scan results to be returned while trying to
connect to a hidden network. This simplifies the logic by separating it
into two independent logical units: scanning, connecting and eliminates
a possibility of a memory leak in the case when Network.Connect being
initiated while Station.ConnectHiddenNetwork is in progress.
If a connection is initiated (via dbus) while a quick scan is in
progress, the quick scan will be aborted. In this case,
station_quick_scan_results will always transition to the
AUTOCONNECT_FULL state regardless of whether it should or not.
Fix this by making sure that we only enter AUTOCONNECT_FULL if we're
still in the AUTOCONNECT_QUICK state.
Reported-by: Alvin Šipraga <alsi@bang-olufsen.dk>
If start_scan_next_request() is called while a scan request
(NL80211_CMD_TRIGGER_SCAN) is still running, the same scan request will
be sent again. Add a check in the function to avoid sending a request if
one is already in progress. For consistency, check also that scan
results are not being requested (NL80211_CMD_GET_SCAN), before trying to
send the next scan request. Finally, remove similar checks at
start_next_scan_request() callsites to simplify the code.
This also fixes a crash that occurs if the following conditions are met:
- the duplicated request is the only request in the scan request
queue, and
- both scan requests fail with an error not EBUSY.
In this case, the first callback to scan_request_triggered() will delete
the request from the scan request queue. The second callback will find
an empty queue and consequently pass a NULL scan_request pointer to
scan_request_failed(), causing a segmentation fault.
If scanning is suspended, have scan_common() queue its scan request
rather than issuing it immediately. This respects the assumption that
scans are not requested while sc->suspended is true.
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.
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.
802.11ai mandates that the RSN element is included during authentication
for FILS. This previously was happening by chance since supplicant_ie
was being included with CMD_AUTHENTICATE. This included more than just
the RSNE so that was removed in an earlier commit. Now FILS builds the
RSNE itself and includes this with CMD_AUTHENTICATE.
build_cmd_ft_authenticate and build_cmd_authenticate were virtually
identical. These have been unified into a single builder.
We were also incorrectly including ATTR_IE to every authenticate
command, which violates the spec for certain protocols, This was
removed and any auth protocols will now add any IEs that they require.
In this situation the kernel is sending a low RSSI event which netdev
picks up, but since we set netdev->connected so early the event is
forwarded to station before IWD has fully connected. Station then
tries to get a neighbor report, which may fail and cause a known
frequency scan. If this is a new network the frequency scan tries to
get any known frequencies in network_info which will be unset and
cause a segfault.
This can be avoided by only sending RSSI events when netdev->operational
is set rather than netdev->connected.
Some full mac cards don't like being given a FT AKM when connecting.
From an API perspective this should be supported, but in practice
these cards behave differently and some do no accept FT AKMs. Until
this becomes more stable any cards not supporting Auth/Assoc commands
(full mac) will not connect using FT AKMs.
This callback gets called way to many times to have a debug print
in the location that it was. Instead only print if a NEW wiphy is
found, and also print the name/id.
Save the value of the watchlist pointer at the beginning of the
WATCHLIST_NOTIFY_* macros as if it was a function. This will fix a
frame-xchg.c scenario in which one of the watch callback removes the
frame watch group and the memory where the watchlist pointer was
becomes unallocated but the macro still needs to access it ones or
twice while it destroys the watchlist. Another option would be for
the pointer to be copied in frame-xchg.c itself.
Use netconfig.c functions to unconditionally run DHCP negotiation,
fail the connection setup if DHCP fails. Only report connection success
after netconfig returns.
Add the final two steps of the connection setup, and corresponding
disconnect logic:
* the WSC connection to the GO to do the client provisioning,
* the netdev_connect call to use the provisioned credentials for the
final WPA2 connection.
Once we've found the provisioning BSS create the P2P-Client interface
that we're going to use for the actual provisioning and the final P2P
connection.
Some devices (a Wi-Fi Display dongle in my case) will send us Probe
Requests and wait for a response before they send us the GO
Negotiation Request that we're waiting for after the peer initially
replied with "Fail: Information Not Available" to our GO Negotiation
attempt. Curiously this specific device I tested would even accept
a Probe Response with a mangled body such that the IE sequence couldn't
be parsed.
Handle the scenario where the peer's P2P state machine doesn't know
whether a connection has been authorized by the user and needs some time
to ask the user or a higher software layer whether to accept a
connection. In that case their GO Negotiation Response to our GO
Negotiation Request will have the status code "Fail: Information Not
Available" and we need to give the peer 120s to start a new GO
Negotiation with us. In this patch we handle the GO Negotiation
responder side where we parse the Request frame, build and send the
Response and finally parse the Confirmation. The existing code so far
only did the initiator side.
Parse the GO Negotiation Response frame and if no errors found send the
GO Negotiation Confirmation. If that gets ACKed wait for the GO to set
up the group.
Add net.connman.iwd.SimpleConfiguration interfaces to peer objects on
DBus and handle method calls. Building and transmitting the actual
action frames to start the connection sequence is done in the following
commits.
Add some of the Device Discovery logic and the DBus API. Device
Discovery is documented as having three states: the Scan Phase, the Find
Phase and the Listen State.
This patch adds the Scan Phase and the next patch adds the Listen State,
which will happen sequentially in a loop until discovery is stopped.
The Find Phase, which is documented as happening at the beginning of the
Discovery Phase, is incorporated into the Scan Phases. The difference
between the two is that Find Phase scans all of the supported channels
while the Scan Phase only scans the three "social" channels. In
practical terms the Find Phase would discover existing groups, which may
operate on any channel, while the Scan Phase will only discover P2P
Devices -- peers that are not in a group yet. To cover existing groups,
we add a few "non-social" channels to each of our active scans
implementing the Scan Phases.
When a new wiphy is added query its regulatory domain and listen for
nl80211 regulatory notifications to be able to provide current
regulatory country code through the new wiphy_get_reg_domain_country().
Implement the Enabled property on device interface. The P2P device is
currently disabled on startup but automatically enabling the P2P device
can be considered.
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
For PSK networks we have netdev.c taking care of setting the linkmode &
operstate. For open adhoc networks, netdev.c was never involved which
resulted in linkmode & operstate never being set. Fix this by invoking
the necessary magic when a connection is established.
adhoc_reset() destroys ssid and sta_states but leaves the pointers
around, athough the adhoc_state structure is not always freed.
This causes a segfault when exiting iwd after a client has done
adhoc start and adhoc stop on a device since adhoc_reset() is called
from adhoc_sta_free although it was previously called from
adhoc_leave_cb().
The netdev_leave_adhoc() returns a negative errno on errors and zero
on success, but adhoc_dbus_stop() assumed the inverse when checking for
an error.
Also, the DBus message was not being referenced in adhoc->pending and
then adhoc_leave_cb() segfaulted attempting to dereference it.
It seems some APs send the IGTK key in big endian format (it is a
uin16). The kernel rightly reports an -EINVAL error when iwd issues a
NEW_KEY with such a value, resulting in the connection being aborted.
Work around this by trying to detect big-endian key indexes and 'fixing'
them up.
This bug has been in here since OWE was written, but a similar bug also
existed in hostapd which allowed the PTK derivation to be identical.
In January 2020 hostapd fixed this bug, which now makes IWD incompatible
when using group 20 or 21.
This patch fixes the bug for IWD, so now OWE should be compatible with
recent hostapd version. This will break compatibility with old hostapd
versions which still have this bug.
If the AP only supports an AKM which requires an auth protocol
CMD_AUTHENTICATE/CMD_ASSOCIATE must be supported or else the
auth protocol cannot be run. All the auth protocols are started
assuming that the card supports these commands, but the support
was never checked when parsing supported commands.
This patch will prevent any fullMAC cards from using
SAE/FILS/OWE. This was the same behavior as before, just an
earlier failure path.
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.
Only add constants for parsing the Device Information subelement as that
is the main thing we care about in P2P code. And since our own WFD IEs
will likely only need to contain the Device Information subelement, we
don't need builder utilities. We do need iterator utilities because we
may receive WFD IEs with more subelements.
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.
In order to support AlwaysRandomizeAddress and AddressOverride, station will
set the desired address into the handshake object. Then, netdev checks if
this was done and will use that address rather than generate one.
This patch adds two new options to a network provisioning file:
AlwaysRandomizeAddress={true,false}
If true, IWD will randomize the MAC address on each connection to this
network. The address does not persists between connections, any new
connection will result in a different MAC.
AddressOverride=<MAC>
If set, the MAC address will be set to <MAC> assuming its a valid MAC
address.
These two options should not be used together, and will only take effect
if [General].AddressRandomization is set to 'network' in the IWD
config file.
If neither of these options are set, and [General].AddressRandomization
is set to 'network', the default behavior remains the same; the MAC
will be generated deterministically on a per-network basis.
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.
If during WATCHLIST_NOTIFY{,_MATCHES,_NO_ARGS} one of the watch
notify callback triggers a call to watchlist_destroy, give up calling
remaining watches and destroy the watchlist without crashing. This is
useful in frame-xchg.c (P2P use case) where a frame watch may trigger
a move to a new state after receiving a specific frame, and remove one
group of frame watches (including its watchlist) to create a different
group.
For privacy reasons its advantageous to randomize or mask
the MAC address when connecting to networks, especially public
networks.
This patch allows netdev to generate a new MAC address on a
per-network basis. The generated MAC will remain the same when
connecting to the same network. This allows reauthentications
or roaming to work, and not have to fully re-connect (which would
be required if the MAC changed on every connection).
Changing the MAC requires bringing the interface down. This does
lead to potential race conditions with respect to external
processes. There are two potential conditions which are explained
in a TODO comment in this patch.
This API is being added to support per-network MAC address
generation. The MAC is generated based on the network SSID
and the adapters permanent address using HMAC-SHA256. The
SHA digest is then constrained to make it MAC address
compliant.
Generating the MAC address like this will ensure that the
MAC remains the same each time a given SSID is connected to.
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).
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.
This API was updated to take an extra boolean which will
automatically power up the device while changing the MAC
address. Since this is what IWD does anyways we can avoid
the need for an intermediate callback and go right into
netdev_initial_up_cb.
iwd would fail to connect using EAP-TLS when no CA certificate was
provided as it checked for successful loading of the CA certificate
instead of the client certificate when attempting to load the client
certificate.
The password for EAP-GTC is directly used in an EAP response. The
response buffer is created on the stack so an overly large password
could cause a stack overflow.
mac80211 drivers seem to send the disconnect event which is triggered by
CMD_DISCONNECT prior to the CMD_DISCONNECT response. However, some
drivers, namely brcmfmac, send the response first and then send the
disconnect event. This confused iwd when a connection was immediately
triggered after a disconnection (network switch operation).
Fix this by making sure that connected variable isn't set until the
connect event is actually processed, and ignore disconnect events which
come after CMD_DISCONNECT has alredy succeeded.
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.
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.
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.
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.
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.
Processing the duplicated TLVs while connecting to a malicious AP may lead
to overflow of the response buffer. This patch ensures that the
duplicated TLVs are not parsed.
The pending wiphy state 'use_default' variable was not set early enough
in some circumstances resulting in weird behavior for blacklisted
drivers. Fix this by adding a manager_wiphy_dump_done callback which
will properly initialize the use_default value.
Fixes: c4b2f10483 ("manager: Handle missing NEW_WIPHY events")
brcmfmac does not allow the removal of the default / primary interface.
So there isn't much point in having iwd attempt this.
Another issue is that brcmfmac _does_ allow the deletion of non-default
interfaces. So starting iwd on a system with a station & ap interface
active can result in iwd attempting to delete all the interfaces. Given
the above, it succeeds in deleting the ap interface but not the station
one. In strange circumstances it might end up thinking that the ap
interface is the 'default' and trying to use it, whereas it was just
successfully removed.
==192== Conditional jump or move depends on uninitialised value(s)
==192== at 0x4531D3: l_queue_find (queue.c:346)
==192== by 0x42F1F8: manager_config_notify (manager.c:667)
==192== by 0x45A895: process_multicast (genl.c:970)
==192== by 0x45A895: received_data (genl.c:1037)
==192== by 0x4577B2: io_callback (io.c:126)
==192== by 0x456B0D: l_main_iterate (main.c:473)
==192== by 0x456BCB: l_main_run (main.c:520)
==192== by 0x456DDA: l_main_run_with_signal (main.c:642)
==192== by 0x4034B0: main (main.c:497)
The kernel emits NEW_WIPHY events whenever a new wiphy is registered.
Unfortunately these events are emitted under the 'legacy' semantics and
have a hard size limit of 4096 bytes. Unfortunately, it is possible for
a NEW_WIPHY message to exceed this limit (ath10k cards seem to be
affected in particular), which results in the kernel never sending these
messages out. This can lead to NEW_INTERFACE events being emitted with
a wiphy_id that had no corresponding NEW_WIPHY event emitted. Such a
sequence can confuse iwd's hardware detection logic, particularly during
hot-plug or system boot.
Fix this by re-dumping the wiphy if such a condition is detected. This
has some interaction with blacklisted wiphys, so the wiphy objects are
now always tracked and marked as blacklisted. Before, the blacklisted
wiphys were simply not added to the iwd list of tracked wiphys.
For the inner EAP methods that support generation of the key material
include it into imck generation. This allows to cryptographically
bind the inner method with the tunnel.
Windows Server 2008 - Network Policy Server (NPS) generates an invalid
Compound MAC for Cryptobinding TLV when is used within PEAPv0 due to
incorrect parsing of the message containing TLS Client Hello.
Setting L bit and including TLS Message Length field, even for the
packets that do not require fragmentation, corrects the issue. The
redundant TLS Message Length field in unfragmented packets doesn't
seem to affect the other server implementations.
Sometimes, at least with brcmfmac, the default interface apparently
takes a moment to get created after the NEW_WIPHY event. We didn't
really consider this case in the NEW_WIPHY handler and we've got a race
condition. It fixes the following bug for me:
https://bugs.archlinux.org/task/63912 -- tested by removing and
re-modprobing the brcmfmac module rather than rebooting.
To work around this wait for the NEW_INTERFACE event and then retry the
setup. We still do the initial attempt directly after NEW_WIPHY to
handle cases like wiphys with no default interfaces and pre-existing
wiphys.
We track mtime as the 'LastConnectedTime' of the network, and also sort
the known network list according to the last connected time.
Unfortunately we were never reacting to ATTRIB changes, and so were
never updating the network_info->connected_time whenever a network was
connected to.
Rework the logic to address this. This also fixes a small bug where the
connected_time was not set properly prior to removal / re-insertion of
the network_info.
We use the mtime on the network profile as the 'Last Connected Time'.
When we update any property and sync the file to disk, the mtime was not
preserved (since we were creating a new temporary file instead of
modifying the old one). This led to LastConnectedTime property change
being emitted / updated incorrectly when a writable property on the
KnownNetwork interface was updated.
Our design preference is to not call any callbacks in the _free/_destroy
method of a class (with the exception of explicit destroy callbacks
provided, if any).
Invoking the callback in this case was unnecessary: wsc_dbus_free was
already replying to pending connect / cancel messages. The only other
thing the callback would attempt to do is to set station back into
autoconnect mode. This was unnecessary as well since the netdev is
already down.
This change removes the callback invocation. Since wsc_enrollee_destroy
is now just calling wsc_enrollee_free, remove this from the API and
expose wsc_enrollee_free instead.
Split the WSC D-Bus interface class (struct wsc) into a base class
common to station mode and P2P mode (struct wsc_dbus) and station-
specific logic like scanning, saving the credentials as a known network
and triggering the station-mode connection (struct wsc_station_dbus).
Make the base class and its utilities public in wsc.h for P2P use.
Create struct wsc_enrollee which is allocated with wsc_enrollee_new,
taking a done callback as a parameter. The callback is always
called so there's no need for a separate destroy callback. The object
only lives until the done callback happens so wsc_enrollee_cancel/destroy
can only be used before this.
Looks like the rest of the file is simplified thanks to this.
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.
Instead of taking the credentials from wsc object directly, have the
caller pass these in. This makes it more consistent with how the
done_cb was done.
Split the interface-specific logic from the core WSC logic. The core
WSC code is the part that we can re-use between P2P and station and
doesn't include the D-Bus code, scanning for the target BSS or the
attempt to make a station mode connection.
Allow netdev_create_from_genl callers to draw a random or non-random MAC
and pass it in the parameter instead of a bool to tell us to generating
the MAC locally. In P2P we are generating the MAC some time before
creating the netdev in order to pass it to the peer during negotiation.
Some server implementation don't seem to provide the valid compound MACs.
In the meantime, iwd will ignore the invalid Crypto-Binding TLVs as their
usage is optional.
The intent was to check for the presence of the add_domain_name
operation, not add_dns operation.
Fixes: 930528e35e ("resolve: Add systemd-resolved domain name installer")
It seems that the kernel uses -EOPNOTSUPP if the change_station
operation is not implemented by the driver. However, some drivers do
implement change_station and choose to report -ENOTSUPP instead of
-EOPNOTSUPP.
To add to the confusion, EOPNOTSUPP and -ENOTSUPP are the same on some
systems (e.g. Gentoo). Be paranoid and allow both errors to be ignored
when sending CMD_SET_STATION.
Fixes: 0238ffb8d9 ("netdev: Use -EOPNOTSUPP instead of -ENOTSUPP")
The first if case should be -10950, not 10950. Without the negative
this first case would get hit every time since signal strength values
are always negative.
The Crypto Binding TLV is used to ensure that the EAP peer and the
EAP server participated in both the inner and the outer EAP
authentications of a PEAP authentication by cryptographically associating
the phase 1 and phase 2 authentications.
The usage of Crypto-Binding in PEAPv0 is optional and is triggered by
the reception of the Crypto-Binding TLV from the server.
The handler for EAP Extensions has been modified to support multiple
TLV types instead of the single Result TLV. This will allow to handle
the other TLVs such as Crypto-Binding TLV.
There are some server implementations that send requests that are
not "Password" but still want us send password. This commit modify
the behavior to send a warning and still try to auth with password.
This makes me able to auth with server in my school which sends
"Enter Aruba Login".
wpa_supplicant does not check if it is "Password".
The kernel uses -EOPNOTSUPP in the case of change_station operation not
being provided. On most systems -EOPNOTSUPP is defined to be the same
as -ENOTSUPP, but seemingly not all systems.
Previously, the key was installed once the tunnel was created
despite the outcome of the second authentication phase. Now, the
key installation is delayed until the successful completion of
the second authentication phase. This excludes the unnecessary
operations in the case of a failure and key reinstallation with
cypro-binding in use.
Commit 1057d8aa74 changed the device interface creation logic
from being unconditional inside netdev.c to instead use NETDEV_WATCH_*
events. However, this broke the assumption that the device interface
was created before all others. The effect is that the scan_wdev_add
might no longer be called prior to station interface being created. Fix
this by moving scan_wdev_add/remove calls to netdev.c instead.
Fixes: 1057d8aa74 ("device: Move device creation from netdev.c to event watch")
#0 0x000055555558ee5d in scan_notify (msg=0x55555560b640, user_data=0x0) at src/scan.c:1706
#1 0x00007ffff7f2c78c in ?? () from /usr/lib/libell.so.0
#2 0x00007ffff7f299ec in ?? () from /usr/lib/libell.so.0
#3 0x00007ffff7f28e4a in l_main_iterate () from /usr/lib/libell.so.0
#4 0x00007ffff7f28efc in l_main_run () from /usr/lib/libell.so.0
#5 0x00007ffff7f290b9 in l_main_run_with_signal () from /usr/lib/libell.so.0
#6 0x00005555555639c4 in main (argc=1, argv=0x7fffffffec18) at src/main.c:497
Save the source frame type in struct scan_bss as it may affect how some
of the data in the struct will be parsed. Also replace the P2P IE
payload data in that struct with a union containing pre-parsed p2p
attributes corresponding to the frame type.
This means users don't have to call the parsers in p2putil.c on that
data, which wouldn't have worked anyway because those parsers assume
input is the raw IE sequence rather than just the "payload".