pc: update wifi driver

The driver falls in line with the previous 'legacy_wifi_drv' component
where the ported wireless LAN stack and device driver is encapsulated
in a library. This library in return is used by the 'Libc::Component'
providing the necessary environment for the 'wpa_supplicant'.

In constrast to the old driver a 'wifi' VFS plugin is in charge of
initalizing the 'Lx_kit::Env' prior to executing any static
constructors.

Fixes #4455.
This commit is contained in:
Josef Söntgen 2022-02-10 18:09:17 +01:00 committed by Christian Helmuth
parent 8056811b4f
commit e7e7893f22
45 changed files with 9614 additions and 0 deletions

View File

@ -0,0 +1,17 @@
PORT_DIR := $(call port_dir,$(REP_DIR)/ports/linux-firmware)
content: ucode_files LICENSE.wifi_drv
.PHONY: ucode_files
ucode_files:
cp $(PORT_DIR)/firmware/*.ucode .
cp $(PORT_DIR)/firmware/regulatory.db .
cp $(PORT_DIR)/firmware/regulatory.db.p7s .
LICENSE.wifi_drv:
for i in $(PORT_DIR)/firmware/LICEN*E.*; do \
echo "$${i##*/}:" >> $@; \
cat $$i >> $@; \
echo >> $@; \
done

View File

@ -0,0 +1 @@
2019-11-25 ff24f3bafaeeb47c053670264b5096dbc4b9a36d

View File

@ -0,0 +1,5 @@
include $(REP_DIR)/lib/mk/wifi.inc
REQUIRES += 32bit
SRC_C += lx_emul/spec/x86_32/atomic64_32.c

View File

@ -0,0 +1,3 @@
include $(REP_DIR)/lib/mk/wifi.inc
REQUIRES += 64bit

View File

@ -0,0 +1,11 @@
SRC_CC = vfs.cc
DDE_LINUX_DIR := $(subst /src/include/lx_kit,,$(call select_from_repositories,src/include/lx_kit))
INC_DIR += $(DDE_LINUX_DIR)/src/include
LIBS := wifi
vpath %.cc $(REP_DIR)/src/lib/vfs/wifi
SHARED_LIB := yes

48
repos/pc/lib/mk/wifi.inc Normal file
View File

@ -0,0 +1,48 @@
REQUIRES := x86
TARGET_LIB_DIR := $(REP_DIR)/src/lib/wifi
SHARED_LIB := yes
LD_OPT += --version-script=$(TARGET_LIB_DIR)/symbol.map
LIBS += base pc_linux_generated pc_lx_emul
INC_DIR := $(TARGET_LIB_DIR)
SRC_CC += wlan.cc
SRC_CC += misc.cc
SRC_CC += time.cc
SRC_CC += firmware.cc
SRC_CC += socket_call.cc
SRC_CC += random.cc
SRC_C += dummies.c
SRC_C += lx_emul.c
SRC_C += uplink.c
CC_OPT_lx_socket_call += -DKBUILD_MODNAME='"lx_socket_call"'
SRC_C += lx_socket_call.c
SRC_C += $(notdir $(wildcard $(TARGET_LIB_DIR)/generated_dummies.c))
SRC_C += pc/lx_emul/common_dummies.c
SRC_C += lx_emul/spec/x86/pci.c
CC_C_OPT += -I$(LX_SRC_DIR)/drivers/net/wireless/intel/iwlwifi
CC_C_OPT += -I$(LX_SRC_DIR)/include/linux
CC_C_OPT += -Wno-address-of-packed-member
#CC_OPT += -DCONFIG_IWLWIFI_DEBUG
vpath %.c $(TARGET_LIB_DIR)
vpath %.cc $(TARGET_LIB_DIR)
vpath pc/lx_emul/common_dummies.c $(REP_DIR)/src/lib
CUSTOM_TARGET_DEPS += $(TARGET_LIB_DIR)/symbol.map
#
# Genode C-API backends
#
SRC_CC += genode_c_api/uplink.cc
vpath genode_c_api/uplink.cc $(subst /genode_c_api,,$(call select_from_repositories,src/lib/genode_c_api))

View File

