# Linux is Friendly - Recovering from Missing Firmware

Occasionally, we folks using Linux find our selves in situations where things break; our computers do not function as intended. In my scenario, I was out on business in another country, and my WiFi device was simply not showing up after a reboot.

I know a lot of people (I was one of them), who at first impulse would want to re-install their operating system to fix something of this sort. Fixing something of this sort is a lot easier than one might think. The purpose of this blog is to illustrate how user friendly, easy and instructive Linux is.

# Error messages are your friend

You typed that command, run that python or bash script, started compiling that code - and……ERROR - we’ve all faced this. The terminal spewing out line after line of debugging messages almost like the devil himself cursing humanity in unholy tongues. Our first impulse is fight or flight - yes, when I started using \*nix systems - specifically programming them, there were times when error messages made me freeze up and do irrational things. For eg.

1. Missing Library - no sweat - nuke the OS, start over.
    
2. Type mismatch - no sweat, toss the machine in the furnace, get a new one
    
3. Kernel panic - no sweat, turn up the cooking gas, blow up the house, leave family……..start life over
    

Life changed for me when I started to actually *read the error messages*. Lo and behold - they were not unholy tongues spoken by a mysterious evil overlord inside my computer - they were actually super user friendly messages, written by programmers - telling you exactly what to do.

# Back to the story

Now that I’m a lot older, I stayed calm. Here is how I got out of my situation.

WiFi Adapter not working - foreign country. First step…diagnose things. Below we can see that there is no wireless adapter at all.

```bash
┌─[apocalypse0@darkmatter]─[~]
└──╼ $ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host noprefixroute 
       valid_lft forever preferred_lft forever
2: ovs-system: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether b2:2c:24:2d:3b:ee brd ff:ff:ff:ff:ff:ff
3: mzbr: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether d2:b5:68:27:9e:4b brd ff:ff:ff:ff:ff:ff
4: dmzbr: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 5a:06:a5:7a:2d:48 brd ff:ff:ff:ff:ff:ff
5: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    link/ether 02:42:f5:2b:b1:4d brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
6: br-b4dcd604c9ec: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    link/ether 02:42:f0:37:01:95 brd ff:ff:ff:ff:ff:ff
    inet 172.19.0.1/16 brd 172.19.255.255 scope global br-b4dcd604c9ec
       valid_lft forever preferred_lft forever
    inet6 fe80::42:f0ff:fe37:195/64 scope link 
       valid_lft forever preferred_lft forever
```

```bash
┌─[root@darkmatter]─[~]
└──╼ #lspci -vnn -k | grep -A 10 -i network
00:14.3 Network controller [0280]: Intel Corporation Comet Lake PCH CNVi WiFi [8086:06f0]
	Subsystem: Intel Corporation Comet Lake PCH CNVi WiFi [8086:0070]
	Flags: fast devsel, IRQ 16, IOMMU group 6
	Memory at 604111c000 (64-bit, non-prefetchable) [size=16K]
	Capabilities: [c8] Power Management version 3
	Capabilities: [d0] MSI: Enable- Count=1/1 Maskable- 64bit+
	Capabilities: [40] Express Root Complex Integrated Endpoint, MSI 00
	Capabilities: [80] MSI-X: Enable- Count=16 Masked-
	Capabilities: [100] Latency Tolerance Reporting
	Capabilities: [164] Vendor Specific Information: ID=0010 Rev=0 Len=014 <?>
	Kernel modules: iwlwifi, wl
```

Great - we now know our chipset, the drivers and modules responsible. Let’s now take a look at `dmesg` for any potential issues

