WiFi

== General information ==
To get wireless LAN working, most WiFi chips need a proprietary firmware blob. While it would be more secure to replace that with open source software in the long term, it isn't feasible right now, so we try to get it working with that closed source firmware.
A great place to start looking for information about many available WiFi chips is this kernel.org page. It often provides driver sources and the required firmware blobs as well. For a start if you want Internet working try the USB Internet guide.
Useful links:
* How to find WiFi firmware files
* How to package WiFi firmware
== Qualcomm WiFi ==
Devices with Qualcomm WiFi chips are usually very easy to get working. 
You need to find the firmware files for your device, the main file is called wcnss.mdt and there should also be more files which are called wcnss.b00, wcnss.b01, etc. Copy them all onto your device into /lib/firmware/postmarketos.
There may also be files starting with WCNSS, e.g. WCNSS_cfg.dat WCNSS_qcom_cfg.ini WCNSS_qcom_wlan_nv.bin - those should go into some path like /lib/firmware/postmarketos/wlan/prima or /lib/firmware/postmarketos/wlan/qca_cld depending on the device. You can use existing firmware packages as examples for which files go where, e.g. aports/firmware/firmware-xiaomi-armani.
Take Samsung phones for example. WCNSS_qcom_wlan_nv.bin can be located as /etc/firmware/wlan/prima/WCNSS_qcom_wlan_nv.bin in Android system partition.
Then you can run as root (sudo -i first) echo 1 > /dev/wcnss_wlan and echo sta > /sys/module/wlan/parameters/fwpath. Check the output of ip link and a wlan0 interface should have appeared! Now you can use NetworkManager to connect to a WiFi network!
If that didn't work, please check the debugging section how to find out what went wrong.
For packaging, see that page and add the wcnss-wlan package (which runs the two commands above at boot automatically) as a dependency to the WiFi subpackage.
Test your packaging by flashing a new rootfs which includes your changes and see if WiFi works without any manual configuration.
== Broadcom WiFi ==
Devices with Broadcom WiFi chips usually have the path to the firmware hardcoded in the kernel, mostly to /system/vendor/firmware. 
In most cases you should be able to set CONFIG_BCMDHD_FW_PATH and CONFIG_BCMDHD_NVRAM_PATH in the kernel config. In other cases, you need to patch the kernel and change the path to /lib/firmware/postmarketos (see this patch).
You can use the command git grep "lib/firmware/postmarketos" device/linux-* in pmaports to find how it's done for other devices.
An example of how Broadcom was made to work can be found at Samsung_Galaxy_S_Advance_(samsung-i9070)#How_drebrez_made_wifi_work and .
 Another example is Medion_Lifetab_S9714_(medion-kai)#How_bonsaiblue_made_wifi_work.