@ -0,0 +1,24 @@
#
# Pseudo library to copy wireless LAN firmware to build directory
#
FW_CONTRIB_DIR := $(call select_from_ports,linux-firmware)
IMAGES := $(notdir $(wildcard $(FW_CONTRIB_DIR)/firmware/*.ucode))
IMAGES += $(notdir $(wildcard $(FW_CONTRIB_DIR)/firmware/*.db))
IMAGES += $(notdir $(wildcard $(FW_CONTRIB_DIR)/firmware/*.p7s))
BIN_DIR := $(BUILD_BASE_DIR)/bin
FW_DIR := $(FW_CONTRIB_DIR)/firmware
CUSTOM_TARGET_DEPS += $(addprefix $(BIN_DIR)/,$(IMAGES))
$(BIN_DIR)/%.ucode: $(FW_DIR)/%.ucode
$(VERBOSE)cp $^ $@
$(BIN_DIR)/%.db: $(FW_DIR)/%.db
$(VERBOSE)cp $^ $@
$(BIN_DIR)/%.p7s: $(FW_DIR)/%.p7s
$(VERBOSE)cp $^ $@
CC_CXX_WARN_STRICT =

View File

@ -0,0 +1,2 @@
Package for bundling pc_wifi_drv and wifi_firmware

View File

@ -0,0 +1,6 @@
_/src/pc_wifi_drv
_/src/openssl
_/src/vfs
_/src/vfs_jitterentropy
_/src/libc
_/raw/wifi_firmware

View File

@ -0,0 +1 @@
2022-03-28-c 2f0c23734634d4c90d6c4ed2d08a5873bd3daed1

View File

@ -0,0 +1,43 @@
<runtime ram="32M" caps="300" binary="pc_wifi_drv">
<requires> <rom label="wifi_config"/> </requires>
<config ld_verbose="yes" verbose="no">
<vfs>
<dir name="dev"> <log/> <rtc/> <null/>
<jitterentropy name="random"/>
<jitterentropy name="urandom"/>
</dir>
</vfs>
<libc stdout="/dev/null" stderr="/dev/null" rtc="/dev/rtc"/>
</config>
<content>
<rom label="ld.lib.so"/>
<rom label="pc_wifi_drv"/>
<rom label="libcrypto.lib.so"/>
<rom label="libc.lib.so"/>
<rom label="libm.lib.so"/>
<rom label="vfs_jitterentropy.lib.so"/>
<rom label="libssl.lib.so"/>
<rom label="wifi.lib.so"/>
<rom label="wpa_driver_nl80211.lib.so"/>
<rom label="wpa_supplicant.lib.so"/>
<rom label="vfs.lib.so"/>
<rom label="iwlwifi-1000-5.ucode"/>
<rom label="iwlwifi-3160-17.ucode"/>
<rom label="iwlwifi-3168-29.ucode"/>
<rom label="iwlwifi-5000-5.ucode"/>
<rom label="iwlwifi-6000-4.ucode"/>
<rom label="iwlwifi-6000g2a-6.ucode"/>
<rom label="iwlwifi-6000g2b-6.ucode"/>
<rom label="iwlwifi-7260-17.ucode"/>
<rom label="iwlwifi-7265-17.ucode"/>
<rom label="iwlwifi-7265D-29.ucode"/>
<rom label="iwlwifi-8000C-36.ucode"/>
<rom label="iwlwifi-8265-36.ucode"/>
<rom label="iwlwifi-9000-pu-b0-jf-b0-34.ucode"/>
<rom label="iwlwifi-9000-pu-b0-jf-b0-46.ucode"/>
<rom label="iwlwifi-QuZ-a0-hr-b0-63.ucode"/>
</content>
</runtime>

View File

@ -0,0 +1,72 @@
#
# Driver portions
#
LIB_MK := $(addprefix lib/mk/,wifi_firmware.mk wifi.inc vfs_wifi.mk) \
$(foreach SPEC,x86_32 x86_64,lib/mk/spec/$(SPEC)/wifi.mk) \
MIRROR_FROM_REP_DIR := src/drivers/wifi/pc \
src/lib/pc/lx_emul \
$(LIB_MK) \
$(shell cd $(REP_DIR); find src/drivers/wifi -type f) \
$(shell cd $(REP_DIR); find src/lib/wifi -type f) \
$(shell cd $(REP_DIR); find src/lib/vfs/wifi -type f)
MIRROR_FROM_OS_DIR := src/lib/genode_c_api/uplink.cc
#
# DDE Linux portions (wpa_supplicant, libnl)
#
DDE_LINUX_REP_DIR := $(GENODE_DIR)/repos/dde_linux
DDE_LINUX_PORT_DIR := $(call port_dir,$(DDE_LINUX_REP_DIR)/ports/dde_linux)
DDE_LINUX_LIB_MK := \
$(addprefix lib/mk/,libnl.inc libnl_include.mk) \
$(foreach SPEC,x86_32 x86_64,lib/mk/spec/$(SPEC)/libnl.mk) \
$(addprefix lib/mk/spec/x86/,wpa_driver_nl80211.mk wpa_supplicant.mk)
MIRROR_FROM_DDE_LINUX_DIR := $(DDE_LINUX_LIB_MK) \
lib/import/import-libnl_include.mk \
lib/import/import-libnl.mk \
include/wifi \
$(shell cd $(DDE_LINUX_REP_DIR); find src/lib/libnl -type f) \
$(shell cd $(DDE_LINUX_REP_DIR); find src/lib/wpa_driver_nl80211 -type f) \
$(shell cd $(DDE_LINUX_REP_DIR); find src/lib/wpa_supplicant -type f)
MIRROR_FROM_DDE_LINUX_PORT_DIR := $(shell cd $(DDE_LINUX_PORT_DIR); find src/lib/libnl -type f) \
$(shell cd $(DDE_LINUX_PORT_DIR); find src/app/wpa_supplicant -type f)
content: $(MIRROR_FROM_REP_DIR) $(MIRROR_FROM_OS_DIR) $(MIRROR_FROM_DDE_LINUX_DIR) \
$(MIRROR_FROM_DDE_LINUX_PORT_DIR) cleanup-wpa
$(MIRROR_FROM_REP_DIR):
$(mirror_from_rep_dir)
$(MIRROR_FROM_OS_DIR):
mkdir -p $(dir $@)
cp -r $(GENODE_DIR)/repos/os/$@ $@
$(MIRROR_FROM_DDE_LINUX_DIR):
mkdir -p $(dir $@)
cp -r $(GENODE_DIR)/repos/dde_linux/$@ $@
$(MIRROR_FROM_DDE_LINUX_PORT_DIR):
mkdir -p $(dir $@)
cp -r $(DDE_LINUX_PORT_DIR)/$@ $@
cleanup-wpa: $(MIRROR_FROM_DDE_LINUX_PORT_DIR)
@for dir in .git doc eap_example hs20 mac80211_hwsim radius_example \
hostapd tests wlantest wpadebug wpaspy; do \
rm -rf src/app/wpa_supplicant/$$dir; done
content: LICENSE
LICENSE:
( echo "Linux is subject to GNU General Public License version 2, see:"; \
echo "https://www.kernel.org/pub/linux/kernel/COPYING"; \
echo; \
echo "Libnl is subject to GNU LESSER GENERAL PUBLIC LICENSE Verson 2.1, see:"; \
echo " src/lib/libnl/COPYING"; \
echo; \
echo "Wpa_supplicant is subject to 3-clause BSD license, see:"; \
echo " src/app/wpa_supplicant/COPYING"; ) > $@

View File

@ -0,0 +1 @@
2022-03-25-d 6b387b53c6390a75e1fdd55586aac54d3812271c

View File

@ -0,0 +1,12 @@
base
genode_c_api
libc
openssl
os
pc_linux
nic_session
platform_session
report_session
timer_session
uplink_session
vfs

283
repos/pc/run/wifi.run Normal file
View File

@ -0,0 +1,283 @@
#
# Configure wireless lan
#
proc wifi_ssid { } {
return $::env(GENODE_WIFI_SSID)
}
proc wifi_psk { } {
return $::env(GENODE_WIFI_PSK)
}
#
# widi_drv config generator (supporting a network list)
#
# You may script your tests with this function in the dynamic_rom config below.
# The syntax for the networks parameter is
#
# { ssid protection passphrase explicit_scan }
#
# Example dynamic_rom config:
#
# {<inline description="auto-connect both networks">
# } [wifi_config 30 5 no [list "net1 WPA2 net1_psk no" "net2 WPA2 net2_psk no"]] {
# </inline>
# <inline description="aquto-connect both, but net2 explicitly">
# } [wifi_config 30 5 no [list "net1 WPA2 net1_psk no" "net2 WPA2 net2_psk yes"]] {
# </inline>}
set wifi_verbose false
set wifi_verbose_state false
proc wifi_config { connected_scan_interval scan_interval rfkill networks } {
global wifi_verbose
global wifi_verbose_state
set config "<wifi_config"
append config " verbose=\"$wifi_verbose\""
append config " verbose_state=\"$wifi_verbose_state\""
append config " connected_scan_interval=\"$connected_scan_interval\""
append config " scan_interval=\"$scan_interval\""
append config " rfkill=\"$rfkill\""
append config ">\n"
foreach n $networks {
append config " <network"
append config " ssid=\"[lindex $n 0]\""
append config " protection=\"[lindex $n 1]\""
append config " passphrase=\"[lindex $n 2]\""
append config " explicit_scan=\"[lindex $n 3]\""
append config "/>\n"
}
append config "</wifi_config>\n"
return $config
}
#
# Restrict platforms
#
assert_spec x86
#
# Build
#
set build_components {
core init timer
drivers/rtc
drivers/wifi/pc
server/report_rom
server/dynamic_rom
server/nic_router
test/lwip/http_srv
lib/vfs/wifi
lib/vfs/jitterentropy
lib/vfs/lwip
}
source ${genode_dir}/repos/base/run/platform_drv.inc
append_platform_drv_build_components
build $build_components
create_boot_directory
#
# Generate config
#
append config {
<config verbose="yes" prio_levels="2">
<parent-provides>
<service name="ROM"/>
<service name="IRQ"/>
<service name="IO_MEM"/>
<service name="IO_PORT"/>
<service name="PD"/>
<service name="RM"/>
<service name="CPU"/>
<service name="LOG"/>
</parent-provides>
<default-route>
<any-service> <parent/> <any-child/> </any-service>
</default-route>
<default caps="100"/>
<start name="timer">
<resource name="RAM" quantum="1M"/>
<provides> <service name="Timer"/> </provides>
</start>
<start name="rtc_drv">
<resource name="RAM" quantum="1M"/>
<provides> <service name="Rtc"/> </provides>
</start>
<start name="test-lwip_httpsrv">
<resource name="RAM" quantum="128M"/>
<config>
<libc stdout="/dev/null" stderr="/dev/log" socket="/socket"/>
<vfs>
<dir name="dev"> <log/> <null/> </dir>
<dir name="socket"> <lwip dhcp="yes"/> </dir>
</vfs>
</config>
<route>
<service name="Nic"> <child name="nic_router"/> </service>
<any-service> <parent/> <any-child/> </any-service>
</route>
</start>
<start name="state_report_rom">
<binary name="report_rom"/>
<resource name="RAM" quantum="2M"/>
<provides> <service name="Report"/> <service name="ROM"/> </provides>
<config verbose="no"/>
</start>
<start name="accesspoints_report_rom">
<binary name="report_rom"/>
<resource name="RAM" quantum="2M"/>
<provides> <service name="Report"/> <service name="ROM"/> </provides>
<config verbose="no"/>
</start>
<start name="config_rom">
<binary name="dynamic_rom"/>
<resource name="RAM" quantum="4M"/>
<provides><service name="ROM"/></provides>
<config verbose="yes">
<rom name="wifi_config">
<inline description="disconnect">
} [wifi_config 30 5 no {}] {
</inline>
<sleep milliseconds="15000"/>
<inline description="connect">
} [wifi_config 30 5 no [list "[wifi_ssid] WPA2 [wifi_psk] yes"]] {
</inline>
<sleep milliseconds="6000000"/>
<inline description="rfkill block">
} [wifi_config 30 5 yes [list "[wifi_ssid] WPA2 [wifi_psk] yes"]] {
</inline>
<sleep milliseconds="30000"/>
<inline description="rfkill unblock">
} [wifi_config 30 5 no [list "[wifi_ssid] WPA2 [wifi_psk] yes"]] {
</inline>
<sleep milliseconds="30000"/>
</rom>
</config>
</start>
<start name="nic_router" caps="150">
<resource name="RAM" quantum="8M"/>
<provides>
<service name="Nic"/>
<service name="Uplink"/>
</provides>
<config verbose="no" verbose_domain_state="yes" dhcp_discover_timeout_sec="10" dhcp_request_timeout_sec="6">
<policy label_prefix="test-lwip_httpsrv" domain="downlink"/>
<policy label_prefix="wifi_drv" domain="uplink"/>
<domain name="uplink" verbose_packets="no" verbose_packet_drop="no" icmp_echo_server="yes">
<nat domain="downlink" tcp-ports="16384"/>
<tcp-forward port="443" domain="downlink" to="10.0.3.2"/>
<tcp-forward port="80" domain="downlink" to="10.0.3.2"/>
</domain>
<domain name="downlink" verbose_packets="no" verbose_packet_drop="no" interface="10.0.3.1/24">
<dhcp-server ip_first="10.0.3.2" ip_last="10.0.3.2"/>
</domain>
</config>
</start>
<start name="devices_report_rom">
<binary name="report_rom"/>
<resource name="RAM" quantum="1200K"/>
<provides> <service name="Report"/> <service name="ROM"/> </provides>
<config verbose="yes"/>
</start>
<start name="wifi_drv" caps="250" priority="-1">
<binary name="pc_wifi_drv"/>
<resource name="RAM" quantum="32M"/>
<config ld_verbose="yes">
<report mac_address="true"/>
<libc stdout="/dev/log" stderr="/dev/log" rtc="/dev/rtc"/>
<vfs>
<dir name="dev"> <log/> <null/> <rtc/>
<jitterentropy name="random"/>
<jitterentropy name="urandom"/>
<wifi/>
</dir>
</vfs>
</config>
<route>
<service name="Uplink"> <child name="nic_router"/> </service>
<service name="Rtc"> <any-child/> </service>
<service name="Report" label="accesspoints"> <child name="accesspoints_report_rom"/> </service>
<service name="Report" label="state"> <child name="state_report_rom"/> </service>
<service name="Report" label="devices"> <child name="devices_report_rom"/> </service>
<service name="ROM" label="wifi_config"> <child name="config_rom"/> </service>
<any-service> <parent/> <any-child/> </any-service>
</route>
</start>
}
append_platform_drv_config
append config {
</config>
}
install_config $config
set firmware_modules {
iwlwifi-1000-5.ucode
iwlwifi-3160-17.ucode
iwlwifi-3168-29.ucode
iwlwifi-5000-5.ucode
iwlwifi-6000-4.ucode
iwlwifi-7260-17.ucode
iwlwifi-7265-17.ucode
iwlwifi-7265D-29.ucode
iwlwifi-8000C-36.ucode
iwlwifi-8265-36.ucode
iwlwifi-9000-pu-b0-jf-b0-34.ucode
iwlwifi-9000-pu-b0-jf-b0-46.ucode
iwlwifi-QuZ-a0-hr-b0-63.ucode
regulatory.db
regulatory.db.p7s
}
#
# Boot modules
#
# generic modules
set boot_modules {
core ld.lib.so init timer rtc_drv report_rom dynamic_rom
vfs_jitterentropy.lib.so
libc.lib.so vfs.lib.so libcrypto.lib.so libssl.lib.so
wpa_driver_nl80211.lib.so wpa_supplicant.lib.so
pc_wifi_drv wifi.lib.so vfs_wifi.lib.so
nic_router
test-lwip_httpsrv
vfs_lwip.lib.so
}
append boot_modules $firmware_modules
append_platform_drv_boot_modules
build_boot_image $boot_modules
run_genode_until forever
# vi: set ft=tcl :

View File

@ -0,0 +1,108 @@
The pc_wifi_drv component is a port of the Linux mac802.11 stack, including
the iwlwifi driver as well as libnl and wpa_supplicant, to Genode.
To start the component the following configuration snippet can be used:
!<start name="pc_wifi_drv" caps="250">
! <resource name="RAM" quantum="32M"/>
! <provides><service name="Nic"/></provides>
! <config>
! <libc stdout="/dev/null" stderr="/dev/null" rtc="/dev/rtc"/>
! <vfs>
! <dir name="dev"> <log/> <null/> <rtc/> <wifi/>
! <jitterentropy name="random"/>
! <jitterentropy name="urandom"/>
! </dir>
! </vfs>
! </config>
! <route>
! <service name="Rtc"> <any-child /> </service>
! <any-service> <parent/> <any-child /> </any-service>
! </route>
!</start
The driver will request access to the ROM module 'wifi_config' to
connect to a network:
!<wifi_config connected_scan_interval="30" scan_interval="10" rfkill="no">
! <network ssid="Foobar" protection="WPA2" passphrase="allyourbase"/>
!</wifi_config>
To temporarily prevent any radio activity, the 'rfkill' attribute
can be set to 'true'.
If the network is protected by, e.g., WPA/WPA2, the protection type, either
'WPA' or 'WPA2' as well as the the passphrase have to be specified.
The 'bssid' attribute can be used to select a specifc accesspoint within a
network. Of all attributes only the 'ssid' attribute is mandatory, all others
are optional and should only be used when needed.
The configuration may contain more than one network. In This case the driver
will try to select the best one it gets a response from. To prevent it
from automatically joining the network the 'auto_connect' attribute must be
set to 'false'; the default value is 'true'. If the 'explicit_scan' attribute
is set, the driver will pro-actively scan for a hidden network with the given
SSID:
!<wifi_config connected_scan_interval="30" scan_interval="10">
! <network ssid="Zero" protection="WPA2" passphrase="allyourbase"/>
! <network ssid="Skynet" protection="WPA" passphrase="12345678"
! explicit_scan="true" auto_connect="false"/>
!</wifi_config>
By default, the driver scans for available networks only when not
connected. This can be changed with the 'connected_scan_interval'
attribute, which specifies the interval for connected scans in
seconds and directly influences any roaming decision, i.e., select
a better fit accesspoint for the configured network.
Also, the driver can be switched to verbose logging during runtime
by setting the 'verbose' or 'verbose_state' attribute to 'true'.
The wifi_drv creates two distinct reports to communicate its state and
information about the wireless infrastructure to other components. The
first one is a list of all available accesspoints. The following examplary
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>
Each accesspoint node has attributes that contain the SSID and the BSSID
of the accesspoint as well as the link quality (signal strength). These
attributes are mandatory. If the network is protected, the node will also
have an attribute describing the type of protection in addition.
The second report provides information about the state of the connection
to the currently connected accesspoint:
!<state>
! <accesspoint ssid="foobar" bssid="01:02:03:04:05:06" quality="70" freq="2418" state="connected"/>
!</state>
Valid state values are 'connected', 'disconnected', 'connecting'. Depending
on the state, there are additional attributes that can be checked. In case
of an authentication error, e.g. the passphrase is wrong, the 'auth_failure'
attribute will be set to 'true'. The 'rfkilled' attribute is set to 'true'
if a disconnect was triggered by disabling the radio activity via setting
the 'rfkill' attribute.
By subscribing to both reports and providing the required 'wifi_config' ROM
module, a component is able control the wireless driver.
Currently only WPA/WPA2 protection using a passphrase is supported and the the
SSID is copied verbatim. At the moment, there is no way to express or escape
non alphanumeric characters.
On certain cards, e.g. Intel Wireless 6200 ABG, it may be necessary to disable
the 11n mode. This can be achieved by setting the 'use_11n' attribute in
the 'wifi_config' node to 'no'.
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>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,147 @@
/*
* \brief Startup Wifi driver
* \author Josef Soentgen
* \date 2014-03-03
*/
/*
* Copyright (C) 2014-2017 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
/* Genode includes */
#include <libc/component.h>
#include <base/attached_rom_dataspace.h>
#include <base/log.h>
#include <base/sleep.h>
#include <os/reporter.h>
#include <timer_session/connection.h>
#include <util/xml_node.h>
/* local includes */
#include <util.h>
#include <wpa.h>
#include <frontend.h>
using namespace Genode;
static Wifi::Frontend *_wifi_frontend = nullptr;
/**
* Notify front end about command processing
*
* Called by the CTRL interface after wpa_supplicant has processed
* the command.
*/
void wifi_block_for_processing(void)
{
if (!_wifi_frontend) {
warning("frontend not available, dropping notification");
return;
}
/*
* Next time we block as long as the front end has not finished
* handling our previous request
*/
_wifi_frontend->block_for_processing();
/* XXX hack to trick poll() into returning faster */
wpa_ctrl_set_fd();
}
void wifi_notify_cmd_result(void)
{
if (!_wifi_frontend) {
warning("frontend not available, dropping notification");
return;
}
Signal_transmitter(_wifi_frontend->result_sigh()).submit();
}
/**
* Notify front end about triggered event
*
* Called by the CTRL interface whenever wpa_supplicant has triggered
* a event.
*/
void wifi_notify_event(void)
{
if (!_wifi_frontend) {
Genode::warning("frontend not available, dropping notification");
return;
}
Signal_transmitter(_wifi_frontend->event_sigh()).submit();
}
/* exported by wifi.lib.so */
extern void wifi_init(Genode::Env&,
Genode::Blockade&,
bool,
Genode::Signal_context_capability);
struct Main
{
Env &env;
Constructible<Wpa_thread> _wpa;
Constructible<Wifi::Frontend> _frontend;
Blockade _wpa_startup_blockade { };
Main(Genode::Env &env) : env(env)
{
_wpa.construct(env, _wpa_startup_blockade);
wifi_init(env, _wpa_startup_blockade, false,
Genode::Signal_context_capability());
}
};
static Main *_main;
/**
* Return shared-memory message buffer
*
* It is used by the wpa_supplicant CTRL interface.
*/
void *wifi_get_buffer(void)
{
/*
* XXX creating the front end at this point is merely a hack
* to post-pone its creation
*/
if (_wifi_frontend)
return &_wifi_frontend->msg_buffer();
Libc::with_libc([&] () {
if (_main->_frontend.constructed())
return;
_main->_frontend.construct(_main->env);
_wifi_frontend = &*_main->_frontend;
});
return &_wifi_frontend->msg_buffer();
}
void Libc::Component::construct(Libc::Env &env)
{
Libc::with_libc([&] () {
static Main server(env);
_main = &server;
});
}

View File

@ -0,0 +1,10 @@
TARGET := pc_wifi_drv
SRC_CC := main.cc wpa.cc
LIBS := base wifi wifi_firmware
LIBS += libc
LIBS += wpa_supplicant
LIBS += libcrypto libssl wpa_driver_nl80211
INC_DIR += $(PRG_DIR)
CC_CXX_WARN_STRICT :=

View File

@ -0,0 +1,90 @@
/*
* \brief Wifi front end utilities
* \author Josef Soentgen
* \date 2018-07-23
*/
/*
* Copyright (C) 2018-2022 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#ifndef _WIFI__UTIL_H_
#define _WIFI__UTIL_H_
/* Genode includes */
#include <util/string.h>
typedef unsigned long size_t;
typedef long long ssize_t;
typedef unsigned char uint8_t;
namespace Util {
using size_t = Genode::size_t;
using uint8_t = Genode::uint8_t;
size_t next_char(char const *s, size_t start, char const c)
{
size_t v = start;
while (s[v]) {
if (s[v] == c) { break; }
v++;
}
return v - start;
}
bool string_contains(char const *str, char const *pattern)
{
char const *p = pattern;
while (*str && *p) {
p = *str == *p ? p + 1 : pattern;
str++;
}
return !*p;
}
void byte2hex(char *dest, uint8_t b)
{
int i = 1;
if (b < 16) { dest[i--] = '0'; }
for (; b > 0; b /= 16) {
uint8_t const v = b % 16;
uint8_t const c = (v > 9) ? v + 'a' - 10 : v + '0';
dest[i--] = (char)c;
}
}
/**********************************
** Front end specific utilities **
**********************************/
inline unsigned approximate_quality(char const *str)
{
long level = 0;
Genode::ascii_to(str, level);
/*
* We provide an quality value by transforming the actual
* signal level [-50,-100] (dBm) to [100,0] (%).
*/
if (level <= -100) { return 0; }
else if (level >= -50) { return 100; }
return 2 * (unsigned)(level + 100);
}
inline Genode::uint64_t check_time(Genode::uint64_t value, Genode::uint64_t min, Genode::uint64_t max)
{
if (value < min) { return min; }
else if (value > max) { return max; }
return value;
}
} /* namespace Util */
#endif /* _WIFI__UTIL_H_ */

View File

@ -0,0 +1,57 @@
/*
* \brief Wpa_supplicant thread of the wifi driver
* \author Josef Soentgen
* \author Christian Helmuth
* \date 2019-12-18
*/
/*
* Copyright (C) 2019 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
/* Genode includes */
#include <base/blockade.h>
#include <base/env.h>
#include <base/sleep.h>
/* libc includes */
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include "wpa.h"
/* entry function */
extern "C" int wpa_main(void);
void * Wpa_thread::_entry_trampoline(void *arg)
{
Wpa_thread *t = (Wpa_thread *)arg;
t->_entry();
return nullptr;
}
void Wpa_thread::_entry()
{
/* wait until the wifi driver is up and running */
_blockade.block();
_exit = wpa_main();
Genode::sleep_forever();
}
Wpa_thread::Wpa_thread(Genode::Env &env, Genode::Blockade &blockade)
: _blockade(blockade), _exit(-1)
{
pthread_t tid = 0;
if (pthread_create(&tid, 0, _entry_trampoline, this) != 0) {
printf("Error: pthread_create() failed\n");
exit(-1);
}
}

View File

@ -0,0 +1,39 @@
/*
* \brief Wpa_supplicant thread of the wifi driver
* \author Josef Soentgen
* \date 2014-03-03
*/
/*
* Copyright (C) 2014-2017 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#ifndef _WIFI__WPA_H_
#define _WIFI__WPA_H_
namespace Genode {
struct Env;
struct Blockade;
}
class Wpa_thread
{
private:
Genode::Blockade &_blockade;
int _exit;
static void * _entry_trampoline(void *arg);
void _entry();
public:
Wpa_thread(Genode::Env &, Genode::Blockade &);
};
#endif /* _WIFI__WPA_H_ */

View File

@ -0,0 +1 @@
LIBS := vfs_wifi

View File

@ -0,0 +1,87 @@
/*
* \brief Minimal VFS plugin for bringing up WLAN driver
* \author Josef Soentgen
* \date 2022-02-20
*
* The sole purpose of this VFS plugin is to call 'Lx_kit::initialize_env'
* at the right time before 'env.exec_static_constructors' is executed.
*/
/*
* Copyright (C) 2022 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
/* Genode includes */
#include <os/vfs.h>
#include <vfs/single_file_system.h>
/* DDE Linux includes */
#include <lx_kit/init.h>
namespace Vfs_wlan
{
using namespace Vfs;
using namespace Genode;
struct File_system;
}
struct Vfs_wlan::File_system : Single_file_system
{
File_system(Vfs::Env &env, Xml_node config)
:
Single_file_system { Vfs::Node_type::CONTINUOUS_FILE, name(),
Vfs::Node_rwx::ro(), config }
{
/*
* Various ports of a DDE Linux based library rely on the
* 'env' being set before any static constructor is executed.
* So we set it here and wait for the user of the library to
* execute the constructors at the proper time.
*/
Lx_kit::initialize(env.env());
}
Open_result open(char const *, unsigned,
Vfs::Vfs_handle **,
Allocator &) override
{
return OPEN_ERR_UNACCESSIBLE;
}
Stat_result stat(char const *, Stat &) override
{
return STAT_ERR_NO_ENTRY;
}
static char const *name() { return "wlan"; }
char const *type() override { return name(); }
};
/**************************
** VFS plugin interface **
**************************/
extern "C" Vfs::File_system_factory *vfs_file_system_factory(void)
{
struct Factory : Vfs::File_system_factory
{
Vfs::File_system *create(Vfs::Env &vfs_env,
Genode::Xml_node node) override
{
static Vfs::File_system *fs =
new (vfs_env.alloc()) Vfs_wlan::File_system(vfs_env, node);
return fs;
}
};
static Factory factory;
return &factory;
}

View File

@ -0,0 +1,798 @@
/*
* \brief Dummy definitions of Linux Kernel functions - handled manually
* \author Josef Soentgen
* \date 2022-02-09
*/
/*
* Copyright (C) 2022 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#include <lx_emul.h>
#include <linux/cpuhotplug.h>
int __cpuhp_setup_state(enum cpuhp_state state,const char * name,bool invoke,int (* startup)(unsigned int cpu),int (* teardown)(unsigned int cpu),bool multi_instance)
{
lx_emul_trace(__func__);
return 0;
}
#include <linux/timekeeper_internal.h>
void update_vsyscall(struct timekeeper * tk)
{
lx_emul_trace(__func__);
}
#include <linux/clocksource.h>
void clocksource_arch_init(struct clocksource * cs)
{
lx_emul_trace(__func__);
}
#include <linux/sched/signal.h>
void ignore_signals(struct task_struct * t)
{
lx_emul_trace(__func__);
}
#include <linux/sched/loadavg.h>
void calc_global_load(void)
{
lx_emul_trace(__func__);
}
#include <linux/kernel_stat.h>
void account_process_tick(struct task_struct * p,int user_tick)
{
lx_emul_trace(__func__);
}
#include <linux/rcupdate.h>
void rcu_sched_clock_irq(int user)
{
lx_emul_trace(__func__);
}
#include <linux/sysfs.h>
int sysfs_create_bin_file(struct kobject * kobj,const struct bin_attribute * attr)
{
lx_emul_trace(__func__);
return 0;
}
#include <linux/sysfs.h>
int sysfs_create_file_ns(struct kobject * kobj,const struct attribute * attr,const void * ns)
{
lx_emul_trace(__func__);
return 0;
}
#include <linux/sysfs.h>
int sysfs_create_groups(struct kobject * kobj,const struct attribute_group ** groups)
{
lx_emul_trace(__func__);
return 0;
}
#include <linux/sysfs.h>
int sysfs_create_group(struct kobject * kobj,const struct attribute_group * grp)
{
lx_emul_trace(__func__);
return 0;
}
#include <linux/sysfs.h>
int sysfs_create_link(struct kobject * kobj,struct kobject * target,const char * name)
{
lx_emul_trace(__func__);
return 0;
}
#include <linux/sysfs.h>
void sysfs_remove_link(struct kobject * kobj,const char * name)
{
lx_emul_trace(__func__);
}
#include <linux/sysfs.h>
void sysfs_remove_file_ns(struct kobject * kobj,const struct attribute * attr,const void * ns)
{
lx_emul_trace(__func__);
}
#include <linux/sysfs.h>
void sysfs_remove_groups(struct kobject * kobj,const struct attribute_group ** groups)
{
lx_emul_trace(__func__);
}
#include <linux/sysfs.h>
void sysfs_remove_dir(struct kobject * kobj)
{
lx_emul_trace(__func__);
}
#include <linux/sysfs.h>
void sysfs_remove_bin_file(struct kobject * kobj,const struct bin_attribute * attr)
{
lx_emul_trace(__func__);
}
#include <linux/kernfs.h>
void kernfs_get(struct kernfs_node * kn)
{
lx_emul_trace(__func__);
}
#include <linux/kernfs.h>
void kernfs_put(struct kernfs_node * kn)
{
lx_emul_trace(__func__);
}
#include <linux/kobject.h>
int kobject_uevent(struct kobject * kobj,enum kobject_action action)
{
lx_emul_trace(__func__);
return 0;
}
#include <linux/random.h>
int add_random_ready_callback(struct random_ready_callback * rdy)
{
lx_emul_trace(__func__);
return 0;
}
#include <linux/random.h>
void add_device_randomness(const void * buf,unsigned int size)
{
lx_emul_trace(__func__);
}
#include <linux/random.h>
void add_interrupt_randomness(int irq,int irq_flags)
{
lx_emul_trace(__func__);
}
extern bool irq_wait_for_poll(struct irq_desc * desc);
bool irq_wait_for_poll(struct irq_desc * desc)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/irq.h>
void note_interrupt(struct irq_desc * desc,irqreturn_t action_ret)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/fs.h>
int __register_chrdev(unsigned int major,unsigned int baseminor,unsigned int count,const char * name,const struct file_operations * fops)
{
lx_emul_trace(__func__);
return 0;
}
#include <linux/fs.h>
int register_chrdev_region(dev_t from,unsigned count,const char * name)
{
lx_emul_trace(__func__);
return 0;
}
extern void register_handler_proc(unsigned int irq,struct irqaction * action);
void register_handler_proc(unsigned int irq,struct irqaction * action)
{
lx_emul_trace(__func__);
}
extern void register_irq_proc(unsigned int irq,struct irq_desc * desc);
void register_irq_proc(unsigned int irq,struct irq_desc * desc)
{
lx_emul_trace(__func__);
}
#include <linux/cdev.h>
void cdev_init(struct cdev * cdev,const struct file_operations * fops)
{
lx_emul_trace(__func__);
}
#include <linux/cdev.h>
int cdev_add(struct cdev * p,dev_t dev,unsigned count)
{
lx_emul_trace(__func__);
return 0;
}
#include <linux/cdev.h>
void cdev_del(struct cdev * p)
{
lx_emul_trace(__func__);
}
#include <linux/syscore_ops.h>
void register_syscore_ops(struct syscore_ops * ops)
{
lx_emul_trace(__func__);
}
#include <linux/proc_fs.h>
struct proc_dir_entry { int dummy; };
struct proc_dir_entry * proc_create_seq_private(const char * name,umode_t mode,struct proc_dir_entry * parent,const struct seq_operations * ops,unsigned int state_size,void * data)
{
static struct proc_dir_entry ret;
lx_emul_trace(__func__);
return &ret;
}
#include <linux/property.h>
int software_node_notify(struct device * dev,unsigned long action)
{
lx_emul_trace(__func__);
return 0;
}
#include <linux/utsname.h>
#include <linux/user_namespace.h>
struct user_namespace init_user_ns;
struct uts_namespace init_uts_ns;
/*
* linux/seq_file.h depends on user_namespace being defined, add
* all dummies pulling in this header below here
*/
#include <linux/seq_file.h>
void seq_vprintf(struct seq_file * m,const char * f,va_list args)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/vt_kern.h>
void unblank_screen(void)
{
lx_emul_trace_and_stop(__func__);
}
extern void pci_allocate_vc_save_buffers(struct pci_dev * dev);
void pci_allocate_vc_save_buffers(struct pci_dev * dev)
{
lx_emul_trace(__func__);
}
extern void pci_vpd_init(struct pci_dev * dev);
void pci_vpd_init(struct pci_dev * dev)
{
lx_emul_trace(__func__);
}
extern int pci_proc_attach_device(struct pci_dev * dev);
int pci_proc_attach_device(struct pci_dev * dev)
{
lx_emul_trace(__func__);
return 0;
}
#include <linux/kernel.h>
bool parse_option_str(const char * str,const char * option)
{
lx_emul_trace(__func__);
return false;
}
extern bool pat_enabled(void);
bool pat_enabled(void)
{
// XXX pat_enabled necessary?
lx_emul_trace(__func__);
return false;
}
#include <linux/mm.h>
bool is_vmalloc_addr(const void * x)
{
lx_emul_trace(__func__);
return false;
}
unsigned long init_stack[THREAD_SIZE / sizeof(unsigned long)];
extern int pci_dev_specific_acs_enabled(struct pci_dev * dev,u16 acs_flags);
int pci_dev_specific_acs_enabled(struct pci_dev * dev,u16 acs_flags)
{
lx_emul_trace(__func__);
return 0;
}
extern int pci_dev_specific_disable_acs_redir(struct pci_dev * dev);
int pci_dev_specific_disable_acs_redir(struct pci_dev * dev)
{
lx_emul_trace(__func__);
return 0;
}
extern int pci_dev_specific_enable_acs(struct pci_dev * dev);
int pci_dev_specific_enable_acs(struct pci_dev * dev)
{
lx_emul_trace(__func__);
return 0;
}
extern int pci_dev_specific_reset(struct pci_dev * dev,int probe);
int pci_dev_specific_reset(struct pci_dev * dev,int probe)
{
lx_emul_trace(__func__);
return 0;
}
#include <linux/pci.h>
void pci_fixup_device(enum pci_fixup_pass pass,struct pci_dev * dev)
{
lx_emul_trace(__func__);
}
#include <linux/pci.h>
int pci_disable_link_state(struct pci_dev * pdev,int state)
{
lx_emul_trace(__func__);
return 0;
}
const unsigned long module_cert_size = 0;
const u8 system_certificate_list[] = { };
const unsigned long system_certificate_list_size = sizeof (system_certificate_list);
const u8 shipped_regdb_certs[] = { };
unsigned int shipped_regdb_certs_len = sizeof (shipped_regdb_certs);
/*
* Generate_dummies.c will otherwise pull in <linux/rcutree.h>
* that clashes with rcutiny.h.
*/
void rcu_barrier(void)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/filter.h>
#include <linux/jump_label.h> /* for DEFINE_STATIC_KEY_FALSE */
void bpf_prog_change_xdp(struct bpf_prog *prev_prog, struct bpf_prog *prog)
{
lx_emul_trace(__func__);
}
DEFINE_STATIC_KEY_FALSE(bpf_stats_enabled_key);
asmlinkage __wsum csum_partial(const void * buff,int len,__wsum sum)
{
lx_emul_trace_and_stop(__func__);
}
struct static_key_false init_on_alloc;
#include <linux/proc_ns.h>
int proc_alloc_inum(unsigned int * inum)
{
*inum = 1; /* according to linux/proc_ns.h without CONFIG_PROC_FS */
return 0;
}
#include <net/net_namespace.h>
__init int net_sysctl_init(void)
{
lx_emul_trace(__func__);
return 0;
}
#include <linux/proc_fs.h>
struct proc_dir_entry * proc_create_net_data(const char * name,umode_t mode,struct proc_dir_entry * parent,const struct seq_operations * ops,unsigned int state_size,void * data)
{
static struct proc_dir_entry _proc_dir_entry;
lx_emul_trace(__func__);
return &_proc_dir_entry;
}
#include <linux/fs.h>
unsigned int get_next_ino(void)
{
static unsigned int count = 0;
return ++count;
}
#include <linux/netdevice.h>
int __init dev_proc_init(void)
{
lx_emul_trace(__func__);
return 0;
}
#include <linux/stringhash.h>
unsigned int full_name_hash(const void * salt,const char * name,unsigned int len)
{
lx_emul_trace(__func__);
return 0;
}
#include <linux/key.h>
static struct key _key;
struct key * keyring_alloc(const char * description,kuid_t uid,kgid_t gid,const struct cred * cred,key_perm_t perm,unsigned long flags,struct key_restriction * restrict_link,struct key * dest)
{
lx_emul_trace(__func__);
return &_key;
}
#include <linux/kobject.h>
int kobject_uevent_env(struct kobject * kobj,enum kobject_action action,char * envp_ext[])
{
lx_emul_trace(__func__);
return 0;
}
#include <linux/sched.h>
void sched_set_fifo(struct task_struct * p)
{
lx_emul_trace(__func__);
}
#include <linux/moduleparam.h>
void kernel_param_lock(struct module * mod)
{
lx_emul_trace(__func__);
}
#include <linux/moduleparam.h>
void kernel_param_unlock(struct module * mod)
{
lx_emul_trace(__func__);
}
unsigned long lpj_fine = 0;
#include <linux/pid.h>
void put_pid(struct pid * pid)
{
lx_emul_trace(__func__);
}
#include <linux/filter.h>
int sk_filter_trim_cap(struct sock * sk,struct sk_buff * skb,unsigned int cap)
{
lx_emul_trace(__func__);
return 0;
}
#include <linux/capability.h>
bool file_ns_capable(const struct file * file,struct user_namespace * ns,int cap)
{
lx_emul_trace(__func__);
return true;
}
#include <linux/rcupdate.h>
void synchronize_rcu(void)
{
lx_emul_trace(__func__);
}
#include <linux/skbuff.h>
void __skb_get_hash(struct sk_buff * skb)
{
lx_emul_trace(__func__);
}
#include <linux/skbuff.h>
bool __skb_flow_dissect(const struct net * net,const struct sk_buff * skb,struct flow_dissector * flow_dissector,void * target_container,const void * data,__be16 proto,int nhoff,int hlen,unsigned int flags)
{
lx_emul_trace(__func__);
return false;
}
#include <linux/pid.h>
pid_t pid_vnr(struct pid * pid)
{
lx_emul_trace(__func__);
return 0;
}
#include <linux/verification.h>
int verify_pkcs7_signature(const void *data, size_t len,
const void *raw_pkcs7, size_t pkcs7_len,
struct key *trusted_keys,
enum key_being_used_for usage,
int (*view_content)(void *ctx,
const void *data, size_t len,
size_t asn1hdrlen),
void *ctx)
{
return true;
}
#include <linux/acpi.h>
#include <acpi/acpi.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpixf.h>
int acpi_device_modalias(struct device *d, char * s, int i)
{
lx_emul_trace_and_stop(__func__);
}
int acpi_device_uevent_modalias(struct device *d, struct kobj_uevent_env *k)
{
lx_emul_trace_and_stop(__func__);
}
int acpi_dma_configure_id(struct device *dev,
enum dev_dma_attr attr,
const u32 *input_id)
{
lx_emul_trace_and_stop(__func__);
}
bool acpi_driver_match_device(struct device *dev, const struct device_driver *drv)
{
lx_emul_trace_and_stop(__func__);
}
union acpi_object *acpi_evaluate_dsm(acpi_handle handle, const guid_t *guid,
u64 rev, u64 func, union acpi_object *argv4)
{
return NULL;
}
acpi_status acpi_evaluate_object(acpi_handle handle,
acpi_string pathname,
struct acpi_object_list *external_params,
struct acpi_buffer *return_buffer)
{
lx_emul_trace_and_stop(__func__);
}
enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev)
{
lx_emul_trace_and_stop(__func__);
}
acpi_status acpi_get_handle(acpi_handle parent,acpi_string pathname,acpi_handle * ret_handle)
{
lx_emul_trace_and_stop(__func__);
}
int acpi_platform_notify(struct device *dev, enum kobject_action action)
{
return 0;
}
bool is_acpi_device_node(const struct fwnode_handle *fwnode)
{
return false;
}
#include <linux/pci.h>
const struct attribute_group pci_dev_acpi_attr_group;
int pci_acpi_program_hp_params(struct pci_dev *dev)
{
return -ENODEV;
}
struct irq_domain *pci_host_bridge_acpi_msi_domain(struct pci_bus *bus)
{
return NULL;
}
bool pciehp_is_native(struct pci_dev *bridge)
{
return true;
}
#include <linux/thermal.h>
struct thermal_cooling_device *thermal_cooling_device_register(const char *s,
void *p, const struct thermal_cooling_device_ops *op)
{
return ERR_PTR(-ENODEV);
}
void thermal_cooling_device_unregister(struct thermal_cooling_device *tcd)
{
lx_emul_trace(__func__);
}
int thermal_zone_device_enable(struct thermal_zone_device *tz)
{
return -ENODEV;
}
struct thermal_zone_device *thermal_zone_device_register(const char *s, int i, int j,
void *p, struct thermal_zone_device_ops *ops,
struct thermal_zone_params *params, int x, int y)
{
return ERR_PTR(-ENODEV);
}
void thermal_zone_device_unregister(struct thermal_zone_device *tzd)
{
lx_emul_trace(__func__);
}
void thermal_zone_device_update(struct thermal_zone_device *tzd,
enum thermal_notify_event e)
{
lx_emul_trace(__func__);
}
#include <linux/net.h>
int net_ratelimit(void)
{
lx_emul_trace(__func__);
/* suppress */
return 0;
}

View File

@ -0,0 +1,106 @@
/*
* \brief Linux wireless stack
* \author Josef Soentgen
* \date 2018-06-29
*/
/*
* Copyright (C) 2018-2022 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
/* Genode includes */
#include <base/log.h>
#include <rom_session/connection.h>
/* local includes */
#include <lx_kit/env.h>
#include <firmware_list.h>
Firmware_list fw_list[] = {
{ "regulatory.db", 4144, nullptr },
{ "regulatory.db.p7s", 1182, nullptr },
{ "iwlwifi-1000-5.ucode", 337520, nullptr },
{ "iwlwifi-3160-17.ucode", 918268, nullptr },
{ "iwlwifi-5000-5.ucode", 340696, nullptr },
{ "iwlwifi-6000-4.ucode", 454608, nullptr },
{ "iwlwifi-6000-6.ucode", 454608, "iwlwifi-6000-4.ucode" },
{ "iwlwifi-6000g2a-6.ucode", 677296, nullptr },
{ "iwlwifi-6000g2b-6.ucode", 679436, nullptr },
{ "iwlwifi-7260-17.ucode", 1049340, nullptr },
{ "iwlwifi-7265-16.ucode", 1180412, nullptr },
{ "iwlwifi-7265D-29.ucode", 1036772, nullptr },
{ "iwlwifi-8000C-22.ucode", 2120860, nullptr },
{ "iwlwifi-8000C-36.ucode", 2428004, nullptr },
{ "iwlwifi-8265-22.ucode", 1811984, nullptr },
{ "iwlwifi-8265-36.ucode", 2436632, nullptr },
{ "iwlwifi-9000-pu-b0-jf-b0-34.ucode", 2678284, nullptr },
{ "iwlwifi-9000-pu-b0-jf-b0-36.ucode", 2678284, "iwlwifi-9000-pu-b0-jf-b0-34.ucode" },
{ "iwlwifi-9000-pu-b0-jf-b0-46.ucode", 1514876, nullptr },
{ "iwlwifi-QuZ-a0-hr-b0-63.ucode", 1334804, nullptr },
{ "iwlwifi-QuZ-a0-hr-b0-64.ucode", 1334804, "iwlwifi-QuZ-a0-hr-b0-63.ucode" },
};
size_t fw_list_len = sizeof(fw_list) / sizeof(fw_list[0]);
/**********************
** linux/firmware.h **
**********************/
extern "C" int lx_emul_request_firmware_nowait(const char *name, void **dest, size_t *result)
{
if (!dest || !result)
return -1;
/* only try to load known firmware images */
Firmware_list *fwl = 0;
for (size_t i = 0; i < fw_list_len; i++) {
if (Genode::strcmp(name, fw_list[i].requested_name) == 0) {
fwl = &fw_list[i];
break;
}
}
if (!fwl) {
Genode::error("firmware '", name, "' is not in the firmware white list");
return -1;
}
char const *fw_name = fwl->available_name
? fwl->available_name : fwl->requested_name;
Genode::Rom_connection rom(Lx_kit::env().env, fw_name);
Genode::Dataspace_capability ds_cap = rom.dataspace();
if (!ds_cap.valid()) {
Genode::error("could not get firmware ROM dataspace");
return -1;
}
/* use allocator because fw is too big for slab */
void *data = Lx_kit::env().heap.alloc(fwl->size);
if (!data)
return -1;
void const *image = Lx_kit::env().env.rm().attach(ds_cap);
Genode::memcpy(data, image, fwl->size);
Lx_kit::env().env.rm().detach(image);
*dest = data;
*result = fwl->size;
return 0;
}
extern "C" void lx_emul_release_firmware(void const *data, size_t size)
{
Lx_kit::env().heap.free(const_cast<void *>(data), size);
}

View File

@ -0,0 +1,26 @@
/*
* \brief List for firmware images and their sizes
* \author Josef Soentgen
* \date 2014-03-26
*/
/*
* Copyright (C) 2014-2017 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#ifndef _FIRMWARE_LIST_H_
#define _FIRMWARE_LIST_H_
typedef __SIZE_TYPE__ size_t;
struct Firmware_list
{
char const *requested_name;
size_t size;
char const *available_name;
};
#endif /* _FIRMWARE_LIST_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,109 @@
/*
* \brief Libc errno values
* \date 2022-03-03
*/
/*
* Copyright (C) 2022 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#ifndef _WLAN__LIBC_ERRNO_H_
#define _WLAN__LIBC_ERRNO_H_
/* Linux errno values */
#include <uapi/asm-generic/errno.h>
namespace Libc {
enum class Errno : int {
/*
* The following numbers correspond to the FreeBSD errno values
*/
BSD_EPERM = 1,
BSD_ENOENT = 2,
BSD_ESRCH = 3,
BSD_EINTR = 4,
BSD_EIO = 5,
BSD_ENXIO = 6,
BSD_E2BIG = 7,
BSD_ENOEXEC = 8,
BSD_EBADF = 9,
BSD_EDEADLK = 11,
BSD_ENOMEM = 12,
BSD_EACCES = 13,
BSD_EFAULT = 14,
BSD_EBUSY = 16,
BSD_EEXIST = 17,
BSD_EXDEV = 18,
BSD_ENODEV = 19,
BSD_EINVAL = 22,
BSD_ENFILE = 23,
BSD_ENOTTY = 25,
BSD_EFBIG = 27,
BSD_ENOSPC = 28,
BSD_ESPIPE = 29,
BSD_EPIPE = 32,
BSD_EDOM = 33,
BSD_ERANGE = 34,
BSD_EAGAIN = 35,
BSD_EINPROGRESS = 36,
BSD_EALREADY = 37,
BSD_ENOTSOCK = 38,
BSD_EDESTADDRREQ = 39,
BSD_EMSGSIZE = 40,
BSD_ENOPROTOOPT = 42,
BSD_EPROTONOSUPPORT = 43,
BSD_ESOCKTNOSUPPORT = 44,
BSD_EOPNOTSUPP = 45,
BSD_EPFNOSUPPORT = 46,
BSD_EAFNOSUPPORT = 47,
BSD_EADDRINUSE = 48,
BSD_EADDRNOTAVAIL = 49,
BSD_ENETDOWN = 50,
BSD_ENETUNREACH = 51,
BSD_ECONNABORTED = 53,
BSD_ECONNRESET = 54,
BSD_ENOBUFS = 55,
BSD_EISCONN = 56,
BSD_ENOTCONN = 57,
BSD_ETIMEDOUT = 60,
BSD_ECONNREFUSED = 61,
BSD_ENAMETOOLONG = 63,
BSD_EHOSTDOWN = 64,
BSD_EHOSTUNREACH = 65,
BSD_ENOSYS = 78,
BSD_ENOMSG = 83,
BSD_EOVERFLOW = 84,
BSD_ECANCELED = 85,
BSD_EILSEQ = 86,
BSD_EBADMSG = 89,
BSD_ENOLINK = 91,
BSD_EPROTO = 92,
/*
* The following numbers correspond to nothing
*/
BSD_EREMOTEIO = 200,
BSD_ERESTARTSYS = 201,
BSD_ENODATA = 202,
BSD_ETOOSMALL = 203,
BSD_ENOIOCTLCMD = 204,
BSD_ENONET = 205,
BSD_ENOTSUPP = 206,
BSD_ENOTUNIQ = 207,
BSD_ERFKILL = 208,
BSD_ETIME = 209,
BSD_EPROBE_DEFER = 210,
BSD_EL3RST = 211,
BSD_ENOKEY = 212,
BSD_ECHRNG = 213,
MAX_ERRNO = 4095,
};
} /* namespace Libc */
#endif /* _WLAN__LIBC_ERRNO_H_ */

View File

@ -0,0 +1,765 @@
/*
* \brief Linux emulation environment specific to this driver
* \author Josef Soentgen
* \date 2022-02-09
*/
/*
* Copyright (C) 2022 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#include <lx_emul.h>
#include <linux/slab.h>
#include <lx_emul/alloc.h>
#include <lx_emul/io_mem.h>
#include <asm-generic/delay.h>
void __const_udelay(unsigned long xloops)
{
lx_emul_time_udelay(xloops / 0x10C7UL);
}
void __udelay(unsigned long usecs)
{
lx_emul_time_udelay(usecs);
}
#include <linux/cpumask.h>
atomic_t __num_online_cpus = ATOMIC_INIT(1);
#include <linux/dma-mapping.h>
dma_addr_t dma_map_page_attrs(struct device * dev,
struct page * page,
size_t offset,
size_t size,
enum dma_data_direction dir,
unsigned long attrs)
{
dma_addr_t const dma_addr = page_to_phys(page);
unsigned long const virt_addr = (unsigned long)page_to_virt(page);
lx_emul_mem_cache_clean_invalidate((void *)(virt_addr + offset), size);
return dma_addr + offset;
}
#include <linux/dmapool.h>
struct dma_pool {
size_t size;
size_t align;
};
void * dma_pool_alloc(struct dma_pool * pool, gfp_t mem_flags, dma_addr_t * handle)
{
void * ret =
lx_emul_mem_alloc_aligned_uncached(pool->size, pool->align);
*handle = lx_emul_mem_dma_addr(ret);
return ret;
}
struct dma_pool * dma_pool_create(const char * name,
struct device * dev,
size_t size,
size_t align,
size_t boundary)
{
struct dma_pool * pool = kmalloc(sizeof(struct dma_pool), GFP_KERNEL);
pool->size = size;
pool->align = align;
return pool;
}
void dma_pool_free(struct dma_pool * pool,void * vaddr,dma_addr_t dma)
{
lx_emul_mem_free(vaddr);
}
struct dma_pool *dmam_pool_create(const char *name,
struct device *dev,
size_t size,
size_t align,
size_t allocation)
{
/*
* Only take care of allocating the pool because
* we do not detach the driver anyway.
*/
return dma_pool_create(name, dev, size, align, 0);
}
#include <linux/dma-mapping.h>
int dma_supported(struct device * dev,u64 mask)
{
lx_emul_trace(__func__);
return 1;
}
#include <linux/dma-mapping.h>
void dma_unmap_page_attrs(struct device * dev,
dma_addr_t addr,
size_t size,
enum dma_data_direction dir,
unsigned long attrs)
{
unsigned long const virt_addr = lx_emul_mem_virt_addr((void*)addr);
if (!virt_addr)
return;
if (dir == DMA_FROM_DEVICE)
lx_emul_mem_cache_invalidate((void *)virt_addr, size);
}
#include <linux/dma-mapping.h>
void dma_sync_single_for_cpu(struct device *dev, dma_addr_t addr,
size_t size, enum dma_data_direction dir)
{
unsigned long const virt_addr = lx_emul_mem_virt_addr((void*)addr);
if (!virt_addr)
return;
lx_emul_mem_cache_invalidate((void *)virt_addr, size);
}
#include <linux/dma-mapping.h>
void dma_sync_single_for_device(struct device *dev, dma_addr_t addr,
size_t size, enum dma_data_direction dir)
{
unsigned long const virt_addr = lx_emul_mem_virt_addr((void*)addr);
if (!virt_addr)
return;
lx_emul_mem_cache_clean_invalidate((void *)virt_addr, size);
}
#include <linux/slab.h>
void * kmalloc_order(size_t size, gfp_t flags, unsigned int order)
{
return kmalloc(size, flags);
}
#include <linux/fs.h>
#include <linux/mount.h>
#include <linux/slab.h>
int simple_pin_fs(struct file_system_type * type, struct vfsmount ** mount, int * count)
{
*mount = kmalloc(sizeof(struct vfsmount), GFP_KERNEL);
return 0;
}
#include <linux/fs.h>
void simple_release_fs(struct vfsmount ** mount,int * count)
{
kfree(*mount);
}
#include <linux/fs.h>
struct inode * alloc_anon_inode(struct super_block * s)
{
return kmalloc(sizeof(struct inode), GFP_KERNEL);
}
#include <linux/interrupt.h>
// softirq.c
void tasklet_setup(struct tasklet_struct * t,
void (* callback)(struct tasklet_struct *))
{
t->next = NULL;
t->state = 0;
atomic_set(&t->count, 0);
t->callback = callback;
t->use_callback = true;
t->data = 0;
}
void __tasklet_schedule(struct tasklet_struct * t)
{
if (test_and_clear_bit(TASKLET_STATE_SCHED, &t->state))
t->callback(t);
}
void __tasklet_hi_schedule(struct tasklet_struct * t)
{
if (test_and_clear_bit(TASKLET_STATE_SCHED, &t->state))
t->callback(t);
}
#include <linux/rcupdate.h>
void call_rcu(struct rcu_head * head,rcu_callback_t func)
{
enum { KVFREE_RCU_OFFSET = 4096, };
if (func < (rcu_callback_t)KVFREE_RCU_OFFSET) {
kvfree((void*)head - (unsigned long)func);
return;
}
func(head);
}
#include <asm-generic/logic_io.h>
void __iomem * ioremap(resource_size_t phys_addr, unsigned long size)
{
return lx_emul_io_mem_map(phys_addr, size);
}
#include <asm-generic/logic_io.h>
void iounmap(volatile void __iomem * addr)
{
(void)addr;
}
#include <linux/slab.h>
struct kmem_cache * kmem_cache_create_usercopy(const char * name,
unsigned int size,
unsigned int align,
slab_flags_t flags,
unsigned int useroffset,
unsigned int usersize,
void (* ctor)(void *))
{
return kmem_cache_create(name, size, align, flags, ctor);
}
#include <linux/fs.h>
int register_filesystem(struct file_system_type * fs)
{
lx_emul_trace(__func__);
return 0;
}
#include <linux/slab.h>
#include <linux/mount.h>
#include <linux/fs.h>
#include <linux/fs_context.h>
#include <linux/pseudo_fs.h>
struct pseudo_fs_context * init_pseudo(struct fs_context *fc,
unsigned long magic)
{
struct pseudo_fs_context *pfs_ctx;
pfs_ctx = kzalloc(sizeof (struct pseudo_fs_context), GFP_KERNEL);
if (pfs_ctx) {
pfs_ctx->magic = magic;
fc->fs_private = pfs_ctx;
}
return pfs_ctx;
}
struct vfsmount * kern_mount(struct file_system_type * type)
{
struct vfsmount *m;
/*
* This sets everything up so that 'new_inode_pseudo()'
* called from 'sock_alloc()' properly allocates the inode.
*/
m = kzalloc(sizeof (struct vfsmount), 0);
if (m) {
struct fs_context fs_ctx;
if (type->init_fs_context) {
type->init_fs_context(&fs_ctx);
m->mnt_sb = kzalloc(sizeof (struct super_block), GFP_KERNEL);
m->mnt_sb->s_type = type;
m->mnt_sb->s_op =
((struct pseudo_fs_context*)fs_ctx.fs_private)->ops;
} else {
kfree(m);
m = (struct vfsmount*)ERR_PTR(-ENOMEM);
}
}
return m;
}
struct inode * new_inode_pseudo(struct super_block * sb)
{
const struct super_operations *ops = sb->s_op;
struct inode *inode;
if (ops->alloc_inode) {
inode = ops->alloc_inode(sb);
}
if (!inode)
return (struct inode*)ERR_PTR(-ENOMEM);
return inode;
}
#include <linux/sysfs.h>
int sysfs_create_dir_ns(struct kobject * kobj,const void * ns)
{
lx_emul_trace(__func__);
kobj->sd = kzalloc(sizeof(*kobj->sd), GFP_KERNEL);
return 0;
}
#include <linux/firmware.h>
#if 0
struct firmware_work {
struct work_struct work;
struct firmware const *firmware;
void *context;
void (*cont)(struct firmware const *, void *);
};
static void request_firmware_work_func(struct work_struct *work)
{
struct firmware_work *fw_work =
container_of(work, struct firmware_work, work);
fw_work->cont(fw_work->firmware, fw_work->context);
kfree(fw_work);
}
#endif
extern int lx_emul_request_firmware_nowait(const char *name, void *dest, size_t *result);
extern void lx_emul_release_firmware(void const *data, size_t size);
extern void rtnl_lock(void);
extern void rtnl_unlock(void);
int request_firmware_nowait(struct module * module,
bool uevent, const char * name,
struct device * device, gfp_t gfp,
void * context,
void (* cont)(const struct firmware * fw,
void * context))
{
struct firmware *fw = kzalloc(sizeof (struct firmware), GFP_KERNEL);
#if 0
struct firmware_work *fw_work;
#endif
bool reg_db;
if (lx_emul_request_firmware_nowait(name, &fw->data, &fw->size)) {
kfree(fw);
return -1;
}
/*
* Normally we would schedule fw_work but for reasons not
* yet understood doing so will lead to a page-fault. So
* for the time being we will execute the callback directly
* and we have to make sure to manage the RTNL lock as the
* callback will grab it while we already hold it.
*/
reg_db = strcmp(name, "regulatory.db") == 0;
if (reg_db)
rtnl_unlock();
cont(fw, context);
if (reg_db)
rtnl_lock();
return 0;
#if 0
fw_work = kzalloc(sizeof (struct firmware_work), GFP_KERNEL);
if (!fw_work) {
kfree(fw);
return -1;
}
fw_work->firmware = fw;
fw_work->context = context;
fw_work->cont = cont;
INIT_WORK(&fw_work->work, request_firmware_work_func);
schedule_work(&fw_work->work);
return 0;
#endif
}
int request_firmware(const struct firmware ** firmware_p,
const char * name, struct device * device)
{
struct firmware *fw;
if (!*firmware_p)
return -1;
fw = kzalloc(sizeof (struct firmware), GFP_KERNEL);
if (lx_emul_request_firmware_nowait(name, &fw->data, &fw->size)) {
kfree(fw);
return -1;
}
*firmware_p = fw;
return 0;
}
void release_firmware(const struct firmware * fw)
{
lx_emul_release_firmware(fw->data, fw->size);
kfree(fw);
}
/*
* This function is only called when using newer WIFI6 devices to
* load 'iwl-debug-yoyo.bin'. We simply deny the request.
*/
int firmware_request_nowarn(const struct firmware ** firmware,const char * name,struct device * device)
{
return -1;
}
#include <linux/pci.h>
int pcim_iomap_regions_request_all(struct pci_dev * pdev,int mask,const char * name)
{
return 0;
}
#include <linux/pci.h>
static unsigned long *_pci_iomap_table;
void __iomem * const * pcim_iomap_table(struct pci_dev * pdev)
{
unsigned i;
if (!_pci_iomap_table)
_pci_iomap_table = kzalloc(sizeof (unsigned long*) * 6, GFP_KERNEL);
if (!_pci_iomap_table)
return NULL;
for (i = 0; i < 6; i++) {
struct resource *r = &pdev->resource[i];
unsigned long phys_addr = r->start;
unsigned long size = r->end - r->start;
if (!phys_addr || !size)
continue;
_pci_iomap_table[i] =
(unsigned long)lx_emul_io_mem_map(phys_addr, size);
}
return (void const *)_pci_iomap_table;
}
#include <linux/task_work.h>
int task_work_add(struct task_struct * task,struct callback_head * work,enum task_work_notify_mode notify)
{
printk("%s: task: %p work: %p notify: %u\n", __func__, task, work, notify);
return -1;
}
#include <linux/vmalloc.h>
void vfree(const void * addr)
{
kfree(addr);
}
#include <linux/vmalloc.h>
void * vmalloc(unsigned long size)
{
return kmalloc(size, GFP_KERNEL);
}
#include <linux/vmalloc.h>
void * vzalloc(unsigned long size)
{
return kzalloc(size, GFP_KERNEL);
}
#include <linux/interrupt.h>
void __raise_softirq_irqoff(unsigned int nr)
{
raise_softirq(nr);
}
#include <linux/slab.h>
void kfree_sensitive(const void *p)
{
size_t ks;
void *mem = (void *)p;
ks = ksize(mem);
if (ks)
memset(mem, 0, ks);
kfree(mem);
}
#include <linux/gfp.h>
void free_pages(unsigned long addr,unsigned int order)
{
__free_pages(virt_to_page((void *)addr), order);
}
#include <linux/gfp.h>
#include <linux/slab.h>
unsigned long get_zeroed_page(gfp_t gfp_mask)
{
return (unsigned long)kzalloc(PAGE_SIZE, gfp_mask | __GFP_ZERO);
}
#include <linux/sched.h>
pid_t __task_pid_nr_ns(struct task_struct * task,
enum pid_type type,
struct pid_namespace * ns)
{
(void)type;
(void)ns;
return lx_emul_task_pid(task);
}
#include <linux/uaccess.h>
unsigned long _copy_from_user(void * to, const void __user * from,
unsigned long n)
{
memcpy(to, from, n);
return 0;
}
#include <linux/uio.h>
size_t _copy_from_iter(void * addr, size_t bytes, struct iov_iter * i)
{
char *kdata;
struct iovec const *iov;
size_t len;
if (bytes > i->count)
bytes = i->count;
if (bytes == 0)
return 0;
kdata = (char*)(addr);
iov = i->iov;
len = bytes;
while (len > 0) {
if (iov->iov_len) {
size_t copy_len = (size_t)len < iov->iov_len ? len
: iov->iov_len;
memcpy(kdata, iov->iov_base, copy_len);
len -= copy_len;
kdata += copy_len;
}
iov++;
}
return bytes;
}
#include <linux/uio.h>
size_t _copy_to_iter(const void * addr, size_t bytes, struct iov_iter * i)
{
char *kdata;
struct iovec const *iov;
size_t len;
if (bytes > i->count)
bytes = i->count;
if (bytes == 0)
return 0;
kdata = (char*)(addr);
iov = i->iov;
len = bytes;
while (len > 0) {
if (iov->iov_len) {
size_t copy_len = (size_t)len < iov->iov_len ? len
: iov->iov_len;
memcpy(iov->iov_base, kdata, copy_len);
len -= copy_len;
kdata += copy_len;
}
iov++;
}
return bytes;
}
#include <linux/printk.h>
asmlinkage __visible void dump_stack(void)
{
lx_backtrace();
}
#include <linux/mm.h>
void __put_page(struct page * page)
{
__free_pages(page, 0);
}
#include <linux/random.h>
u32 get_random_u32(void)
{
return lx_emul_get_random_u32();
}
int __must_check get_random_bytes_arch(void *buf, int nbytes)
{
if (nbytes < 0)
return -1;
lx_emul_get_random_bytes(buf, (unsigned long)nbytes);
return 0;
}
void get_random_bytes(void *buf, int nbytes)
{
get_random_bytes_arch(buf, nbytes);
}
#include <linux/prandom.h>
void prandom_bytes(void *buf, size_t bytes)
{
lx_emul_get_random_bytes(buf, bytes);
}
u32 prandom_u32(void)
{
return lx_emul_get_random_u32();
}
#include <linux/gfp.h>
void *page_frag_alloc_align(struct page_frag_cache *nc,
unsigned int fragsz, gfp_t gfp_mask,
unsigned int align_mask)
{
(void)nc;
unsigned int const order = fragsz / PAGE_SIZE;
struct page *page = __alloc_pages(gfp_mask, order, 0, NULL);
if (!page)
return NULL;
/* see page_frag_free */
if (order > 0)
printk("%s: alloc might leak memory: fragsz: %u PAGE_SIZE: %u "
"order: %u page: %p addr: %p\n", __func__, fragsz, PAGE_SIZE, order, page, page->virtual);
return page->virtual;
}
#include <linux/gfp.h>
void page_frag_free(void * addr)
{
struct page *page = lx_emul_virt_to_pages(addr, 1ul);
if (!page) {
printk("BUG %s: page for addr: %p not found\n", __func__, addr);
lx_backtrace();
}
__free_pages(page, 0ul);
}

