forked from dan/liminix
Compare commits
258 Commits
main
...
tp-archer-
Author | SHA1 | Date | |
---|---|---|---|
|
ac8b456c29 | ||
471c63b399 | |||
782feaeafa | |||
ac54c89427 | |||
5a3646cb29 | |||
e249f48cff | |||
6661e42684 | |||
b9ba9ef835 | |||
8b69dcc209 | |||
9b3a3b9ff7 | |||
7d08497bcb | |||
0e84adaa0e | |||
660ed5df8f | |||
792a11c8c0 | |||
7e4a05bbf8 | |||
a4ba5c85e1 | |||
723ef73d5a | |||
3d4e782929 | |||
1b6a05aec5 | |||
80628a3d90 | |||
bf0cafffed | |||
e49aba127c | |||
324465bc18 | |||
b33249a050 | |||
b9c084415e | |||
cf9cadd212 | |||
a116fe084a | |||
74cf3e0711 | |||
9795f03da4 | |||
cdb23b147c | |||
dbd1264352 | |||
834858d5bc | |||
18335b95e3 | |||
6bee2f67ac | |||
b4ba3eea21 | |||
16af3984c9 | |||
ce7e395295 | |||
7e13e017eb | |||
bbf2f53c0e | |||
032d0f8aca | |||
b8ac9e5279 | |||
ff2604ca5d | |||
72789984ce | |||
90d9d0e811 | |||
97a8ae1c84 | |||
52eb283a26 | |||
cbb1de804e | |||
f9c03998b8 | |||
50de1b090f | |||
648382f64a | |||
e9370358ae | |||
762ce7b6b8 | |||
b1c0560f4f | |||
e34135c41a | |||
712c9b266f | |||
4df963996c | |||
349bfecbb8 | |||
450d3820b2 | |||
771585546d | |||
73abf952d5 | |||
8af4e9fd5b | |||
7e19d80130 | |||
0f0688c802 | |||
b43f17f655 | |||
adf62d4483 | |||
68eb1360f6 | |||
19ad6cd278 | |||
00076c7b81 | |||
721e7499f3 | |||
fc723b9a35 | |||
a5f16dfa81 | |||
41a4b1f7ef | |||
42a5699326 | |||
ea2b25168e | |||
5564cf0554 | |||
f3a13630d3 | |||
f233acf9ff | |||
b6a054c588 | |||
b231664a06 | |||
f4bf3029fa | |||
05f2c9a2f7 | |||
5df5c822ea | |||
4795dd05b7 | |||
a192f08881 | |||
a873dc6608 | |||
2fb4756a7f | |||
04f5174425 | |||
dca2e4def1 | |||
b60126775a | |||
76f11bcc93 | |||
efcfdcc21d | |||
77f1a78331 | |||
28a5dec7dd | |||
fad0a47b75 | |||
af52aafc84 | |||
34442b6069 | |||
b8a46fc05e | |||
8ac2c6cec1 | |||
8879b2d1ba | |||
83e346d5a0 | |||
156b1fe64a | |||
1a314e55b7 | |||
9263b21faa | |||
0a820a702a | |||
4ea518e296 | |||
98318b450d | |||
e4ac7f19dc | |||
9c22744850 | |||
c697be8c28 | |||
202a37221a | |||
436eb03a7b | |||
e5963ae3f7 | |||
f164f19d95 | |||
dd4ab41f6a | |||
5d5dff6729 | |||
570d29c368 | |||
725af00dc9 | |||
e1b932ec27 | |||
7173b6fb1c | |||
ed9548f21d | |||
0787807a7f | |||
38ed91f641 | |||
ffe9603c39 | |||
cbd3dfefc5 | |||
018c1868b5 | |||
5184ff63f7 | |||
35909c9a23 | |||
4383462199 | |||
9730cdd63b | |||
095853214b | |||
9d6e50cbbc | |||
94dbc56595 | |||
2cd7f932eb | |||
|
27c7735f02 | ||
|
29c9de248d | ||
3ca0d87c27 | |||
8f30db58ae | |||
f9ab0590a6 | |||
84fa8d65f4 | |||
9b0149ecb7 | |||
|
baf3cf7413 | ||
|
c5145b5fc9 | ||
|
628f4dfdbe | ||
|
da59e2a349 | ||
|
c0a9571a13 | ||
|
d6ffdd7be6 | ||
|
985f982435 | ||
|
a893c0dc4c | ||
|
3ec29dc1b9 | ||
|
0e81953b67 | ||
|
3c70a0d037 | ||
|
422f3edab1 | ||
|
c14b2f6356 | ||
|
cdafff2095 | ||
|
13f1bb9f52 | ||
|
019fef6929 | ||
|
63007859c2 | ||
|
e9ab8d7183 | ||
|
3dc58de0eb | ||
|
dde8386f75 | ||
|
c59364d623 | ||
|
b76c5b4abe | ||
|
0a8343be66 | ||
|
d14ee41325 | ||
|
8f814658fe | ||
60508f4d4e | |||
ca64e9035e | |||
4bcc3d5b28 | |||
28fe37d555 | |||
175db9f604 | |||
b5722a0153 | |||
c373152673 | |||
7e7171556f | |||
6920ee765d | |||
71a1ef286e | |||
ffe0e9d26b | |||
2b22c7aa91 | |||
3c950704e1 | |||
8578a554c7 | |||
3851698d35 | |||
f69ebbb6f5 | |||
16e4b05653 | |||
8ac848b1e6 | |||
b7efbd3e21 | |||
a654577ac2 | |||
c50423f689 | |||
65479e206b | |||
79926c6fe7 | |||
ae4856ea7c | |||
b9c0d93670 | |||
11287a8436 | |||
57aece0709 | |||
c1d285a220 | |||
dce983ec79 | |||
812f497660 | |||
1206d02200 | |||
7c196bf9b4 | |||
86d19c54b3 | |||
aca3e11631 | |||
273c66b2d3 | |||
87f6a31a06 | |||
a9ea01428e | |||
92b0bec038 | |||
82537bbe68 | |||
efb29c5901 | |||
29e61be26c | |||
6f1f9d6f20 | |||
34291292c0 | |||
c9e4c1b0da | |||
|
63e3f2aa58 | ||
|
61494fdc0c | ||
891d6e5f20 | |||
c4041b00f6 | |||
f875622100 | |||
49ec4a2961 | |||
c8154a2db9 | |||
02cf2c6b80 | |||
b0709a6443 | |||
86f5c9b568 | |||
ef707de8b1 | |||
89c88dd472 | |||
c1ad139310 | |||
f682b26c29 | |||
84ce618213 | |||
9e199c6957 | |||
c8e3d84bf4 | |||
dd8ec18881 | |||
1730cf07b1 | |||
de51bfe13d | |||
b09723345c | |||
1781d4b6e4 | |||
c219350d7c | |||
6f83282ff5 | |||
|
04895f9cf6 | ||
5f2d1660bd | |||
|
7642e23c0a | ||
83ee488e4c | |||
f19a937eda | |||
f0490f37d5 | |||
c1101d3af5 | |||
9a3d7a387e | |||
228c0a1668 | |||
63f034e362 | |||
6971d03520 | |||
7bc9cb6c55 | |||
a251ceeb99 | |||
38a7f0b03b | |||
c0c4752350 | |||
3c941b4ce2 | |||
243295aab8 | |||
45e8db09e1 | |||
2a93f24a58 | |||
64898eada8 | |||
|
d5026c2074 | ||
136c5e6f32 | |||
fa9a2c6413 | |||
049cdbb610 | |||
5ee4adff10 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -6,3 +6,4 @@ result-*
|
||||
_build
|
||||
*-secrets.nix
|
||||
examples/static-leases.nix
|
||||
/doc/hardware.rst
|
||||
|
78
NEWS
78
NEWS
@ -23,5 +23,83 @@ the name of an outputs that gloms together other filesystem-like
|
||||
outputs with some kind of partition table - so we might in future have
|
||||
gptimage or lvmimage or ubimage.
|
||||
|
||||
2024-01-03
|
||||
|
||||
Liminix is now targeted to Nixpkgs 23.11 (not 23.05 as previously).
|
||||
Upstream changes that have led to incompatible Liminix changes are:
|
||||
|
||||
* newer U-Boot version
|
||||
* util-linux can now be built (previously depended on systemd)
|
||||
|
||||
2024-01-30
|
||||
|
||||
New port! Thanks to Arnout Engelen <arnout@bzzt.net>, Liminix
|
||||
now runs on the TP-Link Archer AX23.
|
||||
|
||||
2024-02-12
|
||||
|
||||
* We now build wifi drivers (mac80211) from the same kernel source as
|
||||
the running kernel, instead of using drivers from the linux-backports
|
||||
project. This may be a regression on some devices that depend on
|
||||
OpenWrt patches for wireless functionality: if you have a device that
|
||||
used to work and now doesn't, refer to OpenWrt
|
||||
package/kernel/mac80211/patches/ to see if there's something in there
|
||||
that needs to be applied.
|
||||
|
||||
* in general, we build kernel modules (e.g. for nftables) at the same
|
||||
time as the kernel itself instead of expecting to be able to build
|
||||
them afterwards as though they were "out of tree". Refer to commit
|
||||
b9c0d93670275e69df24902b05bf4aa4f0fcbe96 for a fuller explanation
|
||||
of how this simplifies things.
|
||||
|
||||
2024-02-13
|
||||
|
||||
So that we can be more consistent about services that would like their
|
||||
state to be preserved across boots (assuming a writable filesystem)
|
||||
these changes have been made
|
||||
|
||||
* /run/service-state has been moved to /run/services/outputs
|
||||
to better reflect what it's used for
|
||||
* /run/services/state is either a symlink to /persist/services/state
|
||||
(if there's a writeable fs on /persist) or a directory (if there
|
||||
isn't)
|
||||
|
||||
The change will lose your ssh host key(s) unless you copy them from
|
||||
the old location to the new one before rebooting into the new system
|
||||
|
||||
mkdir -m 02751 -p /run/services/state/dropbear
|
||||
cp /persist/secrets/dropbear/* /run/services/state/dropbear
|
||||
|
||||
The `output`, `mkoutputs` functions defined by ${serviceFns}
|
||||
have been updated for the new location.
|
||||
|
||||
2024-02-16
|
||||
|
||||
New (or at least, previously unreported) port! Liminix now runs on the
|
||||
Turris Omnia and has been serving my family's internet needs for most
|
||||
of this week. Thanks to NGI0 Entrust and the NLnet Foundation for
|
||||
sponsoring this development (and funding the hardware)
|
||||
|
||||
2024-02-21
|
||||
|
||||
New port! Thanks to Raito Bezarius, Liminix now runs on the Zyxel NWA50AX,
|
||||
an MT7621 (MIPS EL) dual radio WiFi AP.
|
||||
|
||||
2024-04-29
|
||||
|
||||
The setup for using `levitate` has changed: now it accepts an entire
|
||||
config fragment, not just a list of services. Hopefully this makes it
|
||||
a bit more useful :-)
|
||||
|
||||
defaultProfile.packages = with pkgs; [
|
||||
...
|
||||
(levitate.override {
|
||||
config = {
|
||||
services = {
|
||||
inherit (config.services) dhcpc sshd watchdog;
|
||||
};
|
||||
defaultProfile.packages = [ mtdutils ];
|
||||
users.root.openssh.authorizedKeys.keys = secrets.root.keys;
|
||||
};
|
||||
})
|
||||
];
|
||||
|
@ -33,7 +33,7 @@ functioning version, see [the CI system](https://build.liminix.org/jobset/limini
|
||||
Documentation is in the [doc](doc/) directory. You can build it
|
||||
by running
|
||||
|
||||
nix-shell -p sphinx --run "make -C doc html"
|
||||
nix-shell -p sphinx --run "make -C doc hardware.rst html"
|
||||
|
||||
Rendered documentation corresponding to the latest commit on `main`
|
||||
is published to [https://www.liminix.org/doc/](https://www.liminix.org/doc/)
|
||||
|
1002
THOUGHTS.txt
1002
THOUGHTS.txt
File diff suppressed because it is too large
Load Diff
@ -4,6 +4,10 @@ let
|
||||
inherit (lib) mkOption mkEnableOption mdDoc types optional optionals;
|
||||
in {
|
||||
options.bordervm = {
|
||||
keys = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
};
|
||||
l2tp = {
|
||||
host = mkOption {
|
||||
description = mdDoc ''
|
||||
@ -108,6 +112,7 @@ in {
|
||||
tufted
|
||||
iptables
|
||||
usbutils
|
||||
busybox
|
||||
];
|
||||
security.sudo.wheelNeedsPassword = false;
|
||||
networking = {
|
||||
@ -122,6 +127,7 @@ in {
|
||||
isNormalUser = true;
|
||||
uid = 1000;
|
||||
extraGroups = [ "wheel"];
|
||||
openssh.authorizedKeys.keys = cfg.keys;
|
||||
};
|
||||
services.getty.autologinUser = "liminix";
|
||||
};
|
||||
|
10
ci.nix
10
ci.nix
@ -9,8 +9,14 @@ let
|
||||
borderVmConf = ./bordervm.conf-example.nix;
|
||||
inherit (pkgs.lib.attrsets) genAttrs;
|
||||
devices = [
|
||||
"gl-ar750" "gl-mt300n-v2" "gl-mt300a"
|
||||
"qemu" "qemu-aarch64" "qemu-armv7l"
|
||||
"gl-ar750"
|
||||
"gl-mt300a"
|
||||
"gl-mt300n-v2"
|
||||
"qemu"
|
||||
"qemu-aarch64"
|
||||
"qemu-armv7l"
|
||||
"tp-archer-ax23"
|
||||
"zyxel-nwa50ax"
|
||||
];
|
||||
vanilla = ./vanilla-configuration.nix;
|
||||
for-device = name:
|
||||
|
13
default.nix
13
default.nix
@ -1,8 +1,10 @@
|
||||
{
|
||||
device
|
||||
deviceName ? null
|
||||
, device ? (import ./devices/${deviceName} )
|
||||
, liminix-config ? <liminix-config>
|
||||
, nixpkgs ? <nixpkgs>
|
||||
, borderVmConf ? ./bordervm.conf.nix
|
||||
, imageType ? "primary"
|
||||
}:
|
||||
|
||||
let
|
||||
@ -19,17 +21,24 @@ let
|
||||
});
|
||||
|
||||
eval = pkgs.lib.evalModules {
|
||||
specialArgs = {
|
||||
modulesPath = builtins.toString ./modules;
|
||||
};
|
||||
modules = [
|
||||
{ _module.args = { inherit pkgs; inherit (pkgs) lim; }; }
|
||||
./modules/hardware.nix
|
||||
./modules/base.nix
|
||||
./modules/busybox.nix
|
||||
./modules/hostname.nix
|
||||
./modules/kernel
|
||||
device.module
|
||||
liminix-config
|
||||
./modules/s6
|
||||
./modules/users.nix
|
||||
./modules/outputs.nix
|
||||
{
|
||||
boot.imageType = imageType;
|
||||
}
|
||||
];
|
||||
};
|
||||
config = eval.config;
|
||||
@ -67,6 +76,8 @@ in {
|
||||
go-l2tp
|
||||
min-copy-closure
|
||||
fennelrepl
|
||||
lzma
|
||||
lua
|
||||
];
|
||||
};
|
||||
}
|
||||
|
@ -57,8 +57,8 @@
|
||||
kernel = {
|
||||
src = pkgs.pkgsBuildBuild.fetchurl {
|
||||
name = "linux.tar.gz";
|
||||
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.71.tar.gz";
|
||||
hash = "sha256-yhO2cXIeIgUxkSZf/4aAsF11uxyh+UUZu6D1h92vCD8=";
|
||||
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.137.tar.gz";
|
||||
hash = "sha256-PkdzUKZ0IpBiWe/RS70J76JKnBFzRblWcKlaIFNxnHQ=";
|
||||
};
|
||||
extraPatchPhase = ''
|
||||
${pkgs.openwrt.applyPatches.mediatek}
|
||||
@ -73,7 +73,7 @@
|
||||
MTK_INFRACFG = "y";
|
||||
|
||||
MTK_PMIC_WRAP = "y";
|
||||
MTK_EFUSE="y";
|
||||
NVMEM_MTK_EFUSE="y";
|
||||
# MTK_HSDMA="y";
|
||||
MTK_SCPSYS="y";
|
||||
MTK_SCPSYS_PM_DOMAINS="y";
|
||||
@ -92,7 +92,6 @@
|
||||
|
||||
MEDIATEK_GE_PHY = "y";
|
||||
# MEDIATEK_MT6577_AUXADC = "y";
|
||||
# MEDIATEK_WATCHDOG = "y";
|
||||
NET_MEDIATEK_SOC = "y";
|
||||
NET_MEDIATEK_SOC_WED = "y";
|
||||
NET_MEDIATEK_STAR_EMAC = "y"; # this enables REGMAP_MMIO
|
||||
@ -144,6 +143,17 @@
|
||||
# SERIAL_8250_NR_UARTS="3";
|
||||
# SERIAL_8250_RUNTIME_UARTS="3";
|
||||
SERIAL_OF_PLATFORM="y";
|
||||
|
||||
# Must enble hardware watchdog drivers. Else the device reboots after several seconds
|
||||
WATCHDOG = "y";
|
||||
MEDIATEK_WATCHDOG = "y";
|
||||
};
|
||||
conditionalConfig = {
|
||||
WLAN= {
|
||||
MT7615E = "m";
|
||||
MT7622_WMAC = "y";
|
||||
MT7915E = "m";
|
||||
};
|
||||
};
|
||||
};
|
||||
boot = {
|
||||
@ -165,12 +175,9 @@
|
||||
hardware =
|
||||
let
|
||||
openwrt = pkgs.openwrt;
|
||||
mac80211 = pkgs.mac80211.override {
|
||||
drivers = [
|
||||
"mt7615e"
|
||||
"mt7915e"
|
||||
];
|
||||
klibBuild = config.system.outputs.kernel.modulesupport;
|
||||
mac80211 = pkgs.kmodloader.override {
|
||||
targets = ["mt7615e" "mt7915e"];
|
||||
inherit (config.system.outputs) kernel;
|
||||
};
|
||||
in {
|
||||
ubi = {
|
||||
|
@ -7,8 +7,8 @@
|
||||
kernel = {
|
||||
src = pkgs.pkgsBuildBuild.fetchurl {
|
||||
name = "linux.tar.gz";
|
||||
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.71.tar.gz";
|
||||
hash = "sha256-yhO2cXIeIgUxkSZf/4aAsF11uxyh+UUZu6D1h92vCD8=";
|
||||
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.137.tar.gz";
|
||||
hash = "sha256-PkdzUKZ0IpBiWe/RS70J76JKnBFzRblWcKlaIFNxnHQ=";
|
||||
};
|
||||
config = {
|
||||
MTD = "y";
|
||||
|
@ -71,9 +71,10 @@
|
||||
cp $blobdir/board.bin $out/ath10k/QCA9887/hw1.0/
|
||||
'';
|
||||
};
|
||||
mac80211 = pkgs.mac80211.override {
|
||||
drivers = ["ath9k" "ath10k_pci"];
|
||||
klibBuild = config.system.outputs.kernel.modulesupport;
|
||||
mac80211 = pkgs.kmodloader.override {
|
||||
targets = ["ath9k" "ath10k_pci"];
|
||||
inherit (config.system.outputs) kernel;
|
||||
dependencies = [ ath10k_cal_data ];
|
||||
};
|
||||
ath10k_cal_data =
|
||||
let
|
||||
@ -132,7 +133,7 @@
|
||||
};
|
||||
wlan5 = link.build {
|
||||
ifname = "wlan1";
|
||||
dependencies = [ mac80211 ath10k_cal_data ];
|
||||
dependencies = [ ath10k_cal_data mac80211 ];
|
||||
};
|
||||
};
|
||||
};
|
||||
@ -152,8 +153,8 @@
|
||||
kernel = {
|
||||
src = pkgs.pkgsBuildBuild.fetchurl {
|
||||
name = "linux.tar.gz";
|
||||
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.71.tar.gz";
|
||||
hash = "sha256-yhO2cXIeIgUxkSZf/4aAsF11uxyh+UUZu6D1h92vCD8=";
|
||||
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.137.tar.gz";
|
||||
hash = "sha256-PkdzUKZ0IpBiWe/RS70J76JKnBFzRblWcKlaIFNxnHQ=";
|
||||
};
|
||||
|
||||
# Mainline linux 5.19 doesn't have device-tree support for
|
||||
@ -161,6 +162,8 @@
|
||||
# OpenWrt kernel patches
|
||||
extraPatchPhase = ''
|
||||
${openwrt.applyPatches.ath79}
|
||||
sed -i.bak -e '\,include <linux/hw_random.h>,a #include <linux/gpio/driver.h>' drivers/net/wireless/ath/ath9k/ath9k.h # context reqd for next patch
|
||||
patch -p1 < ${openwrt.src}/package/kernel/mac80211/patches/ath9k/552-ath9k-ahb_of.patch
|
||||
'';
|
||||
|
||||
config = {
|
||||
@ -211,14 +214,21 @@
|
||||
WATCHDOG = "y";
|
||||
ATH79_WDT = "y"; # watchdog timer
|
||||
|
||||
# this is all copied from nixwrt ath79 config. Clearly not all
|
||||
# of it is device config, some of it is wifi config or
|
||||
# installation method config or ...
|
||||
|
||||
EARLY_PRINTK = "y";
|
||||
|
||||
PRINTK_TIME = "y";
|
||||
};
|
||||
conditionalConfig = {
|
||||
WLAN = {
|
||||
WLAN_VENDOR_ATH = "y";
|
||||
ATH_COMMON = "m";
|
||||
ATH9K = "m";
|
||||
ATH9K_AHB = "y";
|
||||
ATH10K = "m";
|
||||
ATH10K_PCI = "m";
|
||||
ATH10K_DEBUG = "y";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
@ -47,9 +47,9 @@
|
||||
let
|
||||
inherit (pkgs.liminix.networking) interface;
|
||||
inherit (pkgs) openwrt;
|
||||
mac80211 = pkgs.mac80211.override {
|
||||
drivers = ["rt2800soc"];
|
||||
klibBuild = config.system.outputs.kernel.modulesupport;
|
||||
mac80211 = pkgs.kmodloader.override {
|
||||
targets = ["rt2800soc"];
|
||||
inherit (config.system.outputs) kernel;
|
||||
};
|
||||
in {
|
||||
imports = [
|
||||
@ -110,13 +110,11 @@
|
||||
ifname = "eth0.1";
|
||||
primary = eth;
|
||||
vid = "1";
|
||||
dependencies = [swconfig eth];
|
||||
};
|
||||
wan = vlan.build {
|
||||
ifname = "eth0.2";
|
||||
primary = eth;
|
||||
vid = "2";
|
||||
dependencies = [swconfig eth];
|
||||
};
|
||||
wlan = link.build {
|
||||
ifname = "wlan0";
|
||||
@ -126,16 +124,18 @@
|
||||
};
|
||||
boot.tftp = {
|
||||
loadAddress = lim.parseInt "0x00A00000";
|
||||
};
|
||||
appendDTB = true;
|
||||
};
|
||||
|
||||
kernel = {
|
||||
src = pkgs.fetchurl {
|
||||
name = "linux.tar.gz";
|
||||
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.71.tar.gz";
|
||||
hash = "sha256-yhO2cXIeIgUxkSZf/4aAsF11uxyh+UUZu6D1h92vCD8=";
|
||||
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.137.tar.gz";
|
||||
hash = "sha256-PkdzUKZ0IpBiWe/RS70J76JKnBFzRblWcKlaIFNxnHQ=";
|
||||
};
|
||||
extraPatchPhase = ''
|
||||
${openwrt.applyPatches.ramips}
|
||||
${openwrt.applyPatches.rt2x00}
|
||||
'';
|
||||
config = {
|
||||
|
||||
@ -178,6 +178,14 @@
|
||||
} // lib.optionalAttrs (config.system.service ? vlan) {
|
||||
SWCONFIG = "y";
|
||||
};
|
||||
conditionalConfig = {
|
||||
WLAN = {
|
||||
WLAN_VENDOR_RALINK = "y";
|
||||
RT2800SOC = "m";
|
||||
RT2X00 = "m";
|
||||
};
|
||||
};
|
||||
|
||||
};
|
||||
};
|
||||
}
|
||||
|
@ -43,9 +43,9 @@
|
||||
inherit (pkgs.pseudofile) dir symlink;
|
||||
inherit (pkgs) openwrt;
|
||||
|
||||
mac80211 = pkgs.mac80211.override {
|
||||
drivers = ["mt7603e"];
|
||||
klibBuild = config.system.outputs.kernel.modulesupport;
|
||||
mac80211 = pkgs.kmodloader.override {
|
||||
targets = ["mt7603e"];
|
||||
inherit (config.system.outputs) kernel;
|
||||
};
|
||||
wlan_firmware = pkgs.fetchurl {
|
||||
url = "https://github.com/openwrt/mt76/raw/f24b56f935392ca1d35fae5fd6e56ef9deda4aad/firmware/mt7628_e2.bin";
|
||||
@ -97,7 +97,7 @@
|
||||
swconfig dev switch0 vlan 2 set ports '0 6t'
|
||||
swconfig dev switch0 set apply
|
||||
'';
|
||||
down = "swconfig dev switch0 set reset";
|
||||
down = "${pkgs.swconfig}/bin/swconfig dev switch0 set reset";
|
||||
};
|
||||
in rec {
|
||||
eth = link.build { ifname = "eth0"; dependencies = [swconfig]; };
|
||||
@ -122,13 +122,14 @@
|
||||
# 20MB seems to give enough room to uncompress the kernel
|
||||
# without anything getting trodden on. 10MB was too small
|
||||
loadAddress = lim.parseInt "0x1400000";
|
||||
appendDTB = true;
|
||||
};
|
||||
|
||||
kernel = {
|
||||
src = pkgs.fetchurl {
|
||||
name = "linux.tar.gz";
|
||||
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.71.tar.gz";
|
||||
hash = "sha256-yhO2cXIeIgUxkSZf/4aAsF11uxyh+UUZu6D1h92vCD8=";
|
||||
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.137.tar.gz";
|
||||
hash = "sha256-PkdzUKZ0IpBiWe/RS70J76JKnBFzRblWcKlaIFNxnHQ=";
|
||||
};
|
||||
extraPatchPhase = ''
|
||||
${openwrt.applyPatches.ramips}
|
||||
@ -185,6 +186,15 @@
|
||||
RALINK_WDT = "y"; # watchdog
|
||||
MT7621_WDT = "y"; # or it might be this one
|
||||
};
|
||||
conditionalConfig = {
|
||||
WLAN = {
|
||||
WLAN_VENDOR_RALINK = "y";
|
||||
WLAN_VENDOR_MEDIATEK = "y";
|
||||
MT7603E = "m";
|
||||
};
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
}
|
||||
|
442
devices/tp-archer-ax23/default.nix
Normal file
442
devices/tp-archer-ax23/default.nix
Normal file
@ -0,0 +1,442 @@
|
||||
{
|
||||
description = ''
|
||||
TP-Link Archer AX23 / AX1800 Dual Band Wi-Fi 6 Router
|
||||
*****************************************************
|
||||
|
||||
Hardware summary
|
||||
================
|
||||
|
||||
- MediaTek MT7621 (880MHz)
|
||||
- 16MB Flash
|
||||
- 128MB RAM
|
||||
- WLan hardware: Mediatek MT7905, MT7975
|
||||
|
||||
Limitations
|
||||
===========
|
||||
|
||||
Status LEDs do not work yet.
|
||||
|
||||
Uploading an image via tftp doesn't work yet, because the Archer uboot
|
||||
version is so old it doesn't support overriding the DTB from the mboot
|
||||
command. The tftpboot module doesn't support this yet, see
|
||||
https://gti.telent.net/dan/liminix/pulls/5 for the WiP.
|
||||
'';
|
||||
|
||||
system = {
|
||||
crossSystem = {
|
||||
config = "mipsel-unknown-linux-musl";
|
||||
gcc = {
|
||||
abi = "32";
|
||||
# https://openwrt.org/docs/techref/instructionset/mipsel_24kc
|
||||
arch = "24kc";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
module = {pkgs, config, lib, lim, ... }:
|
||||
let firmware = pkgs.stdenv.mkDerivation {
|
||||
name = "wlan-firmware";
|
||||
phases = ["installPhase"];
|
||||
installPhase = ''
|
||||
mkdir $out
|
||||
cp ${pkgs.linux-firmware}/lib/firmware/mediatek/{mt7915,mt7615,mt7622}* $out
|
||||
'';
|
||||
};
|
||||
in {
|
||||
imports = [
|
||||
../../modules/arch/mipsel.nix
|
||||
../../modules/outputs/tftpboot.nix
|
||||
../../modules/outputs/tplink-safeloader.nix
|
||||
];
|
||||
config = {
|
||||
kernel = {
|
||||
src = pkgs.pkgsBuildBuild.fetchurl {
|
||||
name = "linux.tar.gz";
|
||||
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.137.tar.gz";
|
||||
hash = "sha256-PkdzUKZ0IpBiWe/RS70J76JKnBFzRblWcKlaIFNxnHQ=";
|
||||
};
|
||||
extraPatchPhase = ''
|
||||
${pkgs.openwrt.applyPatches.ramips}
|
||||
'';
|
||||
config = {
|
||||
# Initially taken from openwrt's ./target/linux/ramips/mt7621/config-5.15,
|
||||
# then tweaked here and there
|
||||
ARCH_32BIT_OFF_T="y";
|
||||
ARCH_HIBERNATION_POSSIBLE="y";
|
||||
ARCH_KEEP_MEMBLOCK="y";
|
||||
ARCH_MMAP_RND_BITS_MAX="15";
|
||||
ARCH_MMAP_RND_COMPAT_BITS_MAX="15";
|
||||
ARCH_SUSPEND_POSSIBLE="y";
|
||||
AT803X_PHY="y";
|
||||
BLK_MQ_PCI="y";
|
||||
BOARD_SCACHE="y";
|
||||
CEVT_R4K="y";
|
||||
CLKSRC_MIPS_GIC="y";
|
||||
CLK_MT7621="y";
|
||||
CLOCKSOURCE_WATCHDOG="y";
|
||||
CLONE_BACKWARDS="y";
|
||||
CMDLINE_BOOL="y";
|
||||
COMMON_CLK="y";
|
||||
COMPAT_32BIT_TIME="y";
|
||||
CPU_GENERIC_DUMP_TLB="y";
|
||||
CPU_HAS_DIEI="y";
|
||||
CPU_HAS_PREFETCH="y";
|
||||
CPU_HAS_RIXI="y";
|
||||
CPU_HAS_SYNC="y";
|
||||
CPU_LITTLE_ENDIAN="y";
|
||||
CPU_MIPS32="y";
|
||||
CPU_MIPS32_R2="y";
|
||||
CPU_MIPSR2="y";
|
||||
CPU_MIPSR2_IRQ_EI="y";
|
||||
CPU_MIPSR2_IRQ_VI="y";
|
||||
CPU_NEEDS_NO_SMARTMIPS_OR_MICROMIPS="y";
|
||||
CPU_R4K_CACHE_TLB="y";
|
||||
CPU_RMAP="y";
|
||||
CPU_SUPPORTS_32BIT_KERNEL="y";
|
||||
CPU_SUPPORTS_HIGHMEM="y";
|
||||
CPU_SUPPORTS_MSA="y";
|
||||
CRC16="y";
|
||||
CRYPTO_DEFLATE="y";
|
||||
CRYPTO_HASH_INFO="y";
|
||||
CRYPTO_LIB_BLAKE2S_GENERIC="y";
|
||||
CRYPTO_LIB_POLY1305_RSIZE="2";
|
||||
CRYPTO_LZO="y";
|
||||
CRYPTO_ZSTD="y";
|
||||
CSRC_R4K="y";
|
||||
DIMLIB="y";
|
||||
DMA_NONCOHERENT="y";
|
||||
DTB_RT_NONE="y";
|
||||
DTC="y";
|
||||
EARLY_PRINTK="y";
|
||||
FIXED_PHY="y";
|
||||
FWNODE_MDIO="y";
|
||||
FW_LOADER_PAGED_BUF="y";
|
||||
GENERIC_ATOMIC64="y";
|
||||
GENERIC_CLOCKEVENTS="y";
|
||||
GENERIC_CMOS_UPDATE="y";
|
||||
GENERIC_CPU_AUTOPROBE="y";
|
||||
GENERIC_FIND_FIRST_BIT="y";
|
||||
GENERIC_GETTIMEOFDAY="y";
|
||||
GENERIC_IOMAP="y";
|
||||
GENERIC_IRQ_CHIP="y";
|
||||
GENERIC_IRQ_EFFECTIVE_AFF_MASK="y";
|
||||
GENERIC_IRQ_SHOW="y";
|
||||
GENERIC_LIB_ASHLDI3="y";
|
||||
GENERIC_LIB_ASHRDI3="y";
|
||||
GENERIC_LIB_CMPDI2="y";
|
||||
GENERIC_LIB_LSHRDI3="y";
|
||||
GENERIC_LIB_UCMPDI2="y";
|
||||
GENERIC_PCI_IOMAP="y";
|
||||
GENERIC_PHY="y";
|
||||
GENERIC_PINCONF="y";
|
||||
GENERIC_SCHED_CLOCK="y";
|
||||
GENERIC_SMP_IDLE_THREAD="y";
|
||||
GENERIC_TIME_VSYSCALL="y";
|
||||
GLOB="y";
|
||||
GPIOLIB_IRQCHIP="y";
|
||||
GPIO_CDEV="y";
|
||||
GPIO_GENERIC="y";
|
||||
GPIO_MT7621="y";
|
||||
GRO_CELLS="y";
|
||||
HANDLE_DOMAIN_IRQ="y";
|
||||
HARDWARE_WATCHPOINTS="y";
|
||||
HAS_DMA="y";
|
||||
HAS_IOMEM="y";
|
||||
HAS_IOPORT_MAP="y";
|
||||
I2C="y";
|
||||
I2C_ALGOBIT="y";
|
||||
I2C_BOARDINFO="y";
|
||||
I2C_CHARDEV="y";
|
||||
I2C_GPIO="y";
|
||||
I2C_MT7621="y";
|
||||
ICPLUS_PHY="y";
|
||||
IRQCHIP="y";
|
||||
IRQ_DOMAIN="y";
|
||||
IRQ_DOMAIN_HIERARCHY="y";
|
||||
IRQ_FORCED_THREADING="y";
|
||||
IRQ_MIPS_CPU="y";
|
||||
IRQ_WORK="y";
|
||||
LIBFDT="y";
|
||||
LOCK_DEBUGGING_SUPPORT="y";
|
||||
LZO_COMPRESS="y";
|
||||
LZO_DECOMPRESS="y";
|
||||
MDIO_BUS="y";
|
||||
MDIO_DEVICE="y";
|
||||
MDIO_DEVRES="y";
|
||||
MEDIATEK_GE_PHY="y";
|
||||
MEMFD_CREATE="y";
|
||||
MFD_SYSCON="y";
|
||||
MIGRATION="y";
|
||||
MIKROTIK="y";
|
||||
MIKROTIK_RB_SYSFS="y";
|
||||
MIPS="y";
|
||||
MIPS_ASID_BITS="8";
|
||||
MIPS_ASID_SHIFT="0";
|
||||
MIPS_CLOCK_VSYSCALL="y";
|
||||
MIPS_CM="y";
|
||||
MIPS_CPC="y";
|
||||
MIPS_CPS="y";
|
||||
MIPS_CPU_SCACHE="y";
|
||||
MIPS_GIC="y";
|
||||
MIPS_L1_CACHE_SHIFT="5";
|
||||
MIPS_LD_CAN_LINK_VDSO="y";
|
||||
MIPS_MT="y";
|
||||
MIPS_MT_FPAFF="y";
|
||||
MIPS_MT_SMP="y";
|
||||
MIPS_NR_CPU_NR_MAP="4";
|
||||
MIPS_PERF_SHARED_TC_COUNTERS="y";
|
||||
MIPS_SPRAM="y";
|
||||
MODULES_USE_ELF_REL="y";
|
||||
MTD_CMDLINE_PARTS="y";
|
||||
MTD_NAND_CORE="y";
|
||||
MTD_NAND_ECC="y";
|
||||
MTD_NAND_ECC_SW_HAMMING="y";
|
||||
MTD_NAND_MT7621="y";
|
||||
MTD_NAND_MTK_BMT="y";
|
||||
MTD_RAW_NAND="y";
|
||||
MTD_ROUTERBOOT_PARTS="y";
|
||||
MTD_SERCOMM_PARTS="y";
|
||||
MTD_SPI_NOR="y";
|
||||
MTD_SPLIT_FIT_FW="y";
|
||||
MTD_SPLIT_MINOR_FW="y";
|
||||
MTD_SPLIT_SEAMA_FW="y";
|
||||
MTD_SPLIT_TPLINK_FW="y";
|
||||
MTD_SPLIT_TRX_FW="y";
|
||||
MTD_SPLIT_UIMAGE_FW="y";
|
||||
MTD_UBI="y";
|
||||
MTD_UBI_BEB_LIMIT="20";
|
||||
MTD_UBI_BLOCK="y";
|
||||
MTD_UBI_WL_THRESHOLD="4096";
|
||||
MTD_VIRT_CONCAT="y";
|
||||
NEED_DMA_MAP_STATE="y";
|
||||
NET_DEVLINK="y";
|
||||
NET_DSA="y";
|
||||
NET_DSA_MT7530="y";
|
||||
NET_DSA_MT7530_MDIO="y";
|
||||
NET_DSA_TAG_MTK="y";
|
||||
NET_FLOW_LIMIT="y";
|
||||
NET_MEDIATEK_SOC="y";
|
||||
NET_SELFTESTS="y";
|
||||
NET_SWITCHDEV="y";
|
||||
NET_VENDOR_MEDIATEK="y";
|
||||
NO_HZ_COMMON="y";
|
||||
NO_HZ_IDLE="y";
|
||||
NR_CPUS="4";
|
||||
NVMEM="y";
|
||||
OF="y";
|
||||
OF_ADDRESS="y";
|
||||
OF_EARLY_FLATTREE="y";
|
||||
OF_FLATTREE="y";
|
||||
OF_GPIO="y";
|
||||
OF_IRQ="y";
|
||||
OF_KOBJ="y";
|
||||
OF_MDIO="y";
|
||||
PAGE_POOL="y";
|
||||
PAGE_POOL_STATS="y";
|
||||
PCI="y";
|
||||
PCIE_MT7621="y";
|
||||
PCI_DISABLE_COMMON_QUIRKS="y";
|
||||
PCI_DOMAINS="y";
|
||||
PCI_DOMAINS_GENERIC="y";
|
||||
PCI_DRIVERS_GENERIC="y";
|
||||
PCS_MTK_LYNXI="y";
|
||||
PERF_USE_VMALLOC="y";
|
||||
PGTABLE_LEVELS="2";
|
||||
PHYLIB="y";
|
||||
PHYLINK="y";
|
||||
PHY_MT7621_PCI="y";
|
||||
PINCTRL="y";
|
||||
PINCTRL_AW9523="y";
|
||||
PINCTRL_MT7621="y";
|
||||
PINCTRL_RALINK="y";
|
||||
PINCTRL_SX150X="y";
|
||||
POWER_RESET="y";
|
||||
POWER_RESET_GPIO="y";
|
||||
POWER_SUPPLY="y";
|
||||
PTP_1588_CLOCK_OPTIONAL="y";
|
||||
QUEUED_RWLOCKS="y";
|
||||
QUEUED_SPINLOCKS="y";
|
||||
RALINK="y";
|
||||
RATIONAL="y";
|
||||
REGMAP="y";
|
||||
REGMAP_I2C="y";
|
||||
REGMAP_MMIO="y";
|
||||
REGULATOR="y";
|
||||
REGULATOR_FIXED_VOLTAGE="y";
|
||||
RESET_CONTROLLER="y";
|
||||
RFS_ACCEL="y";
|
||||
RPS="y";
|
||||
RTC_CLASS="y";
|
||||
RTC_DRV_BQ32K="y";
|
||||
RTC_DRV_PCF8563="y";
|
||||
RTC_I2C_AND_SPI="y";
|
||||
SCHED_SMT="y";
|
||||
SERIAL_8250="y";
|
||||
SERIAL_8250_CONSOLE="y";
|
||||
SERIAL_8250_NR_UARTS="3";
|
||||
SERIAL_8250_RUNTIME_UARTS="3";
|
||||
SERIAL_MCTRL_GPIO="y";
|
||||
SERIAL_OF_PLATFORM="y";
|
||||
SGL_ALLOC="y";
|
||||
SMP="y";
|
||||
SMP_UP="y";
|
||||
SOCK_RX_QUEUE_MAPPING="y";
|
||||
SOC_BUS="y";
|
||||
SOC_MT7621="y";
|
||||
SPI="y";
|
||||
SPI_MASTER="y";
|
||||
SPI_MEM="y";
|
||||
SPI_MT7621="y";
|
||||
SRCU="y";
|
||||
SWPHY="y";
|
||||
SYNC_R4K="y";
|
||||
SYSCTL_EXCEPTION_TRACE="y";
|
||||
SYS_HAS_CPU_MIPS32_R1="y";
|
||||
SYS_HAS_CPU_MIPS32_R2="y";
|
||||
SYS_HAS_EARLY_PRINTK="y";
|
||||
SYS_SUPPORTS_32BIT_KERNEL="y";
|
||||
SYS_SUPPORTS_ARBIT_HZ="y";
|
||||
SYS_SUPPORTS_HIGHMEM="y";
|
||||
SYS_SUPPORTS_HOTPLUG_CPU="y";
|
||||
SYS_SUPPORTS_LITTLE_ENDIAN="y";
|
||||
SYS_SUPPORTS_MIPS16="y";
|
||||
SYS_SUPPORTS_MIPS_CPS="y";
|
||||
SYS_SUPPORTS_MULTITHREADING="y";
|
||||
SYS_SUPPORTS_SCHED_SMT="y";
|
||||
SYS_SUPPORTS_SMP="y";
|
||||
SYS_SUPPORTS_ZBOOT="y";
|
||||
TARGET_ISA_REV="2";
|
||||
TICK_CPU_ACCOUNTING="y";
|
||||
TIMER_OF="y";
|
||||
TIMER_PROBE="y";
|
||||
TREE_RCU="y";
|
||||
TREE_SRCU="y";
|
||||
UBIFS_FS="y";
|
||||
USB_SUPPORT="y";
|
||||
USE_OF="y";
|
||||
WEAK_ORDERING="y";
|
||||
XPS="y";
|
||||
XXHASH="y";
|
||||
ZLIB_DEFLATE="y";
|
||||
ZLIB_INFLATE="y";
|
||||
ZSTD_COMPRESS="y";
|
||||
ZSTD_DECOMPRESS="y";
|
||||
} // lib.optionalAttrs (config.system.service ? watchdog) {
|
||||
RALINK_WDT = "y"; # watchdog
|
||||
MT7621_WDT = "y"; # or it might be this one
|
||||
};
|
||||
conditionalConfig = {
|
||||
WLAN = {
|
||||
MT7915E = "m";
|
||||
};
|
||||
};
|
||||
};
|
||||
tplink-safeloader.board = "ARCHER-AX23-V1";
|
||||
boot = {
|
||||
commandLine = [ "console=ttyS0,115200" ];
|
||||
tftp = {
|
||||
# Should be a segment of free RAM, where the tftp artifact
|
||||
# can be stored before unpacking it to the 'hardware.loadAddress'
|
||||
# The 'hardware.loadAddress' is 0x80001000, which suggests the
|
||||
# RAM would start at 0x8000000 and (being 128MB) go to
|
||||
# to 0x8800000. Let's put it at the 100MB mark at
|
||||
# 0x8000000+0x0640000=0x86400000
|
||||
loadAddress = lim.parseInt "0x86400000";
|
||||
};
|
||||
};
|
||||
filesystem =
|
||||
let inherit (pkgs.pseudofile) dir symlink;
|
||||
in
|
||||
dir {
|
||||
lib = dir {
|
||||
firmware = dir {
|
||||
mediatek = symlink firmware;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
hardware =
|
||||
let
|
||||
openwrt = pkgs.openwrt;
|
||||
mac80211 = pkgs.kmodloader.override {
|
||||
targets = [
|
||||
"mt7915e"
|
||||
];
|
||||
inherit (config.system.outputs) kernel;
|
||||
};
|
||||
in {
|
||||
# from OEM bootlog (openwrt wiki):
|
||||
# 4 cmdlinepart partitions found on MTD device raspi
|
||||
# Creating 4 MTD partitions on "raspi":
|
||||
# 0x000000000000-0x000000040000 : "uboot"
|
||||
# 0x000000040000-0x000000440000 : "uImage"
|
||||
# 0x000000440000-0x000000ff0000 : "rootfs"
|
||||
# 0x000000ff0000-0x000001000000 : "ART"
|
||||
# from openwrt bootlog (openwrt wiki):
|
||||
# 5 fixed-partitions partitions found on MTD device spi0.0
|
||||
# OF: Bad cell count for /palmbus@1e000000/spi@b00/flash@0/partitions
|
||||
# OF: Bad cell count for /palmbus@1e000000/spi@b00/flash@0/partitions
|
||||
# OF: Bad cell count for /palmbus@1e000000/spi@b00/flash@0/partitions
|
||||
# OF: Bad cell count for /palmbus@1e000000/spi@b00/flash@0/partitions
|
||||
# Creating 5 MTD partitions on "spi0.0":
|
||||
# 0x000000000000-0x000000040000 : "u-boot"
|
||||
# 0x000000040000-0x000000fa0000 : "firmware"
|
||||
# 2 uimage-fw partitions found on MTD device firmware
|
||||
# Creating 2 MTD partitions on "firmware":
|
||||
# 0x000000000000-0x0000002c0000 : "kernel"
|
||||
# 0x0000002c0000-0x000000f60000 : "rootfs"
|
||||
# mtd: setting mtd3 (rootfs) as root device
|
||||
# 1 squashfs-split partitions found on MTD device rootfs
|
||||
# 0x000000640000-0x000000f60000 : "rootfs_data"
|
||||
# 0x000000fa0000-0x000000fb0000 : "config"
|
||||
# 0x000000fb0000-0x000000ff0000 : "tplink"
|
||||
# 0x000000ff0000-0x000001000000 : "radio"
|
||||
flash = {
|
||||
# from the OEM bootlog 'Booting image at bc040000'
|
||||
# (0x40000 from 0xbc000000)
|
||||
address = lim.parseInt "0xbc040000";
|
||||
# 0x000000040000-0x000000fa0000
|
||||
size = lim.parseInt "0xf60000";
|
||||
# TODO: find in /proc/mtd on a running system
|
||||
eraseBlockSize = 65536;
|
||||
};
|
||||
|
||||
# since this is mentioned in the partition table as well?
|
||||
defaultOutput = "tplink-safeloader";
|
||||
# taken from openwrt sysupgrade image:
|
||||
# openwrt-23.05.2-ramips-mt7621-tplink_archer-ax23-v1-squashfs-sysupgrade.bin: u-boot legacy uImage, MIPS OpenWrt Linux-5.15.137, Linux/MIPS, OS Kernel Image (lzma), 2797386 bytes, Tue Nov 14 13:38:11 2023, Load Address: 0X80001000, Entry Point: 0X80001000, Header CRC: 0X19F74C5B, Data CRC: 0XF685563C
|
||||
loadAddress = lim.parseInt "0x80001000";
|
||||
entryPoint = lim.parseInt "0x80001000";
|
||||
rootDevice = "/dev/mtdblock3";
|
||||
dts = {
|
||||
src = "${openwrt.src}/target/linux/ramips/dts/mt7621_tplink_archer-ax23-v1.dts";
|
||||
includes = [
|
||||
"${openwrt.src}/target/linux/ramips/dts"
|
||||
"${config.system.outputs.kernel.modulesupport}/arch/arm64/boot/dts/mediatek/"
|
||||
];
|
||||
};
|
||||
|
||||
networkInterfaces =
|
||||
let
|
||||
inherit (config.system.service.network) link;
|
||||
inherit (config.system.service) bridge;
|
||||
in rec {
|
||||
lan1 = link.build { ifname = "lan1"; };
|
||||
lan2 = link.build { ifname = "lan2"; };
|
||||
lan3 = link.build { ifname = "lan3"; };
|
||||
lan4 = link.build { ifname = "lan4"; };
|
||||
wan = link.build { ifname = "wan"; };
|
||||
|
||||
wlan = link.build {
|
||||
ifname = "wlan0";
|
||||
dependencies = [ mac80211 ];
|
||||
};
|
||||
wlan5 = link.build {
|
||||
ifname = "wlan1";
|
||||
dependencies = [ mac80211 ];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
348
devices/tp-archer-c7-v1/default.nix
Normal file
348
devices/tp-archer-c7-v1/default.nix
Normal file
@ -0,0 +1,348 @@
|
||||
{
|
||||
description = ''
|
||||
TP-Link Archer C7 1.1
|
||||
*********************
|
||||
|
||||
Hardware summary
|
||||
================
|
||||
|
||||
- Qualcomm Atheros QCA9558 ver 1 rev 0 (720MHz, MIPS 74Kc)
|
||||
- 8MB Flash
|
||||
- 128MB RAM
|
||||
- WLan hardware: Qualcomm Atheros QCA9558, Qualcomm Atheros QCA9880-AR1A
|
||||
|
||||
Limitations
|
||||
===========
|
||||
|
||||
5G is not supported on the v1 revision
|
||||
|
||||
ath10k may cause a bootloop, build without ath10k there
|
||||
'';
|
||||
|
||||
system = {
|
||||
crossSystem = {
|
||||
config = "mips-unknown-linux-musl";
|
||||
gcc = {
|
||||
abi = "32";
|
||||
arch = "74kc";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
module = {pkgs, config, lib, lim, ... }:
|
||||
let firmware = pkgs.stdenv.mkDerivation {
|
||||
name = "wlan-firmware";
|
||||
phases = ["installPhase"];
|
||||
installPhase = ''
|
||||
mkdir $out
|
||||
cp -r ${pkgs.linux-firmware}/lib/firmware/ath10k/QCA988X $out
|
||||
'';
|
||||
};
|
||||
in {
|
||||
imports = [
|
||||
../../modules/arch/mips.nix
|
||||
../../modules/outputs/tftpboot.nix
|
||||
../../modules/outputs/jffs2.nix
|
||||
];
|
||||
config = {
|
||||
kernel = {
|
||||
src = pkgs.pkgsBuildBuild.fetchurl {
|
||||
name = "linux.tar.gz";
|
||||
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.137.tar.gz";
|
||||
hash = "sha256-PkdzUKZ0IpBiWe/RS70J76JKnBFzRblWcKlaIFNxnHQ=";
|
||||
};
|
||||
extraPatchPhase = ''
|
||||
${pkgs.openwrt.applyPatches.ath79}
|
||||
'';
|
||||
config = {
|
||||
# Initially taken from openwrt's ./target/linux/ath79/config-5.15,
|
||||
# then tweaked here and there
|
||||
AG71XX="y";
|
||||
AG71XX_DEBUG_FS="y";
|
||||
AR8216_PHY="y";
|
||||
#AR8216_PHY_LEDS="y";
|
||||
ARCH_32BIT_OFF_T="y";
|
||||
ARCH_HIBERNATION_POSSIBLE="y";
|
||||
ARCH_KEEP_MEMBLOCK="y";
|
||||
ARCH_MMAP_RND_BITS_MAX="15";
|
||||
ARCH_MMAP_RND_COMPAT_BITS_MAX="15";
|
||||
ARCH_SUSPEND_POSSIBLE="y";
|
||||
AT803X_PHY="y";
|
||||
ATH79="y";
|
||||
WATCHDOG="y";
|
||||
ATH79_WDT="y";
|
||||
BLK_MQ_PCI="y";
|
||||
CEVT_R4K="y";
|
||||
CLONE_BACKWARDS="y";
|
||||
#CMDLINE="rootfstype=squashfs,jffs2";
|
||||
CMDLINE_BOOL="y";
|
||||
COMMON_CLK="y";
|
||||
COMPAT_32BIT_TIME="y";
|
||||
CPU_BIG_ENDIAN="y";
|
||||
CPU_GENERIC_DUMP_TLB="y";
|
||||
CPU_HAS_DIEI="y";
|
||||
CPU_HAS_PREFETCH="y";
|
||||
CPU_HAS_RIXI="y";
|
||||
CPU_HAS_SYNC="y";
|
||||
CPU_MIPS32="y";
|
||||
CPU_MIPS32_R2="y";
|
||||
CPU_MIPSR2="y";
|
||||
CPU_NEEDS_NO_SMARTMIPS_OR_MICROMIPS="y";
|
||||
CPU_R4K_CACHE_TLB="y";
|
||||
CPU_SUPPORTS_32BIT_KERNEL="y";
|
||||
CPU_SUPPORTS_HIGHMEM="y";
|
||||
CPU_SUPPORTS_MSA="y";
|
||||
#CRYPTO_BLAKE2S="y";
|
||||
CRYPTO_LIB_BLAKE2S_GENERIC="y";
|
||||
CRYPTO_LIB_POLY1305_RSIZE="2";
|
||||
CRYPTO_RNG2="y";
|
||||
CSRC_R4K="y";
|
||||
DMA_NONCOHERENT="y";
|
||||
DTC="y";
|
||||
EARLY_PRINTK="y";
|
||||
FIXED_PHY="y";
|
||||
FWNODE_MDIO="y";
|
||||
FW_LOADER_PAGED_BUF="y";
|
||||
GENERIC_ATOMIC64="y";
|
||||
GENERIC_CLOCKEVENTS="y";
|
||||
GENERIC_CMOS_UPDATE="y";
|
||||
GENERIC_CPU_AUTOPROBE="y";
|
||||
GENERIC_FIND_FIRST_BIT="y";
|
||||
GENERIC_GETTIMEOFDAY="y";
|
||||
GENERIC_IOMAP="y";
|
||||
GENERIC_IRQ_CHIP="y";
|
||||
GENERIC_IRQ_EFFECTIVE_AFF_MASK="y";
|
||||
GENERIC_IRQ_SHOW="y";
|
||||
GENERIC_LIB_ASHLDI3="y";
|
||||
GENERIC_LIB_ASHRDI3="y";
|
||||
GENERIC_LIB_CMPDI2="y";
|
||||
GENERIC_LIB_LSHRDI3="y";
|
||||
GENERIC_LIB_UCMPDI2="y";
|
||||
GENERIC_PCI_IOMAP="y";
|
||||
GENERIC_PHY="y";
|
||||
#GENERIC_PINCONF="y";
|
||||
#GENERIC_PINCTRL_GROUPS="y";
|
||||
#GENERIC_PINMUX_FUNCTIONS="y";
|
||||
GENERIC_SCHED_CLOCK="y";
|
||||
GENERIC_SMP_IDLE_THREAD="y";
|
||||
GENERIC_TIME_VSYSCALL="y";
|
||||
GPIOLIB_IRQCHIP="y";
|
||||
GPIO_74X164="y";
|
||||
GPIO_ATH79="y";
|
||||
GPIO_CDEV="y";
|
||||
GPIO_GENERIC="y";
|
||||
HANDLE_DOMAIN_IRQ="y";
|
||||
HARDWARE_WATCHPOINTS="y";
|
||||
HAS_DMA="y";
|
||||
HAS_IOMEM="y";
|
||||
HAS_IOPORT_MAP="y";
|
||||
HZ_PERIODIC="y";
|
||||
#IMAGE_CMDLINE_HACK="y";
|
||||
#INITRAMFS_SOURCE="";
|
||||
IRQCHIP="y";
|
||||
IRQ_DOMAIN="y";
|
||||
IRQ_FORCED_THREADING="y";
|
||||
IRQ_MIPS_CPU="y";
|
||||
IRQ_WORK="y";
|
||||
#LEDS_GPIO="y";
|
||||
LIBFDT="y";
|
||||
LOCK_DEBUGGING_SUPPORT="y";
|
||||
MDIO_BITBANG="y";
|
||||
MDIO_BUS="y";
|
||||
MDIO_DEVICE="y";
|
||||
MDIO_DEVRES="y";
|
||||
MDIO_GPIO="y";
|
||||
MEMFD_CREATE="y";
|
||||
MFD_SYSCON="y";
|
||||
MIGRATION="y";
|
||||
MIPS="y";
|
||||
MIPS_ASID_BITS="8";
|
||||
MIPS_ASID_SHIFT="0";
|
||||
MIPS_CLOCK_VSYSCALL="y";
|
||||
#MIPS_CMDLINE_FROM_DTB="y";
|
||||
#MIPS_EBPF_JIT="y";
|
||||
MIPS_L1_CACHE_SHIFT="5";
|
||||
MIPS_LD_CAN_LINK_VDSO="y";
|
||||
#MIPS_RAW_APPENDED_DTB="y";
|
||||
MIPS_SPRAM="y";
|
||||
MODULES_USE_ELF_REL="y";
|
||||
MTD_CFI="y";
|
||||
MTD_GEN_PROBE="y";
|
||||
MTD_CFI_ADV_OPTIONS="y";
|
||||
MTD_CFI_GEOMETRY="y";
|
||||
MTD_CMDLINE_PARTS="y";
|
||||
MTD_PARSER_CYBERTAN="y";
|
||||
MTD_PHYSMAP="y";
|
||||
MTD_SPI_NOR="y";
|
||||
MTD_SPLIT_ELF_FW="y";
|
||||
MTD_SPLIT_LZMA_FW="y";
|
||||
MTD_SPLIT_SEAMA_FW="y";
|
||||
MTD_SPLIT_TPLINK_FW="y";
|
||||
MTD_SPLIT_UIMAGE_FW="y";
|
||||
MTD_SPLIT_WRGG_FW="y";
|
||||
MTD_VIRT_CONCAT="y";
|
||||
NEED_DMA_MAP_STATE="y";
|
||||
NEED_PER_CPU_KM="y";
|
||||
NET_SELFTESTS="y";
|
||||
NO_GENERIC_PCI_IOPORT_MAP="y";
|
||||
NVMEM="y";
|
||||
OF="y";
|
||||
OF_ADDRESS="y";
|
||||
OF_EARLY_FLATTREE="y";
|
||||
OF_FLATTREE="y";
|
||||
OF_GPIO="y";
|
||||
OF_IRQ="y";
|
||||
OF_KOBJ="y";
|
||||
OF_MDIO="y";
|
||||
PCI="y";
|
||||
PCI_AR71XX="y";
|
||||
PCI_AR724X="y";
|
||||
PCI_DISABLE_COMMON_QUIRKS="y";
|
||||
PCI_DOMAINS="y";
|
||||
PCI_DRIVERS_LEGACY="y";
|
||||
PERF_USE_VMALLOC="y";
|
||||
PGTABLE_LEVELS="2";
|
||||
PHYLIB="y";
|
||||
PINCTRL="y";
|
||||
PTP_1588_CLOCK_OPTIONAL="y";
|
||||
RATIONAL="y";
|
||||
REGMAP="y";
|
||||
REGMAP_MMIO="y";
|
||||
REGULATOR="y";
|
||||
RESET_ATH79="y";
|
||||
RESET_CONTROLLER="y";
|
||||
SERIAL_8250="y";
|
||||
SERIAL_8250_CONSOLE="y";
|
||||
SERIAL_8250_NR_UARTS="1";
|
||||
SERIAL_8250_RUNTIME_UARTS="1";
|
||||
SERIAL_AR933X="y";
|
||||
SERIAL_AR933X_CONSOLE="y";
|
||||
SERIAL_AR933X_NR_UARTS="2";
|
||||
SERIAL_MCTRL_GPIO="y";
|
||||
SERIAL_OF_PLATFORM="y";
|
||||
SPI="y";
|
||||
SPI_AR934X="y";
|
||||
SPI_ATH79="y";
|
||||
SPI_BITBANG="y";
|
||||
SPI_GPIO="y";
|
||||
SPI_MASTER="y";
|
||||
SPI_MEM="y";
|
||||
SRCU="y";
|
||||
SWCONFIG="y";
|
||||
#SWCONFIG_LEDS="y";
|
||||
SWPHY="y";
|
||||
SYSCTL_EXCEPTION_TRACE="y";
|
||||
SYS_HAS_CPU_MIPS32_R2="y";
|
||||
SYS_HAS_EARLY_PRINTK="y";
|
||||
SYS_SUPPORTS_32BIT_KERNEL="y";
|
||||
SYS_SUPPORTS_ARBIT_HZ="y";
|
||||
SYS_SUPPORTS_BIG_ENDIAN="y";
|
||||
SYS_SUPPORTS_MIPS16="y";
|
||||
SYS_SUPPORTS_ZBOOT="y";
|
||||
SYS_SUPPORTS_ZBOOT_UART_PROM="y";
|
||||
TARGET_ISA_REV="2";
|
||||
TICK_CPU_ACCOUNTING="y";
|
||||
TINY_SRCU="y";
|
||||
USB_SUPPORT="y";
|
||||
USE_OF="y";
|
||||
};
|
||||
conditionalConfig = {
|
||||
WLAN = {
|
||||
#MT7915E = "m";
|
||||
};
|
||||
};
|
||||
};
|
||||
boot = {
|
||||
commandLine = [ "console=ttyS0,115200" ];
|
||||
tftp = {
|
||||
# Should be a segment of free RAM, where the tftp artifact
|
||||
# can be stored before unpacking it to the 'hardware.loadAddress'
|
||||
# The commands in 'printenv' for 'lu', 'lf' and 'lk'
|
||||
# seem to suggest files are trtp'ed to 0x80060000 before
|
||||
# copying them to the flash, so let's try that.
|
||||
loadAddress = lim.parseInt "0x80060000";
|
||||
appendDTB = true;
|
||||
};
|
||||
};
|
||||
filesystem =
|
||||
let inherit (pkgs.pseudofile) dir symlink;
|
||||
in
|
||||
dir {
|
||||
lib = dir {
|
||||
firmware = dir {
|
||||
mediatek = symlink firmware;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
hardware =
|
||||
let
|
||||
openwrt = pkgs.openwrt;
|
||||
mac80211 = pkgs.kmodloader.override {
|
||||
inherit (config.system.outputs) kernel;
|
||||
targets = [ /*TODO "ath9k"*/ ];
|
||||
};
|
||||
in {
|
||||
# from openwrt bootlog
|
||||
# [ 0.896994] 5 tp-link partitions found on MTD device spi0.0
|
||||
# [ 0.902676] Creating 5 MTD partitions on "spi0.0":
|
||||
# [ 0.907544] 0x000000000000-0x000000020000 : "u-boot"
|
||||
# [ 0.913624] 0x000000020000-0x0000001a3cc8 : "kernel"
|
||||
# [ 0.920249] 0x0000001a3cc8-0x0000007f0000 : "rootfs"
|
||||
# [ 0.925932] mtd: device 2 (rootfs) set to be root filesystem
|
||||
# [ 0.931748] 1 squashfs-split partitions found on MTD device rootfs
|
||||
# [ 0.938019] 0x0000003b0000-0x0000007f0000 : "rootfs_data"
|
||||
# [ 0.945224] 0x0000007f0000-0x000000800000 : "art"
|
||||
# [ 0.951066] 0x000000020000-0x0000007f0000 : "firmware"
|
||||
flash = {
|
||||
# from the uboot bootlog 'Booting image at 9f020000'
|
||||
# (0x20000 from 0x9f000000)
|
||||
# also confirmed from default bootcmd in env: "bootm 0x9f020000"
|
||||
address = lim.parseInt "0x9f020000";
|
||||
# 0x000000020000-0x0000007f0000
|
||||
size = lim.parseInt "0x7d0000";
|
||||
# TODO: find in /proc/mtd on a running system
|
||||
eraseBlockSize = 65536;
|
||||
};
|
||||
|
||||
# guessed - might also be mtdimage? or something else?
|
||||
defaultOutput = "uimage";
|
||||
# not found in openwrt sysupgrade image:
|
||||
# openwrt-23.05.2-ath79-generic-tplink_archer-c7-v1-squashfs-sysupgrade.bin: firmware 7500 v1 OpenWrt r23630-842932a63d, 8126464 bytes or less, at 0x200 2329811 bytes , at 0x238ed4 3676624 bytes \012- Squashfs filesystem, little endian, version 4.0, xz compressed, 3676624 bytes, 1352 inodes, blocksize: 262144 bytes, created: Tue Nov 14 13:38:11 2023
|
||||
loadAddress = lim.parseInt "0x80001000";
|
||||
entryPoint = lim.parseInt "0x80001000";
|
||||
# from openwrt bootlog:
|
||||
# [ 0.925932] mtd: device 2 (rootfs) set to be root filesystem
|
||||
rootDevice = "/dev/mtdblock2";
|
||||
dts = {
|
||||
src = "${openwrt.src}/target/linux/ath79/dts/qca9558_tplink_archer-c7-v1.dts";
|
||||
includes = [
|
||||
"${openwrt.src}/target/linux/ath79/dts"
|
||||
#"${config.system.outputs.kernel.modulesupport}/arch/arm64/boot/dts/mediatek/"
|
||||
];
|
||||
};
|
||||
|
||||
networkInterfaces =
|
||||
let
|
||||
inherit (config.system.service.network) link;
|
||||
inherit (config.system.service) bridge;
|
||||
in rec {
|
||||
lan1 = link.build { ifname = "lan1"; };
|
||||
lan2 = link.build { ifname = "lan2"; };
|
||||
lan3 = link.build { ifname = "lan3"; };
|
||||
lan4 = link.build { ifname = "lan4"; };
|
||||
wan = link.build { ifname = "wan"; };
|
||||
|
||||
wlan = link.build {
|
||||
ifname = "wlan0";
|
||||
dependencies = [ mac80211 ];
|
||||
};
|
||||
#wlan5 = link.build {
|
||||
# ifname = "wlan1";
|
||||
# dependencies = [ mac80211 ];
|
||||
#};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
@ -2,6 +2,149 @@
|
||||
description = ''
|
||||
Turris Omnia
|
||||
************
|
||||
|
||||
This is a 32 bit ARMv7 MVEBU device, which is usually shipped with
|
||||
TurrisOS, an OpenWrt-based system. Rather than reformatting the
|
||||
builtin storage, we install Liminix on to the existing btrfs
|
||||
filesystem so that the vendor snapshot/recovery system continues
|
||||
to work (and provides you an easy rollback if you decide you don't
|
||||
like Liminix after all).
|
||||
|
||||
The install process has two stages, and is intended that you
|
||||
should not need to open the device and add a serial console
|
||||
(although it may be handy for visibility, and in case anything
|
||||
goes wrong). First we build a minimal installation/recovery
|
||||
system, then we reboot into that recovery image to prepare the
|
||||
device for the full target install.
|
||||
|
||||
Installation using a USB stick
|
||||
==============================
|
||||
|
||||
First, build the image for the USB stick. Review
|
||||
:file:`examples/recovery.nix` in order to change the default
|
||||
root password (which is ``secret``) and/or the SSH keys, then
|
||||
build it with
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ nix-build -I liminix-config=./examples/recovery.nix \
|
||||
--arg device "import ./devices/turris-omnia" \
|
||||
-A outputs.mbrimage -o mbrimage
|
||||
$ file -L mbrimage
|
||||
mbrimage: DOS/MBR boot sector; partition 1 : ID=0x83, active, start-CHS (0x0,0,5), end-CHS (0x6,130,26), startsector 4, 104602 sectors
|
||||
|
||||
Next, copy the image from your build machine to a USB storage
|
||||
medium using :command:`dd` or your other most favoured file copying
|
||||
tool, which might be a comand something like this:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ dd if=mbrimage of=/dev/path/to/the/usb/stick \
|
||||
bs=1M conv=fdatasync status=progress
|
||||
|
||||
The Omnia's default boot order only checks USB after it has failed
|
||||
to boot from eMMC, which is not ideal for our purpose. Unless you
|
||||
have a serial cable, the easiest way to change this is by booting
|
||||
to TurrisOS and logging in with ssh:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
root@turris:/# fw_printenv boot_targets
|
||||
boot_targets=mmc0 nvme0 scsi0 usb0 pxe dhcp
|
||||
root@turris:/# fw_setenv boot_targets usb0 mmc0
|
||||
root@turris:/# fw_printenv boot_targets
|
||||
boot_targets=usb0 mmc0
|
||||
root@turris:/# reboot -f
|
||||
|
||||
It should now boot into the recovery image. It expects a network
|
||||
cable to be plugged into LAN2 with something on the other end of
|
||||
it that serves DHCP requests. Check your DHCP server logs for a
|
||||
request from a ``liminix-recovery`` host and figure out what IP
|
||||
address was assigned.
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ ssh liminix-recovery.lan
|
||||
|
||||
You should get a "Busybox" banner and a root prompt. Now you can
|
||||
start preparing the device to install Liminix on it. First we'll
|
||||
mount the root filesystem and take a snapshot:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
# mkdir /dest && mount /dev/mmcblk0p1 /dest
|
||||
# schnapps -d /dest create "pre liminix"
|
||||
# schnapps -d /dest list
|
||||
ERROR: not a valid btrfs filesystem: /
|
||||
# | Type | Size | Date | Description
|
||||
------+-----------+-------------+---------------------------+------------------------------------
|
||||
1 | single | 16.00KiB | 1970-01-01 00:11:49 +0000 | pre liminix
|
||||
|
||||
(``not a valid btrfs filesystem: /`` is not a real error)
|
||||
|
||||
then we can remove all the files
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
# rm -r /dest/@/*
|
||||
|
||||
and then it's ready to install the real Liminix system onto. On
|
||||
your build system, create the Liminix configuration you wish to
|
||||
install: here we'll use the ``rotuer`` example.
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
build$ nix-build -I liminix-config=./examples/rotuer.nix \
|
||||
--arg device "import ./devices/turris-omnia" \
|
||||
-A outputs.systemConfiguration
|
||||
|
||||
and then use :command:`min-copy-closure` to copy it to the device.
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
build$ nix-shell --run \
|
||||
"min-copy-closure -r /dest/@ root@liminix-recovery.lan result"
|
||||
|
||||
and activate it
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
build$ ssh root@liminix-recovery.lan \
|
||||
"/dest/@/$(readlink result)/bin/install /dest/@"
|
||||
|
||||
The final steps are performed directly on the device again: add
|
||||
a symlink so U-Boot can find :file:`/boot`, then restore the
|
||||
default boot order and reboot into the new configuration.
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
# cd /dest && ln -s @/boot .
|
||||
# fw_setenv boot_targets "mmc0 nvme0 scsi0 usb0 pxe dhcp"
|
||||
# cd / ; umount /dest
|
||||
# reboot
|
||||
|
||||
|
||||
Installation using a TFTP server and serial console
|
||||
===================================================
|
||||
|
||||
If you have a :ref:`serial` console connection and a TFTP server,
|
||||
and would rather use them than fiddling with USB sticks, the
|
||||
:file:`examples/recovery.nix` configuration also works
|
||||
using the ``tftpboot`` output. So you can do
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
build$ nix-build -I liminix-config=./examples/recovery.nix \
|
||||
--arg device "import ./devices/turris-omnia" \
|
||||
-A outputs.tftpboot
|
||||
|
||||
and then paste the generated :file:`result/boot.scr` into
|
||||
U-Boot, and you will end up with the same system as you would
|
||||
have had after booting from USB. If you don't have a serial
|
||||
console connection you could probably even get clever with
|
||||
elaborate use of :command:`fw_setenv`, but that is left as
|
||||
an exercise for the reader.
|
||||
|
||||
'';
|
||||
|
||||
system = {
|
||||
@ -30,7 +173,6 @@
|
||||
imports = [
|
||||
../../modules/arch/arm.nix
|
||||
../../modules/outputs/tftpboot.nix
|
||||
../../modules/outputs/ext4fs.nix
|
||||
../../modules/outputs/mbrimage.nix
|
||||
../../modules/outputs/extlinux.nix
|
||||
];
|
||||
@ -40,12 +182,10 @@
|
||||
kernel = {
|
||||
src = pkgs.pkgsBuildBuild.fetchurl {
|
||||
name = "linux.tar.gz";
|
||||
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.71.tar.gz";
|
||||
hash = "sha256-yhO2cXIeIgUxkSZf/4aAsF11uxyh+UUZu6D1h92vCD8=";
|
||||
url = "https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.7.4.tar.gz";
|
||||
hash = "sha256-wIrmL0BS63nRwWfm4nw+dRNVPUzGh9M4X7LaHzAn5tU=";
|
||||
};
|
||||
extraPatchPhase = ''
|
||||
${pkgs.openwrt.applyPatches.mvebu}
|
||||
'';
|
||||
version = "6.7.4";
|
||||
config = {
|
||||
PCI = "y";
|
||||
OF = "y";
|
||||
@ -57,11 +197,27 @@
|
||||
ARCH_MULTI_V7= "y";
|
||||
PCI_MVEBU = "y";
|
||||
AHCI_MVEBU = "y";
|
||||
|
||||
RTC_CLASS = "y";
|
||||
RTC_DRV_ARMADA38X = "y"; # this may be useful anyway?
|
||||
|
||||
EXPERT = "y";
|
||||
ALLOW_DEV_COREDUMP = "n";
|
||||
|
||||
|
||||
# dts has a compatible for this but dmesg is not
|
||||
# showing it
|
||||
EEPROM_AT24 = "y"; # atmel,24c64
|
||||
|
||||
I2C = "y";
|
||||
I2C_MUX = "y";
|
||||
I2C_MUX_PCA954x = "y";
|
||||
|
||||
MACH_ARMADA_38X = "y";
|
||||
SMP = "y";
|
||||
# this is disabled for the moment because it relies on a GCC
|
||||
# plugin that requires gmp.h to build, and I can't see right now
|
||||
# how to confgure it to find gmp
|
||||
# this is disabled for the moment because it relies on a
|
||||
# GCC plugin that requires gmp.h to build, and I can't see
|
||||
# right now how to confgure it to find gmp
|
||||
STACKPROTECTOR_PER_TASK = "n";
|
||||
NR_CPUS = "4";
|
||||
VFP = "y";
|
||||
@ -73,7 +229,7 @@
|
||||
PSTORE = "y";
|
||||
PSTORE_RAM = "y";
|
||||
PSTORE_CONSOLE = "y";
|
||||
PSTORE_DEFLATE_COMPRESS = "n";
|
||||
# PSTORE_DEFLATE_COMPRESS = "n";
|
||||
|
||||
BLOCK = "y";
|
||||
MMC="y";
|
||||
@ -110,6 +266,7 @@
|
||||
MVNETA_BM_ENABLE = "y";
|
||||
SRAM = "y"; # mmio-sram is "compatible" for bm_bppi reqd by BM
|
||||
PHY_MVEBU_A38X_COMPHY = "y"; # for eth2
|
||||
MARVELL_PHY = "y";
|
||||
|
||||
MVPP2 = "y";
|
||||
MV_XOR = "y";
|
||||
@ -126,14 +283,27 @@
|
||||
NET_DSA = "y";
|
||||
NET_DSA_MV88E6XXX = "y"; # depends on PTP_1588_CLOCK_OPTIONAL
|
||||
};
|
||||
conditionalConfig = {
|
||||
USB = {
|
||||
USB_XHCI_MVEBU = "y";
|
||||
USB_XHCI_HCD = "y";
|
||||
};
|
||||
WLAN = {
|
||||
WLAN_VENDOR_ATH = "y";
|
||||
ATH_COMMON = "m";
|
||||
ATH9K = "m";
|
||||
ATH9K_PCI = "y";
|
||||
ATH10K = "m";
|
||||
ATH10K_PCI = "m";
|
||||
ATH10K_DEBUG = "y";
|
||||
};
|
||||
};
|
||||
};
|
||||
rootfsType = "ext4";
|
||||
boot = {
|
||||
commandLine = [
|
||||
"console=ttyS0,115200"
|
||||
"pcie_aspm=off" # ath9k pci incompatible with PCIe ASPM
|
||||
];
|
||||
imageFormat = "fit";
|
||||
};
|
||||
filesystem =
|
||||
let
|
||||
@ -142,9 +312,9 @@
|
||||
name = "wlan-firmware";
|
||||
phases = ["installPhase"];
|
||||
installPhase = ''
|
||||
mkdir $out
|
||||
cp -r ${pkgs.linux-firmware}/lib/firmware/ath10k/QCA988X $out
|
||||
'';
|
||||
mkdir $out
|
||||
cp -r ${pkgs.linux-firmware}/lib/firmware/ath10k/QCA988X $out
|
||||
'';
|
||||
};
|
||||
in dir {
|
||||
lib = dir {
|
||||
@ -162,26 +332,26 @@
|
||||
};
|
||||
|
||||
boot.tftp = {
|
||||
loadAddress = lim.parseInt "0x1000000";
|
||||
loadAddress = lim.parseInt "0x1700000";
|
||||
kernelFormat = "zimage";
|
||||
compressRoot = true;
|
||||
};
|
||||
|
||||
hardware = let
|
||||
mac80211 = pkgs.mac80211.override {
|
||||
drivers = ["ath9k_pci" "ath10k_pci"];
|
||||
klibBuild = config.system.outputs.kernel.modulesupport;
|
||||
mac80211 = pkgs.kmodloader.override {
|
||||
inherit (config.system.outputs) kernel;
|
||||
targets = ["ath9k" "ath10k_pci"];
|
||||
};
|
||||
in {
|
||||
defaultOutput = "mtdimage";
|
||||
loadAddress = lim.parseInt "0x00800000"; # "0x00008000";
|
||||
entryPoint = lim.parseInt "0x00800000"; # "0x00008000";
|
||||
rootDevice = "/dev/mtdblock0";
|
||||
rootDevice = "/dev/mmcblk0p1";
|
||||
|
||||
dts = {
|
||||
src = "${config.system.outputs.kernel.modulesupport}/arch/arm/boot/dts/armada-385-turris-omnia.dts";
|
||||
src = "${config.system.outputs.kernel.modulesupport}/arch/arm/boot/dts/marvell/armada-385-turris-omnia.dts";
|
||||
includes = [
|
||||
"${config.system.outputs.kernel.modulesupport}/arch/arm/boot/dts/"
|
||||
"${config.system.outputs.kernel.modulesupport}/arch/arm/boot/dts/marvell/"
|
||||
];
|
||||
};
|
||||
flash.eraseBlockSize = 65536; # only used for tftpboot
|
||||
@ -210,7 +380,7 @@
|
||||
# per
|
||||
# https://www.kernel.org/doc/html/latest/networking/dsa/configuration.html#affinity-of-user-ports-to-cpu-ports
|
||||
# but apparently OpenWrt doesn't either so maybe it's more
|
||||
# complicated than it looks
|
||||
# complicated than it looks.
|
||||
|
||||
wan = link.build {
|
||||
# in armada-38x.dtsi this is eth2. It may be connected to
|
||||
@ -219,9 +389,13 @@
|
||||
ifname = "wan";
|
||||
};
|
||||
|
||||
lan = link.build {
|
||||
ifname = "lan1";
|
||||
};
|
||||
lan0 = link.build { ifname = "lan0"; };
|
||||
lan1 = link.build { ifname = "lan1"; };
|
||||
lan2 = link.build { ifname = "lan2"; };
|
||||
lan3 = link.build { ifname = "lan3"; };
|
||||
lan4 = link.build { ifname = "lan4"; };
|
||||
lan5 = link.build { ifname = "lan5"; };
|
||||
lan = lan0; # maybe we should build a bridge?
|
||||
|
||||
wlan = link.build {
|
||||
ifname = "wlan0";
|
||||
|
155
devices/zyxel-nwa50ax/a_image/mt7621_zyxel_nwa-ax-for-ab.dtsi
Normal file
155
devices/zyxel-nwa50ax/a_image/mt7621_zyxel_nwa-ax-for-ab.dtsi
Normal file
@ -0,0 +1,155 @@
|
||||
#include "mt7621.dtsi"
|
||||
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/input/input.h>
|
||||
|
||||
/ {
|
||||
aliases {
|
||||
label-mac-device = &gmac0;
|
||||
};
|
||||
};
|
||||
|
||||
&nand {
|
||||
status = "okay";
|
||||
|
||||
mediatek,nmbm;
|
||||
mediatek,bmt-max-ratio = <15>;
|
||||
mediatek,bmt-max-reserved-blocks = <64>;
|
||||
mediatek,bmt-remap-range =
|
||||
<0x0 0x980000>,
|
||||
<0x2980000 0x7800000>;
|
||||
|
||||
partitions {
|
||||
compatible = "fixed-partitions";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
partition@0 {
|
||||
label = "u-boot";
|
||||
reg = <0x0 0x80000>;
|
||||
read-only;
|
||||
};
|
||||
|
||||
partition@80000 {
|
||||
label = "u-boot-env";
|
||||
reg = <0x80000 0x80000>;
|
||||
read-only;
|
||||
};
|
||||
|
||||
factory: partition@100000 {
|
||||
label = "factory";
|
||||
reg = <0x100000 0x80000>;
|
||||
read-only;
|
||||
};
|
||||
|
||||
partition@180000 {
|
||||
label = "firmware_a";
|
||||
reg = <0x180000 0x2800000>;
|
||||
|
||||
compatible = "fixed-partitions";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
partition@0 {
|
||||
label = "kernel_a";
|
||||
reg = <0x0 0x800000>;
|
||||
};
|
||||
|
||||
partition@400000 {
|
||||
label = "ubi";
|
||||
reg = <0x800000 0x2000000>;
|
||||
};
|
||||
};
|
||||
|
||||
partition@2980000 {
|
||||
label = "firmware_b";
|
||||
reg = <0x2980000 0x2800000>;
|
||||
|
||||
compatible = "fixed-partitions";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
partition@0 {
|
||||
label = "kernel_b";
|
||||
reg = <0x0 0x800000>;
|
||||
};
|
||||
|
||||
partition@400000 {
|
||||
label = "ubi_b";
|
||||
reg = <0x800000 0x2000000>;
|
||||
};
|
||||
};
|
||||
|
||||
partition@5180000 {
|
||||
label = "rootfs_data";
|
||||
reg = <0x5180000 0x1400000>;
|
||||
};
|
||||
|
||||
partition@6580000 {
|
||||
label = "logs";
|
||||
reg = <0x6580000 0xd00000>;
|
||||
};
|
||||
|
||||
partition@7280000 {
|
||||
label = "vendor-myzyxel";
|
||||
reg = <0x7280000 0x480000>;
|
||||
read-only;
|
||||
};
|
||||
|
||||
partition@7700000 {
|
||||
label = "bootconfig";
|
||||
reg = <0x7700000 0x80000>;
|
||||
};
|
||||
|
||||
mrd: partition@7780000 {
|
||||
label = "mrd";
|
||||
reg = <0x7780000 0x80000>;
|
||||
read-only;
|
||||
|
||||
nvmem-layout {
|
||||
compatible = "fixed-layout";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
macaddr_mrd_1fff8: macaddr@1fff8 {
|
||||
reg = <0x1fff8 0x6>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&pcie {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&pcie1 {
|
||||
wlan_5g: wifi@0,0 {
|
||||
reg = <0x0 0 0 0 0>;
|
||||
compatible = "mediatek,mt76";
|
||||
|
||||
mediatek,mtd-eeprom = <&factory 0x0>;
|
||||
/* MAC-Address set in userspace */
|
||||
};
|
||||
};
|
||||
|
||||
&gmac0 {
|
||||
nvmem-cells = <&macaddr_mrd_1fff8>;
|
||||
nvmem-cell-names = "mac-address";
|
||||
};
|
||||
|
||||
&switch0 {
|
||||
ports {
|
||||
port@4 {
|
||||
status = "okay";
|
||||
label = "lan";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&state_default {
|
||||
gpio {
|
||||
groups = "uart3";
|
||||
function = "gpio";
|
||||
};
|
||||
};
|
155
devices/zyxel-nwa50ax/b_image/mt7621_zyxel_nwa-ax-for-ab.dtsi
Normal file
155
devices/zyxel-nwa50ax/b_image/mt7621_zyxel_nwa-ax-for-ab.dtsi
Normal file
@ -0,0 +1,155 @@
|
||||
#include "mt7621.dtsi"
|
||||
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/input/input.h>
|
||||
|
||||
/ {
|
||||
aliases {
|
||||
label-mac-device = &gmac0;
|
||||
};
|
||||
};
|
||||
|
||||
&nand {
|
||||
status = "okay";
|
||||
|
||||
mediatek,nmbm;
|
||||
mediatek,bmt-max-ratio = <15>;
|
||||
mediatek,bmt-max-reserved-blocks = <64>;
|
||||
mediatek,bmt-remap-range =
|
||||
<0x0 0x980000>,
|
||||
<0x2980000 0x7800000>;
|
||||
|
||||
partitions {
|
||||
compatible = "fixed-partitions";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
partition@0 {
|
||||
label = "u-boot";
|
||||
reg = <0x0 0x80000>;
|
||||
read-only;
|
||||
};
|
||||
|
||||
partition@80000 {
|
||||
label = "u-boot-env";
|
||||
reg = <0x80000 0x80000>;
|
||||
read-only;
|
||||
};
|
||||
|
||||
factory: partition@100000 {
|
||||
label = "factory";
|
||||
reg = <0x100000 0x80000>;
|
||||
read-only;
|
||||
};
|
||||
|
||||
partition@2980000 {
|
||||
label = "firmware_b";
|
||||
reg = <0x2980000 0x2800000>;
|
||||
|
||||
compatible = "fixed-partitions";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
partition@0 {
|
||||
label = "kernel_b";
|
||||
reg = <0x0 0x800000>;
|
||||
};
|
||||
|
||||
partition@400000 {
|
||||
label = "ubi";
|
||||
reg = <0x800000 0x2000000>;
|
||||
};
|
||||
};
|
||||
|
||||
partition@180000 {
|
||||
label = "firmware_a";
|
||||
reg = <0x180000 0x2800000>;
|
||||
|
||||
compatible = "fixed-partitions";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
partition@0 {
|
||||
label = "kernel_a";
|
||||
reg = <0x0 0x800000>;
|
||||
};
|
||||
|
||||
partition@400000 {
|
||||
label = "ubi_a";
|
||||
reg = <0x800000 0x2000000>;
|
||||
};
|
||||
};
|
||||
|
||||
partition@5180000 {
|
||||
label = "rootfs_data";
|
||||
reg = <0x5180000 0x1400000>;
|
||||
};
|
||||
|
||||
partition@6580000 {
|
||||
label = "logs";
|
||||
reg = <0x6580000 0xd00000>;
|
||||
};
|
||||
|
||||
partition@7280000 {
|
||||
label = "vendor-myzyxel";
|
||||
reg = <0x7280000 0x480000>;
|
||||
read-only;
|
||||
};
|
||||
|
||||
partition@7700000 {
|
||||
label = "bootconfig";
|
||||
reg = <0x7700000 0x80000>;
|
||||
};
|
||||
|
||||
mrd: partition@7780000 {
|
||||
label = "mrd";
|
||||
reg = <0x7780000 0x80000>;
|
||||
read-only;
|
||||
|
||||
nvmem-layout {
|
||||
compatible = "fixed-layout";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
macaddr_mrd_1fff8: macaddr@1fff8 {
|
||||
reg = <0x1fff8 0x6>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&pcie {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&pcie1 {
|
||||
wlan_5g: wifi@0,0 {
|
||||
reg = <0x0 0 0 0 0>;
|
||||
compatible = "mediatek,mt76";
|
||||
|
||||
mediatek,mtd-eeprom = <&factory 0x0>;
|
||||
/* MAC-Address set in userspace */
|
||||
};
|
||||
};
|
||||
|
||||
&gmac0 {
|
||||
nvmem-cells = <&macaddr_mrd_1fff8>;
|
||||
nvmem-cell-names = "mac-address";
|
||||
};
|
||||
|
||||
&switch0 {
|
||||
ports {
|
||||
port@4 {
|
||||
status = "okay";
|
||||
label = "lan";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&state_default {
|
||||
gpio {
|
||||
groups = "uart3";
|
||||
function = "gpio";
|
||||
};
|
||||
};
|
367
devices/zyxel-nwa50ax/default.nix
Normal file
367
devices/zyxel-nwa50ax/default.nix
Normal file
@ -0,0 +1,367 @@
|
||||
{
|
||||
system = {
|
||||
crossSystem = {
|
||||
config = "mipsel-unknown-linux-musl";
|
||||
gcc = {
|
||||
abi = "32";
|
||||
arch = "mips32"; # mips32r2?
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
description = ''
|
||||
Zyxel NWA50AX
|
||||
********************
|
||||
|
||||
Zyxel NWA50AX is quite close to the GL-MT300N-v2 "Mango" device, but it is based on the MT7621
|
||||
chipset instead of the MT7628.
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
This device is pretty, but, due to its A/B capabilities, can be a bit hard
|
||||
to use completely.
|
||||
|
||||
The stock vendor firmware is a downstream fork of U-Boot: <https://github.com/RaitoBezarius/uboot-nwa50ax>
|
||||
with restricted boot commands. Fortunately, OpenWrt folks figured out trivial command injections,
|
||||
so you can use most of the OpenWrt commands without trouble by just command injecting
|
||||
atns, atna or atnf, e.g. atns "; $real_command".
|
||||
|
||||
From factory web UI, you can upload the result of the zyxel-nwa-fit output.
|
||||
From another operating system, you need to `dumpimage -T flat_dt -p 0 $zyxel-nwa-fit -o firmware.bin`,
|
||||
`flash_erase $(mtd partition of the target partition firmware or zy_firmware) 0 0`, then you complete by
|
||||
`nandwrite -p $(mtd partition of the target partition firmware or zy_firmware) firmware.bin`.
|
||||
|
||||
How to put the firmware.bin on the machine is left to you as an exercise, e.g. SSH, TFTP, whatever.
|
||||
|
||||
From serial, you have two choices:
|
||||
|
||||
- Flash this system via U-Boot:
|
||||
same reasoning as from an existing Linux system, two choices:
|
||||
- ymodem the binary, perform the write manually, you can inspire yourself
|
||||
from the `script` contained in the vendor firmware, those are just a FIT containing a script.
|
||||
- prepare a FIT containing a script executing your commands, tftpboot this.
|
||||
|
||||
- boot from an existing Liminix system, e.g. TFTPBOOT image.
|
||||
- boot from an OpenWrt system, i.e. follow OpenWrt steps.
|
||||
|
||||
Once you are in a Linux system, understand that this device has A/B boot.
|
||||
|
||||
OpenWrt provides you with `zyxel-bootconfig` to set/unset the image status and choice.
|
||||
|
||||
The kernel is booted with `bootImage=<number>` which tells you which slot are you on.
|
||||
|
||||
You should find yourself with 10ish MTD partitions, the most interesting ones are two:
|
||||
|
||||
- firmware: 40MB
|
||||
- firmware_1: 40MB
|
||||
|
||||
In the current setup, they are split further into kernel (8MB) and ubi (32MB).
|
||||
|
||||
Once you are done with first installation, note that if you want to use the A/B feature,
|
||||
you need to write a _secondary_ image on the slot B. There is no proper flashing code
|
||||
that will set the being-updated slot to `new` and boot on it to verify if it's working.
|
||||
This is a WIP.
|
||||
|
||||
Upgrading your system can be achieved via:
|
||||
|
||||
- `liminix-rebuild` for the userspace.
|
||||
- `flash_erase` + `nandwrite` for the kernelspace to the other slot than the one you are booted on,
|
||||
note that you can just nandwrite the mtd partition corresponding to the *kernel* and not the whole firmware.
|
||||
|
||||
If you soft-bricked your AP, i.e. you cannot boot anything in U-Boot, no worries, just plug the serial console,
|
||||
prepare a TFTP server (via `tufted` for example), download vendor firmware, set up `atns`, `atnf`, etc. and run `atnz`.
|
||||
|
||||
This will reflash everything back to normal via TFTP.
|
||||
|
||||
If you hard-bricked your AP, i.e. U-Boot is telling you to transfer a valid bootloader via ymodem, just extract
|
||||
a U-Boot from the vendor OS, send it via ymodem and use the previous operations to perform a full flash this time
|
||||
of all partitions.
|
||||
|
||||
Note that if you erased your MRD partition, you lost your serial and MAC address. There's no way to recover the original one
|
||||
except by reading the physical label on your… device!
|
||||
|
||||
If you super-hard-bricked your AP, i.e. no output on serial console, congratulations, you reached one of the rare state
|
||||
of this device. You need an external NAND flasher to repair it and write the first stage from Mediatek to continue the previous
|
||||
recovery operations.
|
||||
|
||||
Development TODO list:
|
||||
|
||||
- Better support for upgrade automation w.r.t. to A/B, e.g. automagic scripts.
|
||||
- Mount the logs partition, mount / as overlayfs of firmware ? rootfs and rootfs_data for extended data.
|
||||
- Jitter-based entropy injection? Device can be slow to initialize its CRNG and hostapd will reject few clients at the start because of that.
|
||||
- Defaults for hostapd based on MT7915 capabilities? See the example for one possible list.
|
||||
- Remove primary/secondary hack and put it in preinit.
|
||||
- Offer ways to reflash the *bootloader* itself to support direct boot via UBI and kernel upgrades via filesystem rewrite.
|
||||
|
||||
Vendor web page: https://www.zyxel.com/fr/fr/products/wireless/ax1800-wifi-6-dual-radio-nebulaflex-access-point-nwa50ax
|
||||
|
||||
OpenWrt web page: https://openwrt.org/inbox/toh/zyxel/nwa50ax
|
||||
OpenWrt tech data: https://openwrt.org/toh/hwdata/zyxel/zyxel_nwa50ax
|
||||
|
||||
'';
|
||||
|
||||
module = { pkgs, config, lib, lim, ...}:
|
||||
let
|
||||
inherit (pkgs.liminix.networking) interface;
|
||||
inherit (pkgs.liminix.services) oneshot;
|
||||
inherit (pkgs.pseudofile) dir symlink;
|
||||
inherit (pkgs) openwrt;
|
||||
|
||||
mac80211 = pkgs.mac80211.override {
|
||||
drivers = [ "mt7915e" ];
|
||||
klibBuild = config.system.outputs.kernel.modulesupport;
|
||||
};
|
||||
# v204520220929
|
||||
wlan_firmware = pkgs.fetchurl {
|
||||
url = "https://github.com/openwrt/mt76/raw/1b88dd07f153b202e57fe29734806744ed006b0e/firmware/mt7915_wa.bin";
|
||||
hash = "sha256-wooyefzb0i8640+lwq3vNhcBXRFCtGuo+jiL7afZaKA=";
|
||||
};
|
||||
wlan_firmware' = pkgs.fetchurl {
|
||||
url = "https://github.com/openwrt/mt76/raw/1b88dd07f153b202e57fe29734806744ed006b0e/firmware/mt7915_wm.bin";
|
||||
hash = "sha256-k62nQewRuKjBLd5R3RxU4F74YKnQx5zr6gqMMImqVQw=";
|
||||
};
|
||||
wlan_firmware'' = pkgs.fetchurl {
|
||||
url = "https://github.com/openwrt/mt76/raw/1b88dd07f153b202e57fe29734806744ed006b0e/firmware/mt7915_rom_patch.bin";
|
||||
hash = "sha256-ifriAjWzFACrxVWCANZpUaEZgB/0pdbhnTVQytx6ddg=";
|
||||
};
|
||||
in {
|
||||
imports = [
|
||||
# We include it to ensure the bridge functionality
|
||||
# is available on the target kernel.
|
||||
../../modules/bridge
|
||||
../../modules/arch/mipsel.nix
|
||||
../../modules/outputs/tftpboot.nix
|
||||
../../modules/outputs/zyxel-nwa-fit.nix
|
||||
../../modules/zyxel-dual-image
|
||||
];
|
||||
|
||||
filesystem = dir {
|
||||
lib = dir {
|
||||
firmware = dir {
|
||||
mediatek = dir {
|
||||
"mt7915_wa.bin" = symlink wlan_firmware;
|
||||
"mt7915_wm.bin" = symlink wlan_firmware';
|
||||
"mt7915_rom_patch.bin" = symlink wlan_firmware'';
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
rootfsType = "ubifs";
|
||||
hardware = {
|
||||
# Taken from OpenWRT
|
||||
# root@OpenWrt:/# ubinfo /dev/ubi0
|
||||
# ubi0
|
||||
# Volumes count: 2
|
||||
# Logical eraseblock size: 126976 bytes, 124.0 KiB
|
||||
# Total amount of logical eraseblocks: 256 (32505856 bytes, 31.0 MiB)
|
||||
# Amount of available logical eraseblocks: 0 (0 bytes)
|
||||
# Maximum count of volumes 128
|
||||
# Count of bad physical eraseblocks: 0
|
||||
# Count of reserved physical eraseblocks: 19
|
||||
# Current maximum erase counter value: 2
|
||||
# Minimum input/output unit size: 2048 bytes
|
||||
# Character device major/minor: 250:0
|
||||
# Present volumes: 0, 1
|
||||
ubi = {
|
||||
minIOSize = "2048";
|
||||
logicalEraseBlockSize = "126976";
|
||||
physicalEraseBlockSize = "128KiB";
|
||||
maxLEBcount = "256";
|
||||
};
|
||||
|
||||
# This is a FIT containing a kernel padded and
|
||||
# a UBI volume rootfs.
|
||||
defaultOutput = "zyxel-nwa-fit";
|
||||
|
||||
loadAddress = lim.parseInt "0x80001000";
|
||||
entryPoint = lim.parseInt "0x80001000";
|
||||
# Aligned on 2kb.
|
||||
alignment = 2048;
|
||||
|
||||
rootDevice = "ubi:rootfs";
|
||||
|
||||
dts = {
|
||||
# Actually, this is not what we want.
|
||||
# This DTS is insufficient.
|
||||
src = ./mt7621_zyxel_nwa50ax.dtsi;
|
||||
includes = [
|
||||
# Here's one weird trick to make `ubi` detection
|
||||
# out of the box.
|
||||
# We will write ubi on /dev/firmware_a:rootfs location
|
||||
# and same for /dev/firmware_b:rootfs.
|
||||
# How do we distinguish both?
|
||||
# We can just use the DTS to point ubi at A or B.
|
||||
# This, unfortunately, means that we have "two images".
|
||||
# But they are really just 1 image with 2 different DTS.
|
||||
# TODO: improve this hack in preinit?
|
||||
(if config.boot.imageType == "primary" then "${./a_image}" else "${./b_image}")
|
||||
"${openwrt.src}/target/linux/ramips/dts"
|
||||
];
|
||||
};
|
||||
networkInterfaces =
|
||||
let
|
||||
inherit (config.system.service.network) link;
|
||||
in {
|
||||
eth = link.build { ifname = "eth0"; };
|
||||
lan = link.build { ifname = "lan"; };
|
||||
wlan0 = link.build {
|
||||
ifname = "wlan0";
|
||||
dependencies = [ mac80211 ];
|
||||
};
|
||||
wlan1 = link.build {
|
||||
ifname = "wlan1";
|
||||
dependencies = [ mac80211 ];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
boot = {
|
||||
# Critical because NWA50AX will extend your cmdline with the image number booted.
|
||||
# and some bootloader version.
|
||||
# You don't want to find yourself being overridden.
|
||||
commandLineDtbNode = "bootargs-override";
|
||||
|
||||
imageFormat = "fit";
|
||||
tftp = {
|
||||
# 5MB is nice.
|
||||
freeSpaceBytes = 5 * 1024 * 1024;
|
||||
loadAddress = lim.parseInt "0x2000000";
|
||||
};
|
||||
};
|
||||
|
||||
# Dual image management service in userspace.
|
||||
services.zyxel-dual-image = config.boot.zyxel-dual-image.build {
|
||||
ensureActiveImage = "primary";
|
||||
# TODO: use mtd names rather…
|
||||
# primary and secondary are always /dev/mtd3 by virtue of the
|
||||
# dtb being not too wrong…
|
||||
# TODO: remove this hack.
|
||||
primaryMtdPartition = "/dev/mtd3";
|
||||
secondaryMtdPartition = "/dev/mtd3";
|
||||
bootConfigurationMtdPartition = "/dev/mtd12";
|
||||
};
|
||||
|
||||
# DEVICE_VENDOR := ZyXEL
|
||||
# KERNEL_SIZE := 8192k
|
||||
# DEVICE_PACKAGES := kmod-mt7915-firmware zyxel-bootconfig
|
||||
# KERNEL := kernel-bin | lzma | fit lzma $$(KDIR)/image-$$(firstword $$(DEVICE_DTS)).dtb
|
||||
# IMAGES += factory.bin ramboot-factory.bin
|
||||
# IMAGE/factory.bin := append-kernel | pad-to $$(KERNEL_SIZE) | append-ubi | zyxel-nwa-fit
|
||||
# IMAGE/ramboot-factory.bin := append-kernel | pad-to $$(KERNEL_SIZE) | append-ubi
|
||||
|
||||
kernel = {
|
||||
src = pkgs.fetchurl {
|
||||
name = "linux.tar.gz";
|
||||
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.137.tar.gz";
|
||||
hash = "sha256-PkdzUKZ0IpBiWe/RS70J76JKnBFzRblWcKlaIFNxnHQ=";
|
||||
};
|
||||
extraPatchPhase = ''
|
||||
${openwrt.applyPatches.ramips}
|
||||
|
||||
'';
|
||||
config = {
|
||||
|
||||
RALINK = "y";
|
||||
PCI = "y";
|
||||
PHY_MT7621_PCI = "y";
|
||||
PCIE_MT7621 = "y";
|
||||
SOC_MT7621 = "y";
|
||||
CLK_MT7621 = "y";
|
||||
CLOCKSOURCE_WATCHDOG = "y";
|
||||
|
||||
SERIAL_8250_CONSOLE = "y";
|
||||
SERIAL_8250 = "y";
|
||||
SERIAL_CORE_CONSOLE = "y";
|
||||
SERIAL_OF_PLATFORM = "y";
|
||||
SERIAL_8250_NR_UARTS = "3";
|
||||
SERIAL_8250_RUNTIME_UARTS = "3";
|
||||
SERIAL_MCTRL_GPIO = "y";
|
||||
|
||||
CONSOLE_LOGLEVEL_DEFAULT = "8";
|
||||
CONSOLE_LOGLEVEL_QUIET = "4";
|
||||
|
||||
# MTD_UBI_BEB_LIMIT = "20";
|
||||
# MTD_UBI_WL_THRESHOLD = "4096";
|
||||
|
||||
MTD = "y";
|
||||
MTD_BLOCK = "y"; # fix undefined ref to register_mtd_blktrans_dev
|
||||
MTD_RAW_NAND = "y";
|
||||
MTD_NAND_MT7621 = "y";
|
||||
MTD_NAND_MTK_BMT = "y"; # Bad-block Management Table
|
||||
MTD_NAND_ECC_SW_HAMMING= "y";
|
||||
MTD_SPI_NAND= "y";
|
||||
MTD_OF_PARTS = "y";
|
||||
MTD_NAND_CORE= "y";
|
||||
MTD_SPLIT_FIRMWARE= "y";
|
||||
MTD_SPLIT_FIT_FW= "y";
|
||||
|
||||
PINCTRL = "y";
|
||||
PINCTRL_MT7621 = "y";
|
||||
|
||||
I2C = "y";
|
||||
I2C_MT7621 = "y";
|
||||
|
||||
SPI = "y";
|
||||
MTD_SPI_NOR = "y";
|
||||
SPI_MT7621 = "y";
|
||||
SPI_MASTER = "y";
|
||||
SPI_MEM = "y";
|
||||
|
||||
REGULATOR = "y";
|
||||
REGULATOR_FIXED_VOLTAGE = "y";
|
||||
RESET_CONTROLLER = "y";
|
||||
POWER_RESET = "y";
|
||||
POWER_RESET_GPIO = "y";
|
||||
POWER_SUPPLY = "y";
|
||||
LED_TRIGGER_PHY = "y";
|
||||
|
||||
PCI_DISABLE_COMMON_QUIRKS = "y";
|
||||
PCI_DOMAINS = "y";
|
||||
PCI_DOMAINS_GENERIC = "y";
|
||||
PCI_DRIVERS_GENERIC = "y";
|
||||
PCS_MTK_LYNXI = "y";
|
||||
|
||||
SOC_BUS = "y";
|
||||
|
||||
NET = "y";
|
||||
ETHERNET = "y";
|
||||
WLAN = "y";
|
||||
|
||||
PHYLIB = "y";
|
||||
AT803X_PHY = "y";
|
||||
FIXED_PHY = "y";
|
||||
GENERIC_PHY = "y";
|
||||
NET_DSA = "y";
|
||||
NET_DSA_MT7530 = "y";
|
||||
NET_DSA_MT7530_MDIO = "y";
|
||||
NET_DSA_TAG_MTK = "y";
|
||||
NET_MEDIATEK_SOC = "y";
|
||||
NET_SWITCHDEV = "y";
|
||||
NET_VENDOR_MEDIATEK = "y";
|
||||
|
||||
SWPHY = "y";
|
||||
|
||||
GPIOLIB = "y";
|
||||
GPIO_MT7621 = "y";
|
||||
OF_GPIO = "y";
|
||||
|
||||
EARLY_PRINTK = "y";
|
||||
|
||||
NEW_LEDS = "y";
|
||||
LEDS_TRIGGERS = "y";
|
||||
LEDS_CLASS = "y"; # required by rt2x00lib
|
||||
LEDS_CLASS_MULTICOLOR = "y";
|
||||
LEDS_BRIGHTNESS_HW_CHANGED = "y";
|
||||
|
||||
PRINTK_TIME = "y";
|
||||
} // lib.optionalAttrs (config.system.service ? vlan) {
|
||||
SWCONFIG = "y";
|
||||
} // lib.optionalAttrs (config.system.service ? watchdog) {
|
||||
RALINK_WDT = "y"; # watchdog
|
||||
MT7621_WDT = "y"; # or it might be this one
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
56
devices/zyxel-nwa50ax/mt7621_zyxel_nwa50ax.dtsi
Normal file
56
devices/zyxel-nwa50ax/mt7621_zyxel_nwa50ax.dtsi
Normal file
@ -0,0 +1,56 @@
|
||||
#include "mt7621_zyxel_nwa-ax-for-ab.dtsi"
|
||||
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/input/input.h>
|
||||
|
||||
/ {
|
||||
compatible = "zyxel,nwa50ax", "mediatek,mt7621-soc";
|
||||
model = "ZyXEL NWA50AX";
|
||||
|
||||
aliases {
|
||||
led-boot = &led_system_green;
|
||||
led-failsafe = &led_system_red;
|
||||
led-running = &led_system_green;
|
||||
led-upgrade = &led_system_red;
|
||||
};
|
||||
|
||||
leds {
|
||||
compatible = "gpio-leds";
|
||||
|
||||
led_system_red: system_red {
|
||||
label = "red:system";
|
||||
gpios = <&gpio 6 GPIO_ACTIVE_HIGH>;
|
||||
};
|
||||
|
||||
led_system_green: system_green {
|
||||
label = "green:system";
|
||||
gpios = <&gpio 7 GPIO_ACTIVE_HIGH>;
|
||||
};
|
||||
|
||||
system_blue {
|
||||
label = "blue:system";
|
||||
gpios = <&gpio 8 GPIO_ACTIVE_HIGH>;
|
||||
};
|
||||
};
|
||||
|
||||
keys {
|
||||
compatible = "gpio-keys";
|
||||
|
||||
reset {
|
||||
label = "reset";
|
||||
gpios = <&gpio 30 GPIO_ACTIVE_LOW>;
|
||||
linux,code = <KEY_RESTART>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
ðernet {
|
||||
pinctrl-0 = <&mdio_pins>, <&rgmii1_pins>;
|
||||
};
|
||||
|
||||
&state_default {
|
||||
gpio {
|
||||
groups = "uart3", "rgmii2";
|
||||
function = "gpio";
|
||||
};
|
||||
};
|
@ -12,9 +12,13 @@ BUILDDIR = _build
|
||||
help:
|
||||
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
|
||||
hardware.rst: hardware.nix
|
||||
@rm -f hardware.rst || true
|
||||
@cp $$(nix-build hardware.nix) hardware.rst
|
||||
|
||||
.PHONY: help Makefile
|
||||
|
||||
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||
%: Makefile
|
||||
html: Makefile
|
||||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
|
@ -24,6 +24,15 @@ writeText "hwdoc" ''
|
||||
Supported hardware
|
||||
##################
|
||||
|
||||
For development, the `GL.iNet GL-MT300A <https://www.gl-inet.com/products/gl-mt300a/>`_
|
||||
is an attractive choice as it has a builtin "debrick" procedure in the
|
||||
boot monitor and is also comparatively simple to
|
||||
attach serial cables to (soldering not required), so it
|
||||
is lower-risk than some devices.
|
||||
|
||||
For a more powerful device, something with an ath10k would be the safe bet,
|
||||
or the Linksys E8450 which seems popular in the openwrt community.
|
||||
|
||||
${lib.concatStringsSep "\n\n" texts}
|
||||
|
||||
''
|
||||
|
@ -138,6 +138,8 @@ unbrick if necessary.
|
||||
work here, but you accept the slightly greater bricking
|
||||
risk if it doesn't.
|
||||
|
||||
See :doc:`hardware` for device support status.
|
||||
|
||||
You may want to read and inwardly digest the Develoment Manual section
|
||||
:ref:`serial` when you start working with Liminix on real hardware. You
|
||||
won't *need* serial access for this example, assuming it works, but it
|
||||
|
@ -28,34 +28,12 @@ in rec {
|
||||
../modules/network
|
||||
../modules/vlan
|
||||
../modules/ssh
|
||||
../modules/usb.nix
|
||||
../modules/watchdog
|
||||
../modules/mount
|
||||
];
|
||||
hostname = "arhcive";
|
||||
|
||||
kernel = {
|
||||
config = {
|
||||
USB = "y";
|
||||
USB_EHCI_HCD = "y";
|
||||
USB_EHCI_HCD_PLATFORM = "y";
|
||||
USB_OHCI_HCD = "y";
|
||||
USB_OHCI_HCD_PLATFORM = "y";
|
||||
USB_SUPPORT = "y";
|
||||
USB_COMMON = "y";
|
||||
USB_STORAGE = "y";
|
||||
USB_STORAGE_DEBUG = "n";
|
||||
USB_UAS = "y";
|
||||
USB_ANNOUNCE_NEW_DEVICES = "y";
|
||||
SCSI = "y";
|
||||
BLK_DEV_SD = "y";
|
||||
USB_PRINTER = "y";
|
||||
MSDOS_PARTITION = "y";
|
||||
EFI_PARTITION = "y";
|
||||
EXT4_FS = "y";
|
||||
EXT4_USE_FOR_EXT2 = "y";
|
||||
FS_ENCRYPTION = "y";
|
||||
};
|
||||
};
|
||||
|
||||
services.dhcpc =
|
||||
let iface = config.hardware.networkInterfaces.lan;
|
||||
@ -105,7 +83,7 @@ in rec {
|
||||
};
|
||||
|
||||
services.mount_external_disk = svc.mount.build {
|
||||
device = "LABEL=backup-disk";
|
||||
partlabel = "backup-disk";
|
||||
mountpoint = "/srv";
|
||||
fstype = "ext4";
|
||||
};
|
||||
@ -145,7 +123,7 @@ in rec {
|
||||
};
|
||||
|
||||
users.root = {
|
||||
passwd = lib.mkForce secrets.root_password;
|
||||
passwd = lib.mkForce secrets.root.passwd;
|
||||
# openssh.authorizedKeys.keys = [
|
||||
# (builtins.readFile "/home/dan/.ssh/id_rsa.pub")
|
||||
# ];
|
||||
@ -159,5 +137,17 @@ in rec {
|
||||
gid=500; usernames = ["backup"];
|
||||
};
|
||||
|
||||
defaultProfile.packages = with pkgs; [e2fsprogs strace tcpdump ];
|
||||
defaultProfile.packages = with pkgs; [
|
||||
e2fsprogs
|
||||
mtdutils
|
||||
(levitate.override {
|
||||
config = {
|
||||
services = {
|
||||
inherit (config.services) dhcpc sshd watchdog;
|
||||
};
|
||||
defaultProfile.packages = [ mtdutils ];
|
||||
users.root.openssh.authorizedKeys.keys = secrets.root.keys;
|
||||
};
|
||||
})
|
||||
];
|
||||
}
|
||||
|
@ -158,7 +158,6 @@ in rec {
|
||||
};
|
||||
|
||||
services.firewall = svc.firewall.build {
|
||||
ruleset = import ./demo-firewall.nix;
|
||||
};
|
||||
|
||||
services.packet_forwarding = svc.network.forward.build { };
|
||||
|
@ -8,12 +8,10 @@
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
modulesPath,
|
||||
...
|
||||
}: let
|
||||
secrets = import ./extneder-secrets.nix;
|
||||
inherit (pkgs.liminix.services) oneshot longrun bundle target;
|
||||
inherit (pkgs.pseudofile) dir symlink;
|
||||
inherit (pkgs) dropbear ifwait serviceFns;
|
||||
svc = config.system.service;
|
||||
in rec {
|
||||
boot = {
|
||||
@ -24,113 +22,32 @@ in rec {
|
||||
};
|
||||
|
||||
imports = [
|
||||
../modules/wlan.nix
|
||||
../modules/vlan
|
||||
../modules/network
|
||||
../modules/hostapd
|
||||
../modules/bridge
|
||||
../modules/ssh
|
||||
"${modulesPath}/profiles/wap.nix"
|
||||
"${modulesPath}/vlan"
|
||||
"${modulesPath}/ssh"
|
||||
];
|
||||
|
||||
hostname = "extneder";
|
||||
|
||||
kernel = {
|
||||
config = {
|
||||
|
||||
NETFILTER_XT_MATCH_CONNTRACK = "y";
|
||||
|
||||
IP6_NF_IPTABLES = "y"; # do we still need these
|
||||
IP_NF_IPTABLES = "y"; # if using nftables directly
|
||||
|
||||
# these are copied from rotuer and need review.
|
||||
# we're not running a firewall, so why do we need
|
||||
# nftables config?
|
||||
IP_NF_NAT = "y";
|
||||
IP_NF_TARGET_MASQUERADE = "y";
|
||||
NETFILTER = "y";
|
||||
NETFILTER_ADVANCED = "y";
|
||||
NETFILTER_XTABLES = "y";
|
||||
|
||||
NFT_COMPAT = "y";
|
||||
NFT_CT = "y";
|
||||
NFT_LOG = "y";
|
||||
NFT_MASQ = "y";
|
||||
NFT_NAT = "y";
|
||||
NFT_REJECT = "y";
|
||||
NFT_REJECT_INET = "y";
|
||||
|
||||
NF_CONNTRACK = "y";
|
||||
NF_NAT = "y";
|
||||
NF_NAT_MASQUERADE = "y";
|
||||
NF_TABLES = "y";
|
||||
NF_TABLES_INET = "y";
|
||||
NF_TABLES_IPV4 = "y";
|
||||
NF_TABLES_IPV6 = "y";
|
||||
};
|
||||
};
|
||||
|
||||
services.hostap = svc.hostapd.build {
|
||||
interface = config.hardware.networkInterfaces.wlan;
|
||||
params = {
|
||||
country_code = "GB";
|
||||
hw_mode = "g";
|
||||
wmm_enabled = 1;
|
||||
ieee80211n = 1;
|
||||
inherit (secrets) ssid channel wpa_passphrase;
|
||||
auth_algs = 1; # 1=wpa2, 2=wep, 3=both
|
||||
wpa = 2; # 1=wpa, 2=wpa2, 3=both
|
||||
wpa_key_mgmt = "WPA-PSK";
|
||||
wpa_pairwise = "TKIP CCMP"; # auth for wpa (may not need this?)
|
||||
rsn_pairwise = "CCMP"; # auth for wpa2
|
||||
};
|
||||
};
|
||||
|
||||
services.int = svc.bridge.primary.build {
|
||||
ifname = "int";
|
||||
};
|
||||
|
||||
services.dhcpc = svc.network.dhcp.client.build {
|
||||
interface = services.int;
|
||||
dependencies = [ config.services.hostname ];
|
||||
};
|
||||
|
||||
services.bridge = svc.bridge.members.build {
|
||||
primary = services.int;
|
||||
members = with config.hardware.networkInterfaces; [
|
||||
profile.wap = {
|
||||
interfaces = with config.hardware.networkInterfaces; [
|
||||
lan
|
||||
wlan
|
||||
];
|
||||
};
|
||||
|
||||
services.sshd = svc.ssh.build {};
|
||||
|
||||
services.resolvconf = oneshot rec {
|
||||
dependencies = [ services.dhcpc ];
|
||||
name = "resolvconf";
|
||||
# CHECK: https://udhcp.busybox.net/README.udhcpc says
|
||||
# 'A list of DNS server' but doesn't say what separates the
|
||||
# list members. Assuming it's a space or other IFS character
|
||||
up = ''
|
||||
. ${serviceFns}
|
||||
( in_outputs ${name}
|
||||
for i in $(output ${services.dhcpc} dns); do
|
||||
echo "nameserver $i" > resolv.conf
|
||||
done
|
||||
)
|
||||
'';
|
||||
};
|
||||
filesystem = dir {
|
||||
etc = dir {
|
||||
"resolv.conf" = symlink "${services.resolvconf}/.outputs/resolv.conf";
|
||||
wireless = {
|
||||
networks.${secrets.ssid} = {
|
||||
interface = config.hardware.networkInterfaces.wlan;
|
||||
inherit (secrets) channel wpa_passphrase;
|
||||
country_code = "GB";
|
||||
hw_mode = "g";
|
||||
wmm_enabled = 1;
|
||||
ieee80211n = 1;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
services.defaultroute4 = svc.network.route.build {
|
||||
via = "$(output ${services.dhcpc} router)";
|
||||
target = "default";
|
||||
dependencies = [services.dhcpc];
|
||||
};
|
||||
|
||||
users.root.passwd = lib.mkForce secrets.root_password;
|
||||
services.sshd = svc.ssh.build {};
|
||||
users.root.passwd = lib.mkForce secrets.root.passwd;
|
||||
defaultProfile.packages = with pkgs; [nftables strace tcpdump swconfig];
|
||||
}
|
||||
|
120
examples/nwa50ax-ap.nix
Normal file
120
examples/nwa50ax-ap.nix
Normal file
@ -0,0 +1,120 @@
|
||||
{ config, pkgs, ... } :
|
||||
let
|
||||
inherit (pkgs.liminix.services) oneshot longrun bundle target;
|
||||
inherit (pkgs) writeText;
|
||||
svc = config.system.service;
|
||||
secrets-1 = {
|
||||
ssid = "Zyxel 2G (N)";
|
||||
wpa_passphrase = "diamond dogs";
|
||||
};
|
||||
secrets-2 = {
|
||||
ssid = "Zyxel 5G (AX)";
|
||||
wpa_passphrase = "diamond dogs";
|
||||
};
|
||||
baseParams = {
|
||||
country_code = "FR";
|
||||
hw_mode = "g";
|
||||
channel = 6;
|
||||
wmm_enabled = 1;
|
||||
ieee80211n = 1;
|
||||
ht_capab = "[LDPC][GF][HT40-][HT40+][SHORT-GI-40][MAX-AMSDU-7935][TX-STBC]";
|
||||
auth_algs = 1;
|
||||
wpa = 2;
|
||||
wpa_key_mgmt = "WPA-PSK";
|
||||
wpa_pairwise = "TKIP CCMP";
|
||||
rsn_pairwise = "CCMP";
|
||||
};
|
||||
|
||||
modernParams = {
|
||||
hw_mode = "a";
|
||||
he_su_beamformer = 1;
|
||||
he_su_beamformee = 1;
|
||||
he_mu_beamformer = 1;
|
||||
preamble = 1;
|
||||
# Allow radar detection.
|
||||
ieee80211d = 1;
|
||||
ieee80211h = 1;
|
||||
ieee80211ac = 1;
|
||||
ieee80211ax = 1;
|
||||
vht_capab = "[MAX-MPDU-7991][SU-BEAMFORMEE][SU-BEAMFORMER][RXLDPC][SHORT-GI-80][MAX-A-MPDU-LEN-EXP3][RX-ANTENNA-PATTERN][TX-ANTENNA-PATTERN][TX-STBC-2BY1][RX-STBC-1][MU-BEAMFORMER]";
|
||||
vht_oper_chwidth = 1;
|
||||
he_oper_chwidth = 1;
|
||||
channel = 36;
|
||||
vht_oper_centr_freq_seg0_idx = 42;
|
||||
he_oper_centr_freq_seg0_idx = 42;
|
||||
require_vht = 1;
|
||||
};
|
||||
mkWifiSta = params: interface: secrets: svc.hostapd.build {
|
||||
inherit interface;
|
||||
params = params // {
|
||||
inherit (secrets) ssid wpa_passphrase;
|
||||
};
|
||||
};
|
||||
in rec {
|
||||
imports = [
|
||||
../modules/wlan.nix
|
||||
../modules/network
|
||||
../modules/hostapd
|
||||
../modules/ssh
|
||||
../modules/ntp
|
||||
../modules/vlan
|
||||
../modules/bridge
|
||||
];
|
||||
|
||||
hostname = "zyxel";
|
||||
|
||||
users.root = {
|
||||
# EDIT: choose a root password and then use
|
||||
# "mkpasswd -m sha512crypt" to determine the hash.
|
||||
# It should start wirh $6$.
|
||||
passwd = "$y$j9T$f8GhLiqYmr3lc58eKhgyD0$z7P/7S9u.kq/cANZExxhS98bze/6i7aBxU6tbl7RMi.";
|
||||
openssh.authorizedKeys.keys = [
|
||||
# EDIT: you can add your ssh pubkey here
|
||||
# "ssh-rsa AAAAB3NzaC1....H6hKd user@example.com";
|
||||
];
|
||||
};
|
||||
|
||||
services.int = svc.bridge.primary.build {
|
||||
ifname = "int";
|
||||
};
|
||||
|
||||
services.bridge = svc.bridge.members.build {
|
||||
primary = services.int;
|
||||
members = with config.hardware.networkInterfaces; [
|
||||
lan
|
||||
wlan0
|
||||
wlan1
|
||||
];
|
||||
};
|
||||
|
||||
services.dhcpv4 =
|
||||
let iface = services.int;
|
||||
in svc.network.dhcp.client.build { interface = iface; };
|
||||
|
||||
services.defaultroute4 = svc.network.route.build {
|
||||
via = "$(output ${services.dhcpv4} address)";
|
||||
target = "default";
|
||||
dependencies = [ services.dhcpv4 ];
|
||||
};
|
||||
|
||||
services.packet_forwarding = svc.network.forward.build { };
|
||||
services.sshd = svc.ssh.build {
|
||||
allowRoot = true;
|
||||
};
|
||||
|
||||
services.ntp = config.system.service.ntp.build {
|
||||
pools = { "pool.ntp.org" = ["iburst"] ; };
|
||||
};
|
||||
|
||||
boot.tftp = {
|
||||
serverip = "192.0.2.10";
|
||||
ipaddr = "192.0.2.12";
|
||||
};
|
||||
|
||||
# wlan0 is the 2.4GHz interface.
|
||||
services.hostap-1 = mkWifiSta baseParams config.hardware.networkInterfaces.wlan0 secrets-1;
|
||||
# wlan1 is the 5GHz interface, e.g. AX capable.
|
||||
services.hostap-2 = mkWifiSta (baseParams // modernParams) config.hardware.networkInterfaces.wlan1 secrets-2;
|
||||
|
||||
defaultProfile.packages = with pkgs; [ zyxel-bootconfig iw min-collect-garbage mtdutils ];
|
||||
}
|
116
examples/recovery.nix
Normal file
116
examples/recovery.nix
Normal file
@ -0,0 +1,116 @@
|
||||
{ config, pkgs, lib, ... } :
|
||||
let
|
||||
inherit (pkgs) serviceFns;
|
||||
svc = config.system.service;
|
||||
inherit (pkgs.pseudofile) dir symlink;
|
||||
inherit (pkgs.liminix.services) oneshot longrun bundle target;
|
||||
some-util-linux = pkgs.runCommand "some-util-linux" {} ''
|
||||
mkdir -p $out/bin
|
||||
cd ${pkgs.util-linux-small}/bin
|
||||
cp fdisk sfdisk mkswap $out/bin
|
||||
'';
|
||||
in rec {
|
||||
imports = [
|
||||
../modules/network
|
||||
../modules/ssh
|
||||
../modules/usb.nix
|
||||
../modules/schnapps
|
||||
../modules/outputs/mtdimage.nix
|
||||
../modules/outputs/mbrimage.nix
|
||||
../modules/outputs/tftpboot.nix
|
||||
../modules/outputs/ubifs.nix
|
||||
../modules/outputs/ubimage.nix
|
||||
../modules/outputs/jffs2.nix
|
||||
../modules/outputs/ext4fs.nix
|
||||
../modules/outputs/extlinux.nix
|
||||
];
|
||||
|
||||
kernel.config = {
|
||||
BTRFS_FS = "y";
|
||||
};
|
||||
|
||||
boot.tftp = {
|
||||
ipaddr = "10.0.0.8"; # my address
|
||||
serverip = "10.0.0.1"; # build machine or other tftp server
|
||||
freeSpaceBytes = 1024 * 1024 * 4;
|
||||
};
|
||||
boot.loader.extlinux.enable = true;
|
||||
|
||||
hostname = "liminix-recovery";
|
||||
|
||||
services.dhcpc = svc.network.dhcp.client.build {
|
||||
interface = config.hardware.networkInterfaces.lan2;
|
||||
|
||||
# don't start DHCP until the hostname is configured,
|
||||
# so it can identify itself to the DHCP server
|
||||
dependencies = [ config.services.hostname ];
|
||||
};
|
||||
|
||||
services.sshd = svc.ssh.build {
|
||||
dependencies = [ config.services.growfs ];
|
||||
};
|
||||
|
||||
services.defaultroute4 = svc.network.route.build {
|
||||
via = "$(output ${services.dhcpc} router)";
|
||||
target = "default";
|
||||
dependencies = [services.dhcpc];
|
||||
};
|
||||
|
||||
services.resolvconf = oneshot rec {
|
||||
dependencies = [ services.dhcpc ];
|
||||
name = "resolvconf";
|
||||
up = ''
|
||||
. ${serviceFns}
|
||||
( in_outputs ${name}
|
||||
for i in $(output ${services.dhcpc} dns); do
|
||||
echo "nameserver $i" > resolv.conf
|
||||
done
|
||||
)
|
||||
'';
|
||||
};
|
||||
|
||||
services.growfs = let name = "growfs"; in oneshot {
|
||||
inherit name;
|
||||
up = ''
|
||||
. ${serviceFns}
|
||||
device=$(grep /persist /proc/1/mountinfo | cut -f9 -d' ')
|
||||
${pkgs.e2fsprogs}/bin/resize2fs $device
|
||||
'';
|
||||
};
|
||||
|
||||
filesystem = dir {
|
||||
etc = dir {
|
||||
"resolv.conf" = symlink "${services.resolvconf}/.outputs/resolv.conf";
|
||||
};
|
||||
mnt = dir {};
|
||||
};
|
||||
rootfsType = "ext4";
|
||||
|
||||
# sda is most likely correct for the boot-from-USB case. For tftp
|
||||
# it's overridden by the boot.scr anyway, so maybe it all works out
|
||||
hardware.rootDevice = lib.mkForce "/dev/sda1";
|
||||
|
||||
users.root = {
|
||||
# the password is "secret". Use mkpasswd -m sha512crypt to
|
||||
# create this hashed password string
|
||||
passwd = "$6$y7WZ5hM6l5nriLmo$5AJlmzQZ6WA.7uBC7S8L4o19ESR28Dg25v64/vDvvCN01Ms9QoHeGByj8lGlJ4/b.dbwR9Hq2KXurSnLigt1W1";
|
||||
|
||||
|
||||
openssh.authorizedKeys.keys =
|
||||
let fromBuild =
|
||||
(builtins.readFile
|
||||
((builtins.toPath (builtins.getEnv "HOME")) + "/.ssh/authorized_keys")
|
||||
);
|
||||
in lib.splitString "\n" fromBuild;
|
||||
};
|
||||
|
||||
defaultProfile.packages = with pkgs; [
|
||||
e2fsprogs # ext4
|
||||
btrfs-progs
|
||||
mtdutils # mtd, jffs2, ubifs
|
||||
dtc # you never know when you might need device tree stuff
|
||||
some-util-linux
|
||||
libubootenv # fw_{set,print}env
|
||||
pciutils
|
||||
];
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
rec {
|
||||
{
|
||||
wpa_passphrase = "you bring light in";
|
||||
ssid = "liminix";
|
||||
l2tp = {
|
||||
name = "abcde@a.1";
|
||||
password = "NotMyIspPassword";
|
||||
@ -10,5 +11,9 @@ rec {
|
||||
openssh.authorizedKeys.keys = [
|
||||
];
|
||||
};
|
||||
root_password = root.passwd;
|
||||
|
||||
lan = {
|
||||
prefix = "10.8.0";
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -6,20 +6,18 @@
|
||||
# problems.
|
||||
|
||||
|
||||
{ config, pkgs, lib, ... } :
|
||||
{ config, pkgs, lib, modulesPath, ... } :
|
||||
let
|
||||
secrets = import ./rotuer-secrets.nix;
|
||||
inherit (pkgs.liminix.services) oneshot longrun bundle;
|
||||
secrets = {
|
||||
domainName = "fake.liminix.org";
|
||||
firewallRules = {};
|
||||
} // (import ./rotuer-secrets.nix);
|
||||
inherit (pkgs.liminix.services) oneshot bundle;
|
||||
inherit (pkgs) serviceFns;
|
||||
svc = config.system.service;
|
||||
wirelessConfig = {
|
||||
country_code = "GB";
|
||||
inherit (secrets) wpa_passphrase;
|
||||
auth_algs = 1; # 1=wpa2, 2=wep, 3=both
|
||||
wpa = 2; # 1=wpa, 2=wpa2, 3=both
|
||||
wpa_key_mgmt = "WPA-PSK";
|
||||
wpa_pairwise = "TKIP CCMP"; # auth for wpa (may not need this?)
|
||||
rsn_pairwise = "CCMP"; # auth for wpa2
|
||||
wmm_enabled = 1;
|
||||
};
|
||||
|
||||
@ -33,53 +31,62 @@ in rec {
|
||||
};
|
||||
|
||||
imports = [
|
||||
../modules/wlan.nix
|
||||
../modules/network
|
||||
../modules/ppp
|
||||
../modules/dnsmasq
|
||||
../modules/dhcp6c
|
||||
../modules/firewall
|
||||
../modules/hostapd
|
||||
../modules/bridge
|
||||
../modules/ntp
|
||||
../modules/ssh
|
||||
"${modulesPath}/profiles/gateway.nix"
|
||||
"${modulesPath}/schnapps"
|
||||
"${modulesPath}/outputs/btrfs.nix"
|
||||
"${modulesPath}/outputs/extlinux.nix"
|
||||
];
|
||||
hostname = "rotuer";
|
||||
rootfsType = "btrfs";
|
||||
rootOptions = "subvol=@";
|
||||
boot.loader.extlinux.enable = true;
|
||||
|
||||
services.hostap = svc.hostapd.build {
|
||||
interface = config.hardware.networkInterfaces.wlan;
|
||||
params = {
|
||||
ssid = "liminix";
|
||||
hw_mode="g";
|
||||
channel = "2";
|
||||
ieee80211n = 1;
|
||||
} // wirelessConfig;
|
||||
};
|
||||
|
||||
services.hostap5 = svc.hostapd.build {
|
||||
interface = config.hardware.networkInterfaces.wlan5;
|
||||
params = rec {
|
||||
ssid = "liminix_5";
|
||||
hw_mode="a";
|
||||
channel = 36;
|
||||
ht_capab = "[HT40+]";
|
||||
vht_oper_chwidth = 1;
|
||||
vht_oper_centr_freq_seg0_idx = channel + 6;
|
||||
ieee80211ac = 1;
|
||||
} // wirelessConfig;
|
||||
};
|
||||
|
||||
services.int = svc.network.address.build {
|
||||
interface = svc.bridge.primary.build { ifname = "int"; };
|
||||
family = "inet"; address ="10.8.0.1"; prefixLength = 16;
|
||||
};
|
||||
|
||||
services.bridge = svc.bridge.members.build {
|
||||
primary = services.int;
|
||||
members = with config.hardware.networkInterfaces;
|
||||
[ wlan
|
||||
wlan5
|
||||
lan ];
|
||||
profile.gateway = {
|
||||
lan = {
|
||||
interfaces = with config.hardware.networkInterfaces;
|
||||
[
|
||||
wlan wlan5
|
||||
lan0 lan1 lan2 lan3 lan4
|
||||
];
|
||||
inherit (secrets.lan) prefix;
|
||||
address = {
|
||||
family = "inet"; address ="${secrets.lan.prefix}.1"; prefixLength = 24;
|
||||
};
|
||||
dhcp = {
|
||||
start = 10;
|
||||
end = 240;
|
||||
hosts = { } // lib.optionalAttrs (builtins.pathExists ./static-leases.nix) (import ./static-leases.nix);
|
||||
localDomain = "lan";
|
||||
};
|
||||
};
|
||||
wan = {
|
||||
interface = config.hardware.networkInterfaces.wan;
|
||||
username = secrets.l2tp.name;
|
||||
password = secrets.l2tp.password;
|
||||
dhcp6.enable = true;
|
||||
};
|
||||
firewall = {
|
||||
enable = true;
|
||||
rules = secrets.firewallRules;
|
||||
};
|
||||
wireless.networks = {
|
||||
"${secrets.ssid}" = {
|
||||
interface = config.hardware.networkInterfaces.wlan;
|
||||
hw_mode="g";
|
||||
channel = "2";
|
||||
ieee80211n = 1;
|
||||
} // wirelessConfig;
|
||||
"${secrets.ssid}5" = rec {
|
||||
interface = config.hardware.networkInterfaces.wlan5;
|
||||
hw_mode="a";
|
||||
channel = 36;
|
||||
ht_capab = "[HT40+]";
|
||||
vht_oper_chwidth = 1;
|
||||
vht_oper_centr_freq_seg0_idx = channel + 6;
|
||||
ieee80211n = 1;
|
||||
ieee80211ac = 1;
|
||||
} // wirelessConfig;
|
||||
};
|
||||
};
|
||||
|
||||
services.ntp = svc.ntp.build {
|
||||
@ -91,98 +98,20 @@ in rec {
|
||||
|
||||
users.root = secrets.root;
|
||||
|
||||
services.dns =
|
||||
let interface = services.int;
|
||||
in svc.dnsmasq.build {
|
||||
resolvconf = services.resolvconf;
|
||||
inherit interface;
|
||||
ranges = [
|
||||
"10.8.0.10,10.8.0.240"
|
||||
# ra-stateless: sends router advertisements with the O and A
|
||||
# bits set, and provides a stateless DHCP service. The client
|
||||
# will use a SLAAC address, and use DHCP for other
|
||||
# configuration information.
|
||||
"::,constructor:$(output ${interface} ifname),ra-stateless"
|
||||
];
|
||||
|
||||
# You can add static addresses for the DHCP server here. I'm
|
||||
# not putting my actual MAC addresses in a public git repo ...
|
||||
hosts = { } // lib.optionalAttrs (builtins.pathExists ./static-leases.nix) (import ./static-leases.nix);
|
||||
|
||||
domain = "fake.liminix.org";
|
||||
};
|
||||
|
||||
services.wan = svc.pppoe.build {
|
||||
interface = config.hardware.networkInterfaces.wan;
|
||||
ppp-options = [
|
||||
"debug" "+ipv6" "noauth"
|
||||
"name" secrets.l2tp.name
|
||||
"password" secrets.l2tp.password
|
||||
];
|
||||
};
|
||||
|
||||
services.resolvconf = oneshot rec {
|
||||
dependencies = [ services.wan ];
|
||||
name = "resolvconf";
|
||||
up = ''
|
||||
. ${serviceFns}
|
||||
( in_outputs ${name}
|
||||
echo "nameserver $(output ${services.wan} ns1)" > resolv.conf
|
||||
echo "nameserver $(output ${services.wan} ns2)" >> resolv.conf
|
||||
chmod 0444 resolv.conf
|
||||
)
|
||||
'';
|
||||
};
|
||||
|
||||
filesystem =
|
||||
let inherit (pkgs.pseudofile) dir symlink;
|
||||
in dir {
|
||||
etc = dir {
|
||||
"resolv.conf" = symlink "${services.resolvconf}/.outputs/resolv.conf";
|
||||
};
|
||||
};
|
||||
|
||||
services.defaultroute4 = svc.network.route.build {
|
||||
via = "$(output ${services.wan} address)";
|
||||
target = "default";
|
||||
dependencies = [ services.wan ];
|
||||
};
|
||||
|
||||
services.defaultroute6 = svc.network.route.build {
|
||||
via = "$(output ${services.wan} ipv6-peer-address)";
|
||||
target = "default";
|
||||
interface = services.wan;
|
||||
};
|
||||
|
||||
services.firewall = svc.firewall.build {
|
||||
ruleset = import ./demo-firewall.nix;
|
||||
};
|
||||
|
||||
services.packet_forwarding = svc.network.forward.build { };
|
||||
|
||||
services.dhcp6c =
|
||||
let client = svc.dhcp6c.client.build {
|
||||
interface = services.wan;
|
||||
};
|
||||
in bundle {
|
||||
name = "dhcp6c";
|
||||
contents = [
|
||||
(svc.dhcp6c.prefix.build {
|
||||
inherit client;
|
||||
interface = services.int;
|
||||
})
|
||||
(svc.dhcp6c.address.build {
|
||||
inherit client;
|
||||
interface = services.wan;
|
||||
})
|
||||
];
|
||||
};
|
||||
|
||||
defaultProfile.packages = with pkgs; [
|
||||
min-collect-garbage
|
||||
nftables
|
||||
strace
|
||||
tcpdump
|
||||
s6
|
||||
];
|
||||
|
||||
programs.busybox.applets = [
|
||||
"fdisk" "sfdisk"
|
||||
];
|
||||
programs.busybox = {
|
||||
applets = [
|
||||
"fdisk" "sfdisk"
|
||||
];
|
||||
options = {
|
||||
FEATURE_FANCY_TAIL = "y";
|
||||
};
|
||||
};
|
||||
}
|
||||
|
@ -9,28 +9,29 @@
|
||||
./busybox.nix
|
||||
./dhcp6c
|
||||
./dnsmasq
|
||||
./outputs/ext4fs.nix
|
||||
./firewall
|
||||
./hardware.nix
|
||||
./hostapd
|
||||
./hostname.nix
|
||||
./outputs/initramfs.nix
|
||||
./outputs/jffs2.nix
|
||||
./kernel.nix
|
||||
./outputs/kexecboot.nix
|
||||
./kernel
|
||||
./mdevd.nix
|
||||
./mount
|
||||
./network
|
||||
./ntp
|
||||
./outputs.nix
|
||||
./outputs/vmroot.nix
|
||||
./outputs/ubimage.nix
|
||||
./outputs/ext4fs.nix
|
||||
./outputs/initramfs.nix
|
||||
./outputs/jffs2.nix
|
||||
./outputs/kexecboot.nix
|
||||
./outputs/mtdimage.nix
|
||||
./outputs/tftpboot.nix
|
||||
./outputs/ubifs.nix
|
||||
./outputs/ubimage.nix
|
||||
./outputs/vmroot.nix
|
||||
./ppp
|
||||
./ramdisk.nix
|
||||
./squashfs.nix
|
||||
./ssh
|
||||
./outputs/tftpboot.nix
|
||||
./outputs/ubifs.nix
|
||||
./users.nix
|
||||
./vlan
|
||||
./watchdog
|
||||
|
@ -12,9 +12,6 @@ let
|
||||
type_service = pkgs.liminix.lib.types.service;
|
||||
|
||||
in {
|
||||
imports = [
|
||||
./kernel.nix # kernel is a separate module for doc purposes
|
||||
];
|
||||
options = {
|
||||
defaultProfile = {
|
||||
packages = mkOption {
|
||||
@ -29,6 +26,10 @@ in {
|
||||
services = mkOption {
|
||||
type = types.attrsOf type_service;
|
||||
};
|
||||
system.callService = mkOption {
|
||||
type = types.functionTo (types.functionTo types.anything);
|
||||
};
|
||||
|
||||
filesystem = mkOption {
|
||||
type = types.anything;
|
||||
description = ''
|
||||
@ -40,18 +41,33 @@ in {
|
||||
rootfsType = mkOption {
|
||||
default = "squashfs";
|
||||
type = types.enum [
|
||||
"btrfs"
|
||||
"ext4"
|
||||
"jffs2"
|
||||
"squashfs"
|
||||
"ubifs"
|
||||
];
|
||||
};
|
||||
rootOptions = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
};
|
||||
|
||||
boot = {
|
||||
commandLine = mkOption {
|
||||
type = types.listOf types.nonEmptyStr;
|
||||
default = [];
|
||||
description = "Kernel command line";
|
||||
};
|
||||
commandLineDtbNode = mkOption {
|
||||
type = types.enum [ "bootargs" "bootargs-override" ];
|
||||
default = "bootargs";
|
||||
description = "Kernel command line's devicetree node";
|
||||
};
|
||||
imageType = mkOption {
|
||||
type = types.enum [ "primary" "secondary" ];
|
||||
default = "primary";
|
||||
};
|
||||
imageFormat = mkOption {
|
||||
type = types.enum ["fit" "uimage"];
|
||||
default = "uimage";
|
||||
@ -94,7 +110,33 @@ in {
|
||||
"root=${config.hardware.rootDevice}"
|
||||
"rootfstype=${config.rootfsType}"
|
||||
"fw_devlink=off"
|
||||
];
|
||||
] ++ lib.optional (config.rootOptions != null) "rootflags=${config.rootOptions}";
|
||||
|
||||
system.callService = path : parameters :
|
||||
let
|
||||
typeChecked = caller: type: value:
|
||||
let
|
||||
inherit (lib) types mergeDefinitions;
|
||||
defs = [{ file = caller; inherit value; }];
|
||||
type' = types.submodule { options = type; };
|
||||
in (mergeDefinitions [] type' defs).mergedValue;
|
||||
cp = lib.callPackageWith(pkgs // { svc = config.system.service; });
|
||||
pkg = cp path {};
|
||||
checkTypes = t : p : typeChecked (builtins.toString path) t p;
|
||||
in {
|
||||
inherit parameters;
|
||||
build = { dependencies ? [], ... } @ args :
|
||||
let
|
||||
s = pkg (checkTypes parameters
|
||||
(builtins.removeAttrs args ["dependencies"]));
|
||||
in s.overrideAttrs (o: {
|
||||
dependencies = (builtins.map (d: d.name) dependencies) ++ o.dependencies;
|
||||
buildInputs = dependencies ++ o.buildInputs;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
||||
users.root = {
|
||||
uid = 0; gid= 0; gecos = "Root of all evaluation";
|
||||
dir = "/home/root/";
|
||||
@ -134,6 +176,7 @@ in {
|
||||
proc = dir {};
|
||||
run = dir {};
|
||||
sys = dir {};
|
||||
tmp = dir {};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
@ -14,6 +14,8 @@ let
|
||||
inherit (pkgs) liminix;
|
||||
in
|
||||
{
|
||||
imports = [ ../ifwait ];
|
||||
|
||||
options = {
|
||||
system.service.bridge = {
|
||||
primary = mkOption { type = liminix.lib.types.serviceDefn; };
|
||||
@ -27,7 +29,7 @@ in
|
||||
description = "bridge interface name to create";
|
||||
};
|
||||
};
|
||||
members = liminix.callService ./members.nix {
|
||||
members = config.system.callService ./members.nix {
|
||||
primary = mkOption {
|
||||
type = liminix.lib.types.interface;
|
||||
description = "primary bridge interface";
|
||||
|
@ -2,6 +2,7 @@
|
||||
liminix
|
||||
, ifwait
|
||||
, lib
|
||||
, svc
|
||||
}:
|
||||
{ members, primary } :
|
||||
|
||||
@ -10,14 +11,20 @@ let
|
||||
inherit (liminix.services) bundle oneshot;
|
||||
inherit (lib) mkOption types;
|
||||
addif = member :
|
||||
oneshot {
|
||||
name = "${primary.name}.member.${member.name}";
|
||||
up = ''
|
||||
dev=$(output ${member} ifname)
|
||||
${ifwait}/bin/ifwait $dev running && ip link set dev $dev master $(output ${primary} ifname)
|
||||
'';
|
||||
down = "ip link set dev $(output ${member} ifname) nomaster";
|
||||
# how do we get sight of services from here? maybe we need to
|
||||
# implement ifwait as a regualr derivation instead of a
|
||||
# servicedefinition
|
||||
svc.ifwait.build {
|
||||
state = "running";
|
||||
interface = member;
|
||||
dependencies = [ primary member ];
|
||||
service = oneshot {
|
||||
name = "${primary.name}.member.${member.name}";
|
||||
up = ''
|
||||
ip link set dev $(output ${member} ifname) master $(output ${primary} ifname)
|
||||
'';
|
||||
down = "ip link set dev $(output ${member} ifname) nomaster";
|
||||
};
|
||||
};
|
||||
in bundle {
|
||||
name = "${primary.name}.members";
|
||||
|
@ -32,23 +32,21 @@ let
|
||||
(a: symlink "${busybox}/bin/busybox");
|
||||
minimalApplets = [
|
||||
# this is probably less minimal than it could be
|
||||
"arch" "ash" "base64" "basename" "bc" "brctl" "bunzip2" "bzcat"
|
||||
"bzip2" "cal" "cat" "chattr" "chgrp" "chmod" "chown" "chpst"
|
||||
"chroot" "clear" "cmp" "comm" "cp" "cpio" "cut" "date" "dd" "df"
|
||||
"dirname" "dmesg" "du" "echo" "egrep" "env" "expand" "expr"
|
||||
"false" "fdisk" "fgrep" "find" "free" "fuser" "grep" "gunzip"
|
||||
"gzip" "head" "hexdump" "hostname" "hwclock" "ifconfig" "ip"
|
||||
"ipaddr" "iplink" "ipneigh" "iproute" "iprule" "kill" "killall"
|
||||
"killall5" "less" "ln" "ls" "lsattr" "lsof" "md5sum" "mkdir"
|
||||
"mknod" "mktemp" "mount" "mv" "nc" "netstat" "nohup" "od" "pgrep"
|
||||
"pidof" "ping" "ping6" "pkill" "pmap" "printenv" "printf" "ps"
|
||||
"pwd" "readlink" "realpath" "reset" "rm" "rmdir" "route" "sed"
|
||||
"seq" "setsid" "sha1sum" "sha256sum" "sha512sum" "sleep" "sort"
|
||||
"stat" "strings" "stty" "su" "sum" "swapoff" "swapon" "sync"
|
||||
"tail" "tee" "test" "time" "touch" "tr" "traceroute" "traceroute6"
|
||||
"true" "truncate" "tty" "udhcpc" "umount" "uname"
|
||||
"unexpand" "uniq" "unlink" "unlzma" "unxz" "unzip" "uptime"
|
||||
"watch" "wc" "whoami" "xargs" "xxd" "xz" "xzcat" "yes" "zcat"
|
||||
"arch" "ash" "base64" "basename" "bc" "brctl" "bunzip2" "bzcat" "bzip2"
|
||||
"cal" "cat" "chattr" "chgrp" "chmod" "chown" "chpst" "chroot" "clear" "cmp"
|
||||
"comm" "cp" "cpio" "cut" "date" "dhcprelay" "dd" "df" "dirname" "dmesg"
|
||||
"du" "echo" "egrep" "env" "expand" "expr" "false" "fdisk" "fgrep" "find"
|
||||
"free" "fuser" "grep" "gunzip" "gzip" "head" "hexdump" "hostname" "hwclock"
|
||||
"ifconfig" "ip" "ipaddr" "iplink" "ipneigh" "iproute" "iprule" "kill"
|
||||
"killall" "killall5" "less" "ln" "ls" "lsattr" "lsof" "md5sum" "mkdir"
|
||||
"mknod" "mktemp" "mount" "mv" "nc" "netstat" "nohup" "od" "pgrep" "pidof"
|
||||
"ping" "ping6" "pkill" "pmap" "printenv" "printf" "ps" "pwd" "readlink"
|
||||
"realpath" "reset" "rm" "rmdir" "route" "sed" "seq" "setsid" "sha1sum"
|
||||
"sha256sum" "sha512sum" "sleep" "sort" "stat" "strings" "stty" "su" "sum"
|
||||
"swapoff" "swapon" "sync" "tail" "tee" "test" "time" "touch" "tr"
|
||||
"traceroute" "traceroute6" "true" "truncate" "tty" "udhcpc" "umount"
|
||||
"uname" "unexpand" "uniq" "unlink" "unlzma" "unxz" "unzip" "uptime" "watch"
|
||||
"wc" "whoami" "xargs" "xxd" "xz" "xzcat" "yes" "zcat"
|
||||
];
|
||||
in {
|
||||
options = {
|
||||
|
@ -1,31 +1,32 @@
|
||||
(local { : system } (require :anoia))
|
||||
(local svc (require :anoia.svc))
|
||||
|
||||
(fn changes [old-addresses new-addresses]
|
||||
(let [added {}
|
||||
deleted {}]
|
||||
(each [n address (pairs new-addresses)]
|
||||
(if (not (. old-addresses n))
|
||||
(table.insert added address)))
|
||||
(fn deletions [old-addresses new-addresses]
|
||||
(let [deleted {}]
|
||||
(each [n address (pairs old-addresses)]
|
||||
(if (not (. new-addresses n))
|
||||
(table.insert deleted address)))
|
||||
(values added deleted)))
|
||||
(let [now (. new-addresses n)]
|
||||
(if (or (not now) (not (= now.len address.len)))
|
||||
(table.insert deleted address))))
|
||||
deleted))
|
||||
|
||||
(fn update-prefixes [device prefixes new-prefixes]
|
||||
(let [(added deleted) (changes prefixes new-prefixes)]
|
||||
(each [_ p (ipairs added)]
|
||||
(system
|
||||
(.. "ip address add " p.address "1/" p.len " dev " device)))
|
||||
(each [_ p (ipairs deleted)]
|
||||
(system
|
||||
(.. "ip address del " p.address "1/" p.len " dev " device)))))
|
||||
(fn update-prefixes [wan-device addresses new-addresses exec]
|
||||
(each [_ p (ipairs (deletions addresses new-addresses))]
|
||||
(exec
|
||||
(.. "ip address del " p.address "1/" p.len " dev " wan-device)))
|
||||
(each [_ p (pairs new-addresses)]
|
||||
(exec
|
||||
(.. "ip address change " p.address "1/" p.len
|
||||
" dev " wan-device
|
||||
" valid_lft " p.valid
|
||||
" preferred_lft " p.preferred
|
||||
)))
|
||||
new-addresses)
|
||||
|
||||
(fn run []
|
||||
(let [[state-directory lan-device] arg
|
||||
dir (svc.open state-directory)]
|
||||
(accumulate [addresses []
|
||||
v (dir:events)]
|
||||
(update-prefixes lan-device addresses (v:output "prefix")))))
|
||||
(update-prefixes lan-device addresses (v:output "prefix") system))))
|
||||
|
||||
{ : changes : run }
|
||||
|
@ -3,8 +3,9 @@
|
||||
, linotify
|
||||
, anoia
|
||||
, lua
|
||||
, lualinux
|
||||
}:
|
||||
writeFennel "acquire-delegated-prefix" {
|
||||
packages = [ linotify anoia lua.pkgs.luafilesystem ];
|
||||
packages = [ linotify anoia lualinux ];
|
||||
mainFunction = "run";
|
||||
} ./acquire-delegated-prefix.fnl
|
||||
|
@ -1,68 +1,124 @@
|
||||
(local subject (require :acquire-wan-address))
|
||||
(local { : view } (require :fennel))
|
||||
(import-macros { : expect= } :anoia.assert)
|
||||
(local { : merge : dup } (require :anoia))
|
||||
|
||||
;; nix-shell --run "cd modules/dhcp6c && fennelrepl acquire-wan-address-test.fnl"
|
||||
|
||||
(local a1
|
||||
{
|
||||
"2001-ab-cd-ef_hjgKHGhKJH" {
|
||||
:address "2001:ab:cd:ef"
|
||||
:len "64"
|
||||
:preferred "200"
|
||||
:valid "200"
|
||||
}
|
||||
"2001-ab-cd-ef" {
|
||||
:address "2001:ab:cd:ef"
|
||||
:len "64"
|
||||
:preferred "3600"
|
||||
:valid "7200"
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
(local a156
|
||||
{
|
||||
"2001-ab-cd-ef" {
|
||||
:address "2001:ab:cd:ef"
|
||||
:len "56"
|
||||
:preferred "3600"
|
||||
:valid "7200"
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
(local a2
|
||||
{
|
||||
"2001-0-1-2-3_aNteBnb" {
|
||||
:address "2001:0:1:2:3"
|
||||
:len "64"
|
||||
:preferred "200"
|
||||
:valid "200"
|
||||
}
|
||||
"2001-0-1-2-3" {
|
||||
:address "2001:0:1:2:3"
|
||||
:len "64"
|
||||
:preferred "3600"
|
||||
:valid "7200"
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
(macro expect [assertion]
|
||||
(let [msg (.. "expectation failed: " (view assertion))]
|
||||
`(when (not ,assertion)
|
||||
(assert false ,msg))))
|
||||
(local a21
|
||||
{
|
||||
"2001-0-1-2-3" {
|
||||
:address "2001:0:1:2:3"
|
||||
:len "64"
|
||||
:preferred "1800"
|
||||
:valid "5400"
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
(fn first-address []
|
||||
(let [(add del)
|
||||
(subject.changes
|
||||
(let [deleted
|
||||
(subject.deletions
|
||||
{ }
|
||||
a1
|
||||
)]
|
||||
(expect (= (# del) 0))
|
||||
(expect (= (# add) 1))
|
||||
(let [[first] add]
|
||||
(expect (= first.address "2001:ab:cd:ef")))))
|
||||
(expect= deleted [])))
|
||||
|
||||
(fn second-address []
|
||||
(let [(add del)
|
||||
(subject.changes
|
||||
(let [del
|
||||
(subject.deletions
|
||||
a1
|
||||
(merge (dup a1) a2)
|
||||
)]
|
||||
(expect (= (# del) 0))
|
||||
(expect (= (# add) 1))
|
||||
(let [[first] add] (expect (= first.address "2001:0:1:2:3")))))
|
||||
(expect= del [])))
|
||||
|
||||
(fn less-address []1
|
||||
(let [(add del)
|
||||
(subject.changes
|
||||
(fn old-address-is-deleted []
|
||||
(let [del
|
||||
(subject.deletions
|
||||
(merge (dup a1) a2)
|
||||
a1
|
||||
)]
|
||||
(expect (= (# add) 0))
|
||||
(expect (= (# del) 1))
|
||||
(expect= (. del 1) (. a2 "2001-0-1-2-3"))
|
||||
))
|
||||
|
||||
(let [[first] del] (expect (= first.address "2001:0:1:2:3")))))
|
||||
(fn changed-lifetime-not-deleted []
|
||||
(let [del
|
||||
(subject.deletions
|
||||
(merge (dup a1) a2)
|
||||
(merge (dup a1) a21)
|
||||
)]
|
||||
;; when an address lifetime changes, "ip address change"
|
||||
;; will update that so it need not (should not) be deleted
|
||||
(expect= del [])))
|
||||
|
||||
(fn changed-prefix-is-deleted []
|
||||
(let [del
|
||||
(subject.deletions a1 a156)]
|
||||
;; when an address prefix changes, "ip address change"
|
||||
;; ignores that cjhange, so we have to remove the
|
||||
;; address before reinstating it
|
||||
(expect= del [(. a1 "2001-ab-cd-ef")])))
|
||||
|
||||
(first-address)
|
||||
(second-address)
|
||||
(less-address)
|
||||
(old-address-is-deleted)
|
||||
(changed-lifetime-not-deleted)
|
||||
(changed-prefix-is-deleted)
|
||||
|
||||
(let [cmds []]
|
||||
(subject.update-addresses
|
||||
"ppp0" a1 (merge (dup a1) a2)
|
||||
(fn [a] (table.insert cmds a)))
|
||||
(expect=
|
||||
(doto cmds table.sort)
|
||||
[
|
||||
;; order of changes is unimportant
|
||||
"ip address change 2001:0:1:2:3/64 dev ppp0 valid_lft 7200 preferred_lft 3600"
|
||||
"ip address change 2001:ab:cd:ef/64 dev ppp0 valid_lft 7200 preferred_lft 3600"
|
||||
]))
|
||||
|
||||
(let [cmds []]
|
||||
(subject.update-addresses
|
||||
"ppp0" (merge (dup a1) a2) a1
|
||||
(fn [a] (table.insert cmds a)))
|
||||
(expect=
|
||||
cmds
|
||||
[
|
||||
;; deletes are executed before changes
|
||||
"ip address del 2001:0:1:2:3/64 dev ppp0"
|
||||
"ip address change 2001:ab:cd:ef/64 dev ppp0 valid_lft 7200 preferred_lft 3600"
|
||||
]))
|
||||
|
||||
(print "OK")
|
||||
|
@ -1,35 +1,32 @@
|
||||
(local { : system } (require :anoia))
|
||||
(local svc (require :anoia.svc))
|
||||
|
||||
;; acquire-delegated-prefix has very similar code: we'd like to move
|
||||
;; this to anoia.svc when we see what the general form would look like
|
||||
|
||||
(fn changes [old-addresses new-addresses]
|
||||
(let [added {}
|
||||
deleted {}]
|
||||
(each [n address (pairs new-addresses)]
|
||||
(if (not (. old-addresses n))
|
||||
(table.insert added address)))
|
||||
(fn deletions [old-addresses new-addresses]
|
||||
(let [deleted {}]
|
||||
(each [n address (pairs old-addresses)]
|
||||
(if (not (. new-addresses n))
|
||||
(table.insert deleted address)))
|
||||
(values added deleted)))
|
||||
(let [now (. new-addresses n)]
|
||||
(if (or (not now) (not (= now.len address.len)))
|
||||
(table.insert deleted address))))
|
||||
deleted))
|
||||
|
||||
(fn update-addresses [wan-device addresses new-addresses]
|
||||
(let [(added deleted) (changes addresses new-addresses)]
|
||||
(each [_ p (ipairs added)]
|
||||
(system
|
||||
(.. "ip address add " p.address "/" p.len " dev " wan-device)))
|
||||
(each [_ p (ipairs deleted)]
|
||||
(system
|
||||
(.. "ip address del " p.address "/" p.len " dev " wan-device)))
|
||||
new-addresses))
|
||||
(fn update-addresses [wan-device addresses new-addresses exec]
|
||||
(each [_ p (ipairs (deletions addresses new-addresses))]
|
||||
(exec
|
||||
(.. "ip address del " p.address "/" p.len " dev " wan-device)))
|
||||
(each [_ p (pairs new-addresses)]
|
||||
(exec
|
||||
(.. "ip address change " p.address "/" p.len
|
||||
" dev " wan-device
|
||||
" valid_lft " p.valid
|
||||
" preferred_lft " p.preferred
|
||||
)))
|
||||
new-addresses)
|
||||
|
||||
(fn run []
|
||||
(let [[state-directory wan-device] arg
|
||||
dir (svc.open state-directory)]
|
||||
(accumulate [addresses []
|
||||
v (dir:events)]
|
||||
(update-addresses wan-device addresses (v:output "address")))))
|
||||
(update-addresses wan-device addresses (v:output "address") system))))
|
||||
|
||||
{ : update-addresses : changes : run }
|
||||
{ : update-addresses : deletions : run }
|
||||
|
@ -2,9 +2,10 @@
|
||||
writeFennel
|
||||
, linotify
|
||||
, anoia
|
||||
, lualinux
|
||||
, lua
|
||||
}:
|
||||
writeFennel "acquire-wan-address" {
|
||||
packages = [ linotify anoia lua.pkgs.luafilesystem ];
|
||||
packages = [ linotify anoia lualinux ];
|
||||
mainFunction = "run";
|
||||
} ./acquire-wan-address.fnl
|
||||
|
@ -11,6 +11,6 @@ let
|
||||
script = callPackage ./acquire-wan-address.nix { };
|
||||
in longrun {
|
||||
inherit name;
|
||||
run = "${script} /run/service-state/${client.name} $(output ${interface} ifname)";
|
||||
run = "${script} $SERVICE_OUTPUTS/${client.name} $(output ${interface} ifname)";
|
||||
dependencies = [ client interface ];
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ in longrun {
|
||||
inherit name;
|
||||
notification-fd = 10;
|
||||
run = ''
|
||||
export SERVICE_STATE=/run/service-state/${name}
|
||||
export SERVICE_STATE=$SERVICE_OUTPUTS/${name}
|
||||
${odhcp6c}/bin/odhcp6c -s ${odhcp-script} -e -v -p /run/${name}.pid -P0 $(output ${interface} ifname)
|
||||
)
|
||||
'';
|
||||
|
@ -11,6 +11,6 @@ let
|
||||
script = callPackage ./acquire-delegated-prefix.nix { };
|
||||
in longrun {
|
||||
inherit name;
|
||||
run = "${script} /run/service-state/${client.name} $(output ${interface} ifname)";
|
||||
run = "${script} $SERVICE_OUTPUTS/${client.name} $(output ${interface} ifname)";
|
||||
dependencies = [ client interface ];
|
||||
}
|
||||
|
@ -41,10 +41,11 @@ longrun {
|
||||
--no-hosts \
|
||||
--log-dhcp \
|
||||
--enable-ra \
|
||||
--log-debug \
|
||||
--log-queries \
|
||||
--log-facility=- \
|
||||
--dhcp-leasefile=/run/${name}.leases \
|
||||
--dhcp-leasefile=$(mkstate ${name})/leases \
|
||||
--pid-file=/run/${name}.pid
|
||||
'';
|
||||
# --log-debug \
|
||||
# --log-queries \
|
||||
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ in {
|
||||
(drop "icmpv6 type destination-unreachable ct state invalid,untracked")
|
||||
];
|
||||
};
|
||||
|
||||
forward-ip6 = {
|
||||
type = "filter";
|
||||
family = "ip6";
|
||||
@ -95,19 +96,23 @@ in {
|
||||
# recognised (outbound-initiated) flow
|
||||
(accept "oifname \"int\" iifname \"ppp0\" ct state established,related")
|
||||
(accept "iifname \"int\" oifname \"ppp0\" ")
|
||||
|
||||
"log prefix \"DENIED CHAIN=forward-ip6 \""
|
||||
];
|
||||
};
|
||||
input-lan = {
|
||||
|
||||
input-ip6-lan = {
|
||||
type = "filter";
|
||||
family = "ip6";
|
||||
|
||||
rules = [
|
||||
(accept "udp dport 547") # dhcp, could restrict to daddr ff02::1:2
|
||||
(accept "udp dport 53") # dns
|
||||
(accept "tcp dport 22")
|
||||
];
|
||||
};
|
||||
|
||||
input-wan = {
|
||||
input-ip6-wan = {
|
||||
type = "filter";
|
||||
family = "ip6";
|
||||
|
||||
@ -123,8 +128,8 @@ in {
|
||||
hook = "input";
|
||||
rules = [
|
||||
(accept "meta l4proto icmpv6")
|
||||
"iifname int jump input-lan"
|
||||
"iifname ppp0 jump input-wan"
|
||||
"iifname int jump input-ip6-lan"
|
||||
"iifname ppp0 jump input-ip6-wan"
|
||||
(if allow-incoming
|
||||
then accept "oifname \"int\" iifname \"ppp0\""
|
||||
else "oifname \"int\" iifname \"ppp0\" jump incoming-allowed-ip6"
|
||||
@ -132,6 +137,7 @@ in {
|
||||
# how does this even make sense in an input chain?
|
||||
(accept "oifname \"int\" iifname \"ppp0\" ct state established,related")
|
||||
(accept "iifname \"int\" oifname \"ppp0\" ")
|
||||
"log prefix \"DENIED CHAIN=input-ip6 \""
|
||||
];
|
||||
};
|
||||
|
||||
@ -154,6 +160,7 @@ in {
|
||||
"oifname \"ppp0\" masquerade"
|
||||
];
|
||||
};
|
||||
|
||||
nat-rx = {
|
||||
type = "nat";
|
||||
hook = "prerouting";
|
||||
@ -167,4 +174,71 @@ in {
|
||||
# packet replies. "
|
||||
];
|
||||
};
|
||||
|
||||
# these chains are for rules that have to be present for things to
|
||||
# basically work at all: for example, the router won't issue DHCP
|
||||
# unless it's allowed to receive DHCP requests. For "site policy"
|
||||
# rules you may prefer to use incoming-allowed-ip[46] instead
|
||||
|
||||
input-ip4-lan = {
|
||||
type = "filter";
|
||||
family = "ip";
|
||||
|
||||
rules = [
|
||||
(accept "udp dport 67") # dhcp
|
||||
(accept "udp dport 53") # dns
|
||||
(accept "tcp dport 22") # ssh
|
||||
];
|
||||
};
|
||||
|
||||
input-ip4-wan = {
|
||||
type = "filter";
|
||||
family = "ip";
|
||||
|
||||
rules = [
|
||||
(accept "udp sport 53")
|
||||
];
|
||||
};
|
||||
|
||||
input-ip4 = {
|
||||
type = "filter";
|
||||
family = "ip";
|
||||
policy = "drop";
|
||||
hook = "input";
|
||||
rules = [
|
||||
"iifname lo accept"
|
||||
"icmp type { echo-request, echo-reply } accept"
|
||||
"iifname int jump input-ip4-lan"
|
||||
"iifname ppp0 jump input-ip4-wan"
|
||||
"oifname \"int\" iifname \"ppp0\" jump incoming-allowed-ip4"
|
||||
"ct state established,related accept"
|
||||
"log prefix \"DENIED CHAIN=input-ip4 \""
|
||||
];
|
||||
};
|
||||
|
||||
forward-ip4 = {
|
||||
type = "filter";
|
||||
family = "ip";
|
||||
policy = "drop";
|
||||
hook = "forward";
|
||||
rules = [
|
||||
"iifname \"int\" accept"
|
||||
"ct state established,related accept"
|
||||
"oifname \"int\" iifname \"ppp0\" jump incoming-allowed-ip4"
|
||||
"log prefix \"DENIED CHAIN=forward-ip4 \""
|
||||
];
|
||||
};
|
||||
|
||||
incoming-allowed-ip4 = {
|
||||
type = "filter";
|
||||
family = "ip";
|
||||
rules = [
|
||||
# This is where you put permitted incoming connections. If
|
||||
# you're using NAT and want to forward a port from outside to
|
||||
# devices on the LAN, then you need a DNAT rule in nat-rx chain
|
||||
# *and* to accept the packet in this chain (specifying the
|
||||
# internal (RFC1918) address).
|
||||
];
|
||||
};
|
||||
|
||||
}
|
@ -10,34 +10,41 @@ let
|
||||
inherit (pkgs) liminix;
|
||||
inherit (pkgs.liminix.services) oneshot;
|
||||
|
||||
kconf = isModule :
|
||||
# setting isModule false is utterly untested and mostly
|
||||
# unimplemented: I say this to preempt any "how on earth is this
|
||||
# even supposed to work?" questions
|
||||
let yes = if isModule then "m" else "y";
|
||||
in {
|
||||
NFT_FIB_IPV4 = yes;
|
||||
NFT_FIB_IPV6 = yes;
|
||||
NF_TABLES = yes;
|
||||
NF_CT_PROTO_DCCP = "y";
|
||||
NF_CT_PROTO_SCTP = "y";
|
||||
NF_CT_PROTO_UDPLITE = "y";
|
||||
# NF_CONNTRACK_FTP = yes;
|
||||
NFT_CT = yes;
|
||||
};
|
||||
kmodules = pkgs.kernel-modules.override {
|
||||
kernelSrc = config.system.outputs.kernel.src;
|
||||
modulesupport = config.system.outputs.kernel.modulesupport;
|
||||
kmodules = pkgs.kmodloader.override {
|
||||
inherit (config.system.outputs) kernel;
|
||||
targets = [
|
||||
"nft_fib_ipv4"
|
||||
"nft_fib_ipv6"
|
||||
"nf_log_syslog"
|
||||
|
||||
"ip6_tables"
|
||||
"ip_tables"
|
||||
"iptable_nat"
|
||||
"nf_conntrack"
|
||||
"nf_defrag_ipv4"
|
||||
"nf_defrag_ipv6"
|
||||
"nf_log_syslog"
|
||||
"nf_nat"
|
||||
"nf_reject_ipv4"
|
||||
"nf_reject_ipv6"
|
||||
"nf_tables"
|
||||
"nft_chain_nat"
|
||||
"nft_ct"
|
||||
"nft_fib"
|
||||
"nft_fib_ipv4"
|
||||
"nft_fib_ipv6"
|
||||
"nft_log"
|
||||
"nft_masq"
|
||||
"nft_nat"
|
||||
"nft_reject"
|
||||
"nft_reject_inet"
|
||||
"nft_reject_ipv4"
|
||||
"nft_reject_ipv6"
|
||||
"x_tables"
|
||||
"xt_MASQUERADE"
|
||||
"xt_nat"
|
||||
"xt_tcpudp"
|
||||
];
|
||||
kconfig = kconf true;
|
||||
};
|
||||
loadModules = oneshot {
|
||||
name = "firewall-modules";
|
||||
up = "sh ${kmodules}/load.sh";
|
||||
down = "sh ${kmodules}/unload.sh";
|
||||
};
|
||||
in
|
||||
{
|
||||
@ -49,44 +56,56 @@ in
|
||||
config = {
|
||||
system.service.firewall =
|
||||
let svc = liminix.callService ./service.nix {
|
||||
ruleset = mkOption {
|
||||
extraRules = mkOption {
|
||||
type = types.attrsOf types.attrs;
|
||||
description = "firewall ruleset";
|
||||
default = {};
|
||||
};
|
||||
rules = mkOption {
|
||||
type = types.attrsOf types.attrs; # we could usefully tighten this a bit :-)
|
||||
default = import ./default-rules.nix;
|
||||
description = "firewall ruleset";
|
||||
};
|
||||
};
|
||||
in svc // {
|
||||
build = args : (svc.build args) // {
|
||||
dependencies = [ loadModules ] ++ (svc.dependencies or []);
|
||||
};
|
||||
build = args :
|
||||
let args' = args // {
|
||||
dependencies = (args.dependencies or []) ++ [kmodules];
|
||||
};
|
||||
in svc.build args' ;
|
||||
};
|
||||
|
||||
# For historical reasons the kernel config is split between
|
||||
# monolithic options and modules. TODO: go through this list
|
||||
# and see what can be moved into the "kconf" definiton above
|
||||
programs.busybox.applets = [
|
||||
"insmod" "rmmod"
|
||||
];
|
||||
kernel.config = {
|
||||
NETFILTER_XT_MATCH_CONNTRACK = "y";
|
||||
|
||||
IP6_NF_IPTABLES= "y";
|
||||
IP_NF_IPTABLES= "y";
|
||||
|
||||
IP_NF_NAT = "y";
|
||||
IP_NF_TARGET_MASQUERADE = "y";
|
||||
NETFILTER = "y";
|
||||
NETFILTER_ADVANCED = "y";
|
||||
NETFILTER_XTABLES = "y";
|
||||
NETFILTER_NETLINK = "m";
|
||||
NF_CONNTRACK = "m";
|
||||
|
||||
NFT_COMPAT = "y";
|
||||
NFT_CT = "y";
|
||||
NFT_LOG = "y";
|
||||
NFT_MASQ = "y";
|
||||
NFT_NAT = "y";
|
||||
NFT_REJECT = "y";
|
||||
NFT_REJECT_INET = "y";
|
||||
NETLINK_DIAG = "y";
|
||||
|
||||
NF_CONNTRACK = "y";
|
||||
NF_NAT = "y";
|
||||
NF_NAT_MASQUERADE = "y";
|
||||
NF_TABLES= "y";
|
||||
IP6_NF_IPTABLES= "m";
|
||||
IP_NF_IPTABLES = "m";
|
||||
IP_NF_NAT = "m";
|
||||
IP_NF_TARGET_MASQUERADE = "m";
|
||||
|
||||
NFT_CT = "m";
|
||||
NFT_FIB_IPV4 = "m";
|
||||
NFT_FIB_IPV6 = "m";
|
||||
NFT_LOG = "m";
|
||||
NFT_MASQ = "m";
|
||||
NFT_NAT = "m";
|
||||
NFT_REJECT = "m";
|
||||
NFT_REJECT_INET = "m";
|
||||
|
||||
NF_CT_PROTO_DCCP = "y";
|
||||
NF_CT_PROTO_SCTP = "y";
|
||||
NF_CT_PROTO_UDPLITE = "y";
|
||||
NF_LOG_SYSLOG = "m";
|
||||
NF_NAT = "m";
|
||||
NF_NAT_MASQUERADE = "y";
|
||||
NF_TABLES = "m";
|
||||
NF_TABLES_INET = "y";
|
||||
NF_TABLES_IPV4 = "y";
|
||||
NF_TABLES_IPV6 = "y";
|
||||
|
@ -4,12 +4,12 @@
|
||||
, firewallgen
|
||||
, nftables
|
||||
}:
|
||||
{ ruleset }:
|
||||
{ rules, extraRules }:
|
||||
let
|
||||
inherit (liminix.services) oneshot;
|
||||
inherit (liminix.lib) typeChecked;
|
||||
inherit (lib) mkOption types;
|
||||
script = firewallgen "firewall.nft" ruleset;
|
||||
script = firewallgen "firewall.nft" (lib.recursiveUpdate rules extraRules);
|
||||
in oneshot {
|
||||
name = "firewall";
|
||||
up = script;
|
||||
|
@ -67,6 +67,7 @@ in {
|
||||
};
|
||||
loadAddress = mkOption { type = types.ints.unsigned; default = null; };
|
||||
entryPoint = mkOption { type = types.ints.unsigned; };
|
||||
alignment = mkOption { type = types.nullOr types.ints.unsigned; default = null; description = "Alignment passed to `mkimage` for FIT"; };
|
||||
radios = mkOption {
|
||||
description = ''
|
||||
Kernel modules (from mac80211 package) required for the
|
||||
@ -76,7 +77,11 @@ in {
|
||||
default = [];
|
||||
example = ["ath9k" "ath10k"];
|
||||
};
|
||||
rootDevice = mkOption { };
|
||||
rootDevice = mkOption {
|
||||
description = "Full path to preferred root device";
|
||||
type = types.str;
|
||||
example = "/dev/mtdblock3";
|
||||
};
|
||||
networkInterfaces = mkOption {
|
||||
type = types.attrsOf types.anything;
|
||||
};
|
||||
|
18
modules/ifwait/default.nix
Normal file
18
modules/ifwait/default.nix
Normal file
@ -0,0 +1,18 @@
|
||||
{ config, pkgs, lib, ... } :
|
||||
let
|
||||
inherit (pkgs) liminix;
|
||||
inherit (lib) mkOption types;
|
||||
in {
|
||||
options.system.service.ifwait =
|
||||
mkOption { type = liminix.lib.types.serviceDefn; };
|
||||
|
||||
config.system.service.ifwait = config.system.callService ./ifwait.nix {
|
||||
state = mkOption { type = types.str; };
|
||||
interface = mkOption {
|
||||
type = liminix.lib.types.interface;
|
||||
};
|
||||
service = mkOption {
|
||||
type = liminix.lib.types.service;
|
||||
};
|
||||
};
|
||||
}
|
16
modules/ifwait/ifwait.nix
Normal file
16
modules/ifwait/ifwait.nix
Normal file
@ -0,0 +1,16 @@
|
||||
{ ifwait, liminix } :
|
||||
{
|
||||
state
|
||||
, interface
|
||||
, service
|
||||
}:
|
||||
let
|
||||
inherit (liminix.services) longrun;
|
||||
in longrun {
|
||||
name = "ifwait.${interface.name}";
|
||||
buildInputs = [ service ];
|
||||
isTrigger = true;
|
||||
run = ''
|
||||
${ifwait}/bin/ifwait -s ${service.name} $(output ${interface} ifname) ${state}
|
||||
'';
|
||||
}
|
@ -13,10 +13,21 @@ let
|
||||
|
||||
type_service = pkgs.liminix.lib.types.service;
|
||||
|
||||
mergeConditionals = conf : conditions :
|
||||
# for each key in conditions, if it is present in conf
|
||||
# then merge the associated value into conf
|
||||
lib.foldlAttrs
|
||||
(acc: name: value:
|
||||
if (conf ? ${name}) && (conf.${name} != "n")
|
||||
then acc // value
|
||||
else acc)
|
||||
conf
|
||||
conditions;
|
||||
in {
|
||||
options = {
|
||||
kernel = {
|
||||
src = mkOption { type = types.path; } ;
|
||||
version = mkOption { type = types.str; default = "5.15.137";} ;
|
||||
modular = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
@ -42,6 +53,20 @@ in {
|
||||
};
|
||||
'';
|
||||
};
|
||||
conditionalConfig = mkOption {
|
||||
description = ''
|
||||
Kernel config options that should only be applied when
|
||||
some other option is present.
|
||||
'';
|
||||
type = types.attrsOf (types.attrsOf types.nonEmptyStr);
|
||||
default = {};
|
||||
example = {
|
||||
USB = {
|
||||
USB_XHCI_MVEBU = "y";
|
||||
USB_XHCI_HCD = "y";
|
||||
};
|
||||
};
|
||||
};
|
||||
makeTargets = mkOption {
|
||||
type = types.listOf types.str;
|
||||
};
|
||||
@ -49,10 +74,15 @@ in {
|
||||
};
|
||||
config = {
|
||||
system.outputs =
|
||||
let k = liminix.builders.kernel.override {
|
||||
inherit (config.kernel) config src extraPatchPhase;
|
||||
targets = config.kernel.makeTargets;
|
||||
};
|
||||
let
|
||||
mergedConfig = mergeConditionals
|
||||
config.kernel.config
|
||||
config.kernel.conditionalConfig;
|
||||
k = liminix.builders.kernel.override {
|
||||
config = mergedConfig;
|
||||
inherit (config.kernel) version src extraPatchPhase;
|
||||
targets = config.kernel.makeTargets;
|
||||
};
|
||||
in {
|
||||
kernel = k.vmlinux;
|
||||
zimage = k.zImage;
|
27
modules/mdevd.nix
Normal file
27
modules/mdevd.nix
Normal file
@ -0,0 +1,27 @@
|
||||
{ config, pkgs, lib, ...} :
|
||||
let inherit (pkgs.liminix.services) oneshot longrun;
|
||||
in {
|
||||
config = {
|
||||
services = rec {
|
||||
mdevd = longrun {
|
||||
name = "mdevd";
|
||||
notification-fd = 3;
|
||||
run = "${pkgs.mdevd}/bin/mdevd -D 3 -b 200000 -O4";
|
||||
};
|
||||
devout = longrun {
|
||||
name = "devout";
|
||||
notification-fd = 10;
|
||||
run = "${pkgs.devout}/bin/devout /run/devout.sock 4";
|
||||
};
|
||||
coldplug = oneshot {
|
||||
name ="coldplug";
|
||||
# would love to know what mdevd-coldplug/udevadm trigger does
|
||||
# that this doesn't
|
||||
up = ''
|
||||
for i in $(find /sys -name uevent); do ( echo change > $i ) ; done
|
||||
'';
|
||||
dependencies = [devout mdevd];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
@ -19,28 +19,39 @@ in {
|
||||
type = liminix.lib.types.serviceDefn;
|
||||
};
|
||||
};
|
||||
config.system.service = {
|
||||
mount = liminix.callService ./service.nix {
|
||||
device = mkOption {
|
||||
type = types.str;
|
||||
example = "/dev/sda1";
|
||||
};
|
||||
mountpoint = mkOption {
|
||||
type = types.str;
|
||||
example = "/mnt/media";
|
||||
};
|
||||
options = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
example = ["noatime" "ro" "sync"];
|
||||
};
|
||||
fstype = mkOption {
|
||||
type = types.str;
|
||||
default = "auto";
|
||||
example = "vfat";
|
||||
};
|
||||
imports = [ ../mdevd.nix ];
|
||||
config.system.service.mount =
|
||||
let svc = liminix.callService ./service.nix {
|
||||
partlabel = mkOption {
|
||||
type = types.str;
|
||||
example = "my-usb-stick";
|
||||
};
|
||||
mountpoint = mkOption {
|
||||
type = types.str;
|
||||
example = "/mnt/media";
|
||||
};
|
||||
options = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
example = ["noatime" "ro" "sync"];
|
||||
};
|
||||
fstype = mkOption {
|
||||
type = types.str;
|
||||
default = "auto";
|
||||
example = "vfat";
|
||||
};
|
||||
};
|
||||
in svc // {
|
||||
build = args:
|
||||
let args' = args // {
|
||||
dependencies = (args.dependencies or []) ++ [
|
||||
config.services.mdevd
|
||||
config.services.devout
|
||||
];
|
||||
};
|
||||
in svc.build args' ;
|
||||
};
|
||||
};
|
||||
|
||||
config.programs.busybox = {
|
||||
applets = ["blkid" "findfs"];
|
||||
options = {
|
||||
|
@ -1,18 +1,26 @@
|
||||
{
|
||||
liminix
|
||||
, uevent-watch
|
||||
, lib
|
||||
}:
|
||||
{ device, mountpoint, options, fstype }:
|
||||
{ partlabel, mountpoint, options, fstype }:
|
||||
let
|
||||
inherit (liminix.services) oneshot;
|
||||
in oneshot {
|
||||
name = "mount.${lib.escapeURL mountpoint}";
|
||||
up = ''
|
||||
while ! findfs ${device}; do
|
||||
echo waiting for device ${device}
|
||||
sleep 1
|
||||
done
|
||||
mount -t ${fstype} -o ${lib.concatStringsSep "," options} ${device} ${mountpoint}
|
||||
inherit (liminix.services) longrun oneshot;
|
||||
device = "/dev/disk/by-partlabel/${partlabel}";
|
||||
options_string =
|
||||
if options == [] then "" else "-o ${lib.concatStringsSep "," options}";
|
||||
mount_service = oneshot {
|
||||
name = "mount.${lib.escapeURL mountpoint}";
|
||||
timeout-up = 3600;
|
||||
up = "mount -t ${fstype} ${options_string} ${device} ${mountpoint}";
|
||||
down = "umount ${mountpoint}";
|
||||
};
|
||||
in longrun {
|
||||
name = "watch-mount.${lib.strings.sanitizeDerivationName mountpoint}";
|
||||
isTrigger = true;
|
||||
buildInputs = [ mount_service ];
|
||||
|
||||
run = ''
|
||||
${uevent-watch}/bin/uevent-watch -s ${mount_service.name} -n ${device} partname=${partlabel} devtype=partition
|
||||
'';
|
||||
down = "umount ${mountpoint}";
|
||||
}
|
||||
|
@ -60,6 +60,9 @@ in
|
||||
Combined kernel and FDT in uImage (U-Boot compatible) format
|
||||
'';
|
||||
};
|
||||
tplink-safeloader = mkOption {
|
||||
type = types.package;
|
||||
};
|
||||
u-boot = mkOption {
|
||||
type = types.package;
|
||||
};
|
||||
@ -108,7 +111,8 @@ in
|
||||
};
|
||||
uimage = liminix.builders.uimage {
|
||||
commandLine = concatStringsSep " " config.boot.commandLine;
|
||||
inherit (config.hardware) loadAddress entryPoint;
|
||||
inherit (config.boot) commandLineDtbNode;
|
||||
inherit (config.hardware) loadAddress entryPoint alignment;
|
||||
inherit (config.boot) imageFormat;
|
||||
inherit (o) kernel dtb;
|
||||
};
|
||||
|
37
modules/outputs/btrfs.nix
Normal file
37
modules/outputs/btrfs.nix
Normal file
@ -0,0 +1,37 @@
|
||||
{
|
||||
config
|
||||
, pkgs
|
||||
, lib
|
||||
, ...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkIf mkOption types;
|
||||
o = config.system.outputs;
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
./initramfs.nix
|
||||
];
|
||||
config = mkIf (config.rootfsType == "btrfs") {
|
||||
kernel.config = {
|
||||
BTRFS_FS = "y";
|
||||
};
|
||||
boot.initramfs.enable = true;
|
||||
system.outputs = {
|
||||
rootfs =
|
||||
let
|
||||
inherit (pkgs.pkgsBuildBuild) runCommand e2fsprogs;
|
||||
in runCommand "mkfs.btrfs" {
|
||||
depsBuildBuild = [ e2fsprogs ];
|
||||
} ''
|
||||
tree=${o.bootablerootdir}
|
||||
size=$(du -s --apparent-size --block-size 1024 $tree |cut -f1)
|
||||
# add 25% for filesystem overhead
|
||||
size=$(( 5 * $size / 4))
|
||||
dd if=/dev/zero of=$out bs=1024 count=$size
|
||||
echo "not implemented" ; exit 1
|
||||
# mke2fs -t ext4 -j -d $tree $out
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
@ -6,6 +6,7 @@
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkIf mkEnableOption mkOption types concatStringsSep;
|
||||
inherit (pkgs.pseudofile) dir symlink;
|
||||
cfg = config.boot.loader.extlinux;
|
||||
o = config.system.outputs;
|
||||
cmdline = concatStringsSep " " config.boot.commandLine;
|
||||
@ -17,23 +18,26 @@ in {
|
||||
};
|
||||
options.boot.loader.extlinux.enable = mkEnableOption "extlinux";
|
||||
|
||||
config = { # mkIf cfg.enable {
|
||||
config = mkIf cfg.enable {
|
||||
system.outputs.extlinux = pkgs.runCommand "extlinux" {} ''
|
||||
mkdir $out
|
||||
cd $out
|
||||
${if wantsDtb then "cp ${o.dtb} dtb" else "true"}
|
||||
cp ${o.initramfs} initramfs
|
||||
cp ${o.zimage} kernel
|
||||
cp ${o.zimage} kernel
|
||||
mkdir extlinux
|
||||
cat > extlinux/extlinux.conf << _EOF
|
||||
menu title Liminix
|
||||
timeout 100
|
||||
timeout 40
|
||||
label Liminix
|
||||
kernel /boot/kernel
|
||||
# initrd /boot/initramfs
|
||||
append ${cmdline} root=/dev/vda1
|
||||
append ${cmdline}
|
||||
${if wantsDtb then "fdt /boot/dtb" else ""}
|
||||
_EOF
|
||||
'';
|
||||
filesystem = dir {
|
||||
boot = symlink config.system.outputs.extlinux;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
@ -7,6 +7,8 @@
|
||||
let
|
||||
inherit (lib) mkOption types concatStringsSep;
|
||||
cfg = config.boot.tftp;
|
||||
hw = config.hardware;
|
||||
arch = pkgs.stdenv.hostPlatform.linuxArch;
|
||||
in {
|
||||
imports = [ ../ramdisk.nix ];
|
||||
options.boot.tftp = {
|
||||
@ -22,6 +24,10 @@ in {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
};
|
||||
appendDTB = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
};
|
||||
};
|
||||
options.system.outputs = {
|
||||
tftpboot = mkOption {
|
||||
@ -62,33 +68,46 @@ in {
|
||||
uimage = "bootm";
|
||||
zimage = "bootz";
|
||||
}; in choices.${cfg.kernelFormat};
|
||||
|
||||
cmdline = concatStringsSep " " config.boot.commandLine;
|
||||
objcopy = "${pkgs.stdenv.cc.bintools.targetPrefix}objcopy";
|
||||
stripAndZip = ''
|
||||
${objcopy} -O binary -R .reginfo -R .notes -R .note -R .comment -R .mdebug -R .note.gnu.build-id -S vmlinux.elf vmlinux.bin
|
||||
rm -f vmlinux.bin.lzma ; lzma -k -z vmlinux.bin
|
||||
'';
|
||||
in
|
||||
pkgs.runCommand "tftpboot" { nativeBuildInputs = with pkgs.pkgsBuildBuild; [ lzma dtc ]; } ''
|
||||
pkgs.runCommand "tftpboot" { nativeBuildInputs = with pkgs.pkgsBuildBuild; [ lzma dtc pkgs.stdenv.cc ubootTools ]; } ''
|
||||
mkdir $out
|
||||
cd $out
|
||||
binsize() { local s=$(stat -L -c %s $1); echo $(($s + 0x1000 &(~0xfff))); }
|
||||
binsize64k() { local s=$(stat -L -c %s $1); echo $(($s + 0x10000 &(~0xffff))); }
|
||||
hex() { printf "0x%x" $1; }
|
||||
|
||||
rootfsStart=${toString cfg.loadAddress}
|
||||
rootfsSize=$(binsize64k ${o.rootfs} )
|
||||
dtbStart=$(($rootfsStart + $rootfsSize))
|
||||
dtbSize=$(binsize ${o.dtb} )
|
||||
imageStart=$(($dtbStart + $dtbSize))
|
||||
imageSize=$(binsize ${image})
|
||||
rootfsSize=$(($rootfsSize + ${toString cfg.freeSpaceBytes} ))
|
||||
|
||||
ln -s ${o.manifest} manifest
|
||||
ln -s ${image} image
|
||||
ln -s ${o.kernel} vmlinux # handy for gdb
|
||||
|
||||
# if we are transferring kernel and dtb separately, the
|
||||
# dtb has to precede the kernel in ram, because zimage
|
||||
# decompression code will assume that any memory after the
|
||||
# end of the kernel is free
|
||||
|
||||
dtbStart=$(($rootfsStart + $rootfsSize))
|
||||
${if cfg.compressRoot
|
||||
then ''
|
||||
lzma -z9cv ${o.rootfs} > rootfs.lz
|
||||
rootfsLzStart=$(($imageStart + $imageSize))
|
||||
rootfsLzStart=$dtbStart
|
||||
rootfsLzSize=$(binsize rootfs.lz)
|
||||
dtbStart=$(($dtbStart + $rootfsLzSize))
|
||||
''
|
||||
else ''
|
||||
ln -s ${o.rootfs} rootfs
|
||||
''
|
||||
else "ln -s ${o.rootfs} rootfs"
|
||||
}
|
||||
|
||||
cat ${o.dtb} > dtb
|
||||
address_cells=$(fdtget dtb / '#address-cells')
|
||||
size_cells=$(fdtget dtb / '#size-cells')
|
||||
@ -103,22 +122,39 @@ in {
|
||||
fdtput -p -t lx dtb /reserved-memory/$node reg $ac_prefix $(hex $rootfsStart) $sz_prefix $(hex $rootfsSize)
|
||||
|
||||
cmd="liminix ${cmdline} mtdparts=phram0:''${rootfsSize}(rootfs) phram.phram=phram0,''${rootfsStart},''${rootfsSize},${toString config.hardware.flash.eraseBlockSize} root=/dev/mtdblock0";
|
||||
fdtput -t s dtb /chosen bootargs "$cmd"
|
||||
fdtput -t s dtb /chosen ${config.boot.commandLineDtbNode} "$cmd"
|
||||
|
||||
# dtc -I dtb -O dts -o /dev/stdout dtb | grep -A10 chosen ; exit 1
|
||||
dtbSize=$(binsize ./dtb )
|
||||
|
||||
${if cfg.appendDTB then ''
|
||||
imageStart=$dtbStart
|
||||
# re-package image with updated dtb
|
||||
cat ${o.kernel} > vmlinux.elf
|
||||
${objcopy} --update-section .appended_dtb=dtb vmlinux.elf
|
||||
${stripAndZip}
|
||||
mkimage -A ${arch} -O linux -T kernel -C lzma -a $(hex ${toString hw.loadAddress}) -e $(hex ${toString hw.entryPoint}) -n '${lib.toUpper arch} Liminix Linux tftpboot' -d vmlinux.bin.lzma image
|
||||
# dtc -I dtb -O dts -o /dev/stdout dtb | grep -A10 chosen ; exit 1
|
||||
tftpcmd="tftpboot $(hex $imageStart) result/image "
|
||||
bootcmd="bootm $(hex $imageStart)"
|
||||
'' else ''
|
||||
imageStart=$(($dtbStart + $dtbSize))
|
||||
tftpcmd="tftpboot $(hex $imageStart) result/image; tftpboot $(hex $dtbStart) result/dtb "
|
||||
ln -s ${image} image
|
||||
bootcmd="${bootCommand} $(hex $imageStart) - $(hex $dtbStart)"
|
||||
''}
|
||||
|
||||
cat > boot.scr << EOF
|
||||
setenv serverip ${cfg.serverip}
|
||||
setenv ipaddr ${cfg.ipaddr}
|
||||
tftpboot $(hex $imageStart) result/image ; ${
|
||||
${
|
||||
if cfg.compressRoot
|
||||
then "tftpboot $(hex $rootfsLzStart) result/rootfs.lz"
|
||||
else "tftpboot $(hex $rootfsStart) result/rootfs"
|
||||
}; tftpboot $(hex $dtbStart) result/dtb
|
||||
}; $tftpcmd
|
||||
${if cfg.compressRoot
|
||||
then "lzmadec $(hex $rootfsLzStart) $(hex $rootfsStart); "
|
||||
else ""
|
||||
} ${bootCommand} $(hex $imageStart) - $(hex $dtbStart)
|
||||
} $bootcmd
|
||||
EOF
|
||||
'';
|
||||
|
||||
|
61
modules/outputs/tplink-safeloader.nix
Normal file
61
modules/outputs/tplink-safeloader.nix
Normal file
@ -0,0 +1,61 @@
|
||||
{
|
||||
config
|
||||
, pkgs
|
||||
, lib
|
||||
, ...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkOption types concatStringsSep;
|
||||
o = config.system.outputs;
|
||||
cfg = config.tplink-safeloader;
|
||||
in {
|
||||
options.tplink-safeloader = {
|
||||
board = mkOption {
|
||||
type = types.str;
|
||||
};
|
||||
};
|
||||
options.system.outputs = {
|
||||
tplink-safeloader = mkOption {
|
||||
type = types.package;
|
||||
description = ''
|
||||
tplink-safeloader
|
||||
*****************
|
||||
|
||||
For creating 'safeloader' images for tp-link devices.
|
||||
|
||||
These can be flashed to the device using the firmware update feature
|
||||
in the TP-link web UI or the OEM bootloader recovery: Use something
|
||||
sharp to hold the 'reset' button while turning on the router until
|
||||
only the orange LED remains lit. The router will assume IP address
|
||||
192.168.0.1 and expect you to take 192.168.0.5 on one of the LAN ports.
|
||||
On NixOS, use something like::
|
||||
|
||||
networking.interfaces.enp0s20f0u1c2 = {
|
||||
ipv4.addresses = [ {
|
||||
address = "192.168.0.5";
|
||||
prefixLength = 24;
|
||||
} ];
|
||||
};
|
||||
networking.networkmanager = {
|
||||
unmanaged = [ "enp0s20f0u1c2" ];
|
||||
};
|
||||
|
||||
This connection is rather somewhat temperamental, it may take a couple
|
||||
of attempts, possibly re-attaching the USB dongle and running
|
||||
``systemctl restart network-start.service``. The web interface does not
|
||||
give accurate feedback (the progress bar is a lie), so you may want
|
||||
to upload the firmware using ``curl -F firmware=@result http://192.168.0.1/f2.htm``.
|
||||
After this shows a 'success' JSON, the image still needs to be
|
||||
transferred from memory to flash, so be patient.
|
||||
'';
|
||||
};
|
||||
};
|
||||
config = {
|
||||
system.outputs = rec {
|
||||
tplink-safeloader =
|
||||
pkgs.runCommand "tplink" { nativeBuildInputs = with pkgs.pkgsBuildBuild; [ firmware-utils ]; } ''
|
||||
tplink-safeloader -B "${cfg.board}" -k "${o.uimage}" -r "${o.rootfs}" -o $out
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
@ -12,9 +12,16 @@ in
|
||||
imports = [
|
||||
./initramfs.nix
|
||||
];
|
||||
|
||||
options.system.outputs.rootubifs = mkOption {
|
||||
type = types.package;
|
||||
internal = true;
|
||||
};
|
||||
|
||||
options.hardware.ubi = {
|
||||
minIOSize = mkOption { type = types.str; };
|
||||
eraseBlockSize = mkOption { type = types.str; }; # LEB
|
||||
logicalEraseBlockSize = mkOption { type = types.str; }; # LEB
|
||||
physicalEraseBlockSize = mkOption { type = types.str; }; # PEB
|
||||
maxLEBcount = mkOption { type = types.str; }; # LEB
|
||||
};
|
||||
|
||||
@ -26,7 +33,7 @@ in
|
||||
};
|
||||
boot.initramfs.enable = true;
|
||||
system.outputs = {
|
||||
rootfs =
|
||||
rootubifs =
|
||||
let
|
||||
inherit (pkgs.pkgsBuildBuild) runCommand mtdutils;
|
||||
cfg = config.hardware.ubi;
|
||||
@ -35,7 +42,7 @@ in
|
||||
} ''
|
||||
mkdir tmp
|
||||
tree=${o.bootablerootdir}
|
||||
mkfs.ubifs -x favor_lzo -c ${cfg.maxLEBcount} -m ${cfg.minIOSize} -e ${cfg.eraseBlockSize} -y -r $tree --output $out --squash-uids -o $out
|
||||
mkfs.ubifs -x favor_lzo -c ${cfg.maxLEBcount} -m ${cfg.minIOSize} -e ${cfg.logicalEraseBlockSize} -y -r $tree --output $out --squash-uids -o $out
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
91
modules/outputs/ubivolume.nix
Normal file
91
modules/outputs/ubivolume.nix
Normal file
@ -0,0 +1,91 @@
|
||||
{
|
||||
config
|
||||
, pkgs
|
||||
, lib
|
||||
, ...
|
||||
}:
|
||||
let
|
||||
inherit (pkgs) liminix;
|
||||
inherit (lib) mkIf mkOption types concatStringsSep optionalString;
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
./initramfs.nix
|
||||
./ubifs.nix
|
||||
];
|
||||
|
||||
options.hardware.ubi = {
|
||||
minIOSize = mkOption { type = types.str; };
|
||||
eraseBlockSize = mkOption { type = types.str; }; # LEB
|
||||
maxLEBcount = mkOption { type = types.str; }; # LEB
|
||||
};
|
||||
|
||||
config = mkIf (config.rootfsType == "ubifs") {
|
||||
kernel.config = {
|
||||
MTD_UBI="y";
|
||||
|
||||
UBIFS_FS = "y";
|
||||
UBIFS_FS_SECURITY = "n";
|
||||
};
|
||||
boot.initramfs.enable = true;
|
||||
|
||||
system.outputs.rootfs =
|
||||
let
|
||||
inherit (pkgs.pkgsBuildBuild) runCommand;
|
||||
ubiVolume = ({ name, volumeId, image, flags ? [] }:
|
||||
''
|
||||
[${name}]
|
||||
mode=ubi
|
||||
vol_id=${toString volumeId}
|
||||
vol_type=dynamic
|
||||
vol_name=${name}
|
||||
vol_alignment=1
|
||||
${optionalString (image != null) ''
|
||||
image=${image}
|
||||
''}
|
||||
${optionalString (image == null) ''
|
||||
vol_size=1MiB
|
||||
''}
|
||||
${optionalString (flags != []) ''
|
||||
vol_flags=${concatStringsSep "," flags}
|
||||
''}
|
||||
'');
|
||||
|
||||
ubiImage = (volumes:
|
||||
let
|
||||
ubinizeConfig = pkgs.writeText "ubinize.conf" (concatStringsSep "\n" volumes);
|
||||
inherit (pkgs.pkgsBuildBuild) mtdutils;
|
||||
in
|
||||
runCommand "ubinize" {
|
||||
depsBuildBuild = [ mtdutils ];
|
||||
# block size := 128kb
|
||||
# page size := 2048
|
||||
# ubninize opts := -E 5
|
||||
} ''
|
||||
ubinize -Q "$SOURCE_DATE_EPOCH" -o $out \
|
||||
-p ${config.hardware.ubi.physicalEraseBlockSize} -m ${config.hardware.ubi.minIOSize} \
|
||||
-e ${config.hardware.ubi.logicalEraseBlockSize} \
|
||||
${ubinizeConfig}
|
||||
'');
|
||||
|
||||
ubiDisk = ({ initramfs }:
|
||||
let
|
||||
initramfsUbi = ubiVolume {
|
||||
name = "rootfs";
|
||||
volumeId = 0;
|
||||
image = initramfs;
|
||||
flags = [ "autoresize" ];
|
||||
};
|
||||
in
|
||||
ubiImage [
|
||||
initramfsUbi
|
||||
]);
|
||||
|
||||
disk = ubiDisk {
|
||||
initramfs = config.system.outputs.rootubifs; # liminix.builders.squashfs config.filesystem.contents; # # assert this is a proper FIT.
|
||||
};
|
||||
|
||||
in
|
||||
disk;
|
||||
};
|
||||
}
|
71
modules/outputs/zyxel-nwa-fit.nix
Normal file
71
modules/outputs/zyxel-nwa-fit.nix
Normal file
@ -0,0 +1,71 @@
|
||||
{
|
||||
config
|
||||
, pkgs
|
||||
, lib
|
||||
, ...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkIf mkEnableOption mkOption types concatStringsSep;
|
||||
models = "6b e1 6f e1 ff ff ff ff ff ff";
|
||||
in {
|
||||
options.system.outputs = {
|
||||
zyxel-nwa-fit = mkOption {
|
||||
type = types.package;
|
||||
description = ''
|
||||
zyxel-nwa-fit
|
||||
*************
|
||||
|
||||
This output provides a FIT image for Zyxel NWA series
|
||||
containing a kernel image and an UBIFS rootfs.
|
||||
|
||||
It can usually be used as a factory image to install Liminix
|
||||
on a system with pre-existing firmware and OS.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
imports = [
|
||||
./ubivolume.nix
|
||||
];
|
||||
|
||||
config = mkIf (config.rootfsType == "ubifs") {
|
||||
|
||||
system.outputs.zyxel-nwa-fit =
|
||||
let
|
||||
o = config.system.outputs;
|
||||
# 8129kb padding.
|
||||
paddedKernel = pkgs.runCommand "padded-kernel" {} ''
|
||||
cp --no-preserve=mode ${o.uimage} $out
|
||||
dd if=/dev/zero of=$out bs=1 count=1 seek=8388607
|
||||
'';
|
||||
firmwareImage = pkgs.runCommand "firmware-image" {} ''
|
||||
cat ${paddedKernel} ${o.rootfs} > $out
|
||||
'';
|
||||
dts = pkgs.writeText "image.its" ''
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
description = "Zyxel FIT (Flattened Image Tree)";
|
||||
compat-models = [${models}];
|
||||
#address-cells = <1>;
|
||||
|
||||
images {
|
||||
firmware {
|
||||
data = /incbin/("${firmwareImage}");
|
||||
type = "firmware";
|
||||
compression = "none";
|
||||
hash@1 {
|
||||
algo = "sha1";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
'';
|
||||
in
|
||||
pkgs.runCommand "zyxel-nwa-fit-${config.boot.imageType}" {
|
||||
nativeBuildInputs = [ pkgs.pkgsBuildBuild.ubootTools pkgs.pkgsBuildBuild.dtc ];
|
||||
} ''
|
||||
mkimage -f ${dts} $out
|
||||
'';
|
||||
};
|
||||
}
|
178
modules/profiles/gateway.nix
Normal file
178
modules/profiles/gateway.nix
Normal file
@ -0,0 +1,178 @@
|
||||
{ config, pkgs, lib, ... } :
|
||||
let
|
||||
svc = config.system.service;
|
||||
cfg = config.profile.gateway;
|
||||
inherit (lib) mkOption mkEnableOption mkIf mdDoc types optional optionals;
|
||||
inherit (pkgs) liminix serviceFns;
|
||||
inherit (liminix.services) bundle oneshot;
|
||||
hostaps =
|
||||
let
|
||||
defaults = {
|
||||
auth_algs = 1; # 1=wpa2, 2=wep, 3=both
|
||||
wpa = 2; # 1=wpa, 2=wpa2, 3=both
|
||||
wpa_key_mgmt = "WPA-PSK";
|
||||
wpa_pairwise = "TKIP CCMP"; # auth for wpa (may not need this?)
|
||||
rsn_pairwise = "CCMP"; # auth for wpa2
|
||||
};
|
||||
in lib.mapAttrs'
|
||||
(name : value :
|
||||
let
|
||||
attrs = defaults // { ssid = name; } // value;
|
||||
in lib.nameValuePair
|
||||
"hostap-${name}"
|
||||
(svc.hostapd.build {
|
||||
interface = attrs.interface;
|
||||
params = lib.filterAttrs (k: v: k != "interface") attrs;
|
||||
}))
|
||||
cfg.wireless.networks;
|
||||
in {
|
||||
|
||||
options.profile.gateway = {
|
||||
lan = {
|
||||
interfaces = mkOption {
|
||||
type = types.listOf liminix.lib.types.interface;
|
||||
default = [];
|
||||
};
|
||||
address = mkOption {
|
||||
type = types.attrs;
|
||||
};
|
||||
prefix = mkOption { type = types.str; };
|
||||
dhcp = {
|
||||
start = mkOption { type = types.int; };
|
||||
end = mkOption { type = types.int; };
|
||||
hosts = mkOption { type = types.attrs; };
|
||||
localDomain = mkOption { type = types.str; };
|
||||
};
|
||||
};
|
||||
|
||||
firewall = {
|
||||
enable = mkEnableOption "firewall";
|
||||
rules = mkOption { type = types.attrsOf types.attrs; };
|
||||
};
|
||||
|
||||
wan = {
|
||||
interface = mkOption { type = liminix.lib.types.interface; };
|
||||
username = mkOption { type = types.str; };
|
||||
password = mkOption { type = types.str; };
|
||||
dhcp6.enable = mkOption { type = types.bool; };
|
||||
};
|
||||
|
||||
wireless = mkOption {
|
||||
type = types.attrsOf types.anything;
|
||||
};
|
||||
};
|
||||
|
||||
imports = [
|
||||
../wlan.nix
|
||||
../network
|
||||
../ppp
|
||||
../dnsmasq
|
||||
../dhcp6c
|
||||
../firewall
|
||||
../hostapd
|
||||
../bridge
|
||||
../ntp
|
||||
../ssh
|
||||
{ config.services = hostaps; }
|
||||
];
|
||||
|
||||
config = {
|
||||
services.int = svc.network.address.build ({
|
||||
interface = svc.bridge.primary.build { ifname = "int"; };
|
||||
} // cfg.lan.address);
|
||||
|
||||
services.bridge = svc.bridge.members.build {
|
||||
primary = config.services.int;
|
||||
members = cfg.lan.interfaces;
|
||||
};
|
||||
|
||||
services.wan = svc.pppoe.build {
|
||||
inherit (cfg.wan) interface;
|
||||
ppp-options = [
|
||||
"debug" "+ipv6" "noauth"
|
||||
"name" cfg.wan.username
|
||||
"password" cfg.wan.password
|
||||
];
|
||||
};
|
||||
|
||||
services.packet_forwarding = svc.network.forward.build { };
|
||||
|
||||
services.dhcp6c =
|
||||
let
|
||||
client = svc.dhcp6c.client.build {
|
||||
interface = config.services.wan;
|
||||
};
|
||||
bundl = bundle {
|
||||
name = "dhcp6c";
|
||||
contents = [
|
||||
(svc.dhcp6c.prefix.build {
|
||||
inherit client;
|
||||
interface = config.services.int;
|
||||
})
|
||||
(svc.dhcp6c.address.build {
|
||||
inherit client;
|
||||
interface = config.services.wan;
|
||||
})
|
||||
];
|
||||
};
|
||||
in mkIf cfg.wan.dhcp6.enable bundl;
|
||||
|
||||
services.dns =
|
||||
let interface = config.services.int;
|
||||
dcfg = cfg.lan.dhcp;
|
||||
in svc.dnsmasq.build {
|
||||
resolvconf = config.services.resolvconf;
|
||||
inherit interface;
|
||||
ranges = [
|
||||
"${cfg.lan.prefix}.${toString dcfg.start},${cfg.lan.prefix}.${toString dcfg.end}"
|
||||
# ra-stateless: sends router advertisements with the O and A
|
||||
# bits set, and provides a stateless DHCP service. The client
|
||||
# will use a SLAAC address, and use DHCP for other
|
||||
# configuration information.
|
||||
"::,constructor:$(output ${interface} ifname),ra-stateless"
|
||||
];
|
||||
|
||||
hosts = dcfg.hosts;
|
||||
upstreams = [ "/${dcfg.localDomain}/" ];
|
||||
domain = dcfg.localDomain;
|
||||
};
|
||||
|
||||
services.defaultroute4 = svc.network.route.build {
|
||||
via = "$(output ${config.services.wan} address)";
|
||||
target = "default";
|
||||
dependencies = [ config.services.wan ];
|
||||
};
|
||||
|
||||
services.defaultroute6 = svc.network.route.build {
|
||||
via = "$(output ${config.services.wan} ipv6-peer-address)";
|
||||
target = "default";
|
||||
interface = config.services.wan;
|
||||
};
|
||||
|
||||
services.firewall = mkIf cfg.firewall.enable
|
||||
(svc.firewall.build {
|
||||
extraRules = cfg.firewall.rules;
|
||||
});
|
||||
|
||||
services.resolvconf = oneshot rec {
|
||||
dependencies = [ config.services.wan ];
|
||||
name = "resolvconf";
|
||||
up = ''
|
||||
. ${serviceFns}
|
||||
( in_outputs ${name}
|
||||
echo "nameserver $(output ${config.services.wan} ns1)" > resolv.conf
|
||||
echo "nameserver $(output ${config.services.wan} ns2)" >> resolv.conf
|
||||
chmod 0444 resolv.conf
|
||||
)
|
||||
'';
|
||||
};
|
||||
|
||||
filesystem =
|
||||
let inherit (pkgs.pseudofile) dir symlink;
|
||||
in dir {
|
||||
etc = dir {
|
||||
"resolv.conf" = symlink "${config.services.resolvconf}/.outputs/resolv.conf";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
98
modules/profiles/wap.nix
Normal file
98
modules/profiles/wap.nix
Normal file
@ -0,0 +1,98 @@
|
||||
{
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit (pkgs) liminix;
|
||||
inherit (lib) mkEnableOption mkOption types isDerivation hasAttr ;
|
||||
|
||||
inherit (pkgs.liminix.services) oneshot longrun bundle target;
|
||||
inherit (pkgs.pseudofile) dir symlink;
|
||||
inherit (pkgs) serviceFns;
|
||||
svc = config.system.service;
|
||||
cfg = config.profile.wap;
|
||||
|
||||
hostaps =
|
||||
let
|
||||
defaults = {
|
||||
auth_algs = 1; # 1=wpa2, 2=wep, 3=both
|
||||
wpa = 2; # 1=wpa, 2=wpa2, 3=both
|
||||
wpa_key_mgmt = "WPA-PSK";
|
||||
wpa_pairwise = "TKIP CCMP"; # auth for wpa (may not need this?)
|
||||
rsn_pairwise = "CCMP"; # auth for wpa2
|
||||
};
|
||||
in lib.mapAttrs'
|
||||
(name : value :
|
||||
let
|
||||
attrs = defaults // { ssid = name; } // value;
|
||||
in lib.nameValuePair
|
||||
"hostap-${name}"
|
||||
(svc.hostapd.build {
|
||||
interface = attrs.interface;
|
||||
params = lib.filterAttrs (k: v: k != "interface") attrs;
|
||||
}))
|
||||
cfg.wireless.networks;
|
||||
|
||||
in {
|
||||
imports = [
|
||||
../wlan.nix
|
||||
../network
|
||||
../hostapd
|
||||
../bridge
|
||||
{ config.services = hostaps; }
|
||||
];
|
||||
|
||||
options.profile.wap = {
|
||||
interfaces = mkOption {
|
||||
type = types.listOf liminix.lib.types.interface;
|
||||
default = [];
|
||||
};
|
||||
wireless = mkOption {
|
||||
type = types.attrsOf types.anything;
|
||||
};
|
||||
};
|
||||
config = {
|
||||
|
||||
services.int = svc.bridge.primary.build {
|
||||
ifname = "int";
|
||||
};
|
||||
|
||||
services.bridge = svc.bridge.members.build {
|
||||
primary = config.services.int;
|
||||
members = cfg.interfaces;
|
||||
};
|
||||
|
||||
services.dhcpc = svc.network.dhcp.client.build {
|
||||
interface = config.services.int;
|
||||
dependencies = [ config.services.hostname ];
|
||||
};
|
||||
|
||||
services.defaultroute4 = svc.network.route.build {
|
||||
via = "$(output ${config.services.dhcpc} router)";
|
||||
target = "default";
|
||||
dependencies = [config.services.dhcpc];
|
||||
};
|
||||
|
||||
services.resolvconf = oneshot rec {
|
||||
dependencies = [ config.services.dhcpc ];
|
||||
name = "resolvconf";
|
||||
# CHECK: https://udhcp.busybox.net/README.udhcpc says
|
||||
# 'A list of DNS server' but doesn't say what separates the
|
||||
# list members. Assuming it's a space or other IFS character
|
||||
up = ''
|
||||
. ${serviceFns}
|
||||
( in_outputs ${name}
|
||||
for i in $(output ${config.services.dhcpc} dns); do
|
||||
echo "nameserver $i" > resolv.conf
|
||||
done
|
||||
)
|
||||
'';
|
||||
};
|
||||
filesystem = dir {
|
||||
etc = dir {
|
||||
"resolv.conf" = symlink "${config.services.resolvconf}/.outputs/resolv.conf";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
@ -17,16 +17,24 @@ shift
|
||||
|
||||
mount -t proc none /proc
|
||||
mount -t sysfs none /sys
|
||||
mount -t tmpfs none /tmp
|
||||
# s6-linux-init mounts /dev before this script is called
|
||||
mkdir /dev/pts
|
||||
mount -t devpts none /dev/pts
|
||||
|
||||
mkdir -m 0751 /run/service-state
|
||||
chgrp system /run/service-state
|
||||
mkdir -m 0751 -p /run/services/outputs
|
||||
chgrp system /run/services/outputs
|
||||
|
||||
if test -d /persist; then
|
||||
mkdir -m 0751 -p /persist/services/state
|
||||
(cd /run/services && ln -s ../../persist/services/state .)
|
||||
else
|
||||
mkdir -m 0751 -p /run/services/state
|
||||
fi
|
||||
|
||||
### If your services are managed by s6-rc:
|
||||
### (replace /run/service with your scandir)
|
||||
s6-rc-init /run/service -d -c /etc/s6-rc/compiled
|
||||
s6-rc-init -d -c /etc/s6-rc/compiled /run/service
|
||||
|
||||
|
||||
### 2. Starting the wanted set of services
|
||||
|
19
modules/schnapps/default.nix
Normal file
19
modules/schnapps/default.nix
Normal file
@ -0,0 +1,19 @@
|
||||
{ config, pkgs, lib, ... } :
|
||||
{
|
||||
config = {
|
||||
programs.busybox = {
|
||||
options = {
|
||||
# schnapps is a shell script that needs
|
||||
# [ command
|
||||
# find -maxdepth -mindepth
|
||||
# head -c
|
||||
# echo -n
|
||||
ASH_TEST = "y";
|
||||
FEATURE_FIND_MAXDEPTH = "y";
|
||||
FEATURE_FANCY_HEAD = "y";
|
||||
FEATURE_FANCY_ECHO = "y";
|
||||
};
|
||||
};
|
||||
defaultProfile.packages = [ pkgs.schnapps ] ;
|
||||
};
|
||||
}
|
@ -29,15 +29,12 @@ let
|
||||
in
|
||||
longrun {
|
||||
name = "sshd";
|
||||
# we need /run/dropbear to point to hostkey storage, as that
|
||||
# pathname is hardcoded into the binary.
|
||||
# env -i clears the environment so we don't pass anything weird to
|
||||
# ssh sessions
|
||||
run = ''
|
||||
if test -d /persist; then
|
||||
mkdir -p /persist/secrets/dropbear
|
||||
ln -s /persist/secrets/dropbear /run
|
||||
else
|
||||
mkdir -p /run/dropbear
|
||||
fi
|
||||
ln -s $(mkstate dropbear) /run
|
||||
. /etc/profile # sets PATH but do we need this? it's the same file as ashrc
|
||||
exec env -i ENV=/etc/ashrc PATH=$PATH ${dropbear}/bin/dropbear ${concatStringsSep " " options}
|
||||
'';
|
||||
|
31
modules/usb.nix
Normal file
31
modules/usb.nix
Normal file
@ -0,0 +1,31 @@
|
||||
# support for USB block devices and the common filesystems
|
||||
# they're likely to provide
|
||||
|
||||
{lib, config, ... }:
|
||||
{
|
||||
kernel = {
|
||||
config = {
|
||||
USB = "y";
|
||||
USB_EHCI_HCD = "y";
|
||||
USB_EHCI_HCD_PLATFORM = "y";
|
||||
USB_OHCI_HCD = "y";
|
||||
USB_OHCI_HCD_PLATFORM = "y";
|
||||
USB_SUPPORT = "y";
|
||||
USB_COMMON = "y";
|
||||
USB_STORAGE = "y";
|
||||
USB_STORAGE_DEBUG = "n";
|
||||
USB_UAS = "y";
|
||||
USB_ANNOUNCE_NEW_DEVICES = "y";
|
||||
SCSI = "y";
|
||||
BLK_DEV_SD = "y";
|
||||
USB_PRINTER = "y";
|
||||
MSDOS_PARTITION = "y";
|
||||
EFI_PARTITION = "y";
|
||||
EXT4_FS = "y";
|
||||
EXT4_USE_FOR_EXT2 = "y";
|
||||
FS_ENCRYPTION = "y";
|
||||
|
||||
|
||||
};
|
||||
};
|
||||
}
|
@ -15,4 +15,5 @@ in oneshot rec {
|
||||
)
|
||||
'';
|
||||
down = "ip link set down dev ${ifname}";
|
||||
dependencies = [ primary ];
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
{
|
||||
liminix
|
||||
, lib
|
||||
, s6
|
||||
}:
|
||||
{ watched, headStart } :
|
||||
let
|
||||
@ -8,5 +9,5 @@ let
|
||||
in longrun {
|
||||
name = "watchdog";
|
||||
run =
|
||||
"HEADSTART=${toString headStart} ${./gaspode.sh} ${lib.concatStringsSep " " (builtins.map (s: s.name) watched)}";
|
||||
"PATH=${s6}/bin:$PATH HEADSTART=${toString headStart} ${./gaspode.sh} ${lib.concatStringsSep " " (builtins.map (s: s.name) watched)}";
|
||||
}
|
||||
|
@ -46,6 +46,14 @@ in {
|
||||
CRYPTO_SHA1 = "y";
|
||||
ENCRYPTED_KEYS = "y";
|
||||
KEYS = "y";
|
||||
|
||||
WLAN = "y";
|
||||
CFG80211 = "m";
|
||||
MAC80211 = "m";
|
||||
EXPERT = "y";
|
||||
CFG80211_CERTIFICATION_ONUS = "y";
|
||||
CFG80211_REQUIRE_SIGNED_REGDB = "n"; # depends on ONUS
|
||||
CFG80211_CRDA_SUPPORT = "n";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
60
modules/zyxel-dual-image/default.nix
Normal file
60
modules/zyxel-dual-image/default.nix
Normal file
@ -0,0 +1,60 @@
|
||||
## Boot blessing via Zyxel
|
||||
## =======================
|
||||
## Boot blessing is the process to bless a particular boot configuration
|
||||
## It is commonly encountered in devices with redundant partitions
|
||||
## for automatic recovery of broken upgrades.
|
||||
## This is also known as A/B schemas, where A represents the primary partition
|
||||
## and B the secondary partition used for recovery.
|
||||
## To use boot blessing on Liminix, you need to have the support of
|
||||
## your bootloader to help you boot on the secondary partition in case of
|
||||
## failure on the primary partition. The exact details are specifics to your device.
|
||||
## See the Zyxel NWA50AX for an example.
|
||||
## TODO: generalize this module.
|
||||
{ config, lib, pkgs, ... }:
|
||||
let
|
||||
inherit (lib) mkOption types;
|
||||
inherit (pkgs) liminix;
|
||||
in
|
||||
{
|
||||
options.boot.zyxel-dual-image = mkOption {
|
||||
type = liminix.lib.types.serviceDefn;
|
||||
};
|
||||
|
||||
config.boot.zyxel-dual-image = liminix.callService ./service.nix {
|
||||
ensureActiveImage = mkOption {
|
||||
type = types.enum [ "primary" "secondary" ];
|
||||
default = "primary";
|
||||
description = ''At boot, ensure that the active image is the one specified.
|
||||
|
||||
If you are already on a broken image, you need to manually boot
|
||||
into the right image via `atgo <image index>` in U-Boot.
|
||||
'';
|
||||
};
|
||||
|
||||
kernelCommandLineSource = mkOption {
|
||||
type = types.enum [ "/proc/cmdline" "/proc/device-tree/chosen/bootargs" ];
|
||||
default = "/proc/device-tree/chosen/bootargs";
|
||||
description = ''Kernel command line arguments source file.
|
||||
On MIPS, Liminix embeds the kernel command line in /proc/device-tree/chosen/bootargs-override.
|
||||
|
||||
In this instance, it does not get concatenated with `/proc/cmdline`.
|
||||
Therefore you may prefer to source it from another place, like `/proc/device-tree/chosen/bootargs`.
|
||||
'';
|
||||
};
|
||||
|
||||
primaryMtdPartition = mkOption {
|
||||
type = types.str;
|
||||
description = "Primary MTD partition device node, i.e. for image 0.";
|
||||
};
|
||||
|
||||
secondaryMtdPartition = mkOption {
|
||||
type = types.str;
|
||||
description = "Secondary MTD partition device node, i.e. for image 1.";
|
||||
};
|
||||
|
||||
bootConfigurationMtdPartition = mkOption {
|
||||
type = types.str;
|
||||
description = "Boot configuration MTD partition device node.";
|
||||
};
|
||||
};
|
||||
}
|
33
modules/zyxel-dual-image/service.nix
Normal file
33
modules/zyxel-dual-image/service.nix
Normal file
@ -0,0 +1,33 @@
|
||||
{
|
||||
liminix
|
||||
, lib
|
||||
, zyxel-bootconfig
|
||||
}:
|
||||
{ ensureActiveImage, primaryMtdPartition, secondaryMtdPartition, bootConfigurationMtdPartition, kernelCommandLineSource }:
|
||||
let
|
||||
inherit (liminix.services) oneshot;
|
||||
activeImageIndex = if ensureActiveImage == "primary" then 0 else 1;
|
||||
in oneshot {
|
||||
name = "zyxel-boot-configure";
|
||||
up = ''
|
||||
set -- $(cat /proc/device-tree/chosen/bootargs)
|
||||
for x in "$@"; do
|
||||
case "$x" in
|
||||
bootImage=*)
|
||||
BOOT_IMAGE="''${x#bootImage=}"
|
||||
echo "Current boot image is $BOOT_IMAGE."
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if test -z "$BOOT_IMAGE"; then
|
||||
echo "No valid image was provided in the kernel command line."
|
||||
exit 1
|
||||
else
|
||||
${lib.getExe zyxel-bootconfig} ${bootConfigurationMtdPartition} set-image-status "$BOOT_IMAGE" valid
|
||||
${lib.getExe zyxel-bootconfig} ${bootConfigurationMtdPartition} set-active-image ${toString activeImageIndex}
|
||||
|
||||
echo "Active image is now ${ensureActiveImage}"
|
||||
fi
|
||||
'';
|
||||
}
|
23
overlay.nix
23
overlay.nix
@ -50,6 +50,12 @@ extraPkgs // {
|
||||
};
|
||||
|
||||
# keep these alphabetical
|
||||
|
||||
btrfs-progs = prev.btrfs-progs.override {
|
||||
udevSupport = false;
|
||||
udev = null;
|
||||
};
|
||||
|
||||
chrony =
|
||||
let chrony' = prev.chrony.overrideAttrs(o: {
|
||||
configureFlags = [
|
||||
@ -71,6 +77,22 @@ extraPkgs // {
|
||||
|
||||
};
|
||||
|
||||
# luarocks wants a cross-compiled cmake (which seems like a bug,
|
||||
# we're never going to run luarocks on the device, but ...)
|
||||
# but https://github.com/NixOS/nixpkgs/issues/284734
|
||||
# so we do surgery on the cmake derivation until that's fixed
|
||||
|
||||
cmake = prev.cmake.overrideAttrs(o:
|
||||
# don't override the build cmake or we'll have to rebuild
|
||||
# half the known universe to no useful benefit
|
||||
if final.stdenv.buildPlatform != final.stdenv.hostPlatform
|
||||
then {
|
||||
preConfigure =
|
||||
builtins.replaceStrings
|
||||
["$configureFlags"] ["$configureFlags $cmakeFlags"] o.preConfigure;
|
||||
}
|
||||
else {}
|
||||
);
|
||||
|
||||
dnsmasq =
|
||||
let d = prev.dnsmasq.overrideAttrs(o: {
|
||||
@ -98,6 +120,7 @@ extraPkgs // {
|
||||
"CONFIG_DRIVER_NL80211=y"
|
||||
"CONFIG_IAPP=y"
|
||||
"CONFIG_IEEE80211AC=y"
|
||||
"CONFIG_IEEE80211AX=y"
|
||||
"CONFIG_IEEE80211N=y"
|
||||
"CONFIG_IEEE80211W=y"
|
||||
"CONFIG_INTERNAL_LIBTOMMATH=y"
|
||||
|
14
pkgs/anoia/Makefile
Normal file
14
pkgs/anoia/Makefile
Normal file
@ -0,0 +1,14 @@
|
||||
|
||||
default: fs.lua init.lua nl.lua svc.lua net/constants.lua
|
||||
|
||||
test:
|
||||
ln -s . anoia
|
||||
fennel test.fnl
|
||||
fennel test-svc.fnl
|
||||
|
||||
net/constants.lua: net/constants.c
|
||||
$(CC) -imacros sys/socket.h -imacros linux/netlink.h -E -P - < net/constants.c | sed 's/ *$$//g' | cat -s > net/constants.lua
|
||||
|
||||
|
||||
%.lua: %.fnl
|
||||
fennel --compile $< > $@
|
21
pkgs/anoia/assert.fnl
Normal file
21
pkgs/anoia/assert.fnl
Normal file
@ -0,0 +1,21 @@
|
||||
;; these are macros; this module should be imported
|
||||
;; using import-macros
|
||||
|
||||
;; e.g. (import-macros { : expect= } :anoia.assert)
|
||||
|
||||
|
||||
(fn expect [assertion]
|
||||
(let [msg (.. "expectation failed: " (view assertion))]
|
||||
`(when (not ,assertion)
|
||||
(assert false ,msg))))
|
||||
|
||||
(fn expect= [actual expected]
|
||||
`(let [view# (. (require :fennel) :view)
|
||||
ve# (view# ,expected)
|
||||
va# (view# ,actual)]
|
||||
(when (not (= ve# va#))
|
||||
(assert false
|
||||
(.. "\nexpected " ve# "\ngot " va#)
|
||||
))))
|
||||
|
||||
{ : expect : expect= }
|
@ -1,22 +1,27 @@
|
||||
{
|
||||
fennel
|
||||
, stdenv
|
||||
, linotify
|
||||
, lua
|
||||
, lualinux
|
||||
, cpio
|
||||
}:
|
||||
let pname = "anoia";
|
||||
in stdenv.mkDerivation {
|
||||
inherit pname;
|
||||
version = "0.1";
|
||||
src = ./.;
|
||||
nativeBuildInputs = [ fennel ];
|
||||
buildInputs = with lua.pkgs; [ luafilesystem ];
|
||||
buildPhase = ''
|
||||
for f in *.fnl ; do
|
||||
fennel --compile $f > `basename $f .fnl`.lua
|
||||
done
|
||||
'';
|
||||
nativeBuildInputs = [ fennel cpio ];
|
||||
buildInputs = with lua.pkgs; [ linotify lualinux ];
|
||||
outputs = [ "out" "dev" ];
|
||||
|
||||
doCheck = true;
|
||||
|
||||
installPhase = ''
|
||||
mkdir -p "$out/share/lua/${lua.luaversion}/${pname}"
|
||||
cp *.lua "$out/share/lua/${lua.luaversion}/${pname}"
|
||||
find . -name \*.lua | cpio -p -d "$out/share/lua/${lua.luaversion}/${pname}"
|
||||
|
||||
mkdir -p "$dev/share/lua/${lua.luaversion}/${pname}"
|
||||
cp assert.fnl "$dev/share/lua/${lua.luaversion}/${pname}"
|
||||
'';
|
||||
}
|
||||
|
@ -1,7 +1,30 @@
|
||||
(local lfs (require :lfs))
|
||||
(local ll (require :lualinux))
|
||||
|
||||
(local S_IFMT 0xf000)
|
||||
(local S_IFSOCK 0xc000)
|
||||
(local S_IFLNK 0xa000)
|
||||
(local S_IFREG 0x8000)
|
||||
(local S_IFBLK 0x6000)
|
||||
(local S_IFDIR 0x4000)
|
||||
(local S_IFCHR 0x2000)
|
||||
(local S_IFIFO 0x1000)
|
||||
|
||||
(fn ifmt-bits [mode] (and mode (band mode 0xf000)))
|
||||
|
||||
(fn file-type [pathname]
|
||||
(. {
|
||||
S_IFDIR :directory
|
||||
S_IFSOCK :socket
|
||||
S_IFLNK :link
|
||||
S_IFREG :file
|
||||
S_IFBLK :block-device
|
||||
S_IFCHR :character-device
|
||||
S_IFIFO :fifo
|
||||
}
|
||||
(ifmt-bits (ll.lstat3 pathname))))
|
||||
|
||||
(fn directory? [pathname]
|
||||
(= (lfs.symlinkattributes pathname :mode) "directory"))
|
||||
(= (file-type pathname) :directory))
|
||||
|
||||
(fn mktree [pathname]
|
||||
(if (or (= pathname "") (= pathname "/"))
|
||||
@ -10,27 +33,37 @@
|
||||
(or (directory? pathname)
|
||||
(let [parent (string.gsub pathname "/[^/]+/?$" "")]
|
||||
(or (directory? parent) (mktree parent))
|
||||
(assert (lfs.mkdir pathname)))))
|
||||
(assert (ll.mkdir pathname)))))
|
||||
|
||||
(fn dir [name]
|
||||
(let [dp (assert (ll.opendir name) name)]
|
||||
(fn []
|
||||
(match (ll.readdir dp)
|
||||
(name type) (values name type)
|
||||
(nil err) (do (if err (print err)) (ll.closedir dp) nil)))))
|
||||
|
||||
(fn rmtree [pathname]
|
||||
(case (lfs.symlinkattributes pathname)
|
||||
(case (file-type pathname)
|
||||
nil true
|
||||
{:mode "directory"}
|
||||
:directory
|
||||
(do
|
||||
(each [f (lfs.dir pathname)]
|
||||
(each [f (dir pathname)]
|
||||
(when (not (or (= f ".") (= f "..")))
|
||||
(rmtree ( .. pathname "/" f)))
|
||||
(lfs.rmdir pathname)))
|
||||
{:mode "file"}
|
||||
(ll.rmdir pathname)))
|
||||
:file
|
||||
(os.remove pathname)
|
||||
{:mode "link"}
|
||||
:link
|
||||
(os.remove pathname)
|
||||
unknown
|
||||
(error (.. "can't remove " pathname " of kind \"" unknown.mode "\""))))
|
||||
(error (.. "can't remove " pathname " of mode \"" unknown "\""))))
|
||||
|
||||
|
||||
{
|
||||
: mktree
|
||||
: rmtree
|
||||
: directory?
|
||||
: dir
|
||||
: file-type
|
||||
:symlink (fn [from to] (ll.symlink from to))
|
||||
}
|
||||
|
@ -1,3 +1,7 @@
|
||||
(fn assoc [tbl k v]
|
||||
(tset tbl k v)
|
||||
tbl)
|
||||
|
||||
(fn merge [table1 table2]
|
||||
(collect [k v (pairs table2) &into table1]
|
||||
k v))
|
||||
@ -14,9 +18,15 @@
|
||||
f (do (f:close) true)
|
||||
_ false))
|
||||
|
||||
(fn basename [path]
|
||||
(string.match path ".*/([^/]-)$"))
|
||||
|
||||
(fn dirname [path]
|
||||
(string.match path "(.*)/[^/]-$"))
|
||||
|
||||
(fn system [s]
|
||||
(match (os.execute s)
|
||||
res res
|
||||
res (do (print (.. "Executed \"" s "\", exit code " (tostring res))) res)
|
||||
(nil err) (error (.. "Error executing \"" s "\" (" err ")"))))
|
||||
|
||||
(fn hash [str]
|
||||
@ -62,4 +72,15 @@
|
||||
(s:sub 1 (- (# s) pad))))
|
||||
|
||||
|
||||
{ : merge : split : file-exists? : system : hash : base64url : dup }
|
||||
{
|
||||
: assoc
|
||||
: base64url
|
||||
: basename
|
||||
: dirname
|
||||
: dup
|
||||
: file-exists?
|
||||
: hash
|
||||
: merge
|
||||
: split
|
||||
: system
|
||||
}
|
||||
|
11
pkgs/anoia/net/constants.c
Normal file
11
pkgs/anoia/net/constants.c
Normal file
@ -0,0 +1,11 @@
|
||||
|
||||
#define MACRO(c) [#c] = c,
|
||||
|
||||
return {
|
||||
MACRO(SOCK_STREAM)
|
||||
MACRO(SOCK_DGRAM)
|
||||
MACRO(SOCK_RAW)
|
||||
MACRO(AF_LOCAL)
|
||||
MACRO(AF_NETLINK)
|
||||
MACRO(NETLINK_KOBJECT_UEVENT)
|
||||
}
|
15
pkgs/anoia/nl.fnl
Normal file
15
pkgs/anoia/nl.fnl
Normal file
@ -0,0 +1,15 @@
|
||||
(local netlink (require :netlink))
|
||||
|
||||
; (local { : view } (require :fennel))
|
||||
|
||||
(fn events [groups]
|
||||
(let [sock (netlink.socket)]
|
||||
(coroutine.wrap
|
||||
(fn []
|
||||
(each [_ e (ipairs (sock:query groups))]
|
||||
(coroutine.yield e))
|
||||
(while (sock:poll)
|
||||
(each [_ e (ipairs (sock:event))]
|
||||
(coroutine.yield e)))))))
|
||||
|
||||
{ : events }
|
@ -1,7 +1,6 @@
|
||||
(local inotify (require :inotify))
|
||||
(local { : file-exists? } (require :anoia))
|
||||
(local { : directory? } (require :anoia.fs))
|
||||
(local lfs (require :lfs))
|
||||
(local { : file-type : dir &as fs } (require :anoia.fs))
|
||||
|
||||
(fn read-line [name]
|
||||
(with-open [f (assert (io.open name :r) (.. "can't open file " name))]
|
||||
@ -20,15 +19,15 @@
|
||||
handle))
|
||||
|
||||
(fn read-value [pathname]
|
||||
(case (lfs.symlinkattributes pathname)
|
||||
(case (file-type pathname)
|
||||
nil nil
|
||||
{:mode "directory"}
|
||||
(collect [f (lfs.dir pathname)]
|
||||
:directory
|
||||
(collect [f (fs.dir pathname)]
|
||||
(when (not (or (= f ".") (= f "..")))
|
||||
(values f (read-value ( .. pathname "/" f)))))
|
||||
{:mode "file"}
|
||||
:file
|
||||
(read-line pathname)
|
||||
{:mode "link"}
|
||||
:link
|
||||
(read-line pathname)
|
||||
unknown
|
||||
(error (.. "can't read " pathname " of kind \"" unknown.mode "\""))))
|
||||
|
7
pkgs/anoia/test-nl.fnl
Normal file
7
pkgs/anoia/test-nl.fnl
Normal file
@ -0,0 +1,7 @@
|
||||
(local nl (require :anoia.nl))
|
||||
(local { : view } (require :fennel))
|
||||
|
||||
(let [events (nl.events {:link true})]
|
||||
(each [ev events]
|
||||
(print "got one ")
|
||||
(print (view ev))))
|
@ -1,4 +1,4 @@
|
||||
(local svc (require :anoia.svc))
|
||||
(local svc (require :svc))
|
||||
(local { : view } (require :fennel))
|
||||
|
||||
(local ex (svc.open "./example-output"))
|
||||
|
@ -1,9 +1,10 @@
|
||||
(local { : hash : base64url } (require :anoia))
|
||||
(local { : hash : base64url } (require :init))
|
||||
(import-macros { : expect= } :assert)
|
||||
|
||||
(assert (= (hash "") 5381))
|
||||
(expect= (hash "") 5381)
|
||||
|
||||
;; these examples from https://theartincode.stanis.me/008-djb2/
|
||||
(assert (= (hash "Hello") 210676686969))
|
||||
(assert (= (hash "Hello!") 6952330670010))
|
||||
(expect= (hash "Hello") 210676686969)
|
||||
(expect= (hash "Hello!") 6952330670010)
|
||||
|
||||
(assert (= (base64url "hello world") "aGVsbG8gd29ybGQ"))
|
||||
(expect= (base64url "hello world") "aGVsbG8gd29ybGQ")
|
||||
|
@ -10,10 +10,7 @@ let
|
||||
type' = types.submodule { options = type; };
|
||||
in (mergeDefinitions [] type' defs).mergedValue;
|
||||
in {
|
||||
pseudofile = callPackage ./pseudofile {};
|
||||
liminix = {
|
||||
services = callPackage ./liminix-tools/services {};
|
||||
networking = callPackage ./liminix-tools/networking {};
|
||||
builders = {
|
||||
squashfs = callPackage ./liminix-tools/builders/squashfs.nix {};
|
||||
dtb = callPackage ./kernel/dtb.nix {};
|
||||
@ -52,32 +49,29 @@ in {
|
||||
};
|
||||
inherit typeChecked;
|
||||
};
|
||||
networking = callPackage ./liminix-tools/networking {};
|
||||
services = callPackage ./liminix-tools/services {};
|
||||
};
|
||||
writeFennelScript = callPackage ./write-fennel-script {};
|
||||
writeFennel = callPackage ./write-fennel {};
|
||||
writeAshScript = callPackage ./write-ash-script {};
|
||||
systemconfig = callPackage ./systemconfig {};
|
||||
s6-init-bin = callPackage ./s6-init-bin {};
|
||||
s6-rc-database = callPackage ./s6-rc-database {};
|
||||
run-liminix-vm = callPackage ./run-liminix-vm {};
|
||||
ppp = callPackage ./ppp {};
|
||||
pppoe = callPackage ./pppoe {};
|
||||
|
||||
kernel-backport = callPackage ./kernel-backport {};
|
||||
mac80211 = callPackage ./mac80211 {};
|
||||
netlink-lua = callPackage ./netlink-lua {};
|
||||
linotify = callPackage ./linotify {};
|
||||
ifwait = callPackage ./ifwait {};
|
||||
# please keep the rest of this list alphabetised :-)
|
||||
|
||||
anoia = callPackage ./anoia {};
|
||||
devout = callPackage ./devout {};
|
||||
fennel = callPackage ./fennel {};
|
||||
fennelrepl = callPackage ./fennelrepl {};
|
||||
firewallgen = callPackage ./firewallgen {};
|
||||
firmware-utils = callPackage ./firmware-utils {};
|
||||
gen_init_cpio = callPackage ./gen_init_cpio {};
|
||||
|
||||
serviceFns = callPackage ./service-fns {};
|
||||
|
||||
# these are packages for the build system not the host/target
|
||||
|
||||
tufted = callPackage ./tufted {};
|
||||
routeros = callPackage ./routeros {};
|
||||
go-l2tp = callPackage ./go-l2tp {};
|
||||
hi = callPackage ./hi {};
|
||||
ifwait = callPackage ./ifwait {};
|
||||
initramfs-peek = callPackage ./initramfs-peek {};
|
||||
kernel-backport = callPackage ./kernel-backport {};
|
||||
kmodloader = callPackage ./kmodloader {};
|
||||
levitate = callPackage ./levitate {};
|
||||
libubootenv = callPackage ./libubootenv {};
|
||||
linotify = callPackage ./linotify {};
|
||||
lualinux = callPackage ./lualinux {};
|
||||
|
||||
# we need to build real lzma instead of using xz, because the lzma
|
||||
# decoder in u-boot doesn't understand streaming lzma archives
|
||||
@ -86,24 +80,37 @@ in {
|
||||
# https://sourceforge.net/p/squashfs/mailman/message/26599379/
|
||||
lzma = callPackage ./lzma {};
|
||||
|
||||
preinit = callPackage ./preinit {};
|
||||
swconfig = callPackage ./swconfig {};
|
||||
odhcp6c = callPackage ./odhcp6c {};
|
||||
|
||||
openwrt = callPackage ./openwrt {};
|
||||
|
||||
initramfs-peek = callPackage ./initramfs-peek {};
|
||||
mac80211 = callPackage ./mac80211 {};
|
||||
zyxel-bootconfig = callPackage ./zyxel-bootconfig {};
|
||||
min-collect-garbage = callPackage ./min-collect-garbage {};
|
||||
min-copy-closure = callPackage ./min-copy-closure {};
|
||||
hi = callPackage ./hi {};
|
||||
firewallgen = callPackage ./firewallgen {};
|
||||
kernel-modules = callPackage ./kernel-modules {};
|
||||
minisock = callPackage ./minisock {};
|
||||
nellie = callPackage ./nellie {};
|
||||
netlink-lua = callPackage ./netlink-lua {};
|
||||
odhcp-script = callPackage ./odhcp-script {};
|
||||
fennel = callPackage ./fennel {};
|
||||
fennelrepl = callPackage ./fennelrepl {};
|
||||
anoia = callPackage ./anoia {};
|
||||
odhcp6c = callPackage ./odhcp6c {};
|
||||
openwrt = callPackage ./openwrt {};
|
||||
ppp = callPackage ./ppp {};
|
||||
pppoe = callPackage ./pppoe {};
|
||||
preinit = callPackage ./preinit {};
|
||||
pseudofile = callPackage ./pseudofile {};
|
||||
routeros = callPackage ./routeros {};
|
||||
run-liminix-vm = callPackage ./run-liminix-vm {};
|
||||
s6-init-bin = callPackage ./s6-init-bin {};
|
||||
s6-rc-database = callPackage ./s6-rc-database {};
|
||||
|
||||
levitate = callPackage ./levitate {};
|
||||
# schnapps is written by Turris and provides a high-level interface
|
||||
# to btrfs snapshots. It may be useful on the Turris Omnia to
|
||||
# install Liminix while retaining the ability to rollback to the
|
||||
# vendor OS, or even to derisk Liminix updates on that device
|
||||
schnapps = callPackage ./schnapps {};
|
||||
|
||||
libubootenv = callPackage ./libubootenv {};
|
||||
serviceFns = callPackage ./service-fns {};
|
||||
swconfig = callPackage ./swconfig {};
|
||||
systemconfig = callPackage ./systemconfig {};
|
||||
tufted = callPackage ./tufted {};
|
||||
uevent-watch = callPackage ./uevent-watch {};
|
||||
writeAshScript = callPackage ./write-ash-script {};
|
||||
writeFennel = callPackage ./write-fennel {};
|
||||
writeFennelScript = callPackage ./write-fennel-script {};
|
||||
}
|
||||
|
26
pkgs/devout/default.nix
Normal file
26
pkgs/devout/default.nix
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
lua
|
||||
, nellie
|
||||
, writeFennel
|
||||
, anoia
|
||||
, fennel
|
||||
, stdenv
|
||||
, fennelrepl
|
||||
, lualinux
|
||||
}:
|
||||
stdenv.mkDerivation {
|
||||
name = "devout";
|
||||
src = ./.;
|
||||
nativeBuildInputs = [ fennelrepl ];
|
||||
postBuild = ''
|
||||
LUA_CPATH=${lualinux}/lib/lua/5.3/?.so\;$LUA_CPATH \
|
||||
fennelrepl ./test.fnl
|
||||
'';
|
||||
installPhase = ''
|
||||
mkdir -p $out/bin
|
||||
cp -p ${writeFennel "devout" {
|
||||
packages = [fennel anoia nellie lualinux];
|
||||
mainFunction = "run";
|
||||
} ./devout.fnl} $out/bin/devout
|
||||
'';
|
||||
}
|
173
pkgs/devout/devout.fnl
Normal file
173
pkgs/devout/devout.fnl
Normal file
@ -0,0 +1,173 @@
|
||||
(local ll (require :lualinux))
|
||||
(local {
|
||||
: AF_LOCAL
|
||||
: AF_NETLINK
|
||||
: SOCK_STREAM
|
||||
: SOCK_RAW
|
||||
: NETLINK_KOBJECT_UEVENT
|
||||
} (require :anoia.net.constants))
|
||||
(local { : view } (require :fennel))
|
||||
|
||||
(fn trace [expr]
|
||||
(do (print :TRACE (view expr)) expr))
|
||||
|
||||
(macro check-errno [expr]
|
||||
(let [{ :view v } (require :fennel)]
|
||||
`(case ,expr
|
||||
val# val#
|
||||
(nil err#) (error (string.format "%s failed: errno=%d" ,(v expr) err#)))))
|
||||
|
||||
(fn format-event [e]
|
||||
(..
|
||||
(string.format "%s@%s\0" e.action e.path)
|
||||
(table.concat
|
||||
(icollect [k v (pairs e.attributes)]
|
||||
(string.format "%s=%s" (string.upper k) v ))
|
||||
"\n")))
|
||||
|
||||
(fn event-matches? [e terms]
|
||||
(accumulate [match? true
|
||||
name value (pairs terms)]
|
||||
(and match? (= value (. e.attributes name)))))
|
||||
|
||||
(fn parse-event [s]
|
||||
(let [at (string.find s "@" 1 true)
|
||||
(nl nxt) (string.find s "\0" 1 true)
|
||||
attributes
|
||||
(collect [k v (string.gmatch
|
||||
(string.sub s (+ 1 nxt))
|
||||
"(%g-)=(%g+)")]
|
||||
(k:lower) v)]
|
||||
{ : attributes
|
||||
:path (string.sub s (+ at 1) (- nl 1))
|
||||
:action (string.sub s 1 (- at 1))
|
||||
:format format-event
|
||||
:matches? event-matches?
|
||||
}))
|
||||
|
||||
(fn find-in-database [db terms]
|
||||
(accumulate [found []
|
||||
_ e (pairs db)]
|
||||
(if (e:matches? terms)
|
||||
(doto found (table.insert e))
|
||||
found)))
|
||||
|
||||
(fn record-event [db subscribers str]
|
||||
(let [e (parse-event str)]
|
||||
(match e.action
|
||||
:add (tset db e.path e)
|
||||
:change (tset db e.path e)
|
||||
;; should we do something for bind?
|
||||
:remove (tset db e.path nil)
|
||||
)
|
||||
(each [_ { : terms : callback } (pairs subscribers)]
|
||||
(if (e:matches? terms) (callback e)))
|
||||
e))
|
||||
|
||||
(fn database []
|
||||
(let [db {}
|
||||
subscribers []]
|
||||
{
|
||||
:find (fn [_ terms] (find-in-database db terms))
|
||||
:add (fn [_ event-string] (when event-string (record-event db subscribers event-string)))
|
||||
:at-path (fn [_ path] (. db path))
|
||||
:subscribe (fn [_ id callback terms]
|
||||
(let [past-events (find-in-database db terms)]
|
||||
(each [_ e (pairs past-events)]
|
||||
(callback e)))
|
||||
(tset subscribers id {: callback : terms }))
|
||||
:unsubscribe (fn [_ id] (tset subscribers id nil))
|
||||
}))
|
||||
|
||||
;; grepped from kernel headers
|
||||
|
||||
(local POLLIN 0x0001)
|
||||
(local POLLPRI 0x0002)
|
||||
(local POLLOUT 0x0004)
|
||||
(local POLLERR 0x0008)
|
||||
(local POLLHUP 0x0010)
|
||||
(local POLLNVAL 0x0020)
|
||||
|
||||
|
||||
(fn unix-socket [name]
|
||||
(let [addr (string.pack "=Hz" AF_LOCAL name)]
|
||||
(case (ll.socket AF_LOCAL SOCK_STREAM 0)
|
||||
fd (case (ll.bind fd addr)
|
||||
0 (doto fd (ll.listen 32))
|
||||
(nil err) (values nil err))
|
||||
(nil err) (values nil err))))
|
||||
|
||||
(fn pollfds-for [fds]
|
||||
(icollect [_ v (ipairs fds)]
|
||||
(bor (lshift v 32) (lshift 1 16))))
|
||||
|
||||
(fn unpack-pollfds [pollfds]
|
||||
(collect [_ v (ipairs pollfds)]
|
||||
(let [fd (band (rshift v 32) 0xffffffff)
|
||||
revent (band v 0xffff)]
|
||||
(values fd (if (> revent 0) revent nil)))))
|
||||
|
||||
(fn parse-terms [str]
|
||||
(collect [n (string.gmatch (str:gsub "\n+$" "") "([^ ]+)")]
|
||||
(string.match n "(.-)=(.+)")))
|
||||
|
||||
(fn handle-client [db client]
|
||||
(match (ll.read client)
|
||||
"" (do
|
||||
(db:unsubscribe client)
|
||||
false)
|
||||
s (do
|
||||
(db:subscribe
|
||||
client
|
||||
(fn [e]
|
||||
(ll.write client (format-event e)))
|
||||
(parse-terms s))
|
||||
true)
|
||||
(nil err) (do (print err) false)))
|
||||
|
||||
(fn open-netlink [groups]
|
||||
(match (ll.socket AF_NETLINK SOCK_RAW NETLINK_KOBJECT_UEVENT)
|
||||
fd (doto fd (ll.bind (string.pack "I2I2I4I4" ; family pad pid groups
|
||||
AF_NETLINK 0 0 groups)))
|
||||
(nil errno) (values nil errno)))
|
||||
|
||||
|
||||
(fn event-loop []
|
||||
(let [fds {}]
|
||||
{
|
||||
:register #(tset fds $2 $3)
|
||||
:feed (fn [_ revents]
|
||||
(each [fd revent (pairs revents)]
|
||||
(when (not ((. fds fd) fd))
|
||||
(tset fds fd nil)
|
||||
(ll.close fd))))
|
||||
:fds #(icollect [fd _ (pairs fds)] fd)
|
||||
:_tbl #(do fds) ;exposed for tests
|
||||
}))
|
||||
|
||||
(fn run []
|
||||
(let [[sockname nl-groups] arg
|
||||
s (check-errno (unix-socket sockname))
|
||||
db (database)
|
||||
nl (check-errno (open-netlink nl-groups))
|
||||
loop (event-loop)]
|
||||
(loop:register
|
||||
s
|
||||
#(case
|
||||
(ll.accept s)
|
||||
(client addr)
|
||||
(do
|
||||
(loop:register client (partial handle-client db))
|
||||
true)
|
||||
(nil err)
|
||||
(print (string.format "error accepting connection, errno=%d" err))))
|
||||
(loop:register
|
||||
nl
|
||||
#(do (db:add (ll.read nl)) true))
|
||||
(ll.write 10 "ready\n")
|
||||
(while true
|
||||
(let [pollfds (pollfds-for (loop:fds))]
|
||||
(ll.poll pollfds 5000)
|
||||
(loop:feed (unpack-pollfds pollfds))))))
|
||||
|
||||
{ : database : run : event-loop : parse-event }
|
210
pkgs/devout/test.fnl
Normal file
210
pkgs/devout/test.fnl
Normal file
@ -0,0 +1,210 @@
|
||||
(local { : database : event-loop : parse-event } (require :devout))
|
||||
(local { : view } (require :fennel))
|
||||
(local ll (require :lualinux))
|
||||
(import-macros { : expect : expect= } :anoia.assert)
|
||||
|
||||
(var failed false)
|
||||
(fn fail [d msg] (set failed true) (print :FAIL d (.. "\n" msg)))
|
||||
|
||||
(macro example [description & body]
|
||||
(if (. body 1)
|
||||
`(let [(ok?# err#) (xpcall (fn [] ,body) debug.traceback)]
|
||||
(if ok?#
|
||||
(print :PASS ,description)
|
||||
(fail ,description err#)))
|
||||
`(print :PENDING ,description)))
|
||||
|
||||
(local sda-uevent
|
||||
"add@/devices/pci0000:00/0000:00:13.0/usb1/1-1/1-1:1.0/host0/target0:0:0/0:0:0:0/block/sda\0ACTION=add
|
||||
DEVPATH=/devices/pci0000:00/0000:00:13.0/usb1/1-1/1-1:1.0/host0/target0:0:0/0:0:0:0/block/sda
|
||||
SUBSYSTEM=block
|
||||
MAJOR=8
|
||||
MINOR=0
|
||||
DEVNAME=sda
|
||||
DEVTYPE=disk
|
||||
DISKSEQ=2
|
||||
SEQNUM=1527")
|
||||
|
||||
(local sdb1-insert
|
||||
"add@/devices/pci0000:00/0000:00:14.0/usb1/1-3/1-3:1.0/host1/target1:0:0/1:0:0:0/block/sdb/sdb1\0ACTION=add
|
||||
DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-3/1-3:1.0/host1/target1:0:0/1:0:0:0/block/sdb/sdb1
|
||||
SUBSYSTEM=block
|
||||
DEVNAME=/dev/sdb1
|
||||
DEVTYPE=partition
|
||||
DISKSEQ=33
|
||||
PARTN=1
|
||||
SEQNUM=82381
|
||||
MAJOR=8
|
||||
MINOR=17")
|
||||
|
||||
(local sdb1-remove
|
||||
"remove@/devices/pci0000:00/0000:00:14.0/usb1/1-3/1-3:1.0/host1/target1:0:0/1:0:0:0/block/sdb/sdb1\0ACTION=remove
|
||||
DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-3/1-3:1.0/host1/target1:0:0/1:0:0:0/block/sdb/sdb1
|
||||
SUBSYSTEM=block
|
||||
DEVNAME=/dev/sdb1
|
||||
DEVTYPE=partition
|
||||
DISKSEQ=33
|
||||
PARTN=1
|
||||
SEQNUM=82386
|
||||
MAJOR=8
|
||||
MINOR=17")
|
||||
|
||||
(example
|
||||
"I can parse an event"
|
||||
(let [e (parse-event sdb1-insert)]
|
||||
(expect= e.attributes.seqnum "82381")
|
||||
(expect= e.attributes.devname "/dev/sdb1")
|
||||
(expect= e.path "/devices/pci0000:00/0000:00:14.0/usb1/1-3/1-3:1.0/host1/target1:0:0/1:0:0:0/block/sdb/sdb1")
|
||||
(expect= e.action :add)
|
||||
(expect= e (parse-event (e:format)))))
|
||||
|
||||
(example
|
||||
"An event can match against terms"
|
||||
(let [terms {:devname "foo" :partname "my-usbstick"}]
|
||||
(expect= (: (parse-event "add@/\0SEQNUM=1") :matches? terms) false)
|
||||
(expect= (: (parse-event "add@/\0DEVNAME=bill") :matches? terms) false)
|
||||
(expect= (: (parse-event "add@/\0DEVNAME=foo\nPARTNAME=my-usbstick") :matches? terms) true)
|
||||
(expect= (: (parse-event "add@/\0DEVNAME=foo\nPARTNAME=my-usbstick\nOTHERTHING=bar") :matches? terms) true)
|
||||
))
|
||||
|
||||
(example
|
||||
"given an empty database, searching it finds no entries"
|
||||
(let [db (database)]
|
||||
(expect= (db:find {:partname "boot"}) [])))
|
||||
|
||||
(example
|
||||
"when I add a device, I can find it"
|
||||
(let [db (database)]
|
||||
(db:add sda-uevent)
|
||||
(let [[m & more] (db:find {:devname "sda"})]
|
||||
(expect= m.attributes.devname "sda")
|
||||
(expect= m.attributes.major "8")
|
||||
(expect= more []))))
|
||||
|
||||
(example
|
||||
"when I add a device, I cannot find it with wrong terms"
|
||||
(let [db (database)]
|
||||
(db:add sda-uevent)
|
||||
(expect= (db:find {:devname "sdb"}) [])))
|
||||
|
||||
(example
|
||||
"when I add a device, I can retrieve it by path"
|
||||
(let [db (database)]
|
||||
(db:add sda-uevent)
|
||||
(let [m (db:at-path "/devices/pci0000:00/0000:00:13.0/usb1/1-1/1-1:1.0/host0/target0:0:0/0:0:0:0/block/sda")]
|
||||
(expect= m.attributes.devname "sda")
|
||||
(expect= m.attributes.major "8"))))
|
||||
|
||||
(example
|
||||
"when I add and then remove a device, I cannot retrieve it by path"
|
||||
(let [db (database)]
|
||||
(db:add sdb1-insert)
|
||||
(db:add sdb1-remove)
|
||||
(expect= (db:at-path "/devices/pci0000:00/0000:00:14.0/usb1/1-3/1-3:1.0/host1/target1:0:0/1:0:0:0/block/sdb/sdb1") nil)))
|
||||
|
||||
(example
|
||||
"when I add and then remove a device, I cannot find it"
|
||||
(let [db (database)]
|
||||
(db:add sdb1-insert)
|
||||
(db:add sda-uevent)
|
||||
(db:add sdb1-remove)
|
||||
(expect= (db:find {:devname "/dev/sdb1"}) [])))
|
||||
|
||||
(example
|
||||
"when I search on multiple terms it uses all of them"
|
||||
(let [db (database)]
|
||||
(db:add sda-uevent)
|
||||
(expect= (# (db:find {:devname "sda" :devtype "disk"})) 1)
|
||||
(expect= (# (db:find {:devname "sda" :devtype "dosk"})) 0)))
|
||||
|
||||
|
||||
;;; tests for indices
|
||||
|
||||
(example "when I add a device with $attributes major minor foo bar baz,
|
||||
it is added to indices for foo bar baz but not major minor")
|
||||
|
||||
(example "a removed device can no longer be found by looking in any index")
|
||||
|
||||
(example "when I query with multiple attributes, the search is performed using the most specific attribute"
|
||||
;; (= the attribute whose
|
||||
;; value at this key has fewest elements)
|
||||
)
|
||||
|
||||
;;; tests for subscriptions
|
||||
|
||||
(example
|
||||
"I can subscribe to some search terms and be notified of matching events"
|
||||
(var received [])
|
||||
(let [db (database)
|
||||
subscriber (fn [e] (table.insert received e))]
|
||||
(db:subscribe :me subscriber {:devname "/dev/sdb1"})
|
||||
(db:add sdb1-insert)
|
||||
(db:add sda-uevent)
|
||||
(db:add sdb1-remove)
|
||||
(expect= (# received) 2)))
|
||||
|
||||
(example
|
||||
"Subscribers get notifications of prior events for present devices"
|
||||
(var received [])
|
||||
(let [db (database)
|
||||
subscriber (fn [e] (table.insert received e))]
|
||||
(db:add sdb1-insert)
|
||||
(db:add sda-uevent)
|
||||
(db:subscribe :me subscriber {:devname "/dev/sdb1"})
|
||||
(expect= (# received) 1)))
|
||||
|
||||
(example
|
||||
"I can unsubscribe after subscribing"
|
||||
(var received [])
|
||||
(let [db (database)
|
||||
subscriber (fn [e] (table.insert received e))]
|
||||
(db:subscribe :me subscriber {:devname "/dev/sdb1"})
|
||||
(db:unsubscribe :me)
|
||||
(db:add sdb1-insert)
|
||||
(db:add sda-uevent)
|
||||
(db:add sdb1-remove)
|
||||
(expect= (# received) 0)))
|
||||
|
||||
|
||||
;;; test for event loop
|
||||
|
||||
(example
|
||||
"I can register a fd with a callback"
|
||||
(let [loop (event-loop)
|
||||
cb #(print $1)]
|
||||
(loop:register 3 cb)
|
||||
(expect= (. (loop:_tbl) 3) cb)))
|
||||
|
||||
(example
|
||||
"when the fd is ready, my callback is called"
|
||||
(let [loop (event-loop)]
|
||||
(var ran? false)
|
||||
(loop:register 3 #(set ran? true))
|
||||
(loop:feed {3 1})
|
||||
(expect= ran? true)
|
||||
))
|
||||
|
||||
(example
|
||||
"when the callback returns true it remains registered"
|
||||
(let [loop (event-loop)]
|
||||
(loop:register 3 #true)
|
||||
(loop:feed {3 1})
|
||||
(expect (. (loop:_tbl) 3))
|
||||
))
|
||||
|
||||
(fn new-fd []
|
||||
(ll.open "/dev/zero" 0 0x1ff))
|
||||
|
||||
(example
|
||||
"when the callback returns false it is unregistered and the fd is closed"
|
||||
(let [loop (event-loop)
|
||||
fd (new-fd)]
|
||||
(expect (> fd 2))
|
||||
(loop:register 3 #false)
|
||||
(loop:feed {3 1})
|
||||
(expect (not (. (loop:_tbl) 3)))
|
||||
(assert (not (os.execute (string.format "test -e /dev/fd/%d" fd))))
|
||||
))
|
||||
|
||||
|
||||
(if failed (os.exit 1) (print "OK"))
|
@ -5,16 +5,20 @@
|
||||
, lib
|
||||
, luaPackages
|
||||
, lua
|
||||
, lualinux
|
||||
, writeScriptBin
|
||||
, linotify
|
||||
, anoia
|
||||
, netlink-lua
|
||||
, fennel
|
||||
}:
|
||||
let packages = [
|
||||
linotify
|
||||
anoia
|
||||
fennel
|
||||
lua.pkgs.luafilesystem
|
||||
lualinux
|
||||
netlink-lua
|
||||
lua.pkgs.readline
|
||||
];
|
||||
join = ps: builtins.concatStringsSep ";" ps;
|
||||
luapath = join (builtins.map (f:
|
||||
@ -29,6 +33,7 @@ in writeScriptBin "fennelrepl" ''
|
||||
package.cpath = ${lib.strings.escapeShellArg luacpath} .. ";" .. (package.cpath or "")
|
||||
local fennel = require "fennel"
|
||||
table.insert(package.loaders or package.searchers,1, fennel.searcher)
|
||||
fennel['macro-path'] = "${anoia.dev}/share/lua/${lua.luaversion}/?.fnl;" .. fennel['macro-path']
|
||||
|
||||
local more_fennel = os.getenv("FENNEL_PATH")
|
||||
if more_fennel then
|
||||
|
24
pkgs/firmware-utils/default.nix
Normal file
24
pkgs/firmware-utils/default.nix
Normal file
@ -0,0 +1,24 @@
|
||||
{ stdenv
|
||||
, fetchFromGitHub
|
||||
, cmake
|
||||
, zlib
|
||||
, openssl
|
||||
}:
|
||||
|
||||
stdenv.mkDerivation {
|
||||
pname = "firmware-utils";
|
||||
version = "snapshot";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "openwrt";
|
||||
repo = "firmware-utils";
|
||||
rev = "e87f23849790a7c77b4cd0e8ef0384da188174e5";
|
||||
hash = "sha256-285Isf9sRuUt5S56SozgqpnS0+LOfnvpxpnWLwuWYUk=";
|
||||
};
|
||||
|
||||
nativeBuildInputs = [
|
||||
cmake
|
||||
zlib
|
||||
openssl
|
||||
];
|
||||
}
|
@ -3,8 +3,9 @@
|
||||
, netlink-lua
|
||||
, writeFennelScript
|
||||
, runCommand
|
||||
, anoia
|
||||
}:
|
||||
runCommand "ifwait" {} ''
|
||||
mkdir -p $out/bin
|
||||
cp -p ${writeFennelScript "ifwait" [netlink-lua] ./ifwait.fnl} $out/bin/ifwait
|
||||
cp -p ${writeFennelScript "ifwait" [anoia netlink-lua] ./ifwait.fnl} $out/bin/ifwait
|
||||
''
|
||||
|
195
pkgs/ifwait/events-fixture
Normal file
195
pkgs/ifwait/events-fixture
Normal file
@ -0,0 +1,195 @@
|
||||
{:event "newlink"
|
||||
:hwaddr "00:00:00:00:00:00"
|
||||
:index 1
|
||||
:mtu 65536
|
||||
:name "lo"
|
||||
:running "yes"
|
||||
:stamp 857161382
|
||||
:up "yes"}
|
||||
{:event "newlink"
|
||||
:hwaddr "50:3e:aa:08:df:52"
|
||||
:index 2
|
||||
:mtu 1500
|
||||
:name "enp1s0"
|
||||
:running "no"
|
||||
:stamp 857161382
|
||||
:up "yes"}
|
||||
{:event "newlink"
|
||||
:hwaddr "1c:1b:0d:9c:39:2d"
|
||||
:index 3
|
||||
:mtu 1500
|
||||
:name "enp0s31f6"
|
||||
:running "yes"
|
||||
:stamp 857161382
|
||||
:up "yes"}
|
||||
{:event "newlink"
|
||||
:hwaddr "da:4d:53:c3:54:43"
|
||||
:index 4
|
||||
:mtu 1500
|
||||
:name "vbridge0"
|
||||
:running "yes"
|
||||
:stamp 857161382
|
||||
:up "yes"}
|
||||
{:event "newlink"
|
||||
:hwaddr "00:28:f8:69:fa:14"
|
||||
:index 6
|
||||
:mtu 1500
|
||||
:name "wlp4s0"
|
||||
:running "no"
|
||||
:stamp 857161382
|
||||
:up "no"}
|
||||
{:event "newlink"
|
||||
:hwaddr "02:42:b1:e6:e5:bd"
|
||||
:index 7
|
||||
:mtu 1500
|
||||
:name "br-7ddfef4820c5"
|
||||
:running "no"
|
||||
:stamp 857161382
|
||||
:up "yes"}
|
||||
{:event "newlink"
|
||||
:hwaddr "02:42:8d:d4:36:34"
|
||||
:index 8
|
||||
:mtu 1500
|
||||
:name "br-95da8b40a7cc"
|
||||
:running "yes"
|
||||
:stamp 857161382
|
||||
:up "yes"}
|
||||
{:event "newlink"
|
||||
:hwaddr "02:42:bc:cf:a8:5e"
|
||||
:index 9
|
||||
:mtu 1500
|
||||
:name "docker0"
|
||||
:running "no"
|
||||
:stamp 857161382
|
||||
:up "yes"}
|
||||
{:event "newlink"
|
||||
:hwaddr "b6:66:50:69:33:a6"
|
||||
:index 11
|
||||
:mtu 1500
|
||||
:name "veth2ff6ec3"
|
||||
:running "yes"
|
||||
:stamp 857161382
|
||||
:up "yes"}
|
||||
{:event "newlink"
|
||||
:hwaddr "e6:94:c8:48:f3:97"
|
||||
:index 13
|
||||
:mtu 1500
|
||||
:name "veth0913974"
|
||||
:running "yes"
|
||||
:stamp 857161382
|
||||
:up "yes"}
|
||||
{:event "newlink"
|
||||
:hwaddr "9a:87:d8:f2:c6:96"
|
||||
:index 15
|
||||
:mtu 1500
|
||||
:name "veth0e74156"
|
||||
:running "yes"
|
||||
:stamp 857161382
|
||||
:up "yes"}
|
||||
{:event "newlink"
|
||||
:hwaddr "5e:d2:92:b9:5f:6d"
|
||||
:index 17
|
||||
:mtu 1500
|
||||
:name "veth89a36b3"
|
||||
:running "yes"
|
||||
:stamp 857161382
|
||||
:up "yes"}
|
||||
{:event "newlink"
|
||||
:hwaddr "ca:88:3f:09:bc:51"
|
||||
:index 19
|
||||
:mtu 1500
|
||||
:name "veth73c1e0b"
|
||||
:running "yes"
|
||||
:stamp 857161382
|
||||
:up "yes"}
|
||||
{:event "newlink"
|
||||
:hwaddr "b6:7d:5c:38:89:1d"
|
||||
:index 21
|
||||
:mtu 1500
|
||||
:name "dummy0"
|
||||
:running "no"
|
||||
:stamp 857161382
|
||||
:up "no"}
|
||||
{:event "newlink"
|
||||
:hwaddr "52:f0:46:da:0c:0c"
|
||||
:index 22
|
||||
:mtu 1500
|
||||
:name "dummy1"
|
||||
:running "yes"
|
||||
:stamp 857161382
|
||||
:up "yes"}
|
||||
{:event "newneigh"
|
||||
:hwaddr "00:22:61:3d:f7:54"
|
||||
:index 4
|
||||
:ip "192.168.8.140"
|
||||
:probes 1
|
||||
:stamp 857165355
|
||||
:state "stale"}
|
||||
{:event "delneigh"
|
||||
:hwaddr "5c:60:ba:58:34:93"
|
||||
:index 3
|
||||
:stamp 857166891
|
||||
:state "stale"}
|
||||
{:event "newneigh"
|
||||
:hwaddr "80:64:6f:9e:15:02"
|
||||
:index 4
|
||||
:ip "192.168.8.161"
|
||||
:probes 1
|
||||
:stamp 857172523
|
||||
:state "stale"}
|
||||
{:event "newneigh"
|
||||
:hwaddr "e4:95:6e:42:c2:6c"
|
||||
:index 3
|
||||
:stamp 857174763
|
||||
:state "reachable"}
|
||||
{:event "newneigh"
|
||||
:hwaddr "e4:b3:18:76:1b:23"
|
||||
:index 4
|
||||
:ip "2001:8b0:de3a:40de:4708:c700:4de2:9264"
|
||||
:probes 1
|
||||
:stamp 857175595
|
||||
:state "stale"}
|
||||
{:event "newneigh"
|
||||
:hwaddr "80:64:6f:9e:10:c6"
|
||||
:index 4
|
||||
:ip "192.168.8.53"
|
||||
:probes 1
|
||||
:stamp 857176619
|
||||
:state "stale"}
|
||||
{:event "newneigh"
|
||||
:hwaddr "80:64:6f:9e:15:02"
|
||||
:index 4
|
||||
:ip "192.168.8.161"
|
||||
:probes 1
|
||||
:stamp 857177643
|
||||
:state "probe"}
|
||||
{:event "newneigh"
|
||||
:hwaddr "80:64:6f:9e:15:02"
|
||||
:index 4
|
||||
:ip "192.168.8.161"
|
||||
:probes 1
|
||||
:stamp 857177644
|
||||
:state "reachable"}
|
||||
{:event "newlink"
|
||||
:hwaddr "b6:7d:5c:38:89:1d"
|
||||
:index 21
|
||||
:mtu 1500
|
||||
:name "dummy0"
|
||||
:running "yes"
|
||||
:stamp 857178258
|
||||
:up "yes"}
|
||||
{:event "newlink"
|
||||
:hwaddr "b6:7d:5c:38:89:1d"
|
||||
:index 21
|
||||
:mtu 1500
|
||||
:name "dummy0"
|
||||
:running "no"
|
||||
:stamp 857181661
|
||||
:up "no"}
|
||||
{:event "newneigh"
|
||||
:hwaddr "80:64:6f:9e:10:c6"
|
||||
:index 4
|
||||
:ip "192.168.8.53"
|
||||
:probes 1
|
||||
:stamp 857182251
|
||||
:state "probe"}
|
@ -1,52 +1,64 @@
|
||||
(local netlink (require :netlink))
|
||||
(local sock (netlink.socket))
|
||||
(local nl (require :anoia.nl))
|
||||
(local { : assoc : system } (require :anoia))
|
||||
|
||||
; (local { : view} (require :fennel))
|
||||
|
||||
(fn assoc [tbl k v]
|
||||
(tset tbl k v)
|
||||
tbl)
|
||||
|
||||
(fn parse-args [args]
|
||||
(match args
|
||||
["-v" & rest] (assoc (parse-args rest) :verbose true)
|
||||
["-t" timeout & rest] (assoc (parse-args rest) :timeout (tonumber timeout))
|
||||
["-s" service & rest] (assoc (parse-args rest) :service service)
|
||||
[linkname "up"] {:link linkname :expecting "up"}
|
||||
[linkname "running"] {:link linkname :expecting "running"}
|
||||
[linkname "present"] {:link linkname :expecting "present"}
|
||||
[linkname nil] {:link linkname :expecting "present"}
|
||||
_ nil))
|
||||
|
||||
(local parameters
|
||||
(or
|
||||
(parse-args arg)
|
||||
(assert false (.. "Usage: " (. arg 0) " [-v] ifname [present|up|running]"))))
|
||||
(fn event-matches? [params v]
|
||||
(let [got
|
||||
(match v
|
||||
;; - up: Reflects the administrative state of the interface (IFF_UP)
|
||||
;; - running: Reflects the operational state (IFF_RUNNING).
|
||||
{:event "newlink" :name params.link :up :yes :running :yes}
|
||||
{:present true :up true :running true}
|
||||
|
||||
(fn run-events [evs]
|
||||
(each [_ v (ipairs evs)]
|
||||
(let [got
|
||||
(match v
|
||||
;; - up: Reflects the administrative state of the interface (IFF_UP)
|
||||
;; - running: Reflects the operational state (IFF_RUNNING).
|
||||
{:event "newlink" :name parameters.link :up :yes :running :yes}
|
||||
{:present true :up true :running true}
|
||||
{:event "newlink" :name params.link :up :yes}
|
||||
{:present :true :up true}
|
||||
|
||||
{:event "newlink" :name parameters.link :up :yes}
|
||||
{:present :true :up true}
|
||||
{:event "newlink" :name params.link}
|
||||
{:present true }
|
||||
|
||||
{:event "newlink" :name parameters.link}
|
||||
{:present true }
|
||||
_
|
||||
{})]
|
||||
(not (not (. got params.expecting)))))
|
||||
|
||||
_
|
||||
{})]
|
||||
(when (. got parameters.expecting)
|
||||
(os.exit 0)))))
|
||||
(var up :unknown)
|
||||
(fn toggle-service [service wanted?]
|
||||
(when (not (= up wanted?))
|
||||
(set up
|
||||
(if wanted?
|
||||
(pcall system (.. "s6-rc -b -u change " service))
|
||||
(not (pcall system (.. "s6-rc -b -d change " service)))))
|
||||
))
|
||||
|
||||
(fn run [args event-fn]
|
||||
(set up :unknown)
|
||||
(let [parameters
|
||||
(assert (parse-args args)
|
||||
(.. "Usage: ifwait [-v] ifname [present|up|running]"))]
|
||||
(when parameters.verbose
|
||||
(print (.. "ifwait: waiting for "
|
||||
parameters.link " to be " parameters.expecting)))
|
||||
|
||||
(when parameters.verbose
|
||||
(print (.. (. arg 0) ": waiting for "
|
||||
parameters.link " to be " parameters.expecting)))
|
||||
(if parameters.service
|
||||
(each [e (event-fn)]
|
||||
(if (= e.name parameters.link)
|
||||
(toggle-service parameters.service (event-matches? parameters e))))
|
||||
(each [e (event-fn)
|
||||
&until (event-matches? parameters e)]
|
||||
true))))
|
||||
|
||||
(run-events (sock:query {:link true}))
|
||||
(when (not (= (. arg 0) "test"))
|
||||
(run arg #(nl.events {:link true})))
|
||||
|
||||
(while (sock:poll) (run-events (sock:event)))
|
||||
{ : run }
|
||||
|
117
pkgs/ifwait/test-ifwait.fnl
Normal file
117
pkgs/ifwait/test-ifwait.fnl
Normal file
@ -0,0 +1,117 @@
|
||||
(local { : view &as fennel } (require :fennel))
|
||||
(local anoia (require :anoia))
|
||||
(import-macros { : expect= } :anoia.assert)
|
||||
|
||||
;; nix-shell --run "cd pkgs/ifwait && fennelrepl test-ifwait.fnl"
|
||||
|
||||
(var fake-system (fn [s] (print "executing " s)))
|
||||
(tset anoia :system #(fake-system $1))
|
||||
|
||||
|
||||
(fn event-generator [events]
|
||||
(coroutine.wrap
|
||||
(fn []
|
||||
(each [_ e (ipairs events)] (coroutine.yield e)))))
|
||||
|
||||
(fn file-events [path]
|
||||
(let [data (with-open [e (io.open path "r")] (e:read "*a"))
|
||||
parse (fennel.parser data)]
|
||||
(icollect [_ ast parse]
|
||||
ast)))
|
||||
|
||||
(set _G.arg (doto [] (tset 0 "test")))
|
||||
(local ifwait (require :ifwait))
|
||||
|
||||
(let [gen (event-generator (file-events "events-fixture"))]
|
||||
(ifwait.run ["dummy0" "up"] #gen)
|
||||
(match (pcall gen)
|
||||
(true _) true
|
||||
(false msg) (error "didn't detect dummy0 up event")))
|
||||
|
||||
(var upsies [])
|
||||
(set fake-system
|
||||
(fn [s]
|
||||
(if (s:match "-u change addmember")
|
||||
(table.insert upsies :u)
|
||||
(s:match "-d change addmember")
|
||||
(table.insert upsies :d))))
|
||||
|
||||
(fn newlink [name up running]
|
||||
{:event "newlink"
|
||||
:hwaddr "b6:7d:5c:38:89:1d"
|
||||
:index (string.unpack ">i2" name)
|
||||
:mtu 1500
|
||||
: name
|
||||
: running
|
||||
:stamp 857161382
|
||||
: up })
|
||||
|
||||
"when it gets events that don't match the interface, nothing happens"
|
||||
|
||||
(let [gen (-> [(newlink "eth1" "no" "no")] event-generator)]
|
||||
(set upsies [])
|
||||
(ifwait.run [ "-s" "addmember" "dummy0" "up"] #gen)
|
||||
(expect= upsies []))
|
||||
|
||||
"when it gets an event that should start the service, the service starts"
|
||||
|
||||
(let [gen (->
|
||||
[(newlink "dummy0" "no" "no")
|
||||
(newlink "dummy0" "yes" "no")
|
||||
(newlink "eth1" "no" "no")]
|
||||
event-generator)]
|
||||
(set upsies [])
|
||||
(ifwait.run ["-s" "addmember" "dummy0" "up"] #gen)
|
||||
(expect= upsies [:d :u]))
|
||||
|
||||
"when it gets an event that should stop the service, the service stops"
|
||||
|
||||
(let [gen (->
|
||||
[(newlink "dummy0" "no" "no")
|
||||
(newlink "dummy0" "yes" "no")
|
||||
(newlink "dummy0" "no" "no")
|
||||
]
|
||||
event-generator)]
|
||||
(set upsies [])
|
||||
(ifwait.run ["-s" "addmember" "dummy0" "up"] #gen)
|
||||
(expect= upsies [:d :u :d]))
|
||||
|
||||
"it does not call s6-rc again if the service is already in required state"
|
||||
|
||||
(let [gen (->
|
||||
[(newlink "dummy0" "no" "no")
|
||||
(newlink "dummy0" "yes" "no")
|
||||
(newlink "dummy0" "yes" "yes")
|
||||
(newlink "dummy0" "yes" "yes")
|
||||
(newlink "dummy0" "yes" "no")
|
||||
(newlink "dummy0" "no" "no")
|
||||
]
|
||||
event-generator)]
|
||||
(set upsies [])
|
||||
(ifwait.run ["-s" "addmember" "dummy0" "up"] #gen)
|
||||
(expect= upsies [:d :u :d]))
|
||||
|
||||
"it handles an error return from s6-rc"
|
||||
|
||||
(set fake-system
|
||||
(fn [s]
|
||||
(if (s:match "-u change addmember")
|
||||
(table.insert upsies :u)
|
||||
(s:match "-d change addmember")
|
||||
(table.insert upsies :d))
|
||||
(error "false")
|
||||
))
|
||||
|
||||
(let [gen (->
|
||||
[(newlink "dummy0" "yes" "no")
|
||||
(newlink "dummy0" "yes" "yes")
|
||||
(newlink "dummy0" "yes" "yes")
|
||||
(newlink "dummy0" "yes" "no")
|
||||
(newlink "dummy0" "no" "no")
|
||||
]
|
||||
event-generator)]
|
||||
(set upsies [])
|
||||
(ifwait.run ["-s" "addmember" "dummy0" "up"] #gen)
|
||||
(expect= upsies [:u :u :u :u]))
|
||||
|
||||
(print "OK")
|
@ -1,3 +0,0 @@
|
||||
|
||||
|
||||
# obj-m += net/ipv4/netfilter/nft_fib_ipv4.o
|
@ -1,55 +0,0 @@
|
||||
{
|
||||
stdenv
|
||||
, buildPackages
|
||||
, kernelSrc ? null
|
||||
, modulesupport ? null
|
||||
, targets ? []
|
||||
, kconfig ? {}
|
||||
, openssl
|
||||
, writeText
|
||||
, lib
|
||||
}:
|
||||
let
|
||||
writeConfig = import ../kernel/write-kconfig.nix { inherit lib writeText; };
|
||||
arch = if stdenv.isMips
|
||||
then "mips"
|
||||
else if stdenv.isAarch64
|
||||
then "arm64"
|
||||
else throw "unknown arch";
|
||||
in stdenv.mkDerivation {
|
||||
name = "kernel-modules";
|
||||
|
||||
nativeBuildInputs = [buildPackages.stdenv.cc] ++
|
||||
(with buildPackages.pkgs; [
|
||||
bc bison flex
|
||||
openssl
|
||||
cpio
|
||||
kmod
|
||||
]);
|
||||
CC = "${stdenv.cc.bintools.targetPrefix}gcc";
|
||||
HOST_EXTRACFLAGS = with buildPackages.pkgs;
|
||||
"-I${buildPackages.openssl.dev}/include -L${buildPackages.openssl.out}/lib";
|
||||
CROSS_COMPILE = stdenv.cc.bintools.targetPrefix;
|
||||
ARCH = arch;
|
||||
KBUILD_BUILD_HOST = "liminix.builder";
|
||||
|
||||
buildPhase = ''
|
||||
cat ${writeConfig "kconfig" kconfig} > .more-config
|
||||
cat .more-config >> .config
|
||||
make olddefconfig
|
||||
for v in $(cat .more-config) ; do grep $v .config || (echo Missing $v && exit 1);done
|
||||
# grep =m .config
|
||||
make modules
|
||||
'';
|
||||
src = modulesupport;
|
||||
installPhase = ''
|
||||
mkdir -p $out/lib/modules/0.0
|
||||
find . -name \*.ko | cpio --verbose --make-directories -p $out/lib/modules/0.0
|
||||
depmod -b $out -v 0.0
|
||||
touch $out/load.sh
|
||||
for i in ${lib.concatStringsSep " " targets}; do
|
||||
modprobe -S 0.0 -d $out --show-depends $i >> $out/load.sh
|
||||
done
|
||||
tac < $out/load.sh | sed 's/^insmod/rmmod/g' > $out/unload.sh
|
||||
'';
|
||||
}
|
@ -6,6 +6,7 @@
|
||||
|
||||
, config
|
||||
, src
|
||||
, version ? "0"
|
||||
, extraPatchPhase ? "echo"
|
||||
, targets ? ["vmlinux"]
|
||||
} :
|
||||
@ -51,9 +52,9 @@ stdenv.mkDerivation rec {
|
||||
|
||||
patches = [
|
||||
./cmdline-cookie.patch
|
||||
./phram-allow-cached-mappings.patch
|
||||
./mips-malta-fdt-from-bootloader.patch
|
||||
];
|
||||
] ++ lib.optional (lib.versionOlder version "5.18.0")
|
||||
./phram-allow-cached-mappings.patch;
|
||||
|
||||
# this is here to work around what I think is a bug in nixpkgs
|
||||
# packaging of ncurses: it installs pkg-config data files which
|
||||
@ -103,8 +104,7 @@ stdenv.mkDerivation rec {
|
||||
mkdir -p $headers
|
||||
cp -a include .config $headers/
|
||||
mkdir -p $modulesupport
|
||||
cp modules.* $modulesupport
|
||||
make clean modules_prepare
|
||||
make modules
|
||||
cp -a . $modulesupport
|
||||
'';
|
||||
}
|
||||
|
@ -15,10 +15,12 @@ let
|
||||
in {
|
||||
kernel
|
||||
, commandLine
|
||||
, commandLineDtbNode ? "bootargs"
|
||||
, entryPoint
|
||||
, extraName ? "" # e.g. socFamily
|
||||
, loadAddress
|
||||
, imageFormat
|
||||
, alignment ? null
|
||||
, dtb ? null
|
||||
} : stdenv.mkDerivation {
|
||||
name = "kernel.image";
|
||||
@ -39,7 +41,7 @@ in {
|
||||
'';
|
||||
mungeDtbPhase = ''
|
||||
dtc -I dtb -O dts -o tmp.dts ${dtb}
|
||||
echo '/{ chosen { bootargs = ${builtins.toJSON commandLine}; }; };' >> tmp.dts
|
||||
echo '/{ chosen { ${commandLineDtbNode} = ${builtins.toJSON commandLine}; }; };' >> tmp.dts
|
||||
dtc -I dts -O dtb -o tmp.dtb tmp.dts
|
||||
'';
|
||||
|
||||
@ -69,7 +71,7 @@ in {
|
||||
};
|
||||
};
|
||||
_VARS
|
||||
mkimage -f mkimage.its kernel.uimage
|
||||
mkimage -f mkimage.its ${lib.optionalString (alignment != null) "-B 0x${lib.toHexString alignment}"} kernel.uimage
|
||||
mkimage -l kernel.uimage
|
||||
'';
|
||||
|
||||
|
43
pkgs/kmodloader/default.nix
Normal file
43
pkgs/kmodloader/default.nix
Normal file
@ -0,0 +1,43 @@
|
||||
{
|
||||
liminix
|
||||
, lib
|
||||
, targets ? []
|
||||
, kernel ? null
|
||||
, runCommand
|
||||
, pkgsBuildBuild
|
||||
, dependencies ? []
|
||||
} :
|
||||
let
|
||||
inherit (liminix.services) oneshot;
|
||||
inherit (lib) concatStringsSep;
|
||||
loader = runCommand "modules" {
|
||||
nativeBuildInputs = with pkgsBuildBuild ;[
|
||||
kmod cpio gawk
|
||||
];
|
||||
} ''
|
||||
kernel=${kernel.modulesupport}
|
||||
|
||||
mkdir -p lib/modules/0.0
|
||||
(cd $kernel && find . -name \*.ko | cpio --verbose --make-directories -p $NIX_BUILD_TOP/lib/modules/0.0)
|
||||
cp $kernel/modules.* lib/modules/0.0
|
||||
depmod -b . 0.0
|
||||
|
||||
(for i in ${lib.concatStringsSep " " targets}; do
|
||||
modprobe -S 0.0 -d $NIX_BUILD_TOP --show-depends $i | sed "s,^insmod $NIX_BUILD_TOP/lib/modules/0.0/,,g"
|
||||
done) | awk '!a[$0]++' > load-order
|
||||
|
||||
mkdir $out
|
||||
for i in $(cat load-order); do
|
||||
install -v $NIX_BUILD_TOP/lib/modules/0.0/$i -D $out/$i
|
||||
done
|
||||
echo "O=$out" > $out/load.sh
|
||||
sed "s,^,insmod \$O/,g" < load-order >> $out/load.sh
|
||||
echo "O=$out" > $out/unload.sh
|
||||
tac load-order | sed "s,^,rmmod \$O/,g" > $out/unload.sh
|
||||
'';
|
||||
in oneshot {
|
||||
name = "kmodloader-" + (concatStringsSep "-" targets);
|
||||
up = "sh ${loader}/load.sh";
|
||||
down = "sh ${loader}/unload.sh";
|
||||
inherit dependencies;
|
||||
}
|
@ -4,7 +4,7 @@
|
||||
, systemconfig
|
||||
, execline
|
||||
, lib
|
||||
, services ? null
|
||||
, config ? {}
|
||||
, liminix
|
||||
, pseudofile
|
||||
, pkgs
|
||||
@ -12,6 +12,7 @@
|
||||
let
|
||||
inherit (pseudofile) dir symlink;
|
||||
inherit (liminix.services) oneshot;
|
||||
paramConfig = config;
|
||||
newRoot = "/run/maintenance";
|
||||
sysconfig =
|
||||
let
|
||||
@ -25,8 +26,8 @@ let
|
||||
emptyenv chroot . /bin/init
|
||||
'';
|
||||
base = {...} : {
|
||||
config = {
|
||||
services = services // {
|
||||
config = {
|
||||
services = {
|
||||
banner = oneshot {
|
||||
name = "banner";
|
||||
up = "cat /etc/banner > /dev/console";
|
||||
@ -60,6 +61,7 @@ let
|
||||
../../modules/users.nix
|
||||
../../modules/busybox.nix
|
||||
base
|
||||
({ ... } : paramConfig)
|
||||
../../modules/s6
|
||||
];
|
||||
};
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user