Convert the handshake event callback type to use variable argument
list to allow for more flexibility in event-specific arguments
passed to the callbacks.
Note the uint16_t reason code is promoted to an int when using variable
arguments so va_arg(args, int) has to be used.
The handshake object had 4 setters for authenticator/supplicant IE.
Since the IE ultimately gets put into the same buffer, there really
only needs to be a single setter for authenticator/supplicant. The
handshake object can deal with parsing to decide what kind of IE it
is (WPA or RSN).
AP still relies on the get_data/set_length semantics. Its more convenient
to still use these since it avoids the need for extra temporary buffers
when building the rates IE.
The TLV builder APIs were not very intuative, and in some (or all)
cases required access to the builder structure directly, either to
set the TLV buffer or to get the buffer at the end.
This change adds a new API, ie_tlv_builder_set_data, which both sets
the length for the current TLV and copies the TLV data in one go.
This will avoid the need for memcpy(ie_tlv_builder_get_data(...),...)
ie_tlv_builder_finalize was also changed to return a pointer to the
start of the build buffer. This will eliminate the need to access
builder.tlv after building the TLVs.
ie_tlv_builder_init was changed to take an optional buffer to hold
the TLV data. Passing NULL/0 will build the TLV in the internal
buffer. Passing in a pointer and length will build into the passed
in buffer.
Supported rates will soon be parsed along with HT/VHT capabilities
to determine the best data rate. This will remove the need for the
supported_rates uintset element in scan_bss, as well as the single
API to only parse the supported rates IE. AP still does rely on
this though (since it only supports basic rates), so the parsing
function was moved into ap.c.
The AP structure was getting cleaned up twice. When the DBus stop method came
in we do AP_STOP on nl80211. In this callback the AP was getting freed in
ap_reset. Also when the DBus interface was cleaned up it triggered ap_reset.
Since ap->started gets set to false in ap_reset, we now check this and bail
out if the AP is already stopped.
Fixes:
++++++++ backtrace ++++++++
0 0x7f099c11ef20 in /lib/x86_64-linux-gnu/libc.so.6
1 0x43fed0 in l_queue_foreach() at ell/queue.c:441 (discriminator 3)
2 0x423a6c in ap_reset() at src/ap.c:140
3 0x423b69 in ap_free() at src/ap.c:162
4 0x44ee86 in interface_instance_free() at ell/dbus-service.c:513
5 0x451730 in _dbus_object_tree_remove_interface() at ell/dbus-service.c:1650
6 0x405c07 in netdev_newlink_notify() at src/netdev.c:4449 (discriminator 9)
7 0x440775 in l_hashmap_foreach() at ell/hashmap.c:534
8 0x4455d3 in process_broadcast() at ell/netlink.c:158
9 0x4439b3 in io_callback() at ell/io.c:126
10 0x442c4e in l_main_iterate() at ell/main.c:473
11 0x442d1c in l_main_run() at ell/main.c:516
12 0x442f2b in l_main_run_with_signal() at ell/main.c:644
13 0x403ab3 in main() at src/main.c:504
14 0x7f099c101b97 in /lib/x86_64-linux-gnu/libc.so.6
+++++++++++++++++++++++++++
AdHoc will also need the same functionality to verify and parse the
key sequence from GET_KEY. This block of code was moved from AP's
GET_KEY callback into nl80211_parse_get_key_seq.
Netdev/AP share several NL80211 commands and each has their own
builder API's. These were moved into a common file nl80211_util.[ch].
A helper was added to AP for building NEW_STATION to make the associate
callback look cleaner (rather than manually building NEW_STATION).
Set a default GTK cipher type same as our current PTK type, generate a
random GTK when the first STA connects and set it up in the kernel, then
pass the values that EAPoL is going to need to the handshake_state.
As a consequence of the previous commit, netdev watches are always
called when the device object is valid. As a result, we can drop the
netdev_get_device calls and checks from individual AP/AdHoc/Station/WSC
netdev watches
Since the interfaces are not supposed to exist when the device is DOWN
(we destroy the interfaces on NETDEV_WATCH_EVENT_DOWN too), don't
create the interfaces if the device hasn't been brought up yet.
To avoid confusion in case of an authenticator side handshake_state
structure and eapol_sm structure, rename own_ie to supplicant_ie and
ap_ie to authenticator_ie. Also rename
handshake_state_set_{own,ap}_{rsn,wpa} and fix when we call
handshake_state_setup_own_ciphers. As a result
handshake_state_set_authenticator, if needed, should be called before
handshake_state_set_{own,ap}_{rsn,wpa}.
After EAPOL logic was moved to eapol.c a check was added to
ap_associate_sta_cb to bitwise compare the AP's RSNE to the RSNE
received in the (Re)Association frame. There is as far as I know no
reason for them to be the same (although they are in our autotest) and
if there was a reason we'd rather validate the (Re)Association RSNE
immediately when received. We also must set different RSNEs as the
"own" (supplicant) and "ap" RSNEs in the handshake_state for validation
of step 2/4 in eapol.c (fixes wpa_supplicant's and MS Windows
connections being rejected)
Make sure we interrupt eapol traffic (4-way handshake) if we receive a
Disassociation from station. Actually do this in ap_del_station because
it's called from both ap_disassoc_cb and ap_success_assoc_resp_cb and
seems to make sense in both cases.
On one hand when we're called with HANDSHAKE_EVENT_FAILED or
HANDSHAKE_EVENT_SETTING_KEYS_FAILED the eapol_sm will be freed in
eapol.c, fix a double-free by setting it to NULL before ap_free_sta
is called.
On the other hand make sure we call eapol_sm_free before setting
sta->sm to NULL in ap_drop_rsna to avoid potential leak and avoid
the eapol_sm continuing to use the handshake_state we freed.
There was somewhat overlapping functionality in the device_watch
infrastructure as well as the netdev_event_watch. This commit combines
the two into a single watch based on the netdev object and cleans up the
various interface additions / removals.
With this commit the interfaces are created when the netdev/device is
switched to Powered=True state AND when the netdev iftype is also in the
correct state for that interface. If the device is brought down, then
all interfaces except the .Device interface are removed.
This will make it easy to implement Device.Mode property properly since
most nl80211 devices need to be brought into Powered=False state prior
to switching the iftype.
This removes the authenticator bit in eapol_sm as well as unifies
eapol_register_authenticator and eapol_register. Taking advantage
of the handshake state authenticator bit we no longer have a need
for 2 separate register functions.
ap, and adhoc were also updated to set the authenticator bit in
the handshake and only use eapol_register to register their sm's.
netdev was updated to use the authenticator bit when choosing the
correct key address for adhoc.
If the sm object (or the handshake object) is NULL, don't call the
corresponding function.
0 0x7fb6cd37da80 in /lib64/libc.so.6
1 0x414764 in eapol_sm_destroy() at eapol.c:673
2 0x42e402 in ap_sta_free() at ap.c:97
3 0x439dbe in l_queue_clear() at /home/parallels/wrk/iwd/ell/queue.c:109
4 0x439e09 in l_queue_destroy() at /home/parallels/wrk/iwd/ell/queue.c:83
5 0x42e4bf in ap_reset() at ap.c:132
6 0x42e519 in ap_free() at ap.c:147
7 0x447456 in interface_instance_free() at /home/parallels/wrk/iwd/ell/dbus-service.c:513
8 0x449be0 in _dbus_object_tree_remove_interface() at /home/parallels/wrk/iwd/ell/dbus-service.c:1595
9 0x449ced in _dbus_object_tree_object_destroy() at /home/parallels/wrk/iwd/ell/dbus-service.c:787
10 0x40fb8c in device_free() at device.c:2717
11 0x405cdb in netdev_free() at netdev.c:605
12 0x439dbe in l_queue_clear() at /home/parallels/wrk/iwd/ell/queue.c:109
13 0x439e09 in l_queue_destroy() at /home/parallels/wrk/iwd/ell/queue.c:83
14 0x40aac2 in netdev_shutdown() at netdev.c:4483
15 0x403b75 in iwd_shutdown() at main.c:80
16 0x43d9f3 in signal_callback() at /home/parallels/wrk/iwd/ell/signal.c:83
17 0x43d4ee in l_main_iterate() at /home/parallels/wrk/iwd/ell/main.c:376
18 0x43d5ac in l_main_run() at /home/parallels/wrk/iwd/ell/main.c:419
19 0x40379b in main() at main.c:454
20 0x7fb6cd36788a in /lib64/libc.so.6
If the device mode it toggled from 'ap' back to 'station' without actually
starting the access point ap_free attempts to zero out the psk, which
causes a crash because it had never been allocated (Start() never was
called). Since ap->psk is actually never used this was removed. Also added
a memset to zero out the pmk on cleanup.
This is the crash observed:
++++++++ backtrace ++++++++
0 0x7f6ffe978a80 in /lib64/libc.so.6
1 0x7f6ffe9d6766 in /lib64/libc.so.6
2 0x42dd51 in memset() at /usr/include/bits/string3.h:90
3 0x42ddd9 in ap_free() at src/ap.c:144
4 0x445ec6 in interface_instance_free() at ell/dbus-service.c:513
5 0x448650 in _dbus_object_tree_remove_interface() at ell/dbus-service.c:1595
6 0x40d980 in device_set_mode_sta() at src/device.c:2113
7 0x447d4c in properties_set() at ell/dbus-service.c:1861
8 0x448a33 in _dbus_object_tree_dispatch() at ell/dbus-service.c:1691
9 0x442587 in message_read_handler() at ell/dbus.c:285
10 0x43cac9 in io_callback() at ell/io.c:123
11 0x43bf5e in l_main_iterate() at ell/main.c:376
12 0x43c01c in l_main_run() at ell/main.c:419
13 0x40379d in main() at src/main.c:460
14 0x7f6ffe96288a in /lib64/libc.so.6
+++++++++++++++++++++++++++
Rather than have device.c manage the creation/removal of
AP/AdHoc interfaces this new event was introduced. Now
anyone can listen for device events and if the mode changes
handle accordingly. This fixes potential memory leaks
in WSC when switching modes as well.
If netdev fails to set the keys, there was no way for device/ap to
know. A new handshake event was added for this. The key setting
failure function was also fixed to support both AP/station iftypes.
It will now automatically send either a disconnect or del_station
depending on the interface type.
In similar manner, netdev_handshake_failed was also modified to
support both AP/station iftypes. Now, any handshake event listeners
should call netdev_handshake_failed upon a handshake failure
event, including AP.
Now, a user can setup an AP as follows:
- Set device "Mode" to ap (ap interface will appear on bus)
- call "Start()" on AP interface
Issuing "Stop()" on the AP interface will stop and cleanup
the internal AP structures, but the AP interface will remain
up. To shutdown completely the device Mode must be switched
back to station. If the AP interface is running, the Mode can
directly be switched to station without calling Stop; this
has the same effect and will take down the AP interface.
Instead of manually sending a deauth/disassociate to a station
during an error or removal, the kernel can do it automatically
with DEL_STATION by including the MGMT_SUBTYPE attribute. This
removes the need for ap_error_deauth_sta and introduces
ap_deauthenticate_sta. Now AP can be explicit when it chooses
to deauth or disassociate.
All handshake packet handling has been removed from ap and
moved to eapol. After association, the AP registers a new
authenticator state machine which handles the AP side of
the handshake. AP will receive a handshake event once the
4-way handshake is complete.
With the introduction of Control Port Over NL80211 feature, the
transport details need to be moved out of eapol and into netdev.c.
Whether a given WiFi hardware supports transfer of Control Port packets
over NL80211 is Wiphy and kernel version related, so the transport
decisions need to be made elsewhere.
Set all the new field values into struct sta_state only after all the
error checks for better readabilty and fixing a possible issue if we
did "sta->rates = rates" and then detected en error and freed "rates".
Also update a comment which I think used the wording from 802.11-2012
instead of 802.11-2016.
DEL_KEY is not needed and will return errors right after NEW_STATION or
right after DEL_STATION. In both cases the kernel makes sure there are
no old keys for the station already.