View File

@ -0,0 +1,37 @@
/**
* \brief Dummy definitions of Linux Kernel functions
* \author Stefan Kalkowski
* \date 2021-03-16
*/
/*
* Copyright (C) 2021 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
/* Needed to trace and stop */
#include <lx_emul/debug.h>
/* fix for wait_for_completion_timeout where the __sched include is missing */
#include <linux/sched/debug.h>
/* fix for missing include in linux/dynamic_debug.h */
#include <linux/compiler_attributes.h>
#ifdef __cplusplus
extern "C" {
#endif
void lx_backtrace(void);
void lx_emul_time_udelay(unsigned long usec);
void lx_emul_get_random_bytes(void *buf, unsigned long nbytes);
unsigned int lx_emul_get_random_u32(void);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,208 @@
/*
* \brief Array defining order of Linux Kernel initcalls
* \author Automatically generated file - do no edit
* \date 2022-02-28
*/
#pragma once
static const char * lx_emul_initcall_order[] = {
"__initcall_init_hw_perf_eventsearly",
"__initcall_start",
"__initcall_init_real_modeearly",
"__initcall_validate_x2apicearly",
"__initcall_register_nmi_cpu_backtrace_handlerearly",
"__initcall_spawn_ksoftirqdearly",
"__initcall_static_call_initearly",
"__initcall_init_zero_pfnearly",
"__initcall_initialize_ptr_randomearly",
"__initcall_init_mmap_min_addr0",
"__initcall_pci_realloc_setup_params0",
"__initcall_net_ns_init0",
"__initcall_reboot_init1",
"__initcall_wq_sysfs_init1",
"__initcall_ksysfs_init1",
"__initcall_rcu_set_runtime_mode1",
"__initcall_init_jiffies_clocksource1",
"__initcall_init_script_binfmt1",
"__initcall_init_elf_binfmt1",
"__initcall_prandom_init_early1",
"__initcall_sock_init1",
"__initcall_net_inuse_init1",
"__initcall_net_defaults_init1",
"__initcall_init_default_flow_dissectors1",
"__initcall_netlink_proto_init1",
"__initcall_genl_init1",
"__initcall_irq_sysfs_init2",
"__initcall_bdi_class_init2",
"__initcall_mm_sysfs_init2",
"__initcall_init_per_zone_wmark_min2",
"__initcall_mpi_init2",
"__initcall_pcibus_class_init2",
"__initcall_pci_driver_init2",
"__initcall_tty_class_init2",
"__initcall_vtconsole_class_init2",
"__initcall_devlink_class_init2",
"__initcall_software_node_init2",
"__initcall_amd_postcore_init2",
"__initcall_kobject_uevent_init2",
"__initcall_bts_init3",
"__initcall_pt_init3",
"__initcall_boot_params_ksysfs_init3",
"__initcall_sbf_init3",
"__initcall_arch_kdebugfs_init3",
"__initcall_intel_pconfig_init3",
"__initcall_cryptomgr_init3",
"__initcall_pci_arch_init3",
"__initcall_init_vdso4",
"__initcall_fixup_ht_bug4",
"__initcall_topology_init4",
"__initcall_uid_cache_init4",
"__initcall_param_sysfs_init4",
"__initcall_user_namespace_sysctl_init4",
"__initcall_oom_init4",
"__initcall_default_bdi_init4",
"__initcall_percpu_enable_async4",
"__initcall_init_user_reserve4",
"__initcall_init_admin_reserve4",
"__initcall_init_reserve_notifier4",
"__initcall_rsa_init4",
"__initcall_crypto_cmac_module_init4",
"__initcall_crypto_null_mod_init4",
"__initcall_sha256_generic_mod_init4",
"__initcall_crypto_ctr_module_init4",
"__initcall_crypto_gcm_module_init4",
"__initcall_crypto_ccm_module_init4",
"__initcall_aes_init4",
"__initcall_ghash_mod_init4",
"__initcall_pci_slot_init4",
"__initcall_misc_init4",
"__initcall_usb_common_init4",
"__initcall_usb_init4",
"__initcall_serio_init4",
"__initcall_input_init4",
"__initcall_proto_init4",
"__initcall_net_dev_init4",
"__initcall_neigh_init4",
"__initcall_fib_notifier_init4",
"__initcall_ethnl_init4",
"__initcall_ieee80211_init4",
"__initcall_pci_subsys_init4",
"__initcall_nmi_warning_debugfs5",
"__initcall_hpet_late_init5",
"__initcall_init_amd_nbs5",
"__initcall_iomem_init_inode5",
"__initcall_clocksource_done_booting5",
"__initcall_init_pipe_fs5",
"__initcall_anon_inode_init5",
"__initcall_proc_cmdline_init5",
"__initcall_proc_consoles_init5",
"__initcall_proc_cpuinfo_init5",
"__initcall_proc_devices_init5",
"__initcall_proc_interrupts_init5",
"__initcall_proc_loadavg_init5",
"__initcall_proc_meminfo_init5",
"__initcall_proc_stat_init5",
"__initcall_proc_uptime_init5",
"__initcall_proc_version_init5",
"__initcall_proc_softirqs_init5",
"__initcall_proc_kmsg_init5",
"__initcall_proc_page_init5",
"__initcall_init_ramfs_fs5",
"__initcall_chr_dev_init5",
"__initcall_firmware_class_init5",
"__initcall_sysctl_core_init5",
"__initcall_eth_offload_init5",
"__initcall_cfg80211_init5",
"__initcall_pcibios_assign_resources5",
"__initcall_pci_apply_final_quirks5s",
"__initcall_populate_rootfsrootfs",
"__initcall_pci_iommu_initrootfs",
"__initcall_rapl_pmu_init6",
"__initcall_packet_init6",
"__initcall_amd_uncore_init6",
"__initcall_amd_ibs_init6",
"__initcall_msr_init6",
"__initcall_intel_uncore_init6",
"__initcall_cstate_pmu_init6",
"__initcall_register_kernel_offset_dumper6",
"__initcall_i8259A_init_ops6",
"__initcall_init_tsc_clocksource6",
"__initcall_add_rtc_cmos6",
"__initcall_umwait_init6",
"__initcall_ioapic_init_ops6",
"__initcall_sysfb_init6",
"__initcall_proc_execdomains_init6",
"__initcall_ioresources_init6",
"__initcall_timekeeping_init_ops6",
"__initcall_init_clocksource_sysfs6",
"__initcall_init_timer_list_procfs6",
"__initcall_alarmtimer_init6",
"__initcall_clockevents_init_sysfs6",
"__initcall_utsname_sysctl_init6",
"__initcall_perf_event_sysfs_init6",
"__initcall_system_trusted_keyring_init6",
"__initcall_kswapd_init6",
"__initcall_workingset_init6",
"__initcall_proc_vmalloc_init6",
"__initcall_fcntl_init6",
"__initcall_proc_filesystems_init6",
"__initcall_start_dirtytime_writeback6",
"__initcall_init_devpts_fs6",
"__initcall_key_proc_init6",
"__initcall_crypto_algapi_init6",
"__initcall_asymmetric_key_init6",
"__initcall_x509_key_init6",
"__initcall_pci_proc_init6",
"__initcall_gpio_clk_driver_init6",
"__initcall_plt_clk_driver_init6",
"__initcall_n_null_init6",
"__initcall_pty_init6",
"__initcall_serial8250_init6",
"__initcall_serial_pci_driver_init6",
"__initcall_exar_pci_driver_init6",
"__initcall_lpss8250_pci_driver_init6",
"__initcall_mid8250_pci_driver_init6",
"__initcall_topology_sysfs_init6",
"__initcall_cacheinfo_sysfs_init6",
"__initcall_net_olddevs_init6",
"__initcall_blackhole_netdev_init6",
"__initcall_iwl_drv_init6",
"__initcall_iwl_init6",
"__initcall_iwl_mvm_init6",
"__initcall_ehci_hcd_init6",
"__initcall_ehci_pci_init6",
"__initcall_ohci_hcd_mod_init6",
"__initcall_ohci_pci_init6",
"__initcall_xhci_hcd_init6",
"__initcall_xhci_pci_init6",
"__initcall_i8042_init6",
"__initcall_serport_init6",
"__initcall_atkbd_init6",
"__initcall_psmouse_init6",
"__initcall_pmc_atom_init6",
"__initcall_sock_diag_init6",
"__initcall_update_mp_table7",
"__initcall_lapic_insert_resource7",
"__initcall_print_ICs7",
"__initcall_create_tlb_single_page_flush_ceiling7",
"__initcall_init_oops_id7",
"__initcall_reboot_ksysfs_init7",
"__initcall_sched_clock_init_late7",
"__initcall_sched_init_debug7",
"__initcall_printk_late_init7",
"__initcall_load_system_certificate_list7",
"__initcall_check_early_ioremap_leak7",
"__initcall_init_root_keyring7",
"__initcall_prandom_init_late7",
"__initcall_pci_resource_alignment_sysfs_init7",
"__initcall_pci_sysfs_init7",
"__initcall_sync_state_resume_initcall7",
"__initcall_deferred_probe_initcall7",
"__initcall_regulatory_init_db7",
"__initcall_clk_disable_unused7s",
"__initcall_con_initcon",
"__initcall_end",
"__initcall_univ8250_console_initcon",
"END_OF_INITCALL_ORDER_ARRAY_DUMMY_ENTRY"
};

View File

@ -0,0 +1,5 @@
#pragma once
static const char * lx_emul_pci_final_fixups[] = {
"END_OF_PCI_FIXUPS"
};

View File

@ -0,0 +1,279 @@
/*
* \brief Linux socket call interface back end
* \author Josef Soentgen
* \date 2022-02-17
*/
/*
* Copyright (C) 2022 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
/* DDE Linux includes */
#include "lx_socket_call.h"
/* kernel includes */
#include <linux/socket.h>
#include <linux/net.h>
#include <net/sock.h>
struct task_struct *lx_socket_call_task;
void *lx_socket_call_task_args;
extern int run_lx_socket_call_task(void *p);
extern struct net init_net;
void lx_user_init(void)
{
int pid = kernel_thread(run_lx_socket_call_task,
lx_socket_call_task_args,
CLONE_FS | CLONE_FILES);
lx_socket_call_task = find_task_by_pid_ns(pid, NULL);
}
int lx_sock_create_kern(int domain, int type, int protocol,
struct socket **res)
{
int const err = __sock_create(&init_net, domain, type, protocol, res, 1);
if (err)
return err;
init_waitqueue_head(&(*res)->wq.wait);
return 0;
}
int lx_sock_release(struct socket *sock)
{
return sock->ops->release(sock);
}
int lx_sock_bind(struct socket *sock, void *sockaddr, int sockaddr_len)
{
return sock->ops->bind(sock, sockaddr, sockaddr_len);
}
int lx_sock_getname(struct socket *sock, void *sockaddr, int peer)
{
return sock->ops->getname(sock, sockaddr, peer);
}
int lx_sock_recvmsg(struct socket *sock, struct lx_msghdr *lx_msg,
int flags, int dontwait)
{
struct msghdr *msg;
struct iovec *iov;
size_t iovlen;
unsigned iov_count;
unsigned i;
int err = -1;
iov_count = lx_msg->msg_iovcount;
msg = kzalloc(sizeof (struct msghdr), GFP_KERNEL);
if (!msg)
goto err_msg;
iov = kzalloc(sizeof (struct iovec) * iov_count, GFP_KERNEL);
if (!iov)
goto err_iov;
iovlen = 0;
for (i = 0; i < iov_count; i++) {
iov[i].iov_base = lx_msg->msg_iov[i].iov_base;
iov[i].iov_len = lx_msg->msg_iov[i].iov_len;
iovlen += lx_msg->msg_iov[i].iov_len;
}
msg->msg_name = lx_msg->msg_name;
msg->msg_namelen = lx_msg->msg_namelen;
msg->msg_iter.iov = iov;
msg->msg_iter.nr_segs = iov_count;
msg->msg_iter.count = iovlen;
msg->msg_flags = flags;
if (dontwait) {
msg->msg_flags |= MSG_DONTWAIT;
flags |= MSG_DONTWAIT;
}
err = sock->ops->recvmsg(sock, msg, iovlen, flags);
kfree(iov);
err_iov:
kfree(msg);
err_msg:
return err;
}
int lx_sock_sendmsg(struct socket *sock, struct lx_msghdr* lx_msg,
int flags, int dontwait)
{
struct msghdr *msg;
struct iovec *iov;
size_t iovlen;
unsigned iov_count;
unsigned i;
int err = -1;
iov_count = lx_msg->msg_iovcount;
msg = kzalloc(sizeof (struct msghdr), GFP_KERNEL);
if (!msg)
goto err_msg;
iov = kzalloc(sizeof (struct iovec) * iov_count, GFP_KERNEL);
if (!iov)
goto err_iov;
iovlen = 0;
for (i = 0; i < iov_count; i++) {
iov[i].iov_base = lx_msg->msg_iov[i].iov_base;
iov[i].iov_len = lx_msg->msg_iov[i].iov_len;
iovlen += lx_msg->msg_iov[i].iov_len;
}
msg->msg_name = lx_msg->msg_name;
msg->msg_namelen = lx_msg->msg_namelen;
msg->msg_iter.iov = iov;
msg->msg_iter.nr_segs = iov_count;
msg->msg_iter.count = iovlen;
msg->msg_flags = flags;
if (dontwait)
msg->msg_flags |= MSG_DONTWAIT;
err = sock->ops->sendmsg(sock, msg, iovlen);
kfree(iov);
err_iov:
kfree(msg);
err_msg:
return err;
}
int lx_sock_setsockopt(struct socket *sock, int level, int optname,
void const *optval, unsigned optlen)
{
sockptr_t soptval = (sockptr_t) { .user = optval };
if (level == SOL_SOCKET)
return sock_setsockopt(sock, level, optname,
soptval, optlen);
return sock->ops->setsockopt(sock, level, optname,
soptval, optlen);
}
unsigned char const* lx_get_mac_addr()
{
static char mac_addr_buffer[16];
struct sockaddr addr;
int err;
size_t length;
memset(mac_addr_buffer, 0, sizeof (mac_addr_buffer));
memset(addr.sa_data, 0, sizeof (addr.sa_data));
err = dev_get_mac_address(&addr, &init_net, "wlan0");
if (err)
return NULL;
length = sizeof (mac_addr_buffer) < sizeof (addr.sa_data)
? sizeof (mac_addr_buffer)
: sizeof (addr.sa_data);
memcpy(mac_addr_buffer, addr.sa_data, length);
return mac_addr_buffer;
}
struct lx_poll_result lx_sock_poll(struct socket *sock)
{
enum {
POLLIN_SET = (EPOLLRDHUP | EPOLLIN | EPOLLRDNORM),
POLLOUT_SET = (EPOLLOUT | EPOLLWRNORM | EPOLLWRBAND),
POLLEX_SET = (EPOLLERR | EPOLLPRI)
};
// enum {
// POLLIN_SET = (EPOLLRDNORM | EPOLLRDBAND | EPOLLIN | EPOLLHUP | EPOLLERR)
// POLLOUT_SET = (EPOLLWRBAND | EPOLLWRNORM | EPOLLOUT | EPOLLERR)
// POLLEX_SET = (EPOLLPRI)
// };
int const mask = sock->ops->poll(0, sock, 0);
struct lx_poll_result result = { false, false, false };
if (mask & POLLIN_SET)
result.in = true;
if (mask & POLLOUT_SET)
result.out = true;
if (mask & POLLEX_SET)
result.ex = true;
return result;
}
int lx_sock_poll_wait(struct socket *socks[], unsigned num, int timeout)
{
unsigned i;
unsigned long j;
signed long ex;
unsigned int to;
enum { NUM_WQE = 8u, };
struct wait_queue_entry sock_wqe[NUM_WQE];
/* should not happen as the number of sockets is capped by libnl */
if ((unsigned)NUM_WQE < num)
printk("%s: more num: %d sockets than available"
"wait queue entries: %d\n", __func__, num, (unsigned)NUM_WQE);
/*
* Add the appropriate wait queue entries and sleep afterwards
* for the requested timeout duration. Either a 'wake_up' call
* or the timeout will get us going again.
*/
__set_current_state(TASK_INTERRUPTIBLE);
for (i = 0; i < num; i++) {
struct socket *sock = socks[i];
if (!sock)
continue;
init_waitqueue_entry(&sock_wqe[i], current);
add_wait_queue(&(sock->sk->sk_wq->wait), &sock_wqe[i]);
}
j = msecs_to_jiffies(timeout);
ex = schedule_timeout(j);
to = jiffies_to_msecs(ex);
for (i = 0; i < num; i++) {
struct socket *sock = socks[i];
if (!sock)
continue;
remove_wait_queue(&(sock->sk->sk_wq->wait), &sock_wqe[i]);
}
return (int)to;
}

View File

@ -0,0 +1,75 @@
/*
* \brief Linux socket call interface back end
* \author Josef Soentgen
* \date 2022-02-17
*/
/*
* Copyright (C) 2022 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#ifndef _LX_SOCKET_CALL_H_
#define _LX_SOCKET_CALL_H_
#ifdef __cplusplus
extern "C" {
#endif
struct lx_iov
{
void *iov_base;
unsigned long iov_len;
};
enum { MAX_IOV_LEN = 8 };
struct lx_msghdr
{
void *msg_name;
unsigned msg_namelen;
struct lx_iov msg_iov[MAX_IOV_LEN];
unsigned msg_iovcount;
/*
* Omit total length covered by vector as it is
* calculated where needed.
*/
void *msg_control;
unsigned msg_controllen;
};
struct socket;
int lx_sock_create_kern(int domain, int type, int protocol,
struct socket **res);
int lx_sock_release(struct socket *sock);
int lx_sock_bind(struct socket *sock, void *sockaddr, int sockaddr_len);
int lx_sock_getname(struct socket *sock, void *sockaddr, int peer);
int lx_sock_recvmsg(struct socket *sock, struct lx_msghdr *lx_msg,
int flags, int dontwait);
int lx_sock_sendmsg(struct socket *socket, struct lx_msghdr* lx_msg,
int flags, int dontwait);
int lx_sock_setsockopt(struct socket *sock, int level, int optname,
void const *optval, unsigned optlen);
unsigned char const* lx_get_mac_addr(void);
struct lx_poll_result
{
int in;
int out;
int ex;
};
struct lx_poll_result lx_sock_poll(struct socket *sock);
int lx_sock_poll_wait(struct socket *sock[], unsigned num, int timeout);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* _LX_SOCKET_CALL_H_ */