Here's a quick rundown of the steps required to get Broadcom WiFi up and running:
* Locate the nvram and firmware files. You might be able to use the ones from firmware-aosp-broadcom-wlan, but if they don't work you can package your own.
* Modify your kernel config to point to the new firmware paths.
* Modify your kernel APKBUILD to build modules, so that you can use bcmdhd.
* Add a modules-load.conf file to your device package and put the bcmdhd module name (usually dhd) in it, then modify the APKBUILD to install the file. (This will auto-load the dhd module on startup.)
See the Galaxy S Advance device package, Galaxy S Advance linux package and Galaxy S Advance firmware package for reference.
== Mediatek WiFi ==
=== Introduction, software ===
Devices with Mediatek WiFi chips are much more complicated to get working. The best way to know how your specific SoC works is to look at the init.rc scripts from an Android ROM available for your phone and look for the chip initialization (search for "/dev/stp", "mtk_stp" and "wmt").
Usually, you may notice wmt_loader and 6620_loader programs doing some work to initialize the wireless communication hardware. The tool called 6620_launcher which (probably) loads the firmware from the filesystem into the kernel. Depending on device, 6620_launcher can use different protocols for communicating with chip. This tool is a binary included in the Android installation and linked against the bionic libc, and could not be run on postmarketOS because it uses linking against musl. There are several solutions to this problem:
* Proprietary source code version of the original tool is available on GitHub, and it can be compiled.
* openmttools written by Dahrkael. At the time of writing this edit, openmttools does not support UART protocol.
The MediaDeb project has made systemd unit files running more or less the commands above on two of their supported devices:
* wifi_loader.service: runs mt6620_loader.sh (which does mknod) & runs wifi_loader bin
* mt6620_launcher.service: runs 6620_launcher (/usr/sbin/6620_launcher -b 4000000 -p /lib/firmware/ -d /dev/ttyMT2)
* wifi.service: runs echo 1 > /dev/wmtWifi
=== MT6589 ===
On the Fairphone 1, the order for initialization should be the following (based on the init.rc files from Android):
# Install the files mt6628_ant_m1.cfg mt6628_patch_e1_hdr.bin mt6628_patch_e2_0_hdr.bin mt6628_patch_e2_1_hdr.bin WIFI_RAM_CODE_MT6628 WMT.cfg into /system/etc/firmware/ (path could be patched in the kernel sources)
insmod mtk_hif_sdio.ko
insmod mtk_stp_wmt.ko
insmod mtk_stp_uart.ko
insmod mtk_stp_gps.ko
insmod mtk_stp_bt.ko
insmod mtk_wmt_wifi.ko
mknod /dev/stpwmt c 190 0
mknod /dev/stpgps c 191 0
mknod /dev/stpbt c 192 0
mknod /dev/wmtWifi c 153 0
insmod wlan_mt6628.ko
6620_launcher -p /system/etc/firmware/
echo 1 > /dev/wmtWifi
=== MT6577 (MT8317) with MT6628 combochip ===
This section describes how arzamas-16 made Wi-Fi work on Acer Iconia B1-A71 (not yet in pmaports) which has mt8317 (tablet revision of mt6577) SoC and mt6628 combochip on downstream kernel (v3.4.113). The combochip on my device uses UART to communicate with operating system. Please keep in mind this section is meant to describe a set of «hacks» I went thru rather than being a complete guide. Also YMMV but at the time of writing scanning for networks, and connecting†, and accessing the internet work.
Following my steps will not make wifi work on mt67xx as these SoCs are more modern than the ancient stuff I have, and they use more tools which may be incompatible with those I describe below. I recommend checking out Dahrkael's and MediaDeb projects (see above).
† there are 2 methods you can get working Wi-Fi right now: using the downstream executables and their dependencies or using the modern software offered by postmarketOS.
Method 	Pros 	Cons
Using downstream executables	Less time demanding. 	Could only be configured through console. Incompatible with networkmanager. Effectively crashes wpa_supplicant and networkmanager services. Requires running many outdated proprietary executables. Needs a lot of space to store these binaries. Less flexible configuring.
Modern approach 	Compatible with postmarketOS services. Configurable via GUI (tested in XFCE4). Uses more fresh open source software. Less dependent on precompiled binaries.	Takes a lot of time in case when your device is specific or very old.
==== Sorting out possible issues with downstream kernels ====
1. Ensure that kernel modules are compiled and packaged into your pmOS installation! In my linux-.../APKBUILD I package them the following way:
package() {
	downstreamkernel_package "$builddir" "$pkgdir" "$_carch" "$_flavor" "$_outdir"
	# Modules
	unset LDFLAGS
	make O="$_outdir" ARCH="$_carch" CC="${CC:-gcc}" \
		KBUILD_BUILD_VERSION="$((pkgrel + 1))-postmarketOS" \
		INSTALL_MOD_PATH="$pkgdir" \
		modules_install
}
In my case, they have been installed to /lib/modules/3.4.113/kernel/mediatek/kernel/drivers/combo
2. For some downstream mediatek kernels gcc6 complains about gl_kal.h, if you will get such errors apply this simple kernel patch!
3. In order to be able to connect to password-protected networks, be sure to have this kernel patch applied!
4. All downstream kernels I've worked with have many hardcoded paths specific to Android. As stated at the top of this page, postmarketOS packages firmware blobs so they will definitely be in the other path. You can either:
* Manually replace hardcoded paths once in the source code
* Make firmware paths customizable with kernel config options so you could change many paths with a single kconfig change. See my commits which do it with wifi and nvram paths. In my kernel config for postmarketOS I've set:
CONFIG_MTK_WMT_FW_PATH="/lib/firmware/postmarketos/"
CONFIG_MTK_NVRAM_PATH="/lib/firmware/postmarketos/"
==== Dumping firmware from Android ====
This step should be done prior to flashing postmarketOS. If you plan to bring up wifi using downstream executables then also check the steps in corresponding section prior to flashing postmarketOS.
Dump the following:
* Contents of /system/etc/firmware/ (there should be ~10 files)
* /data/nvram directory
After flashing postmarketOS, copy the dumped files to /lib/firmware/postmarketos so the structure will look like
giordano:~$ ll /lib/firmware/postmarketos/
total 3.9M
drwxr-xr-x 3 root 4.0K Aug 24 21:57 .
drwxr-xr-x 3 root 4.0K Jan 1 2012 ..
drwxr-xr-x 5 root 4.0K Aug 24 21:57 nvram/
-rw-r--r-- 1 root 682K Aug 24 21:53 DSP_ROM
(some stuff)
-rw-r--r-- 1 root 28K Aug 24 21:53 mt6628_patch_e1_hdr.bin
-rw-r--r-- 1 root 25K Aug 24 21:53 mt6628_patch_e2_hdr.bin
==== Loading modules ====
First of all, it's important to understand how Wi-Fi initialization happens on your device when running Android. For this, you will need to acquire .rc scripts from the ramdisk. Look for init.rc and whatever it invokes. In my case I had 2 files: init.rc and init.project.rc. Here is the part related to wifi from init.rc (omitting unnecessary stuff like numerous chmod's and chown's):
#
# MT6620 related device nodes & configuration (begin)
#
# STP, WMT, GPS, FM and BT Driver
 insmod /system/lib/modules/mtk_hif_sdio.ko
 insmod /system/lib/modules/mtk_stp_wmt.ko
 insmod /system/lib/modules/mtk_stp_uart.ko
 insmod /system/lib/modules/mtk_stp_gps.ko
 insmod /system/lib/modules/mtk_stp_bt.ko
 insmod /system/lib/modules/mtk_wmt_wifi.ko
