The wifi component consists of a port of the Linux mac802.11 stack as well
as libnl and wpa_supplicant to Genode. Depending on the used platform it
features a selection of drivers for wireless devices. For example on the
PC platform it contains the ath9k, iwlwifi and rtlwifi drivers for PCI(e)
devices.

In contrast to other DDE Linux based drivers the actual driver portion is
confined to its own library to better isolate the various parts of the driver.
The 'wifi' binary is the generic management part that includes the Wifi
configuration interface and the 'wpa_supplicant'. A suitable driver library
is loaded at run-time (see section [Debugging]).


Configuration
~~~~~~~~~~~~~

This configuration snippet shows how to start the component on the PC
platform.

!<start name="wifi" caps="250">
!  <resource name="RAM" quantum="32M"/>
!  <provides><service name="Nic"/></provides>
!  <config>
!    <libc stdout="/dev/log" stderr="/dev/null" rtc="/dev/rtc"/>
!    <vfs>
!      <dir name="dev"> <log/> <null/> <rtc/>
!          <jitterentropy name="random"/>
!          <jitterentropy name="urandom"/>
!      </dir>
!      <dir name="firmware"> <tar name="wifi_firmware.tar"/> </dir>
!    </vfs>
!  </config>
!  <route>
!    <service name="ROM" label="wifi.lib.so">
!      <parent label="pc_wifi.lib.so"/>
!    </service>
!    <service name="ROM" label="wifi_firmware.tar">
!      <parent label="pc_wifi_firmware.tar"/>
!    </service>
!    <service name="Rtc"> <any-child /> </service>
!    <any-service> <parent/> <any-child /> </any-service>
!  </route>
!</start>

On other platforms the wifi library will be different. So, the
following snippet illustrates the use of the driver on the PinePhone.

!<start name="wifi" caps="250">
!  <resource name="RAM" quantum="32M"/>
!  <provides><service name="Nic"/></provides>
!  <config>
!    <libc stdout="/dev/log" stderr="/dev/null" rtc="/dev/rtc"/>
!    <vfs>
!      <dir name="dev"> <log/> <null/> <rtc/>
!        <jitterentropy name="random"/>
!        <jitterentropy name="urandom"/>
!      </dir>
!      <dir name="firmware"> <tar name="wifi_firmware.tar"/> </dir>
!    </vfs>
!  </config>
!  <route>
!    <service name="ROM" label="wifi.lib.so">
!      <parent label="a64_wifi.lib.so"/>
!    </service>
!    <service name="ROM" label="wifi_firmware.tar">
!      <parent label="a64_wifi_firmware.tar"/>
!    </service>
!    <service name="ROM" label="dtb">
!      <parent label="wifi-pinephone.dtb"/>
!    </service>
!    <service name="Rtc"> <any-child /> </service>
!    <any-service> <parent/> <any-child /> </any-service>
!  </route>
!</start>

Note the ROM route for the device-tree binary that is essential on
ARM-based platforms. The name of the request DTB can by changed
by setting the 'dtb' attribute in the config node.

Depending on the used device additional firmware images might be
required. The driver will request them by accessing the '/firmware'
directory in the driver's local VFS. It is up to the configuration
how those files are made available. In these examples they are
contained in an '.tar' archive that is request as a ROM module.

The driver will request access to the 'wifi_config' ROM module that
contains its actual configuration in the '<wifi_config>' node. This
node features the following attributes.

* :scan_interval: sets the time interval in seconds in which scan
  operations are requested and is used when not already connected
  to a network. The default is 5 seconds.

* :update_quality_interval: sets the time interval in which the current
  signal quality of the connected access point is updated (RSSI polling).
  The default value is 30 seconds.

* :rfkill: allows to temporarily prevent any radio activity. The
  default is 'false'.

* :bgscan: is an expert option that configures the way the
  supplicant performs background scanning to steer or rather optimize
  roaming decisions within the same network (SSID). The syntax of the
  option string corresponds to the original WPA-supplicant 'bgscan' option.
  The default value is set to 'simple:30:-70:600'. This functionality can
  be disabled by specifying an empty value, e.g. 'bgscan=""'. If bgscan is
  disabled the 'accesspoints' report will not be updated while the
  supplicant is connected to a network.

* :log_level: allows for steering the verbosity of the supplicant
  and may assist while diagnosing problems with the driver.
  Valid values correspond to levels used by the supplicant
  and are as follows 'excessive', 'msgdump', 'debug', 'info',
  'warning' and 'error'. The default value is 'error' and configures
  the least amount of verbosity.

* :verbose: allows for logging of diagnostic messages generated
  by the managing portion of the driver. The default is 'false'.

Besides those attributes the '<wifi_config>' node can host one or
more '<network>' nodes. Such a node describes the parameters of
a network and has the following attributes.

* :ssid: sets the name of the network.

  Note: the SSID is copied verbatim and at the moment, there is no way
        to express or escape non alphanumeric characters.

* :bssid: can be used to select a specific access point within a
  network.