View File

@ -0,0 +1,20 @@
/*
* \brief Misc
* \author Josef Soentgen
* \date 2022-01-20
*/
/*
* Copyright (C) 2022 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
/* Genode includes */
#include <os/backtrace.h>
extern "C" void lx_backtrace(void)
{
Genode::backtrace();
}

View File

@ -0,0 +1,111 @@
/*
* \brief Linux random emulation code
* \author Josef Soentgen
* \date 2016-10-19
*
* For all intents and purposes this random back end should be treated
* as a gloryfied counter.
*/
/*
* Copyright (C) 2016-2021 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
/* Genode includes */
#include <base/log.h>
#include <base/fixed_stdint.h>
#include <util/string.h>
using Genode::uint64_t;
/*
* Xoroshiro128+ written in 2014-2016 by Sebastiano Vigna (vigna@acm.org)
*
* (see http://xoroshiro.di.unimi.it/xorshift128plus.c and
* http://xoroshiro.di.unimi.it/splitmix64.c)
*/
struct Xoroshiro
{
uint64_t seed;
uint64_t splitmix64()
{
uint64_t z = (seed += __UINT64_C(0x9E3779B97F4A7C15));
z = (z ^ (z >> 30)) * __UINT64_C(0xBF58476D1CE4E5B9);
z = (z ^ (z >> 27)) * __UINT64_C(0x94D049BB133111EB);
return z ^ (z >> 31);
}
Xoroshiro(uint64_t seed) : seed(seed)
{
s[0] = splitmix64();
s[1] = splitmix64();
}
uint64_t s[2];
static uint64_t rotl(uint64_t const x, int k) {
return (x << k) | (x >> (64 - k));
}
uint64_t get()
{
uint64_t const s0 = s[0];
uint64_t s1 = s[1];
uint64_t const result = s0 + s1;
s1 ^= s0;
s[0] = rotl(s0, 55) ^ s1 ^ (s1 << 14);
s[1] = rotl(s1, 36);
return result;
}
};
static Xoroshiro &xoroshiro()
{
static Xoroshiro inst(0x636864324d766931);
return inst;
}
/********************
** linux/random.h **
********************/
extern "C" void lx_emul_get_random_bytes(void *buf, unsigned long nbytes)
{
if (!buf || !nbytes)
return;
char *p = reinterpret_cast<char*>(buf);
unsigned long const rounds = nbytes / 8;
for (unsigned long i = 0; i < rounds; i++) {
uint64_t const v = xoroshiro().get();
Genode::memcpy(p, &v, 8);
p += 8;
}
unsigned long const remain = nbytes - rounds * 8;
if (!remain) {
return;
}
uint64_t const v = xoroshiro().get();
Genode::memcpy(p, &v, remain);
}
extern "C" unsigned int lx_emul_get_random_u32(void)
{
return (unsigned int)xoroshiro().get();
}

