diff --git a/.gitignore b/.gitignore
index b05ae27..73fc79c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
.vscode/
-venv/
\ No newline at end of file
+venv/
+secrets/
diff --git a/arch/base.md b/arch/base.md
index 05a701d..79f51fd 100644
--- a/arch/base.md
+++ b/arch/base.md
@@ -55,6 +55,8 @@ I have instructions for building a:
- [CUPS Printing](#cups-printing)
- [Yubikey](#yubikey)
- [Bashrc](#bashrc)
+ - [Colorized Prompt](#colorized-prompt)
+ - [Standard Bashrc](#standard-bashrc)
## Installation
@@ -899,6 +901,12 @@ systemctl enable --now iscsid
# Log out of all sessions
iscsiadm -m node -u
+
+ # Log out of a single session
+ iscsiadm -m node -T iqn.2023-01.driveripper.reeselink.com:2024-01-framework --logout
+
+ # Remove session
+ iscsiadm -m node -o delete -T iqn.2023-01.driveripper.reeselink.com:2023-01-framework
```
## Software Stores
@@ -1001,6 +1009,20 @@ sudo systemctl enable --now pcscd
## Bashrc
+### Colorized Prompt
+
+
+
+You can change the prompt color by setting PROMPT_COLOR at the top of your .bashrc
+
+Examples:
+
+Yellow: `PROMPT_COLOR=33;`
+Orange: `PROMPT_COLOR=38;5;208;`
+Red: `PROMPT_COLOR=38;5;160;`
+
+### Standard Bashrc
+
Don't do this if you installed `zsh`
~/.bashrc
diff --git a/arch/gaming.md b/arch/gaming.md
index 8153ee3..60d159c 100644
--- a/arch/gaming.md
+++ b/arch/gaming.md
@@ -167,6 +167,11 @@ network streaming to any device that can run moonlight.
I used the Archlinux pkg. Follow the instructions (including the autostart instructions).
+```bash
+wget https://github.com/LizardByte/Sunshine/releases/latest/download/sunshine.pkg.tar.zst
+pacman -U --noconfirm sunshine.pkg.tar.zst
+```
+
### Install Moonlight
diff --git a/arch/workstation.md b/arch/workstation.md
index 9fa0750..1715ac8 100644
--- a/arch/workstation.md
+++ b/arch/workstation.md
@@ -2,10 +2,12 @@
- [Workstation](#workstation)
- [Framework AMD Notes](#framework-amd-notes)
- - [Wifi](#wifi)
+ - [ATH12K Wifi Drivers](#ath12k-wifi-drivers)
- [Microcode](#microcode)
+ - [linux-git kernel](#linux-git-kernel)
- [Base Tools](#base-tools)
- [ZSH](#zsh)
+ - [Prompt Themes](#prompt-themes)
- [Aliases](#aliases)
- [Rollback Pacman Update](#rollback-pacman-update)
- [Podman](#podman)
@@ -31,6 +33,7 @@
- [Initialization](#initialization)
- [Development](#development)
- [Cura](#cura)
+ - [Creality Print](#creality-print)
- [AWS CLI](#aws-cli)
- [NSlookup](#nslookup)
- [rpi-imager](#rpi-imager)
@@ -40,7 +43,7 @@
## Framework AMD Notes
-### Wifi
+### ATH12K Wifi Drivers
Install the wireless-regdb to set the regulatory domain to US
@@ -50,20 +53,21 @@ pacman -S wireless-regdb
Edit `/etc/conf.d/wireless-regdom` to set the domain
-Switch to iwd for the NetworkManager backend.
+
-```bash
-pacman -S iwd
-```
+1. `git clone https://git.codelinaro.org/clo/ath-firmware/ath12k-firmware`
+2. `cd ath12k-firmware`
+3. Run the following:
-Edit `/etc/NetworkManager/conf.d/wifi_backend.conf`
+ ```bash
+ wget https://github.com/qca/qca-swiss-army-knife/raw/master/tools/scripts/ath12k/ath12k-fw-repo
+ chmod 755 ath12k-fw-repo
+ sudo ./ath12k-fw-repo --install /lib/firmware
+ ```
-```conf
-[device]
-wifi.backend=iwd
-```
-
-Finally, reboot the machine for the changes to take effect.
+4. `sudo cp ath12k/board.bin /lib/firmware/ath12k/WCN7850/hw2.0/`
+5. `sudo cp ath12k/regdb.bin /lib/firmware/ath12k/WCN7850/hw2.0/`
+6. Reboot
### Microcode
@@ -81,10 +85,20 @@ initrd /initramfs-linux.img
options ...
```
+### linux-git kernel
+
+
+
+1. `git clone https://aur.archlinux.org/linux-git.git`
+2. `cd linux-git`
+3. `makepkg`
+4. `sudo pacman -U linux-git... linux-git-headers...`
+
## Base Tools
```bash
-pacman -S rsync which git iperf3 pwgen dosfstools exfatprogs
+# gvfs and gvfs-dnssd are for webdav support
+pacman -S rsync which git iperf3 pwgen dosfstools exfatprogs gvfs gvfs-dnssd
```
## ZSH
@@ -92,7 +106,43 @@ pacman -S rsync which git iperf3 pwgen dosfstools exfatprogs
```bash
pacman -S zsh grml-zsh-config
chsh -s $(which zsh)
-echo "autoload -U compinit; compinit" > ~/.zshrc
+
+cat < ~/.zshrc
+# Basic settings
+autoload bashcompinit && bashcompinit
+autoload -U compinit; compinit
+zstyle ':completion:*' menu select
+
+# Prompt settings
+autoload -Uz promptinit
+promptinit
+PROMPT_EOL_MARK=
+
+# Syntax Highlighting
+source /usr/share/zsh/plugins/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh
+source /usr/share/zsh/plugins/zsh-autosuggestions/zsh-autosuggestions.zsh
+
+# Command Not Found Autocomplete
+source /usr/share/doc/pkgfile/command-not-found.zsh
+
+### Custom Commands and Aliases ###
+EOF
+```
+
+### Prompt Themes
+
+See:
+
+Use `prompt -l` to list prompts
+
+Use `prompt -p` to see previews
+
+In your `.zshrc` set the following:
+
+```bash
+autoload -Uz promptinit
+promptinit
+prompt grml
```
### Aliases
@@ -444,6 +494,23 @@ Icon=/home/ducoterra/.icons/cura.png
Type=Application
```
+## Creality Print
+
+
+
+```bash
+mv ~/Downloads/Creality_Print*.AppImage ~/Applications/Creality_Print.AppImage
+chmod +x ~/Applications/*.AppImage
+```
+
+```conf
+[Desktop Entry]
+Name=Creality Print
+Exec=/home/ducoterra/Applications/Creality_Print.AppImage
+Icon=/home/ducoterra/.icons/creality_print.png
+Type=Application
+```
+
## AWS CLI
diff --git a/ath12k/ath12k-fw-repo b/ath12k/ath12k-fw-repo
new file mode 100755
index 0000000..edec54c
--- /dev/null
+++ b/ath12k/ath12k-fw-repo
@@ -0,0 +1,1032 @@
+#!/usr/bin/python3
+#
+# Copyright (c) 2016 Qualcomm Atheros, Inc.
+# Copyright (c) 2018,2020 The Linux Foundation. All rights reserved.
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+import os
+import logging
+import re
+import argparse
+import shutil
+import sys
+import filecmp
+import functools
+import subprocess
+import email
+
+# global variables
+logger = None
+
+BRANCH_DEFAULT_PRIORITY = 1000
+BRANCH_PRIORITY_FILE = '.priority'
+WHENCE_FILE = 'WHENCE'
+NOTICE_FILE = 'Notice.txt'
+NOTICE_FILE_LEN_MIN = 5000
+ATH12K_DIR = 'ath12k'
+TESTING_BRANCH = 'testing'
+
+FIRMWARE_BLACKLIST = [
+]
+
+BRANCH_BLACKLIST = [
+ 'msm',
+]
+
+
+@functools.total_ordering
+class Hardware():
+ def get_path(self):
+ return os.path.join(self.hw, self.hw_ver)
+
+ def __eq__(self, other):
+ return self.name == other.name
+
+ def __lt__(self, other):
+ return self.name < other.name
+
+ def __repr__(self):
+ return self.__str__()
+
+ def __str__(self):
+ return 'Hardware(\'%s\'): %s %s' % (self.name, self.board_files,
+ sorted(self.firmware_branches))
+
+ def __init__(self, hw, hw_ver):
+ # QCA6174
+ self.hw = hw
+
+ # hw3.0
+ self.hw_ver = hw_ver
+
+ self.name = '%s %s' % (hw, hw_ver)
+
+ self.firmware_branches = []
+ self.board_files = []
+
+
+@functools.total_ordering
+class FirmwareBranch():
+ # return the branch name without 'testing/' prefix
+ def get_clean_name(self):
+ if self.testing_branch:
+ return self.name[len(TESTING_BRANCH):]
+
+ return self.name
+
+ def __eq__(self, other):
+ return self.priority == other.priority and \
+ self.get_clean_name() == other.get_clean_name()
+
+ def __lt__(self, other):
+ # '.' is always of the lower priority
+ if self.name == '.':
+ return True
+
+ if other.name == '.':
+ return False
+
+ if self.priority != other.priority:
+ if self.priority < other.priority:
+ return True
+ else:
+ return False
+
+ return self.get_clean_name() < other.get_clean_name()
+
+ def __repr__(self):
+ return self.__str__()
+
+ def __str__(self):
+ return 'FirmwareBranch(\'%s\'): %s' % (self.name, sorted(self.firmwares))
+
+ def __init__(self, name, path=None):
+ self.name = name
+ self.firmwares = []
+
+ if name.startswith(TESTING_BRANCH):
+ self.testing_branch = True
+
+ # testing branches use lower priority by default so that
+ # they are ordered below normal branches
+ self.priority = 0
+ else:
+ self.testing_branch = False
+ self.priority = BRANCH_DEFAULT_PRIORITY
+
+ if path:
+ priority_path = os.path.join(path, BRANCH_PRIORITY_FILE)
+ if os.path.isfile(priority_path):
+ try:
+ f = open(priority_path, 'r')
+ buf = f.read()
+ f.close()
+
+ self.priority = int(buf)
+ except Exception as e:
+ logger.error('Failed to read %s: %s' % (priority_path, e))
+
+
+class BoardFile():
+
+ @staticmethod
+ def create_from_path(path):
+ filename = os.path.basename(path)
+
+ match = re.search(r'^board-(\d+).bin', filename)
+ if match is None:
+ match = re.search(r'^board.bin', filename)
+ if match is None:
+ return None
+
+ if len(match.groups()) > 1:
+ bd_api = match.group(1)
+ else:
+ bd_api = None
+
+ return BoardFile(path, bd_api)
+
+ def get_basename(self):
+ return os.path.basename(self.path)
+
+ def __repr__(self):
+ return self.__str__()
+
+ def __str__(self):
+ return '%s' % (self.get_basename())
+
+ def __init__(self, path, bd_api):
+ # full path to the board file, including directories and filename
+ self.path = path
+
+ # board api version, eg. '2' in board-2.bin
+ self.bd_api = bd_api
+
+
+class Firmware():
+
+ @staticmethod
+ def create_from_path(path):
+ if not os.path.isdir(path):
+ raise Exception('Firmware path %s is not a directory')
+
+ fw_ver = os.path.basename(path)
+
+ return Firmware(fw_ver, path)
+
+ def get_files_with_path(self):
+ result = []
+
+ for filename in self.filenames:
+ result.append(os.path.join(self.path, filename))
+ return result
+
+ def get_notice_path(self):
+ return os.path.join(self.path, self.notice_filename)
+
+ def __eq__(self, other):
+ return self.fw_ver == other.fw_ver
+
+ def __ne__(self, other):
+ return not self.__eq__(other)
+
+ # FIXME: firmware-5.bin_10.4-3.2-00080 and
+ # firmware-5.bin_10.4-3.2.1-00028 are sorted incorrectly
+ def __lt__(self, other):
+ s = self.fw_ver
+ o = other.fw_ver
+
+ # FIXME: An ugly hack that to make the comparison easier to
+ # implement. Just to get some sort of simple sorting working
+ # replace '-' with '.' in version string. But now for example
+ # '10.2.4.70.2 > 10.2.4.70-2' is not compared correctly.
+
+ s = s.replace('-', '.')
+ o = o.replace('-', '.')
+
+ s = s.split('.')
+ o = o.split('.')
+
+ s2 = s
+ o2 = o
+
+ s = []
+ o = []
+
+ for t in s2:
+ try:
+ k = int(t)
+ except:
+ k = t
+
+ s.append(k)
+
+ for t in o2:
+ try:
+ k = int(t)
+ except:
+ k = t
+
+ o.append(k)
+
+ l = min(len(s), len(o))
+
+ for i in range(l):
+
+ if s[i] < o[i]:
+ return True
+ elif s[i] > o[i]:
+ return False
+
+ if len(s) > len(o):
+ return False
+
+ return True
+
+ def __le__(self, other):
+ return self.__lt__(other) or self.__eq__(other)
+
+ def __gt__(self, other):
+ return not self.__le__(other)
+
+ def __ge__(self, other):
+ return self.__gt__(other) or self.__eq__(other)
+
+ def __repr__(self):
+ return self.__str__()
+
+ def __str__(self):
+ return '%s' % (self.fw_ver)
+
+ # path can be None with unittests
+ def __init__(self, fw_ver, path=None):
+ # path to the release directory, no filenames
+ self.path = path
+
+ # filenames of all firmware files, excluding notice file
+ self.filenames = []
+
+ # filename of the notice file, excluding path
+ self.notice_filename = None
+
+ # firmware version
+ self.fw_ver = fw_ver
+
+ if path:
+ files = os.listdir(path)
+ files.sort()
+
+ for filename in files:
+ if filename == NOTICE_FILE:
+ logger.debug('%s: %s' % (self.fw_ver, filename))
+ self.notice_filename = filename
+ continue
+
+ self.filenames.append(filename)
+
+ logger.debug('%s: %s' % (self.fw_ver, self.filenames))
+
+ # check notice file
+ if self.notice_filename is None:
+ print('%s: missing %s' % (self.path, NOTICE_FILE))
+ return
+
+ notice_path = os.path.join(self.path, self.notice_filename)
+ f = open(notice_path, 'r')
+ try:
+ buf = f.read()
+ except UnicodeDecodeError as e:
+ print('%s: invalid utf-8: %s' % (notice_path, e))
+ self.notice_filename = None
+ return
+ finally:
+ f.close()
+
+ if len(buf) < NOTICE_FILE_LEN_MIN:
+ print('%s: too short: %d B' % (notice_path, len(buf)))
+ self.notice_filename = None
+ return
+
+
+def scan_branch_dir(path):
+ fw_list = []
+
+ files = os.listdir(path)
+ files.sort()
+
+ for f in files:
+ f_path = os.path.join(path, f)
+
+ if not os.path.isdir(f_path):
+ continue
+
+ firmware = Firmware.create_from_path(f_path)
+ if firmware:
+ if firmware.fw_ver in FIRMWARE_BLACKLIST:
+ logger.debug('Blacklisted firmware release: %s' % (firmware.fw_ver))
+ continue
+
+ logger.debug('Found firmware release: %s' % (firmware.fw_ver))
+ fw_list.append(firmware)
+ continue
+
+ logger.warning('Unknown file: %s' % (f_path))
+
+ return fw_list
+
+
+# QCA988X/hw2.0
+def scan_hw_ver(hw):
+ path = hw.get_path()
+ files = os.listdir(path)
+ files.sort()
+
+ for fw_branch in files:
+ if fw_branch == TESTING_BRANCH:
+ # scan all directories under testing branch, eg. testing/1.2.3.4
+ dirs = os.listdir(os.path.join(path, fw_branch))
+ fw_branches = []
+ for d in dirs:
+ fw_branches.append(os.path.join(TESTING_BRANCH, d))
+ else:
+ fw_branches = [fw_branch]
+
+ for fw_branch in fw_branches:
+ fw_branch_path = os.path.join(path, fw_branch)
+
+ if not os.path.isdir(fw_branch_path):
+ continue
+
+ if os.path.basename(fw_branch_path) in BRANCH_BLACKLIST:
+ logger.debug('Blacklisted firmware branch: %s' % (fw_branch_path))
+ continue
+
+ logger.debug('Found firmware branch: %s' % (fw_branch))
+ fb = FirmwareBranch(fw_branch, fw_branch_path)
+ hw.firmware_branches.append(fb)
+
+ fw = scan_branch_dir(fw_branch_path)
+ fb.firmwares += fw
+
+ files = os.listdir(path)
+ for f_path in files:
+ boardfile = BoardFile.create_from_path(os.path.join(path, f_path))
+ if boardfile:
+ logger.debug('Found board file: %s' % (f_path))
+ hw.board_files.append(boardfile)
+ continue
+
+
+# QCA98XX
+def scan_hw(path):
+ hws = []
+
+ files = os.listdir(path)
+ files.sort()
+
+ for hw_ver in files:
+ hw_ver_path = os.path.join(path, hw_ver)
+
+ if not os.path.isdir(hw_ver_path):
+ continue
+
+ # skip symbolic links, for example WCN6855 hw2.1
+ if os.path.islink(hw_ver_path):
+ continue
+
+ logger.debug('Found hw version: %s' % (hw_ver))
+
+ hw = Hardware(path, hw_ver)
+ scan_hw_ver(hw)
+
+ if len(hw.firmware_branches) == 0:
+ logger.debug('Skipping due to no firmware branches found: %s' % (hw.name))
+ continue
+
+ hws.append(hw)
+
+ return hws
+
+
+def scan_repository(directory):
+ hws = {}
+
+ files = os.listdir(directory)
+ files.sort()
+
+ for hw_name in files:
+ if not os.path.isdir(hw_name):
+ continue
+
+ # skip hidden directories
+ if hw_name.startswith('.'):
+ continue
+
+ logger.debug('Found hw: %s' % (hw_name))
+
+ hw_list = scan_hw(hw_name)
+
+ for hw in hw_list:
+ hws[hw.name] = hw
+
+ return hws
+
+
+# srcpath: full pathname (directory + filename) where copy from
+def install_file(args, srcpath, destdir, destfilename):
+ logger.debug('install_file(%s, %s, %s)' % (srcpath, destdir, destfilename))
+
+ if args.dry_run:
+ return
+
+ destpath = os.path.join(destdir, destfilename)
+
+ destdir = os.path.dirname(destpath)
+ if not os.path.isdir(destdir):
+ os.makedirs(destdir)
+
+ logger.info('\t%s -> %s' % (srcpath, destpath))
+ shutil.copyfile(srcpath, destpath)
+
+ return destpath
+
+
+def get_firmware_version(path):
+ cmd = ['ath12k-fwencoder', '--info', path]
+ info = subprocess.check_output(cmd, universal_newlines=True)
+ msg = email.message_from_string(info)
+ return msg['FirmwareVersion']
+
+
+def get_board_crc32(path):
+ cmd = ['ath12k-fwencoder', '--crc32', path]
+ return subprocess.check_output(cmd, universal_newlines=True).strip()
+
+
+# print indent
+def pi(level, msg):
+ print('%s%s' % (level * '\t', msg))
+
+
+# The WHENCE file update is implemented by using board-2.bin entry as
+# an "anchor". All entries (including File, Version and License) for
+# that hardware directory will be replaces by the new ones. As the
+# filepaths is always sorted the changes visible in git-diff will be
+# actually changed files.
+#
+# Only called during firmware updates. Board file updates don't need
+# changes in WHENCE and that's why this function doesn't support board
+# file changes.
+def whence_update(linux_firmware, filepaths, version):
+ whencepath = os.path.join(linux_firmware, WHENCE_FILE)
+ license_relpath = None
+
+ if not os.path.exists(whencepath):
+ return None
+
+ f = open(whencepath, 'r')
+ buf = f.read()
+ f.close()
+
+ dirname = os.path.dirname(os.path.relpath(filepaths[0], linux_firmware))
+
+ pattern = r'(File: %s/board-\d+.bin\n)(.*%s.*?\n)+' % (dirname,
+ dirname)
+
+ # \g<1> is same as \1 but needed to separate from the version string
+ replace = r'\g<1>'
+
+ for filepath in filepaths:
+ relpath = os.path.relpath(filepath, linux_firmware)
+ if relpath.endswith(NOTICE_FILE):
+ license_relpath = relpath
+ continue
+
+ replace += r'File: %s\n' % (relpath)
+
+ if version is not None:
+ replace += r'Version: %s\n' % (version)
+
+ # license (or notice.txt to be exact) needs to be last
+ if license_relpath is not None:
+ replace += r'File: %s\n' % (license_relpath)
+
+ (buf, sub_count) = re.subn(pattern, replace, buf,
+ flags=re.MULTILINE | re.DOTALL)
+
+ if sub_count != 1:
+ logger.error('Failed to add %s to WHENCE: %d' % (version, sub_count))
+ return None
+
+ f = open(whencepath, 'w')
+ f.write(buf)
+ f.close()
+
+ return whencepath
+
+
+def whence_add(linux_firmware, filepaths, version=None):
+ whencepath = os.path.join(linux_firmware, WHENCE_FILE)
+ license_relpath = None
+
+ if not os.path.exists(whencepath):
+ return None
+
+ f = open(whencepath, 'r')
+ buf = f.read()
+ f.close()
+
+ pattern = r'(Driver: ath12k.*?\n\n.*?)\n\n'
+
+ # \g<1> is same as \1 but needed to separate from the version string
+ replace = r'\g<1>\n'
+
+ for filepath in filepaths:
+ relpath = os.path.relpath(filepath, linux_firmware)
+ if relpath.endswith(NOTICE_FILE):
+ license_relpath = relpath
+ continue
+
+ replace += r'File: %s\n' % (relpath)
+
+ if version is not None:
+ replace += r'Version: %s\n' % (version)
+
+ # license (or notice.txt to be exact) needs to be last
+ if license_relpath is not None:
+ replace += r'File: %s\n' % (license_relpath)
+
+ # empty line before the 'Licence: Redistributable.' line
+ replace += r'\n'
+
+ (buf, sub_count) = re.subn(pattern, replace, buf,
+ flags=re.MULTILINE | re.DOTALL)
+
+ if sub_count != 1:
+ logger.error('Failed to add %s to WHENCE: %d' % (version, sub_count))
+ return None
+
+ f = open(whencepath, 'w')
+ f.write(buf)
+ f.close()
+
+ return whencepath
+
+
+def git_commit(args, msg, repodir, files):
+ if not args.commit:
+ # nothing to do
+ return
+
+ cmd = ['git', '-C', repodir, 'commit', '--quiet', '--signoff', '-m', msg] + files
+
+ logger.debug('Running: %r' % (cmd))
+ subprocess.check_call(cmd)
+
+
+def git_add(args, repodir, files):
+ if not args.commit:
+ # nothing to do
+ return
+
+ cmd = ['git', '-C', repodir, 'add'] + files
+
+ logger.debug('Running: %r' % (cmd))
+ subprocess.check_call(cmd)
+
+
+def git_rm(args, repodir, files):
+ if not args.commit:
+ # nothing to do
+ return
+
+ cmd = ['git', '-C', repodir, 'rm', '--quiet'] + files
+
+ logger.debug('Running: %r' % (cmd))
+ subprocess.check_call(cmd)
+
+
+def cmd_check(args):
+ scan_repository('.')
+
+
+def cmd_list(args):
+ level = 0
+
+ hws = scan_repository('.')
+ for hw in sorted(hws.values()):
+ pi(level, '%s:' % (hw.name))
+ level += 1
+
+ # print board files
+ if len(hw.board_files) > 0:
+ pi(level, 'board')
+ level += 1
+
+ for board_file in sorted(hw.board_files):
+ pi(level, board_file)
+
+ level -= 1
+
+ # print firmware branches
+ for branch in sorted(hw.firmware_branches):
+ if len(branch.firmwares) == 0:
+ # don't print empty branches
+ continue
+
+ pi(level, '%s' % (branch.name))
+ level += 1
+
+ for fw in sorted(branch.firmwares):
+ pi(level, fw.fw_ver)
+
+ level -= 1
+
+ level -= 1
+
+
+def cmd_list_hardware(args):
+ hws = scan_repository('.')
+ for hw in sorted(hws.values()):
+ print(hw.name)
+
+
+def cmd_list_branches(args):
+ hw_name = args.list_branches[0]
+ hw_ver = args.list_branches[1]
+
+ hws = scan_repository('.')
+ for hw in sorted(hws.values()):
+ if hw.name == '%s %s' % (hw_name, hw_ver):
+ for branch in sorted(hw.firmware_branches):
+ print(branch.name)
+
+ return
+
+
+def cmd_list_releases(args):
+ hw_name = args.list_releases[0]
+ hw_ver = args.list_releases[1]
+ fw_branch = args.list_releases[2]
+
+ hws = scan_repository('.')
+ for hw in sorted(hws.values()):
+ if hw.name == '%s %s' % (hw_name, hw_ver):
+ for branch in sorted(hw.firmware_branches):
+ if fw_branch == branch.name:
+ for fw in branch.firmwares:
+ print(fw.fw_ver)
+
+ return
+
+
+def cmd_list_lib_dir(args):
+ fw_dir = args.list_lib_dir[0]
+ ath12k_dir = os.path.join(fw_dir, ATH12K_DIR)
+
+ if not os.path.exists(ath12k_dir):
+ logger.error('directory %s does not exist, aborting' % (ath12k_dir))
+ sys.exit(1)
+
+ if not os.path.isdir(ath12k_dir):
+ logger.error('%s is not a directory, aborting' % (ath12k_dir))
+ sys.exit(1)
+
+ # sort the results based on dirpath
+ for (dirpath, dirnames, filenames) in sorted(os.walk(ath12k_dir)):
+ found = []
+ for filename in sorted(filenames):
+ path = os.path.join(dirpath, filename)
+
+ match = re.match(r'firmware.*\.bin', filename)
+ if match is not None:
+ # this is a firmware file
+ s = '%s\t%s' % (filename, get_firmware_version(path))
+ found.append(s)
+
+ match = re.match(r'board.*\.bin', filename)
+ if match is not None:
+ # this is a board file
+ s = '%s\t%s' % (filename, get_board_crc32(path))
+ found.append(s)
+
+ if len(found) > 0:
+ # Just show QCA1234/hw1.0 directories. I would have liked
+ # to use os.path functions here but just could not find
+ # anything sensible there.
+ pi(0, '%s:' % ('/'.join(dirpath.split('/')[-2:])))
+ for line in found:
+ pi(1, line)
+
+
+def cmd_get_latest_in_branch(args):
+ # As this command is mostly for scripts to parse, don't show
+ # warnings etc to clutter the output, unless we are debugging of
+ # course.
+ if not args.debug:
+ logger.setLevel(logging.ERROR)
+
+ hws = scan_repository('.')
+
+ args_hw = args.get_latest_in_branch[0]
+ args_hwver = args.get_latest_in_branch[1]
+ args_fwbranch = args.get_latest_in_branch[2]
+
+ # TODO: hw is always in uppercase and hwver lower case, check that
+ hw_name = '%s %s' % (args_hw, args_hwver)
+
+ if hw_name not in hws:
+ logger.error('Did not find hardware: %s' % (hw_name))
+ sys.exit(1)
+
+ hw = hws[hw_name]
+
+ fw_branch = None
+
+ for b in hw.firmware_branches:
+ if b.name == args_fwbranch:
+ fw_branch = b
+ break
+
+ if fw_branch is None:
+ logger.error('Did not find firmware branch: %s' % (args_fwbranch))
+ sys.exit(1)
+
+ if len(fw_branch.firmwares) == 0:
+ # no firmware images in this branch, just use return value 0 with no output
+ sys.exit(0)
+
+ print(sorted(fw_branch.firmwares)[-1].path)
+
+ sys.exit(0)
+
+
+def cmd_get_latest_in_hw(args):
+ # As this command is mostly for scripts to parse, don't show
+ # warnings etc to clutter the output, unless we are debugging of
+ # course.
+ if not args.debug:
+ logger.setLevel(logging.ERROR)
+
+ hws = scan_repository('.')
+
+ args_hw = args.get_latest[0]
+ args_hwver = args.get_latest[1]
+
+ # TODO: hw is always in uppercase and hwver lower case, check that
+ hw_name = '%s %s' % (args_hw, args_hwver)
+
+ if hw_name not in hws:
+ logger.error('Did not find hardware: %s' % (hw_name))
+ sys.exit(1)
+
+ hw = hws[hw_name]
+
+ for branch in sorted(hw.firmware_branches, reverse=True):
+ if len(branch.firmwares) == 0:
+ # ignore an empty branch
+ continue
+
+ print(sorted(branch.firmwares)[-1].path)
+ break
+
+ sys.exit(0)
+
+
+def cmd_install(args):
+ hws = scan_repository('.')
+
+ linux_firmware = args.install[0]
+ ath12kdir = os.path.join(linux_firmware, ATH12K_DIR)
+
+ if not os.path.exists(ath12kdir):
+ os.makedirs(ath12kdir)
+
+ if not os.path.isdir(ath12kdir):
+ logger.error('%s is not a directory' % (ath12kdir))
+ sys.exit(1)
+
+ logger.debug('Installing to directory %s' % (ath12kdir))
+
+ for hw in sorted(hws.values()):
+ bd_list = hw.board_files
+
+ # every Hardware() should have at least one firmware branch, the
+ # main '.' branch so no need to check the length
+ fw_list = sorted(sorted(hw.firmware_branches)[-1].firmwares)
+
+ if len(fw_list) == 0:
+ logger.debug('no firmware images found for %s' % (hw))
+ continue
+
+ destdir = os.path.join(ath12kdir, hw.get_path())
+
+ # install board files first as that's used as an "anchor" for
+ # firmware files WHENCE updates
+ for bd in bd_list:
+ installed = []
+ dest = os.path.join(ath12kdir, bd.path)
+ if not os.path.exists(dest) or not filecmp.cmp(bd.path, dest):
+ if os.path.exists(dest):
+ action = 'update'
+ else:
+ action = 'add'
+
+ logger.info('Installing board file %s' % (bd.path))
+ destpath = install_file(args, bd.path, destdir,
+ bd.get_basename())
+ installed.append(destpath)
+
+ if action == 'add':
+ whencepath = whence_add(linux_firmware, installed)
+ if whencepath is not None:
+ installed.append(whencepath)
+
+ git_add(args, linux_firmware, installed)
+
+ msg = 'ath12k: %s: %s %s' % (hw.name,
+ action,
+ bd.get_basename())
+ git_commit(args, msg, linux_firmware, installed)
+ else:
+ logger.debug('No update needed for %s' % (bd.path))
+
+ # install latest firmware
+ fw = fw_list[-1]
+
+ to_add = []
+ to_update = []
+ to_remove = []
+
+ # remove notice and board files from to_remove
+ if os.path.exists(destdir):
+ for filename in os.listdir(destdir):
+ if filename in [NOTICE_FILE, 'board-2.bin']:
+ continue
+
+ to_remove.append(filename)
+
+ # investigate what changes are needed
+ for filepath in fw.get_files_with_path():
+ filename = os.path.basename(filepath)
+ dest = os.path.join(destdir, filename)
+
+ if not os.path.exists(dest):
+ to_add.append(filename)
+ continue
+
+ if not filecmp.cmp(filepath, dest):
+ to_update.append(filename)
+
+ to_remove.remove(filename)
+
+ if len(to_add) > 0 or len(to_update) > 0 or len(to_remove) > 0:
+ if len(to_update) > 0 or len(to_remove) > 0:
+ action = 'update'
+ else:
+ action = 'add'
+
+ logger.info('Installing %s to %s' % (fw.fw_ver, destdir))
+ installed = []
+
+ for filepath in fw.get_files_with_path():
+ destpath = install_file(args, filepath, destdir,
+ os.path.basename(filepath))
+ installed.append(destpath)
+
+ # install notice file (every release must have a notice file)
+ destpath = install_file(args, fw.get_notice_path(), destdir,
+ fw.notice_filename)
+ installed.append(destpath)
+
+ # TODO: whence is not working with ath12k
+ if action == 'update':
+ # updating an existing firmware file
+ whencepath = whence_update(linux_firmware, installed, fw.fw_ver)
+ else:
+ # adding a new firmware file
+ whencepath = whence_add(linux_firmware, installed, fw.fw_ver)
+
+ if whencepath is not None:
+ installed.append(whencepath)
+
+ git_add(args, linux_firmware, installed)
+
+ for filename in to_remove:
+ filepath = os.path.join(ath12kdir, hw.get_path(), filename)
+
+ if os.path.basename(filepath) == 'regdb.bin':
+ logger.debug('ignore %s so that it is not removed from target' % (filepath))
+ continue
+
+ logger.info('\trm %s' % (filepath))
+
+ # even git_rm() removes the file need to remove the
+ # file separately in case --commit is not used
+ os.remove(filepath)
+
+ git_rm(args, linux_firmware, [filepath])
+ installed.append(filepath)
+
+ # "ath12k: QCA6390 hw2.0: update to WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1"
+ msg = 'ath12k: %s: %s to %s' % (hw.name,
+ action,
+ fw.fw_ver)
+
+ git_commit(args, msg, linux_firmware, installed)
+ else:
+ logger.debug('No update needed in %s for %s' % (hw.name, fw.fw_ver))
+
+
+def main():
+ global logger
+
+ logger = logging.getLogger('ath12k-fw-repo')
+
+ parser = argparse.ArgumentParser(
+ description='Install firmware images from the ath12k-firmware git repository. Run it from the top directory of the working tree.')
+
+ parser.add_argument('--debug', action='store_true',
+ help='Enable debug messages.')
+ parser.add_argument('--dry-run', action='store_true',
+ help='Do not run any actual commands.')
+
+ parser.add_argument('--check', action='store_true',
+ help='Check the ath12k-firmware repository content for validity.')
+ parser.add_argument('--list', action='store_true',
+ help='List all files found from the ath12k-firmware repository.')
+
+ parser.add_argument('--list-hardware', action='store_true',
+ help='List all possible hardware versions found from the ath12k-firmware repository.')
+
+ parser.add_argument('--list-branches', action='store',
+ nargs=2,
+ help='List all firmware branches for for this hardware version.')
+
+ parser.add_argument('--list-releases', action='store',
+ nargs=3,
+ help='List all releases from a firmware branch.')
+
+ parser.add_argument('--list-lib-dir', action='store',
+ nargs=1, metavar='LIB_FIRMWARE_DIRECTORY',
+ help='List all files found from the specified directory, which can either be a linux-firmware repository or /lib/firmware directory.')
+
+ parser.add_argument('--install', action='store', nargs=1, metavar='DESTINATION',
+ help='Install all ath12k firmware images to DESTINATION folder, for example /lib/firmware.')
+
+ parser.add_argument('--commit', action='store_true',
+ help='When installing files also git commit them, for example when updating linux-firmware.git.')
+
+ parser.add_argument('--get-latest-in-branch', action='store', nargs=3,
+ metavar=('HW', 'HWVER', 'BRANCH'),
+ help='Show latest firmware version from a firmware branch. Just outputs the version for easy parsing in scripts.')
+
+ parser.add_argument('--get-latest', action='store', nargs=2,
+ metavar=('HW', 'HWVER'),
+ help='Show latest firmware version for hardware version. Just outputs the version for easy parsing in scripts.')
+
+ args = parser.parse_args()
+
+ if args.debug:
+ logging.basicConfig(format='%(levelname)s: %(message)s')
+ logger.setLevel(logging.DEBUG)
+ else:
+ logging.basicConfig(format='%(message)s')
+ logger.setLevel(logging.INFO)
+
+ # commands
+ if args.check:
+ cmd_check(args)
+ elif args.list:
+ cmd_list(args)
+ elif args.list_hardware:
+ cmd_list_hardware(args)
+ elif args.list_branches:
+ cmd_list_branches(args)
+ elif args.list_releases:
+ cmd_list_releases(args)
+ elif args.list_lib_dir:
+ cmd_list_lib_dir(args)
+ elif args.install:
+ cmd_install(args)
+ elif args.get_latest_in_branch:
+ cmd_get_latest_in_branch(args)
+ elif args.get_latest:
+ cmd_get_latest_in_hw(args)
+ else:
+ logger.error('No command defined')
+ parser.print_usage()
+
+if __name__ == "__main__":
+ main()
diff --git a/ath12k/board.bin b/ath12k/board.bin
new file mode 100644
index 0000000..94a2152
Binary files /dev/null and b/ath12k/board.bin differ
diff --git a/ath12k/regdb.bin b/ath12k/regdb.bin
new file mode 100644
index 0000000..4eeaded
Binary files /dev/null and b/ath12k/regdb.bin differ
diff --git a/fedora_server.md b/fedora_server.md
index 06c1b0a..0411942 100644
--- a/fedora_server.md
+++ b/fedora_server.md
@@ -58,7 +58,7 @@ dnf install tpm2-tss
# For machines where prioritizing a secure boot environment is important we need to
# specify --tpm2-pcrs=0+7 -- 0 meaning the firmware has not changed and 7 meaning
# secure boot is enabled
-systemd-cryptenroll /dev/nvme0n1p3 --wipe-slot=tpm2 --tpm2-device=auto --tpm2-pcrs=7
+systemd-cryptenroll /dev/nvme0n1p3 --wipe-slot=tpm2 --tpm2-device=auto --tpm2-pcrs=""
# Add tpm2-tss to dracut
# Edit /etc/dracut.conf.d/tpm2.conf
diff --git a/wireguard/README.md b/wireguard/README.md
new file mode 100644
index 0000000..b9d7b73
--- /dev/null
+++ b/wireguard/README.md
@@ -0,0 +1,62 @@
+# Wireguard Setup
+
+## Fedora
+
+```bash
+dnf install wireguard
+```
+
+/etc/sysctl.d/10-wireguard.conf
+
+```conf
+net.ipv4.ip_forward=1
+net.ipv6.conf.all.forwarding=1
+```
+
+```bash
+sysctl -p
+```
+
+### Server
+
+```bash
+wg genkey | tee /etc/wireguard/private.key
+cat /etc/wireguard/private.key | wg pubkey | tee /etc/wireguard/public.key
+```
+
+```bash
+cat < /etc/wireguard/wg0.conf
+[Interface]
+Address = 10.10.10.1/24,fd10:10:10::1/64
+ListenPort = 51820
+PrivateKey = $(cat /etc/wireguard/private.key)
+SaveConfig = true
+PostUp = iptables -t nat -I POSTROUTING -o bridge0 -j MASQUERADE
+PostUp = ip6tables -t nat -I POSTROUTING -o bridge0 -j MASQUERADE
+PreDown = iptables -t nat -D POSTROUTING -o bridge0 -j MASQUERADE
+PreDown = ip6tables -t nat -D POSTROUTING -o bridge0 -j MASQUERADE
+EOF
+```
+
+```bash
+wg set wg0 peer ndUMratPyYXKiOlU6AT5lYI7v3iohBAimgZY3/jsWik= allowed-ips 10.10.10.2,fd10:10:10::2
+```
+
+### Client
+
+```conf
+[interface]
+PrivateKey = KHgXS7zIqqfb46cfUVKvRZesswZcvib71hhYYcN39mQ=
+Address = 10.10.10.2/32,fd10:10:10::2/32
+
+[Peer]
+PublicKey = kzbHUGzYk6Uyan/NFYY5mh3pxf2IX/WzWZtImeyp6Sw=
+Endpoint = 2600:1700:1e6c:a81f:793d:7abf:e94d:9bc4:51820
+AllowedIPs = 0.0.0.0/0,::/0
+```
+
+### Testing
+
+```bash
+curl -6 icanhazip.com
+```
diff --git a/wireguard/add_client.sh b/wireguard/add_client.sh
new file mode 100644
index 0000000..2da340d
--- /dev/null
+++ b/wireguard/add_client.sh
@@ -0,0 +1,37 @@
+#!/bin/bash
+
+export CLIENT_NAME=$1
+export CLIENT_IP_SUFFIX=$2
+
+if [ -z $CLIENT_NAME ];
+ then echo 'Client name required. `./add_client.sh client_name 3`';
+ exit 1;
+fi
+
+if [ -z $CLIENT_IP_SUFFIX ];
+ then echo 'Client IP suffix. `./add_client.sh client_name 3`';
+ exit 1;
+fi
+
+export SERVER_PUBKEY=$(cat /etc/wireguard/publickey)
+mkdir /etc/wireguard/$CLIENT_NAME
+cd /etc/wireguard/$CLIENT_NAME
+export PRIVKEY=$(wg genkey)
+echo $PRIVKEY | tee $CLIENT_NAME"_privkey"
+export PUBKEY=$(echo $PRIVKEY | wg pubkey)
+echo $PUBKEY | tee $CLIENT_NAME"_pubkey"
+
+cat > $CLIENT_NAME".conf" <