* :protection: specifies the used protection mechanism of the
  network. Valid values are 'WPA', 'WPA2', 'WPA3' and 'NONE'.
  The last one is used in case the network uses other means of
  protection and access is open.

  Note: currently only personal WPA protection using a pre-shared-key
        (PSK) is supported.

* :passphrase: sets the PSK that is required should the
  network be protected.

* :auto_connect: allows for joining a network automatically. The
  default value is 'true'. When more than one network is configured
  with enabled 'auto_connect' the driver will try to select the best
  one it gets a response from.

  Note:  If configured auto-connect networks overlap in locality, the
         driver might switch dynamically between the networks.

* :explicit_scan: must be set to explicitly scan for hidden networks.
  The default is 'false' and it should only be set for networks
  that are hidden indeed.

Of all attributes solely the 'ssid' attribute is mandatory and all
others are optional. They should be used when needed only.

The following exemplary snippet showcases a config for two networks where
the first one should be automatically considered for joining and uses 'WPA2'
while the second one is hidden but should show up in the scan results and
uses 'WPA'.

!<wifi_config scan_interval="10" update_quality_interval="30">
!  <network ssid="Zero" protection="WPA2" passphrase="allyourbase"
!           auto_connect="true"/>
!  <network ssid="Skynet" protection="WPA" passphrase="12345678"
!           explicit_scan="true"/>
!</wifi_config>


The wifi driver uses two distinct reports, 'state' and 'accesspoints',
to communicate its state of connectivity and information about the wireless
access points in the vicinity to other components.
This exemplary 'accesspoints' report shows its general structure.

!<accesspoints>
!  <accesspoint ssid="skynet" bssid="00:01:02:03:04:05" quality="40"/>
!  <accesspoint ssid="foobar" bssid="01:02:03:04:05:06" quality="70" protection="WPA2"/>
!  <accesspoint ssid="foobar" bssid="01:02:03:04:05:07" quality="10" protection="WPA2"/>
!</accesspoints>

The '<accesspoints>' node can contain a fluctuating number of '<accesspoint>'
nodes that describe an access point with the following attributes.

* :ssid: specifies the name of the network the access point advertises.
  Empty SSIDs are not reported.

* :bssid: specifies the physical address of the access point.

* :freq: specifies the frequency used by the access point.

* :quality: specifies the approximated link quality (calculated from the
  RSSI value).

* :protection: specifies which kind of protection is employed by the access
  point.

  Note: when a mixed protection is used by the network, like WPA2-PSK and
        WPA3-PSK mixed-mode, only the strongest protection (WPA3-PSK) is
        advertised.

The 'state' report provides information about the state of the connectivity
and looks as follows.

!<state>
!  <accesspoint ssid="foobar" bssid="01:02:03:04:05:06" quality="70" freq="2418" state="connected"/>
!</state>

The '<state>' node encompasses one '<accesspoint>' node that has the
following additional attributes beside the ones already discussed.

* :state: specifies the actual state of connectivity. Valid values
  are 'connected', 'connecting' and 'disconnected'.

* :auth_failure: is an optional attribute and set to 'true' in case
  the PSK was wrong

* :rfkilled: is an optional attribute and set to 'true' whenever
  radio activity was temporarily disabled.

* :not_found: is an optional attribute and is only set when a single
  auto-connect network was configured but could not be found.

By subscribing to both reports and providing the required 'wifi_config'
ROM module, a component is able control the wireless driver.

The driver optionally reports the following information under the
label "devices" if requested in the config as depicted.

! <config> <report mac_address="true"/> </config>

! <devices> <nic mac_address="02:00:00:00:00:01"/> </devices>


Debugging
~~~~~~~~~

As mentioned in the introduction the 'wifi' component is special in the
regard that the actual driver is provided as a shared-object to better isolate
it from the the driver binary that is a Libc::Component managing the
'wpa_supplicant'. Since this code and in return the binary is the same for each
platform it is linked against an artificial 'wifi' library that only exists as
an ABI stub created via 'lib/symbols/wifi'. In case the driver is integrated
via depot archives this is, besides setting the proper ROM routes, of no
concern. However, when the driver is built without the depot, the boot image
assemble-mechanism tries to include the non-existent 'wifi.lib.so' library. To
prevent that from failing one way is adding a dummy file - the
'repos/pc/run/pc_wifi.run' illustrates how to do that.

During development it might be necessary to automatically generate certain
dummy functions as is normally the case with drivers ported over from Linux.
To make the existing tooling (tool/dde_linux) work with the wifi driver it
is necessary to link the driver binary directly against the driver library
rather then stub ABI library. This is achieved by adapting the driver's
'target.mk' file. In

!TARGET  := wifi
!SRC_CC  := main.cc wpa.cc access_firmware.cc
!LIBS    := base wifi
![…]

'LIBS' must be changed as follows in case the PC wifi driver library is
used.

!LIBS    := base pc_wifi

Afterwards the driver library is built by the 'driver/wifi' target and
since it is now a direct dependency 'tool/dde_linux/create_dummies' can
by used to created the 'generated_dummies.c' file.