View File

@ -0,0 +1,724 @@
/*
* \brief Linux socket call interface front end
* \author Josef Soentgen
* \date 2014-08-04
*/
/*
* Copyright (C) 2014-2022 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
/* Genode includes */
#include <base/allocator.h>
#include <base/env.h>
#include <base/log.h>
/* DDE Linux includes */
#include <wifi/socket_call.h>
#include <lx_emul/task.h>
#include <lx_kit/env.h>
/* local includes */
#include "lx_socket_call.h"
#include "libc_errno.h"
/*
* The values were taken from 'uapi/asm-generic/socket.h',
* 'uapi/linux/netlink.h' and 'linux/socket.h' and must be
* kept in sync.
*/
enum : int {
SOL_SOCKET = 1,
SOL_NETLINK = 270,
SO_SNDBUF = 7,
SO_RCVBUF = 8,
SO_PASSCRED = 16,
SO_WIFI_STATUS = 41,
NETLINK_ADD_MEMBERSHIP = 1,
NETLINK_DROP_MEMBERSHIP = 2,
NETLINK_PKTINFO = 3,
MSG_DONTWAIT = 0x40,
MSG_ERRQUEUE = 0x2000,
};
static int convert_errno_from_linux(int linux_errno)
{
if (linux_errno >= 0)
return linux_errno;
linux_errno *= -1;
switch (linux_errno) {
case 0: return 0;
case E2BIG: return -(int)Libc::Errno::BSD_E2BIG;
case EACCES: return -(int)Libc::Errno::BSD_EACCES;
case EADDRINUSE: return -(int)Libc::Errno::BSD_EADDRINUSE;
case EADDRNOTAVAIL: return -(int)Libc::Errno::BSD_EADDRNOTAVAIL;
case EAFNOSUPPORT: return -(int)Libc::Errno::BSD_EAFNOSUPPORT;
case EAGAIN: return -(int)Libc::Errno::BSD_EAGAIN;
case EALREADY: return -(int)Libc::Errno::BSD_EALREADY;
case EBADF: return -(int)Libc::Errno::BSD_EBADF;
case EBADMSG: return -(int)Libc::Errno::BSD_EBADMSG;
case EBUSY: return -(int)Libc::Errno::BSD_EBUSY;
case ECANCELED: return -(int)Libc::Errno::BSD_ECANCELED;
case ECONNABORTED: return -(int)Libc::Errno::BSD_ECONNABORTED;
case ECONNREFUSED: return -(int)Libc::Errno::BSD_ECONNREFUSED;
case ECONNRESET: return -(int)Libc::Errno::BSD_ECONNRESET;
case EDEADLK: return -(int)Libc::Errno::BSD_EDEADLK;
case EDESTADDRREQ: return -(int)Libc::Errno::BSD_EDESTADDRREQ;
case EDOM: return -(int)Libc::Errno::BSD_EDOM;
case EEXIST: return -(int)Libc::Errno::BSD_EEXIST;
case EFAULT: return -(int)Libc::Errno::BSD_EFAULT;
case EFBIG: return -(int)Libc::Errno::BSD_EFBIG;
case EHOSTDOWN: return -(int)Libc::Errno::BSD_EHOSTDOWN;
case EHOSTUNREACH: return -(int)Libc::Errno::BSD_EHOSTUNREACH;
case EILSEQ: return -(int)Libc::Errno::BSD_EILSEQ;
case EINPROGRESS: return -(int)Libc::Errno::BSD_EINPROGRESS;
case EINTR: return -(int)Libc::Errno::BSD_EINTR;
case EINVAL: return -(int)Libc::Errno::BSD_EINVAL;
case EIO: return -(int)Libc::Errno::BSD_EIO;
case EISCONN: return -(int)Libc::Errno::BSD_EISCONN;
case EMSGSIZE: return -(int)Libc::Errno::BSD_EMSGSIZE;
case ENAMETOOLONG: return -(int)Libc::Errno::BSD_ENAMETOOLONG;
case ENETDOWN: return -(int)Libc::Errno::BSD_ENETDOWN;
case ENETUNREACH: return -(int)Libc::Errno::BSD_ENETUNREACH;
case ENFILE: return -(int)Libc::Errno::BSD_ENFILE;
case ENOBUFS: return -(int)Libc::Errno::BSD_ENOBUFS;
case ENODEV: return -(int)Libc::Errno::BSD_ENODEV;
case ENOENT: return -(int)Libc::Errno::BSD_ENOENT;
case ENOEXEC: return -(int)Libc::Errno::BSD_ENOEXEC;
case ENOLINK:
Genode::error("ENOLINK (", (int) ENOLINK, ") -> ", (int)Libc::Errno::BSD_ENOLINK);
return -(int)Libc::Errno::BSD_ENOLINK;
case ENOMEM: return -(int)Libc::Errno::BSD_ENOMEM;
case ENOMSG: return -(int)Libc::Errno::BSD_ENOMSG;
case ENOPROTOOPT: return -(int)Libc::Errno::BSD_ENOPROTOOPT;
case ENOSPC: return -(int)Libc::Errno::BSD_ENOSPC;
case ENOSYS: return -(int)Libc::Errno::BSD_ENOSYS;
case ENOTCONN: return -(int)Libc::Errno::BSD_ENOTCONN;
case ENOTSOCK: return -(int)Libc::Errno::BSD_ENOTSOCK;
case ENOTTY: return -(int)Libc::Errno::BSD_ENOTTY;
case ENXIO: return -(int)Libc::Errno::BSD_ENXIO;
case EOPNOTSUPP: return -(int)Libc::Errno::BSD_EOPNOTSUPP;
case EOVERFLOW: return -(int)Libc::Errno::BSD_EOVERFLOW;
case EPERM: return -(int)Libc::Errno::BSD_EPERM;
case EPFNOSUPPORT: return -(int)Libc::Errno::BSD_EPFNOSUPPORT;
case EPIPE: return -(int)Libc::Errno::BSD_EPIPE;
case EPROTO: return -(int)Libc::Errno::BSD_EPROTO;
case EPROTONOSUPPORT: return -(int)Libc::Errno::BSD_EPROTONOSUPPORT;
case ERANGE: return -(int)Libc::Errno::BSD_ERANGE;
case ESOCKTNOSUPPORT: return -(int)Libc::Errno::BSD_ESOCKTNOSUPPORT;
case ESPIPE: return -(int)Libc::Errno::BSD_ESPIPE;
case ESRCH: return -(int)Libc::Errno::BSD_ESRCH;
case ETIMEDOUT: return -(int)Libc::Errno::BSD_ETIMEDOUT;
case EXDEV: return -(int)Libc::Errno::BSD_EXDEV;
default:
Genode::error(__func__, ": unhandled errno ", linux_errno);
return linux_errno;
}
}
static_assert((unsigned)Wifi::Msghdr::MAX_IOV_LEN == (unsigned)MAX_IOV_LEN);
extern "C" struct task_struct *lx_socket_call_task;
extern "C" void *lx_socket_call_task_args;
/* XXX move Wifi::Socket definition to better location */
struct Wifi::Socket
{
void *socket = nullptr;
bool non_block = false;
Socket() { }
explicit Socket(void *s) : socket(s) { }
void print(Genode::Output &out) const
{
Genode::print(out, "this: ", this, " socket: ", socket, " non_block: ", non_block);
}
};
struct Call
{
enum Opcode {
NONE, SOCKET, CLOSE,
BIND, GETSOCKNAME, RECVMSG, SENDMSG, SENDTO, SETSOCKOPT,
GET_MAC_ADDRESS, POLL_ALL, NON_BLOCK,
};
Opcode opcode = NONE;
Wifi::Socket *handle = nullptr;
union {
struct
{
int domain;
int type;
int protocol;
void *result;
} socket;
struct { /* no args */ } close;
struct
{
void const *addr;
int addrlen;
} bind;
struct
{
void *addr;
int *addrlen;
} getsockname;
struct
{
lx_msghdr msg;
int flags;
} recvmsg;
struct
{
lx_msghdr msg;
int flags;
} sendmsg;
struct {
int level;
int optname;
void const *optval;
unsigned optlen;
} setsockopt;
struct
{
unsigned char *addr;
unsigned int addr_len;
} get_mac_address;
struct
{
Wifi::Poll_socket_fd *sockets;
unsigned num;
int timeout;
} poll_all;
struct
{
bool value;
} non_block;
};
int err = 0;
};
static Call _call;
static Genode::Semaphore _block;
namespace Lx {
class Socket;
}
/**
* Context for socket calls
*/
class Lx::Socket
{
private:
Socket(const Socket&) = delete;
Socket& operator=(const Socket&) = delete;
Genode::Signal_transmitter _sender { };
Genode::Signal_handler<Lx::Socket> _dispatcher;
struct socket *_sock_poll_table[Wifi::MAX_POLL_SOCKETS] { };
struct socket *_call_socket()
{
struct socket *sock = static_cast<struct socket*>(_call.handle->socket);
if (!sock)
Genode::error("BUG: sock is zero");
return sock;
}
void _do_socket()
{
struct socket *s;
int res = lx_sock_create_kern(_call.socket.domain, _call.socket.type,
_call.socket.protocol, &s);
if (!res) {
_call.socket.result = s;
_call.err = 0;
return;
}
_call.socket.result = nullptr;
_call.err = res;
}
void _do_close()
{
struct socket *sock = _call_socket();
_call.err = lx_sock_release(sock);
}
void _do_bind()
{
struct socket *sock = _call_socket();
_call.err = lx_sock_bind(sock,
const_cast<void*>(_call.bind.addr),
_call.bind.addrlen);
}
void _do_getsockname()
{
struct socket *sock = _call_socket();
int addrlen = *_call.getsockname.addrlen;
_call.err = lx_sock_getname(sock, _call.getsockname.addr, 0);
*_call.getsockname.addrlen = addrlen;
}
void _do_recvmsg()
{
struct socket *sock = _call_socket();
_call.err = lx_sock_recvmsg(sock, &_call.recvmsg.msg,
_call.recvmsg.flags,
_call.handle->non_block);
}
void _do_sendmsg()
{
struct socket *sock = _call_socket();
_call.err = lx_sock_sendmsg(sock, &_call.sendmsg.msg,
_call.sendmsg.flags,
_call.handle->non_block);
}
void _do_setsockopt()
{
struct socket *sock = _call_socket();
_call.err = lx_sock_setsockopt(sock,
_call.setsockopt.level,
_call.setsockopt.optname,
_call.setsockopt.optval,
_call.setsockopt.optlen);
}
void _do_get_mac_address()
{
unsigned const char *addr = lx_get_mac_addr();
if (!addr)
return;
Genode::size_t const copy = 6 > _call.get_mac_address.addr_len
? _call.get_mac_address.addr_len
: 6;
Genode::memcpy(_call.get_mac_address.addr, addr, copy);
}
void _do_poll_all()
{
Wifi::Poll_socket_fd *sockets = _call.poll_all.sockets;
unsigned num = _call.poll_all.num;
int timeout = _call.poll_all.timeout;
int nready = 0;
bool timeout_triggered = false;
bool woken_up = false;
do {
/**
* Timeout was triggered, exit early.
*/
if (timeout_triggered) {
break;
}
/**
* Poll each socket and check if there is something of interest.
*/
for (unsigned i = 0; i < num; i++) {
struct socket *sock = static_cast<struct socket*>(sockets[i].s->socket);
struct lx_poll_result result = lx_sock_poll(sock);
sockets[i].revents = 0;
if (result.in)
sockets[i].revents |= sockets[i].events & Wifi::WIFI_POLLIN ? Wifi::WIFI_POLLIN : 0;
if (result.out)
sockets[i].revents |= sockets[i].events & Wifi::WIFI_POLLOUT ? Wifi::WIFI_POLLOUT : 0;
if (result.ex)
sockets[i].revents |= sockets[i].events & Wifi::WIFI_POLLEX ? Wifi::WIFI_POLLEX : 0;
if (sockets[i].revents)
nready++;
}
/**
* We were woken up but there is still nothing of interest.
*/
if (woken_up) {
break;
}
/**
* Exit the loop if either a socket is ready or there is
* no timeout given.
*/
if (nready || !timeout) {
break;
}
/**
* In case of a timeout add all sockets to an artificial wait list
* so at least one is woken up an sk_data_ready() call.
*/
for (unsigned i = 0; i < num; i++) {
struct socket *sock = static_cast<struct socket*>(sockets[i].s->socket);
_sock_poll_table[i] = sock;
}
timeout_triggered = !lx_sock_poll_wait(_sock_poll_table, num, timeout);
woken_up = true;
} while (1);
_call.err = nready;
}
void _do_non_block()
{
_call.handle->non_block = _call.non_block.value;
}
void _handle()
{
lx_emul_task_unblock(lx_socket_call_task);
Lx_kit::env().scheduler.schedule();
}
public:
Socket(Genode::Entrypoint &ep)
:
_dispatcher(ep, *this, &Lx::Socket::_handle)
{
_sender.context(_dispatcher);
}
void exec_call()
{
switch (_call.opcode) {
case Call::BIND: _do_bind(); break;
case Call::CLOSE: _do_close(); break;
case Call::GETSOCKNAME: _do_getsockname(); break;
case Call::POLL_ALL: _do_poll_all(); break;
case Call::RECVMSG: _do_recvmsg(); break;
case Call::SENDMSG: _do_sendmsg(); break;
case Call::SETSOCKOPT: _do_setsockopt(); break;
case Call::SOCKET: _do_socket(); break;
case Call::GET_MAC_ADDRESS: _do_get_mac_address(); break;
case Call::NON_BLOCK: _do_non_block(); break;
case Call::NONE: [[fallthrough]];/* ignore silently */
default:
_call.err = -1;
break;
}
/*
* Save old call opcode as we may only release the blocker
* when actually did something useful, i.e., were called by
* some socket operation and not by kicking the socket.
*/
Call::Opcode old = _call.opcode;
_call.opcode = Call::NONE;
if (old != Call::NONE) { _block.up(); }
}
void submit_and_block()
{
_sender.submit();
_block.down();
}
};
static Lx::Socket *_socket;
extern Genode::Blockade *wpa_blockade;
extern "C" void uplink_init(void);
extern "C" int run_lx_socket_call_task(void *)
{
static Lx::Socket inst(Lx_kit::env().env.ep());
_socket = &inst;
uplink_init();
wpa_blockade->wakeup();
while (true) {
_socket->exec_call();
lx_emul_task_schedule(true);
}
}
void wifi_kick_socketcall()
{
/* ignore silently, the function might be called to before init */
if (!_socket) { return; }
lx_emul_task_unblock(lx_socket_call_task);
Lx_kit::env().scheduler.schedule();
}
/**************************
** Socket_call instance **
**************************/
Wifi::Socket_call socket_call;
/***************************
** Socket_call interface **
***************************/
using namespace Wifi;
Wifi::Socket *Socket_call::socket(int domain, int type, int protocol)
{
/* FIXME domain, type, protocol values */
_call.opcode = Call::SOCKET;
_call.socket.domain = domain;
_call.socket.type = type & 0xff;
_call.socket.protocol = protocol;
_socket->submit_and_block();
if (_call.socket.result == 0)
return 0;
Wifi::Socket *s = new (Lx_kit::env().heap) Wifi::Socket(_call.socket.result);
return s;
}
int Socket_call::close(Socket *s)
{
_call.opcode = Call::CLOSE;
_call.handle = s;
_socket->submit_and_block();
if (_call.err)
Genode::warning("closing socket failed: ", _call.err);
destroy(Lx_kit::env().heap, s);
return _call.err;
}
int Socket_call::bind(Socket *s, Wifi::Sockaddr const *addr, unsigned addrlen)
{
/* FIXME convert to/from Sockaddr */
_call.opcode = Call::BIND;
_call.handle = s;
_call.bind.addr = (void const *)addr;
_call.bind.addrlen = addrlen;
_socket->submit_and_block();
return convert_errno_from_linux(_call.err);
}
int Socket_call::getsockname(Socket *s, Wifi::Sockaddr *addr, unsigned *addrlen)
{
/* FIXME convert to/from Sockaddr */
/* FIXME unsigned * -> int * */
_call.opcode = Call::GETSOCKNAME;
_call.handle = s;
_call.getsockname.addr = (void *)addr;
_call.getsockname.addrlen = (int *)addrlen;
_socket->submit_and_block();
return convert_errno_from_linux(_call.err);
}
int Socket_call::poll_all(Poll_socket_fd *s, unsigned num, int timeout)
{
_call.opcode = Call::POLL_ALL;
_call.handle = 0;
_call.poll_all.sockets = s;
_call.poll_all.num = num;
_call.poll_all.timeout = timeout;
_socket->submit_and_block();
return convert_errno_from_linux(_call.err);
}
static inline int msg_flags(Wifi::Flags in)
{
int out = Wifi::WIFI_F_NONE;
if (in & Wifi::WIFI_F_MSG_ERRQUEUE)
out |= MSG_ERRQUEUE;
if (in & Wifi::WIFI_F_MSG_DONTWAIT) {
out |= MSG_DONTWAIT;
}
return out;
};
Wifi::ssize_t Socket_call::recvmsg(Socket *s, Wifi::Msghdr *msg, Wifi::Flags flags)
{
_call.opcode = Call::RECVMSG;
_call.handle = s;
_call.recvmsg.msg.msg_name = msg->msg_name;
_call.recvmsg.msg.msg_namelen = msg->msg_namelen;
_call.recvmsg.msg.msg_iovcount = msg->msg_iovlen;
_call.recvmsg.msg.msg_control = msg->msg_control;
_call.recvmsg.msg.msg_controllen = msg->msg_controllen;
_call.recvmsg.flags = msg_flags(flags);
for (unsigned i = 0; i < msg->msg_iovlen; ++i) {
_call.recvmsg.msg.msg_iov[i].iov_base = msg->msg_iov[i].iov_base;
_call.recvmsg.msg.msg_iov[i].iov_len = msg->msg_iov[i].iov_len;
}
_socket->submit_and_block();
msg->msg_namelen = _call.recvmsg.msg.msg_namelen;
return convert_errno_from_linux(_call.err);
}
Wifi::ssize_t Socket_call::sendmsg(Socket *s, Wifi::Msghdr const *msg, Wifi::Flags flags)
{
_call.opcode = Call::SENDMSG;
_call.handle = s;
_call.sendmsg.msg.msg_name = msg->msg_name;
_call.sendmsg.msg.msg_namelen = msg->msg_namelen;
_call.sendmsg.msg.msg_iovcount = msg->msg_iovlen;
_call.sendmsg.msg.msg_control = 0;
_call.sendmsg.msg.msg_controllen = 0;
_call.sendmsg.flags = msg_flags(flags);
for (unsigned i = 0; i < msg->msg_iovlen; ++i) {
_call.sendmsg.msg.msg_iov[i].iov_base = msg->msg_iov[i].iov_base;
_call.sendmsg.msg.msg_iov[i].iov_len = msg->msg_iov[i].iov_len;
}
_socket->submit_and_block();
return convert_errno_from_linux(_call.err);
}
static int sockopt_level(Sockopt_level const in)
{
switch (in) {
case Wifi::WIFI_SOL_SOCKET: return SOL_SOCKET;
case Wifi::WIFI_SOL_NETLINK: return SOL_NETLINK;
}
return -1;
}
static int sockopt_name(Sockopt_level const level, Sockopt_name const in)
{
switch (level) {
case Wifi::WIFI_SOL_SOCKET:
switch (in) {
case Wifi::WIFI_SO_SNDBUF: return SO_SNDBUF;
case Wifi::WIFI_SO_RCVBUF: return SO_RCVBUF;
case Wifi::WIFI_SO_PASSCRED: return SO_PASSCRED;
case Wifi::WIFI_SO_WIFI_STATUS: return SO_WIFI_STATUS;
default: return -1;
}
case Wifi::WIFI_SOL_NETLINK:
switch (in) {
case Wifi::WIFI_NETLINK_ADD_MEMBERSHIP: return NETLINK_ADD_MEMBERSHIP;
case Wifi::WIFI_NETLINK_DROP_MEMBERSHIP: return NETLINK_DROP_MEMBERSHIP;
case Wifi::WIFI_NETLINK_PKTINFO: return NETLINK_PKTINFO;
default: return -1;
}
}
return -1;
}
int Socket_call::setsockopt(Socket *s,
Wifi::Sockopt_level level, Wifi::Sockopt_name optname,
const void *optval, unsigned optlen)
{
/* FIXME optval values */
_call.opcode = Call::SETSOCKOPT;
_call.handle = s;
_call.setsockopt.level = sockopt_level(level);
_call.setsockopt.optname = sockopt_name(level, optname);
_call.setsockopt.optval = optval;
_call.setsockopt.optlen = optlen;
_socket->submit_and_block();
return convert_errno_from_linux(_call.err);
}
void Socket_call::non_block(Socket *s, bool value)
{
_call.opcode = Call::NON_BLOCK;
_call.handle = s;
_call.non_block.value = value;
_socket->submit_and_block();
}
void Socket_call::get_mac_address(unsigned char *addr)
{
_call.opcode = Call::GET_MAC_ADDRESS;
_call.handle = 0;
_call.get_mac_address.addr = addr;
_call.get_mac_address.addr_len = 6; // XXX enforce and set from caller
_socket->submit_and_block();
}