# Create char device file for WMT, GPS, BT, FM, WIFI
 mknod /dev/stpwmt c 190 0;
 mknod /dev/stpgps c 191 0;
 mknod /dev/stpbt c 192 0;
 mknod /dev/wmtWifi c 153 0
# Load WiFi Driver
 insmod /system/lib/modules/wlan.ko (COMMENT: this is a symlink to wlan_mt6628.ko)
#
# MT6620 related device nodes & configuration (end)
#
The next step is to load said modules and I wrote a simple script for doing this on my device: Github Gist, invokation: sudo ./01-load-wifi-modules.sh. At this point we've replicated the work done in init.rc on Android regarding wifi.
==== Programs overview ====
Here is the part related to wifi from init.project.rc (omitting unnecessary parts like detailed service parameters):
service 6620_launcher /system/bin/6620_launcher -m 1 -b 4000000 -p /system/etc/firmware/ -d /dev/ttyMT2 (config omitted...)
service stp_dump /system/bin/stp_dump3 (config omitted...)
service hald /system/bin/hald (config omitted...) 
service p2p_supplicant (config omitted...)
service wpa_supplicant /system/bin/logwrapper /system/bin/wpa_supplicant \
	-iwlan0 -Dnl80211 -c/data/misc/wifi/wpa_supplicant.conf -e/data/misc/wifi/entropy.bin -ddd
	(config omitted...)
service ap_daemon (config omitted...)
Now it's necessary to sort out which programs (services) are required to start wifi. Below is a very short description of programs mentioned in my init.project.rc file.
* 6620_launcherrequired establishes a connection with a combochip, does some simple initialization and uploads a firmware blob.
* stp_dump3 is used for debugging. Comments in the code say this program can break/disrupt wpa_supplicant.
* haldrequired. On Android it loads and unloads kernel modules and manages combochip power. In fact, on postmarketOS this whole program could be replaced with one (worst case: two) shell command (more on that below).
* p2p_supplicant manages features such as Wi-Fi Direct. I don't need it in my case.
* wpa_supplicantrequired manages wifi connection. A vital part of wireless networking.
* ap_daemon allows to create a wireless access point. I don't need it in my case.
As we can see, only 6620_launcher, and hald, and wpa_supplicant are required to start wifi.
==== (1) Bringing up wifi using downstream executables ====
In this part I will lack some details but you'll be able to easily figure out what to do.
1. From the running Android, dump:
* /system/bin/linker, do not forget it as this thing is very important
* /system/bin/6620_launcher
* /system/bin/wpa_supplicant
* The whole /system/lib directory
Recreate same structure in your postmarketOS installation: put dumped /system/... stuff in the root.
2. Stop and disable wpa_supplicant and networkmanager, I've made a stupid script for this:
#!/bin/sh
for s in "networkmanager" "wpa_supplicant"; do
	sudo rc-update del "$s" default
	sudo rc-service "$s" stop
	rc-service "$s" status