```bash
┌─[root@darkmatter]─[~]
└──╼ #dmesg | grep -i iwlwifi
[   11.235547] iwlwifi 0000:00:14.3: enabling device (0000 -> 0002)
[   11.248125] iwlwifi 0000:00:14.3: Detected crf-id 0x3617, cnv-id 0x20000302 wfpm id 0x80000000
[   11.248161] iwlwifi 0000:00:14.3: PCI dev 06f0/0070, rev=0x351, rfid=0x10a100
[   11.248175] iwlwifi 0000:00:14.3: Detected Intel(R) Wi-Fi 6 AX201 160MHz
[   11.248978] iwlwifi 0000:00:14.3: firmware: failed to load iwlwifi-QuZ-a0-hr-b0-77.ucode (-2)
[   11.249028] iwlwifi 0000:00:14.3: firmware: failed to load iwlwifi-QuZ-a0-hr-b0-77.ucode (-2)
[   11.249036] iwlwifi 0000:00:14.3: Direct firmware load for iwlwifi-QuZ-a0-hr-b0-77.ucode failed with error -2
[   11.249049] iwlwifi 0000:00:14.3: no suitable firmware found!
[   11.249060] iwlwifi 0000:00:14.3: iwlwifi-QuZ-a0-hr-b0-77 is required
[   11.249070] iwlwifi 0000:00:14.3: check git://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git
[   11.572733] Modules linked in: wl(POE+) intel_pmc_core_pltdrv(-) snd_sof snd_sof_utils snd_soc_hdac_hda x86_pkg_temp_thermal intel_powerclamp snd_soc_acpi_intel_match snd_soc_acpi soundwire_bus coretemp kvm_intel snd_soc_avs uvcvideo snd_soc_hda_codec snd_hda_ext_core snd_intel_dspcfg videobuf2_vmalloc btusb snd_intel_sdw_acpi uvc btrtl kvm videobuf2_memops snd_soc_core videobuf2_v4l2 mei_hdcp mei_wdt mei_pxp intel_rapl_msr btintel snd_ctl_led snd_compress rapl videodev btbcm processor_thermal_device_pci_legacy snd_pcm_dmaengine iwlwifi btmtk rmi_smbus(+) iTCO_wdt snd_hda_codec intel_cstate videobuf2_common processor_thermal_device bluetooth snd_hda_core processor_thermal_wt_hint intel_uncore intel_pmc_bxt think_lmi(+) mc pcspkr snd_hwdep processor_thermal_rfim intel_wmi_thunderbolt rmi_core firmware_attributes_class cfg80211 wmi_bmof snd_pcm thinkpad_acpi iTCO_vendor_support watchdog mei_me ee1004 processor_thermal_rapl intel_rapl_common snd_timer ucsi_acpi nvram processor_thermal_wt_req mei sparse_keymap
```

Great - we see that there is a missing file, and we know where we should download it - all of it is there

Let’s sort it out . I used my mobile with USB tethering to get access to the internet.

```bash
wget https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git/plain/iwlwifi-QuZ-a0-hr-b0-77.ucode -O /lib/firmware/iwlwifi-QuZ-a0-hr-b0-77.ucode
```

Now let’s load it up

```bash
modprobe -r iwlwifi
modprobe iwlwifi
```

That’s it - all works.

```bash
┌─[✗]─[root@darkmatter]─[/etc/modprobe.d]
└──╼ #ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: ovs-system: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether b2:2c:24:2d:3b:ee brd ff:ff:ff:ff:ff:ff
3: mzbr: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether d2:b5:68:27:9e:4b brd ff:ff:ff:ff:ff:ff
4: dmzbr: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 5a:06:a5:7a:2d:48 brd ff:ff:ff:ff:ff:ff
5: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default 
    link/ether 02:42:f5:2b:b1:4d brd ff:ff:ff:ff:ff:ff
6: br-b4dcd604c9ec: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default 
    link/ether 02:42:f0:37:01:95 brd ff:ff:ff:ff:ff:ff
9: enx3c18a0562589: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000
    link/ether 3c:18:a0:56:25:89 brd ff:ff:ff:ff:ff:ff
10: wlp0s20f3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DORMANT group default qlen 1000
    link/ether 20:1e:88:1b:41:21 brd ff:ff:ff:ff:ff:ff
```

The main thing is to keep calm and read the error messages.