View File

@ -0,0 +1,273 @@
arch/x86/pci/legacy.c
drivers/base/bus.c
drivers/base/class.c
drivers/base/component.c
drivers/base/core.c
drivers/base/dd.c
drivers/base/devres.c
drivers/base/driver.c
drivers/base/platform.c
drivers/base/property.c
drivers/clk/clk-devres.c
drivers/pci/access.c
drivers/pci/bus.c
drivers/pci/host-bridge.c
drivers/pci/msi.c
drivers/pci/pci.c
drivers/pci/pci-driver.c
drivers/pci/pci-sysfs.c
drivers/pci/probe.c
drivers/pci/rom.c
drivers/pci/search.c
drivers/pci/setup-res.c
drivers/pci/slot.c
fs/nls/nls_base.c
kernel/irq/chip.c
kernel/irq/devres.c
kernel/irq/handle.c
kernel/irq/irqdesc.c
kernel/irq/irqdomain.c
kernel/irq/manage.c
kernel/irq/resend.c
kernel/kthread.c
kernel/locking/mutex.c
kernel/locking/osq_lock.c
kernel/locking/rwsem.c
kernel/notifier.c
kernel/panic.c
kernel/resource.c
kernel/sched/clock.c
kernel/sched/completion.c
kernel/sched/swait.c
kernel/sched/wait.c
kernel/smpboot.c
kernel/time/clockevents.c
kernel/time/clocksource.c
kernel/time/hrtimer.c
kernel/time/jiffies.c
kernel/time/ntp.c
kernel/time/tick-common.c
kernel/time/time.c
kernel/time/timeconv.c
kernel/time/timecounter.c
kernel/time/timekeeping.c
kernel/time/timer.c
kernel/time/timer_list.c
kernel/workqueue.c
lib/bitmap.c
lib/crc32.c
lib/ctype.c
lib/debug_locks.c
lib/find_bit.c
lib/hexdump.c
lib/idr.c
lib/irq_regs.c
lib/kasprintf.c
lib/klist.c
lib/kobject.c
lib/kstrtox.c
lib/list_sort.c
lib/iomap.c
lib/math/div64.c
lib/pci_iomap.c
lib/radix-tree.c
lib/rbtree.c
lib/refcount.c
lib/scatterlist.c
lib/siphash.c
lib/sort.c
lib/string.c
lib/timerqueue.c
lib/vsprintf.c
lib/xarray.c
mm/mempool.c
mm/util.c
certs/common.c
crypto/acompress.c
crypto/aead.c
crypto/aes_generic.c
crypto/ahash.c
crypto/akcipher.c
crypto/algapi.c
crypto/algboss.c
crypto/api.c
crypto/ccm.c
crypto/cipher.c
crypto/cmac.c
crypto/compress.c
crypto/crypto_null.c
crypto/ctr.c
crypto/gcm.c
crypto/geniv.c
crypto/gf128mul.c
crypto/ghash-generic.c
crypto/hash_info.c
crypto/kpp.c
crypto/memneq.c
crypto/proc.c
crypto/rng.c
crypto/scatterwalk.c
crypto/scompress.c
crypto/sha256_generic.c
crypto/shash.c
crypto/skcipher.c
crypto/testmgr.c
drivers/net/Space.c
drivers/net/loopback.c
drivers/net/wireless/intel/iwlwifi/cfg/1000.c
drivers/net/wireless/intel/iwlwifi/cfg/2000.c
drivers/net/wireless/intel/iwlwifi/cfg/22000.c
drivers/net/wireless/intel/iwlwifi/cfg/5000.c
drivers/net/wireless/intel/iwlwifi/cfg/6000.c
drivers/net/wireless/intel/iwlwifi/cfg/7000.c
drivers/net/wireless/intel/iwlwifi/cfg/8000.c
drivers/net/wireless/intel/iwlwifi/cfg/9000.c
drivers/net/wireless/intel/iwlwifi/dvm/calib.c
drivers/net/wireless/intel/iwlwifi/dvm/devices.c
drivers/net/wireless/intel/iwlwifi/dvm/lib.c
drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c
drivers/net/wireless/intel/iwlwifi/dvm/main.c
drivers/net/wireless/intel/iwlwifi/dvm/power.c
drivers/net/wireless/intel/iwlwifi/dvm/rs.c
drivers/net/wireless/intel/iwlwifi/dvm/rx.c
drivers/net/wireless/intel/iwlwifi/dvm/rxon.c
drivers/net/wireless/intel/iwlwifi/dvm/scan.c
drivers/net/wireless/intel/iwlwifi/dvm/sta.c
drivers/net/wireless/intel/iwlwifi/dvm/tt.c
drivers/net/wireless/intel/iwlwifi/dvm/tx.c
drivers/net/wireless/intel/iwlwifi/dvm/ucode.c
drivers/net/wireless/intel/iwlwifi/fw/acpi.c
drivers/net/wireless/intel/iwlwifi/fw/dbg.c
drivers/net/wireless/intel/iwlwifi/fw/dump.c
drivers/net/wireless/intel/iwlwifi/fw/img.c
drivers/net/wireless/intel/iwlwifi/fw/init.c
drivers/net/wireless/intel/iwlwifi/fw/notif-wait.c
drivers/net/wireless/intel/iwlwifi/fw/paging.c
drivers/net/wireless/intel/iwlwifi/fw/pnvm.c
drivers/net/wireless/intel/iwlwifi/fw/smem.c
drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c
drivers/net/wireless/intel/iwlwifi/iwl-debug.c
drivers/net/wireless/intel/iwlwifi/iwl-drv.c
drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.c
drivers/net/wireless/intel/iwlwifi/iwl-eeprom-read.c
drivers/net/wireless/intel/iwlwifi/iwl-io.c
drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
drivers/net/wireless/intel/iwlwifi/iwl-phy-db.c
drivers/net/wireless/intel/iwlwifi/iwl-trans.c
drivers/net/wireless/intel/iwlwifi/mvm/binding.c
drivers/net/wireless/intel/iwlwifi/mvm/coex.c
drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c
drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c
drivers/net/wireless/intel/iwlwifi/mvm/fw.c
drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c
drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
drivers/net/wireless/intel/iwlwifi/mvm/nvm.c
drivers/net/wireless/intel/iwlwifi/mvm/offloading.c
drivers/net/wireless/intel/iwlwifi/mvm/ops.c
drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c
drivers/net/wireless/intel/iwlwifi/mvm/power.c
drivers/net/wireless/intel/iwlwifi/mvm/quota.c
drivers/net/wireless/intel/iwlwifi/mvm/rfi.c
drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c
drivers/net/wireless/intel/iwlwifi/mvm/rs.c
drivers/net/wireless/intel/iwlwifi/mvm/rx.c
drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
drivers/net/wireless/intel/iwlwifi/mvm/scan.c
drivers/net/wireless/intel/iwlwifi/mvm/sf.c
drivers/net/wireless/intel/iwlwifi/mvm/sta.c
drivers/net/wireless/intel/iwlwifi/mvm/tdls.c
drivers/net/wireless/intel/iwlwifi/mvm/time-event.c
drivers/net/wireless/intel/iwlwifi/mvm/tt.c
drivers/net/wireless/intel/iwlwifi/mvm/tx.c
drivers/net/wireless/intel/iwlwifi/mvm/utils.c
drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c
drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c
drivers/net/wireless/intel/iwlwifi/pcie/drv.c
drivers/net/wireless/intel/iwlwifi/pcie/rx.c
drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c
drivers/net/wireless/intel/iwlwifi/pcie/trans.c
drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c
drivers/net/wireless/intel/iwlwifi/pcie/tx.c
drivers/net/wireless/intel/iwlwifi/queue/tx.c
lib/asn1_decoder.c
lib/bsearch.c
lib/crypto/aes.c
lib/dynamic_queue_limits.c
lib/hweight.c
lib/nlattr.c
lib/rhashtable.c
net/core/datagram.c
net/core/dev.c
net/core/dev_addr_lists.c
net/core/link_watch.c
net/core/net-sysfs.c
net/core/net_namespace.c
net/core/rtnetlink.c
net/core/skbuff.c
net/core/sock.c
net/core/xdp.c
net/ethernet/eth.c
net/ethtool/common.c
net/socket.c
net/sched/sch_generic.c
net/sched/sch_mq.c
net/mac80211/aead_api.c
net/mac80211/aes_cmac.c
net/mac80211/aes_gmac.c
net/mac80211/agg-rx.c
net/mac80211/agg-tx.c
net/mac80211/airtime.c
net/mac80211/cfg.c
net/mac80211/chan.c
net/mac80211/driver-ops.c
net/mac80211/ethtool.c
net/mac80211/fils_aead.c
net/mac80211/he.c
net/mac80211/ht.c
net/mac80211/ibss.c
net/mac80211/iface.c
net/mac80211/key.c
net/mac80211/main.c
net/mac80211/michael.c
net/mac80211/mlme.c
net/mac80211/ocb.c
net/mac80211/offchannel.c
net/mac80211/rate.c
net/mac80211/rc80211_minstrel_ht.c
net/mac80211/rx.c
net/mac80211/s1g.c
net/mac80211/scan.c
net/mac80211/spectmgmt.c
net/mac80211/sta_info.c
net/mac80211/status.c
net/mac80211/tdls.c
net/mac80211/tkip.c
net/mac80211/trace.c
net/mac80211/tx.c
net/mac80211/util.c
net/mac80211/vht.c
net/mac80211/wep.c
net/mac80211/wme.c
net/mac80211/wpa.c
net/netlink/af_netlink.c
net/netlink/genetlink.c
net/netlink/policy.c
net/packet/af_packet.c
net/wireless/ap.c
net/wireless/chan.c
net/wireless/core.c
net/wireless/ethtool.c
net/wireless/ibss.c
net/wireless/mesh.c
net/wireless/mlme.c
net/wireless/nl80211.c
net/wireless/ocb.c
net/wireless/pmsr.c
net/wireless/radiotap.c
net/wireless/reg.c
net/wireless/scan.c
net/wireless/sme.c
net/wireless/sysfs.c
net/wireless/trace.c
net/wireless/util.c

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,273 @@
arch/x86/pci/legacy.c
drivers/base/bus.c
drivers/base/class.c
drivers/base/component.c
drivers/base/core.c
drivers/base/dd.c
drivers/base/devres.c
drivers/base/driver.c
drivers/base/platform.c
drivers/base/property.c
drivers/clk/clk-devres.c
drivers/pci/access.c
drivers/pci/bus.c
drivers/pci/host-bridge.c
drivers/pci/msi.c
drivers/pci/pci.c
drivers/pci/pci-driver.c
drivers/pci/pci-sysfs.c
drivers/pci/probe.c
drivers/pci/rom.c
drivers/pci/search.c
drivers/pci/setup-res.c
drivers/pci/slot.c
fs/nls/nls_base.c
kernel/irq/chip.c
kernel/irq/devres.c
kernel/irq/handle.c
kernel/irq/irqdesc.c
kernel/irq/irqdomain.c
kernel/irq/manage.c
kernel/irq/resend.c
kernel/kthread.c
kernel/locking/mutex.c
kernel/locking/osq_lock.c
kernel/locking/rwsem.c
kernel/notifier.c
kernel/panic.c
kernel/resource.c
kernel/sched/clock.c
kernel/sched/completion.c
kernel/sched/swait.c
kernel/sched/wait.c
kernel/smpboot.c
kernel/time/clockevents.c
kernel/time/clocksource.c
kernel/time/hrtimer.c
kernel/time/jiffies.c
kernel/time/ntp.c
kernel/time/tick-broadcast.c
kernel/time/tick-common.c
kernel/time/time.c
kernel/time/timeconv.c
kernel/time/timecounter.c
kernel/time/timekeeping.c
kernel/time/timer.c
kernel/time/timer_list.c
kernel/workqueue.c
lib/bitmap.c
lib/crc32.c
lib/ctype.c
lib/debug_locks.c
lib/find_bit.c
lib/hexdump.c
lib/idr.c
lib/irq_regs.c
lib/kasprintf.c
lib/klist.c
lib/kobject.c
lib/kstrtox.c
lib/list_sort.c
lib/iomap.c
lib/pci_iomap.c
lib/radix-tree.c
lib/rbtree.c
lib/refcount.c
lib/scatterlist.c
lib/siphash.c
lib/sort.c
lib/string.c
lib/timerqueue.c
lib/vsprintf.c
lib/xarray.c
mm/mempool.c
mm/util.c
certs/common.c
crypto/acompress.c
crypto/aead.c
crypto/aes_generic.c
crypto/ahash.c
crypto/akcipher.c
crypto/algapi.c
crypto/algboss.c
crypto/api.c
crypto/ccm.c
crypto/cipher.c
crypto/cmac.c
crypto/compress.c
crypto/crypto_null.c
crypto/ctr.c
crypto/gcm.c
crypto/geniv.c
crypto/gf128mul.c
crypto/ghash-generic.c
crypto/hash_info.c
crypto/kpp.c
crypto/memneq.c
crypto/proc.c
crypto/rng.c
crypto/scatterwalk.c
crypto/scompress.c
crypto/sha256_generic.c
crypto/shash.c
crypto/skcipher.c
crypto/testmgr.c
drivers/net/Space.c
drivers/net/loopback.c
drivers/net/wireless/intel/iwlwifi/cfg/1000.c
drivers/net/wireless/intel/iwlwifi/cfg/2000.c
drivers/net/wireless/intel/iwlwifi/cfg/22000.c
drivers/net/wireless/intel/iwlwifi/cfg/5000.c
drivers/net/wireless/intel/iwlwifi/cfg/6000.c
drivers/net/wireless/intel/iwlwifi/cfg/7000.c
drivers/net/wireless/intel/iwlwifi/cfg/8000.c
drivers/net/wireless/intel/iwlwifi/cfg/9000.c
drivers/net/wireless/intel/iwlwifi/dvm/calib.c
drivers/net/wireless/intel/iwlwifi/dvm/devices.c
drivers/net/wireless/intel/iwlwifi/dvm/lib.c
drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c
drivers/net/wireless/intel/iwlwifi/dvm/main.c
drivers/net/wireless/intel/iwlwifi/dvm/power.c
drivers/net/wireless/intel/iwlwifi/dvm/rs.c
drivers/net/wireless/intel/iwlwifi/dvm/rx.c
drivers/net/wireless/intel/iwlwifi/dvm/rxon.c
drivers/net/wireless/intel/iwlwifi/dvm/scan.c
drivers/net/wireless/intel/iwlwifi/dvm/sta.c
drivers/net/wireless/intel/iwlwifi/dvm/tt.c
drivers/net/wireless/intel/iwlwifi/dvm/tx.c
drivers/net/wireless/intel/iwlwifi/dvm/ucode.c
drivers/net/wireless/intel/iwlwifi/fw/acpi.c
drivers/net/wireless/intel/iwlwifi/fw/dbg.c
drivers/net/wireless/intel/iwlwifi/fw/dump.c
drivers/net/wireless/intel/iwlwifi/fw/img.c
drivers/net/wireless/intel/iwlwifi/fw/init.c
drivers/net/wireless/intel/iwlwifi/fw/notif-wait.c
drivers/net/wireless/intel/iwlwifi/fw/paging.c
drivers/net/wireless/intel/iwlwifi/fw/pnvm.c
drivers/net/wireless/intel/iwlwifi/fw/smem.c
drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c
drivers/net/wireless/intel/iwlwifi/iwl-debug.c
drivers/net/wireless/intel/iwlwifi/iwl-drv.c
drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.c
drivers/net/wireless/intel/iwlwifi/iwl-eeprom-read.c
drivers/net/wireless/intel/iwlwifi/iwl-io.c
drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
drivers/net/wireless/intel/iwlwifi/iwl-phy-db.c
drivers/net/wireless/intel/iwlwifi/iwl-trans.c
drivers/net/wireless/intel/iwlwifi/mvm/binding.c
drivers/net/wireless/intel/iwlwifi/mvm/coex.c
drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c
drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c
drivers/net/wireless/intel/iwlwifi/mvm/fw.c
drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c
drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
drivers/net/wireless/intel/iwlwifi/mvm/nvm.c
drivers/net/wireless/intel/iwlwifi/mvm/offloading.c
drivers/net/wireless/intel/iwlwifi/mvm/ops.c
drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c
drivers/net/wireless/intel/iwlwifi/mvm/power.c
drivers/net/wireless/intel/iwlwifi/mvm/quota.c
drivers/net/wireless/intel/iwlwifi/mvm/rfi.c
drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c
drivers/net/wireless/intel/iwlwifi/mvm/rs.c
drivers/net/wireless/intel/iwlwifi/mvm/rx.c
drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
drivers/net/wireless/intel/iwlwifi/mvm/scan.c
drivers/net/wireless/intel/iwlwifi/mvm/sf.c
drivers/net/wireless/intel/iwlwifi/mvm/sta.c
drivers/net/wireless/intel/iwlwifi/mvm/tdls.c
drivers/net/wireless/intel/iwlwifi/mvm/time-event.c
drivers/net/wireless/intel/iwlwifi/mvm/tt.c
drivers/net/wireless/intel/iwlwifi/mvm/tx.c
drivers/net/wireless/intel/iwlwifi/mvm/utils.c
drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c
drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c
drivers/net/wireless/intel/iwlwifi/pcie/drv.c
drivers/net/wireless/intel/iwlwifi/pcie/rx.c
drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c
drivers/net/wireless/intel/iwlwifi/pcie/trans.c
drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c
drivers/net/wireless/intel/iwlwifi/pcie/tx.c
drivers/net/wireless/intel/iwlwifi/queue/tx.c
lib/asn1_decoder.c
lib/bsearch.c
lib/crypto/aes.c
lib/dynamic_queue_limits.c
lib/hweight.c
lib/nlattr.c
lib/rhashtable.c
net/core/datagram.c
net/core/dev.c
net/core/dev_addr_lists.c
net/core/link_watch.c
net/core/net-sysfs.c
net/core/net_namespace.c
net/core/rtnetlink.c
net/core/skbuff.c
net/core/sock.c
net/core/xdp.c
net/ethernet/eth.c
net/ethtool/common.c
net/socket.c
net/sched/sch_generic.c
net/sched/sch_mq.c
net/mac80211/aead_api.c
net/mac80211/aes_cmac.c
net/mac80211/aes_gmac.c
net/mac80211/agg-rx.c
net/mac80211/agg-tx.c
net/mac80211/airtime.c
net/mac80211/cfg.c
net/mac80211/chan.c
net/mac80211/driver-ops.c
net/mac80211/ethtool.c
net/mac80211/fils_aead.c
net/mac80211/he.c
net/mac80211/ht.c
net/mac80211/ibss.c
net/mac80211/iface.c
net/mac80211/key.c
net/mac80211/main.c
net/mac80211/michael.c
net/mac80211/mlme.c
net/mac80211/ocb.c
net/mac80211/offchannel.c
net/mac80211/rate.c
net/mac80211/rc80211_minstrel_ht.c
net/mac80211/rx.c
net/mac80211/s1g.c
net/mac80211/scan.c
net/mac80211/spectmgmt.c
net/mac80211/sta_info.c
net/mac80211/status.c
net/mac80211/tdls.c
net/mac80211/tkip.c
net/mac80211/trace.c
net/mac80211/tx.c
net/mac80211/util.c
net/mac80211/vht.c
net/mac80211/wep.c
net/mac80211/wme.c
net/mac80211/wpa.c
net/netlink/af_netlink.c
net/netlink/genetlink.c
net/netlink/policy.c
net/packet/af_packet.c
net/wireless/ap.c
net/wireless/chan.c
net/wireless/core.c
net/wireless/ethtool.c
net/wireless/ibss.c
net/wireless/mesh.c
net/wireless/mlme.c
net/wireless/nl80211.c
net/wireless/ocb.c
net/wireless/pmsr.c
net/wireless/radiotap.c
net/wireless/reg.c
net/wireless/scan.c
net/wireless/sme.c
net/wireless/sysfs.c
net/wireless/trace.c
net/wireless/util.c