done
3. After you've loaded the kernel modules, start the 6620_loader using parameters from the .rc scripts from your device but change the path to firmware. As Vernee Thor wiki page states, this program needs to keep running, so better send it to background with &. Example:
/system/bin/6620_launcher -m 1 -b 4000000 -p /lib/firmware/postmarketos/ -d /dev/ttyMT2 &
Hit enter second time to return to console.
4. Power on the combochip:
echo -n '1' > /dev/wmtWifi
This takes few seconds to run and you will see some logs from 6620_launcher indicating uploading firmware into the combochip which has been turned on.
5. Launch wpa_supplicant parameters from the .rc scripts from your device. It's safe to omit entropy file and don't forget to supply the conf file. Depending on the wpa_supplicant implementation, you may or may not see the log output. You can also run this program in background using the &. Example:
/system/bin/wpa_supplicant -iwlan0 -Dnl80211 -c/home/user/my_wifi_network.conf -ddd
6. The last thing is to acquire an IP address from your access point! Use whatever program you want, I used dhcpcd
==== (2) Bringing up wifi using modern approach ====
1. The first and the hardest step is to find compatible 6620_launcher and build it.
The problem is Mediatek doesn't provide the source code of this tool as part of the kernel source code. Chances are extremely low but if your device vendor supplies 6620_launcher source code, you saved yourself tons of time. In my case I went straight to Github and began searching for the source code, usually there are various versions accidentally shared either by mediatek or device vendors.
Another huge problem is how Mediatek does versioning of 6620_launcher - all executables I've seen have "1.0-release" version code but their functionality varies to the greatest extent. For example, the MediaDeb Project's source code did not work on my device at all because it invokes IOCTL calls which are not supported by the old WMT driver at all. You will need to either rely on luck or carefully read through the source code.
You can use my Github search query but you'll need to sign into your account. At the time of writing, there are 66 repositories with 6620_launcher.
I also had to load my 6620_launcher from Android into Ghidra SRE on my PC to compare algorithms with sources on GH and to dump strings - some of them are unique to specific versions and it makes searching easier, for example my version doesn't have this string: "SOC chip no need do combo chip power on.\n". 
After all of this, I've found working stp_uart_launcher in wedoinnov/HD5_lichee repo, omitting the firmware blobs. Most likely this tool will work on other old mt6575/mt6577/mt8317/mt8377 devices with mt6620/mt6628 combochips that work over UART.
2. After you've loaded the kernel modules, start the freshly compiled 6620_launcher using parameters from the .rc scripts from your device but change the path to firmware. As Vernee Thor wiki page states, this program needs to keep running, so better send it to background with &. Example:
/home/user/wifi/HD5_lichee/6620_launcher -m 1 -b 4000000 -p /lib/firmware/postmarketos/ -d /dev/ttyMT2 &
Hit enter second time to return to console.
3. Power on the combochip:
echo -n '1' > /dev/wmtWifi
This takes few seconds to run and you will see some logs from 6620_launcher indicating uploading firmware into the combochip which has been turned on.
4. Wait for a few seconds for the network interface to initialize and now you will be able to connect to wifi using network manager of your desktop environment. Enjoy the internet!
== HiSilicon WiFi ==
=== Introduction, software ===
Devices with HiSilicon WiFi chips are comparatively easy to get working. If following instructions don't work for your device, you'll need to look at the *.rc scripts from an Android ROM available for your phone, as well as any other relevant for wifi scripts that they point to (search for hisi, hi110x, hi1101, hi1102, connectivity). In them you'll find `echo` (or `write` that can be translated to `echo`) commands that need to be run to initialize the wireless communication hardware.
The path to the firmware is usually hardcoded in the kernel and firmware files themselves to /vendor/firmware or /system/vendor/firmware, so if you want to change the path to /lib/firmware/postmarketos you'll need to patch the kernel and edit the *_cfg firmware files (see this patch).
An example of how HiSilicon was made to work can be found at https://wiki.postmarketos.org/wiki/User:Ignapk#How_ignapk_made_wifi_work and 
For packaging, see that page and add the hisi-wlan package as a dependency to the WiFi subpackage.
=== Hi1101 ===
On the Huawei P8 Lite, the order of the initialization should be the following (based on the *.rc files from Android 1 2):
# Install the firmware blobs into /system/vendor/firmware
echo 1 > /sys/devices/hi110x_ps/bfg_lowpower_enable
echo 12 > /sys/devices/hi110x_power/powerpin_state
echo 1 > /proc/wifi_enable/wifi_start
echo 1 > /proc/oam_enable/oam_start
=== Hi1102 ===
On the Huawei P10 Lite, the order of the initialization should be the following (based on the *.rc files from Android):
# Install the files bfgx_and_wifi_cfg, wifi_cfg, bfgx_cfg, cr4_asic.bin, CPU_RAM_SCHED.bin, CPU_RAM_WBS.bin into /vendor/firmware/ (path could be
# patched in the kernel sources) and make sure the wifi and platform drivers are set as builtin, not modules (Y instead of M in kernel config)
echo 1 > /sys/hisys/boot/plat
echo 1 > /sys/hisys/boot/wifi
# The above commands can be run automatically on boot by installing hisi-wlan package
== Debugging ==
First check, if the network interface is available by running ip link (wlan0 on most phones).
If the network interface is not listed and you've followed the section for your WiFi chip above, it's most likely an error of missing or misplaced firmware files:
* dmesg
* tail /var/log/firmwareload.log
If no issue pops up in the log files, it could also be that you are missing a configuration option in kernel config.
For example: in the Sony Xperia Z downstream kernel we needed to enable these config options to get WiFi working:
 #
 # Qualcomm Atheros Prima WLAN module
 #
