IWD has supported randomizing the adapters MAC address on startup for quite some time, but this only randomizes the address once for the lifetime of IWD. In the 1.6 release address randomization on a per-network basis was added. Enabling this can be done inside IWD's main config file (default
# main.conf [General] AddressRandomization=network
This option was added to
AddressRandomization but truthfully this is not random. The MAC address is generated using a SHA256 digest from the permanent adapters address and the SSID being connected to. This is a deterministic operation which will allow the same MAC to be used on every connection to a given SSID. Generally this is the behavior the average user wants. For fully randomized MAC addresses see AlwaysRandomizeAddress.
The (AlwaysRandomizeAddress) option was added to network provisioning files. Its value only takes effect when
AddressRandomization is set to
network. When enabled the MAC address is randomized on each connection to a network in a non-deterministic fashion. To the access point it will appear as if a brand new client is connecting every time.
The (AddressOverride) option was added to network provisioning files. Its value only takes effect when
AddressRandomization is set to
network. When enabled the MAC address will be set to this value when connecting to the network that the provisioning file dictates, and only for this network.
# /var/lib/MySSID.psk [Settings] AddressOverride=11:22:33:44:55:66
The networking subsystem has several caveats which limit the efficiency of MAC address randomization, as well as introduce potential race conditions. Both of these shortfalls come down to the fact that the adapter must be powered down to change the MAC address.
During testing it was found that it takes at least 300ms to power the adapter down, change the MAC, and power it back up. Since these new options were added on a per-network basis this delay more or less triples IWD's average connection time. This is a problem with any software using the RTNL subsystem for operations like this. There is even a note in the Android (documentation):
Note: You may experience up to a three-second delay when connecting to a network due to the driver flushing saved scan results when the interface goes down. If this is the case, check with your silicon partners to resolve the issue.
We have only measured this delay on a few cards, so its not out of the question that some cards may have a much longer delay. If you are seeing excessive delays we ask you to reach out on the mailing list or IRC.
Since IWD is asynchronous and it takes some time to complete a MAC address change there is a potential for race conditions. This is an unfortunate consequence of the way RTNL was designed, at least in terms of powering the adapter. We have identified two potential race conditions which are unlikely to ever happen, but still possible. These scenarios involve an external process doing operations on the interface IWD manages.
IWD RTNL External Process | | <--------- Power Down | | Power Down --------> | | | Success <----------- | ---------> Success | | | | | Change MAC --------> | | | Success <----------- | | | | | | Power Up ----------> | | | Success <----------- | |
In the above example an external process brought the interface down just before IWD did. RTNL does not consider two down operations an error so it returns success on both. IWD does get a notification that the interface went down, but assumes this was its own doing. The MAC change operation continues and ultimately the interface is brought back up. To the external process (e.g. a user doing
ifconfig wlan0 down) it would appear as if their command had no effect as the interface would still be in an up state.
IWD RTNL External Process | | | | Power Down --------> | | | Success <----------- | | | | <----------- Power Up | | | -----------> Success | | Change MAC --------> | | | Failed <----------- | |
In the above example an external process brings the interface up after IWD powers it down, but before changing the MAC. This would result in the MAC change operation failing, resulting in a failed connection attempt. Ultimately this is recoverable and issuing another connect command should work. This is quite unlikely since any external process shouldn't be trying to bring an interface up that is already up.
There are several solutions which have been looked at, all of which require kernel changes. The optimal solution would be to allow the adapters MAC address to be changed without powering down. This solves both the timing cost and the race conditions. This has been implemented, but met with opposition from the maintainers: https://marc.info/?l=linux-wireless&m=156762443831647&w=2
A similar solution could also be implemented for RTNL, where-as the above patches are only in nl80211. The RTNL path was not even pursued because that subsystem is quite old and invasive changes are difficult to get upstreamed.
Another solution would be to include some kind of cookie associated with RTNL requests. This would allow IWD to determine who caused an interface to go down. This would eliminate the race conditions, but the timing cost would still exist.