View File

@ -0,0 +1,29 @@
{
global:
/* needed by vfs_wlan */
*Lx_kit*initialize*;
/* initialize function */
_*wifi_init*;
/* Wifi::Socket_call interface */
*Socket_call*;
/* Wifi::Socket_call instance */
socket_call;
/* rfkill interface */
_*wifi_*_rfkill*;
_*wifi_kick_*;
/* interface for libnl/wpa_driver_nl82011 */
wifi_if*;
/* used by libnl's time() */
jiffies;
/* for general debugging purposes */
lx_backtrace;
local:
*;
};

View File

@ -0,0 +1,25 @@
/*
* \brief Lx_emul udelay function for very short delays
* \author Stefan Kalkowski
* \date 2021-07-10
*/
/*
* Copyright (C) 2021 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#include <base/log.h>
#include <lx_kit/env.h>
extern "C" void lx_emul_time_udelay(unsigned long usec);
extern "C" void lx_emul_time_udelay(unsigned long usec)
{
if (usec > 100)
Genode::error("Cannot delay that long ", usec, " microseconds");
unsigned long long start = Lx_kit::env().timer.curr_time().trunc_to_plain_us().value;
while (Lx_kit::env().timer.curr_time().trunc_to_plain_us().value < (start + usec)) { ; }
}

View File

@ -0,0 +1,285 @@
/*
* \brief Wireless LAN driver uplink back end
* \author Norman Feske
* \author Josef Soentgen
* \date 2021-06-02
*/
/*
* Copyright (C) 2021-2022 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#include <linux/kthread.h>
#include <linux/netdevice.h>
#include <lx_user/init.h>
#include <genode_c_api/uplink.h>
static struct genode_uplink *dev_genode_uplink(struct net_device *dev)
{
return (struct genode_uplink *)dev->ifalias;
}
struct genode_uplink_rx_context
{
struct net_device *dev;
};
struct genode_uplink_tx_packet_context
{
struct sk_buff *skb;
};
static unsigned long uplink_tx_packet_content(struct genode_uplink_tx_packet_context *ctx,
char *dst, unsigned long dst_len)
{
struct sk_buff * const skb = ctx->skb;
unsigned long total = 0;
unsigned long result = 0;
unsigned long linear = 0;
/*
* We always get the ethernet header from the headroom. In case
* the payload is stored in frags we have to copy them as well.
*/
/* get ethernet header from head before calling skb_headlen */
skb_push(skb, ETH_HLEN);
total = skb->len;
if (dst_len < total) {
printk("uplink_tx_packet_content: packet exceeds uplink packet size\n");
memset(dst, 0, dst_len);
return 0;
}
linear = min_t(int, skb_headlen(skb), total);
skb_copy_from_linear_data(skb, dst, linear);
total -= linear;
result += linear;
if (total && skb_shinfo(skb)->nr_frags) {
unsigned int i;
for (i = skb_shinfo(skb)->nr_frags - 1; (int)i >= 0; i--) {
unsigned int size = skb_frag_size(&skb_shinfo(skb)->frags[i]);
void const * frag = skb_frag_address_safe(&skb_shinfo(skb)->frags[i]);
memcpy(dst + result, frag, size);
result += size;
}
}
return result;
}
static rx_handler_result_t handle_rx(struct sk_buff **pskb)
{
struct sk_buff *skb = *pskb;
struct net_device *dev = skb->dev;
struct genode_uplink_tx_packet_context ctx = { .skb = skb };
/*
* Pass on EAPOL related frames to send them to the
* wpa_supplicant.
*/
if (ntohs(skb->protocol) == ETH_P_PAE)
return RX_HANDLER_PASS;
{
bool uplink_available = !!dev_genode_uplink(dev);
bool progress = uplink_available &&
genode_uplink_tx_packet(dev_genode_uplink(dev),
uplink_tx_packet_content,
&ctx);
if (!progress && uplink_available)
printk("handle_rx: uplink saturated, dropping packet\n");
if (progress)
genode_uplink_notify_peers();
}
kfree_skb(skb);
return RX_HANDLER_CONSUMED;
}
/**
* Create Genode uplink for given net device
*
* The uplink is registered at the dev->ifalias pointer.
*/
static void handle_create_uplink(struct net_device *dev)
{
struct genode_uplink_args args;
if (dev_genode_uplink(dev))
return;
if (!netif_carrier_ok(dev))
return;
printk("create uplink for net device %s\n", &dev->name[0]);
memset(&args, 0, sizeof(args));
if (dev->addr_len != sizeof(args.mac_address)) {
printk("error: net device has unexpected addr_len %u\n", dev->addr_len);
return;
}
{
unsigned i;
for (i = 0; i < dev->addr_len; i++)
args.mac_address[i] = dev->dev_addr[i];
}
args.label = &dev->name[0];
dev->ifalias = (struct dev_ifalias *)genode_uplink_create(&args);
}
static void handle_destroy_uplink(struct net_device *dev)
{
struct genode_uplink *uplink = dev_genode_uplink(dev);
if (!uplink)
return;
if (netif_carrier_ok(dev))
return;
genode_uplink_destroy(uplink);
dev->ifalias = NULL;
}
static genode_uplink_rx_result_t uplink_rx_one_packet(struct genode_uplink_rx_context *ctx,
char const *ptr, unsigned long len)
{
struct sk_buff *skb = alloc_skb(len + 128, GFP_KERNEL);
skb_reserve(skb, 128);
if (!skb) {
printk("alloc_skb failed\n");
return GENODE_UPLINK_RX_RETRY;
}
skb_copy_to_linear_data(skb, ptr, len);
skb_put(skb, len);
skb->dev = ctx->dev;
if (dev_queue_xmit(skb) < 0) {
printk("lx_user: failed to xmit packet\n");
return GENODE_UPLINK_RX_REJECTED;
}
return GENODE_UPLINK_RX_ACCEPTED;
}
struct task_struct *uplink_task_struct_ptr; /* used by 'Main' for lx_emul_task_unblock */
#include <linux/notifier.h>
struct netdev_event_notification
{
struct notifier_block nb;
struct netdev_net_notifier nn;
bool registered;
};
static int uplink_netdev_event(struct notifier_block *this,
unsigned long event, void *ptr)
{
/*
* For now we ignore what kind of event occurred and simply
* unblock the uplink task.
*/
if (uplink_task_struct_ptr)
lx_emul_task_unblock(uplink_task_struct_ptr);
return NOTIFY_DONE;
}
static int user_task_function(void *arg)
{
struct netdev_event_notification events;
memset(&events, 0, sizeof (struct netdev_event_notification));
events.nb.notifier_call = uplink_netdev_event;
events.registered = false;
for (;;) {
struct net_device *dev;
for_each_netdev(&init_net, dev) {
/* there might be more devices, e.g. 'lo', in the netnamespace */
if (strcmp(&dev->name[0], "wlan0") != 0)
continue;
/* enable link sensing, repeated calls are handled by testing IFF_UP */
dev_open(dev, 0);
/* install rx handler once */
if (!netdev_is_rx_handler_busy(dev))
netdev_rx_handler_register(dev, handle_rx, NULL);
/* register notifier once */
if (!events.registered) {
events.registered =
!register_netdevice_notifier_dev_net(dev,
&events.nb,
&events.nn);
}
/* respond to cable plug/unplug */
handle_create_uplink(dev);
handle_destroy_uplink(dev);
/* transmit packets received from the uplink session */
if (netif_carrier_ok(dev)) {
struct genode_uplink_rx_context ctx = { .dev = dev };
while (genode_uplink_rx(dev_genode_uplink(dev),
uplink_rx_one_packet,
&ctx));
}
};
/* block until lx_emul_task_unblock */
lx_emul_task_schedule(true);
}
return 0;
}
void uplink_init(void)
{
pid_t pid;
skb_init();
pid = kernel_thread(user_task_function, NULL, CLONE_FS | CLONE_FILES);
uplink_task_struct_ptr = find_task_by_pid_ns(pid, NULL);
}