-# CONFIG_PRIMA_WLAN is not set
+CONFIG_PRIMA_WLAN=y
+# CONFIG_PRIMA_WLAN_BTAMP is not set
+CONFIG_PRIMA_WLAN_LFR=y
+CONFIG_PRIMA_WLAN_OKC=y
+# CONFIG_PRIMA_WLAN_11AC_HIGH_TP is not set
+# CONFIG_QCOM_VOWIFI_11R is not set
+CONFIG_QCOM_TDLS=y
In case you need any more help, just ask in our Matrix/IRC channel!
== Connecting to APs ==
=== Using NetworkManager ===
You can use NetworkManager from the command line either with nmtui (a terminal user interface) or nmcli.
To use nmtui, just run sudo nmtui in your terminal.
To use nmcli, you can use the following commands, modified for your use case:
$ sudo nmcli device wifi list ifname wlan0
$ sudo nmcli device wifi connect "$SSID" password "$PASSWORD" ifname "wlan0"
See also: https://wiki.postmarketos.org/wiki/NetworkManager/DHCP
=== Using wpa_supplicant ===
postmarketOS currently configures the wpa_supplicant service to start on boot. This service will fail to start unless /etc/wpa_supplicant/wpa_supplicant.conf has been defined. This can be configured using the wpa_passphrase utility:
$ wpa_passphrase YOUR_SSID YOUR_PASSPHRASE | sudo tee /etc/wpa_supplicant/wpa_supplicant.conf
Note: If you are connecting to a hidden wireless network, make sure to add line "scan_ssid=1" after the ssid line in your generated conf file
Scanning for networks is possible with these commands
ifconfig wlan0 up
iw dev wlan0 scan
Next you'll need to set up the networking service by adding interfaces to /etc/network/interfaces. In some cases, the loopback device may need to precede the wlan interface:
auto lo 
iface lo inet loopback 
auto wlan0 
iface wlan0 inet dhcp
Finally, set the networking service to start on boot:
$ sudo rc-update add networking default
Note that on some systems, you may have to configure wpa_supplicant to use the Linux kernel wireless extensions by editing /etc/conf.d/wpa_supplicant:
wpa_supplicant_args="-Dwext"
You will have to reboot, or manually restart the aforementioned services, before your device will connect to the access point.
=== Using wpa_supplicant (manually) ===
If you experience problems or just want to test wifi you can start wpa supplicant (using -Dwext or nl80211 driver) and the dhcp service:
sudo wpa_supplicant -u -Dnl80211 -B -c /etc/wpa_supplicant/wpa_supplicant.conf -iwlan0
sudo udhcpc -i wlan0
== Troubleshooting ==
=== WiFi doesn't auto connect ===
If the WiFi does not auto connect after booting, there's likely a configuration issue in the network manager connection settings.
This can be fixed by editing /etc/NetworkManager/system-connections/<CONNECTION>.nmconnection and changing permissions=user:user:; to permissions=.
Alternatively, set 'Available to all users' in nmtui (nmtui might not work properly on your phone's screen, though).
see 
=== Wifi Hotspot not connectable with Android ===
If you can not connect to a hotspot made with pmos, delete it and create one from commandline:
nmcli dev wifi hotspot ifname wlan0 ssid hotspotname password "password"
Then you also need to disable pmf:
sudo nmcli c modify Hotspot-1 802-11-wireless-security.pmf 1
sudo nmcli c modify Hotspot wifi-sec.pmf disable
== See also ==
* samsung-i9070: How drebrez made wifi work
Category:Guide