View File

@ -0,0 +1,104 @@
/*
* \brief Wireless network driver Linux port
* \author Josef Soentgen
* \date 2022-02-10
*/
/*
* Copyright (C) 2022 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
/* Genode includes */
#include <base/attached_rom_dataspace.h>
#include <base/component.h>
#include <base/env.h>
#include <genode_c_api/uplink.h>
/* DDE Linux includes */
#include <lx_emul/init.h>
#include <lx_emul/page_virt.h>
#include <lx_emul/task.h>
#include <lx_kit/env.h>
#include <lx_kit/init.h>
#include <lx_user/io.h>
extern "C" void lx_user_handle_io(void) { }
using namespace Genode;
bool wifi_get_rfkill(void)
{
return false;
}
void wifi_set_rfkill(bool blocked)
{
(void)blocked;
}
extern "C" unsigned int wifi_ifindex(void)
{
/* TODO replace with actual qyery */
return 2;
}
extern "C" char const *wifi_ifname(void)
{
/* TODO replace with actual qyery */
return "wlan0";
}
extern "C" struct task_struct *uplink_task_struct_ptr;
struct Wlan
{
Env &_env;
Io_signal_handler<Wlan> _signal_handler { _env.ep(), *this,
&Wlan::_handle_signal };
void _handle_signal()
{
if (uplink_task_struct_ptr) {
lx_emul_task_unblock(uplink_task_struct_ptr);
Lx_kit::env().scheduler.schedule();
}
genode_uplink_notify_peers();
}
Wlan(Env &env) : _env { env }
{
genode_uplink_init(genode_env_ptr(_env),
genode_allocator_ptr(Lx_kit::env().heap),
genode_signal_handler_ptr(_signal_handler));
lx_emul_start_kernel(nullptr);
}
};
Genode::Blockade *wpa_blockade;
void wifi_init(Genode::Env &env,
Genode::Blockade &blockade,
bool disable_11n,
Genode::Signal_context_capability rfkill)
{
(void)disable_11n;
(void)rfkill;
wpa_blockade = &blockade;
static Wlan wlan(env);
}