forked from dan/liminix
Compare commits
224 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 26b4a7a145 | |||
| 2663f58807 | |||
| 9dbc285605 | |||
| 8b6aa2134e | |||
| 3df1ec76ff | |||
| 0d3218127f | |||
| e94bf62ec1 | |||
| 16a2499d74 | |||
| d4d8093f97 | |||
| 7c9c801afc | |||
| c4185617c0 | |||
| 06d28e9b08 | |||
| 9540fc2641 | |||
| adc84108ad | |||
| eae99051fa | |||
| 49d1703428 | |||
| 1d337588f9 | |||
| 29a869b4fa | |||
| 5ae1b0a193 | |||
| 473a4947a5 | |||
| 50bad5c604 | |||
| c22e3fb2ef | |||
| f898e4dca2 | |||
| 5121a8563d | |||
| 78be354b6e | |||
| be13ab23ca | |||
| 4b30cd7a75 | |||
| b15542b668 | |||
| 6daeaf29a0 | |||
| e6ca5ea064 | |||
| e6e4665a18 | |||
| 2c10790a6d | |||
| 571adf84c0 | |||
| c8c79fd75a | |||
| 884d8d194e | |||
| f091bbd706 | |||
| 37d7e20582 | |||
| 04b068f7a3 | |||
| 53f57c1a8c | |||
| 19aba0d873 | |||
| 7d00b39249 | |||
| 7aa8633cde | |||
| 58bec8a40f | |||
| a3fca5bf05 | |||
| e0bd7aec1e | |||
| e815f61bb5 | |||
| af9200a136 | |||
| 898958fa10 | |||
| fa0f262706 | |||
| 71aeb27b2f | |||
| 530b4080c9 | |||
| 58cd007ccc | |||
| 3a56798eb5 | |||
| 758c7ef657 | |||
| 73225a70b2 | |||
| ab304dd3f1 | |||
| 0d49f0f7a7 | |||
| e64390460a | |||
| c0ef6ce282 | |||
| bd6ec5201f | |||
| b4068da9fe | |||
| aa4b09da85 | |||
| 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 |
25
NEWS
25
NEWS
@@ -34,7 +34,7 @@ Upstream changes that have led to incompatible Liminix changes are:
|
||||
2024-01-30
|
||||
|
||||
New port! Thanks to Arnout Engelen <arnout@bzzt.net>, Liminix
|
||||
now runs on the TP-Link Archer AX23
|
||||
now runs on the TP-Link Archer AX23.
|
||||
|
||||
2024-02-12
|
||||
|
||||
@@ -80,3 +80,26 @@ 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;
|
||||
};
|
||||
})
|
||||
];
|
||||
|
||||
1050
THOUGHTS.txt
1050
THOUGHTS.txt
File diff suppressed because it is too large
Load Diff
20
boot.expect
Normal file
20
boot.expect
Normal file
@@ -0,0 +1,20 @@
|
||||
# This is for use with minicom, but needs you to configure it to
|
||||
# use expect as its "Script program" instead of runscript. Try
|
||||
# Ctrl+A O -> Filenames and paths -> D
|
||||
|
||||
log_user 0
|
||||
log_file -a -open stderr
|
||||
set f [open "result/boot.scr"]
|
||||
send "version\r"
|
||||
set timeout 60
|
||||
while {[gets $f line] >= 0} {
|
||||
puts stderr "next line $line\r"
|
||||
puts stderr "waiting for prompt\r"
|
||||
expect {
|
||||
"ath>" {}
|
||||
"BusyBox" { puts stderr "DONE"; exit 0 }
|
||||
}
|
||||
send "$line\r\n"
|
||||
}
|
||||
puts stderr "done\r\n"
|
||||
close $f
|
||||
@@ -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 ''
|
||||
@@ -51,18 +55,17 @@ in {
|
||||
<nixpkgs/nixos/modules/virtualisation/qemu-vm.nix>
|
||||
];
|
||||
config = {
|
||||
boot.kernelParams = [
|
||||
"loglevel=9"
|
||||
];
|
||||
boot.kernelParams = [ "loglevel=9" ];
|
||||
systemd.services.pppoe =
|
||||
let conf = pkgs.writeText "kpppoed.toml"
|
||||
''
|
||||
interface_name = "eth1"
|
||||
services = [ "myservice" ]
|
||||
lns_ipaddr = "${cfg.l2tp.host}:${builtins.toString cfg.l2tp.port}"
|
||||
ac_name = "kpppoed-1.0"
|
||||
'';
|
||||
in {
|
||||
let
|
||||
conf = pkgs.writeText "kpppoed.toml" ''
|
||||
interface_name = "eth1"
|
||||
services = [ "myservice" ]
|
||||
lns_ipaddr = "${cfg.l2tp.host}:${builtins.toString cfg.l2tp.port}"
|
||||
ac_name = "kpppoed-1.0"
|
||||
'';
|
||||
in
|
||||
{
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "network-online.target" ];
|
||||
serviceConfig = {
|
||||
@@ -76,24 +79,36 @@ in {
|
||||
};
|
||||
};
|
||||
services.openssh.enable = true;
|
||||
services.dnsmasq = {
|
||||
enable = true;
|
||||
resolveLocalQueries = false;
|
||||
settings = {
|
||||
# domain-needed = true;
|
||||
dhcp-range = [ "10.0.0.10,10.0.0.240" ];
|
||||
interface = "eth1";
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services.sshd.wantedBy = pkgs.lib.mkForce [ "multi-user.target" ];
|
||||
|
||||
virtualisation = {
|
||||
qemu = {
|
||||
networkingOptions = [];
|
||||
options = [] ++
|
||||
optional cfg.ethernet.pci.enable
|
||||
"-device vfio-pci,host=${cfg.ethernet.pci.id}" ++
|
||||
optionals cfg.ethernet.usb.enable [
|
||||
networkingOptions = [ ];
|
||||
options =
|
||||
[ ]
|
||||
++ optional cfg.ethernet.pci.enable "-device vfio-pci,host=${cfg.ethernet.pci.id}"
|
||||
++ optionals cfg.ethernet.usb.enable [
|
||||
"-device usb-ehci,id=ehci"
|
||||
"-device usb-host,bus=ehci.0,vendorid=${cfg.ethernet.usb.vendor},productid=${cfg.ethernet.usb.product}"
|
||||
] ++ [
|
||||
]
|
||||
++ [
|
||||
"-nographic"
|
||||
"-serial mon:stdio"
|
||||
];
|
||||
};
|
||||
sharedDirectories = {
|
||||
liminix = {
|
||||
securityModel = "none";
|
||||
source = builtins.toString ./.;
|
||||
target = "/home/liminix/liminix";
|
||||
};
|
||||
@@ -108,6 +123,7 @@ in {
|
||||
tufted
|
||||
iptables
|
||||
usbutils
|
||||
busybox
|
||||
];
|
||||
security.sudo.wheelNeedsPassword = false;
|
||||
networking = {
|
||||
@@ -117,11 +133,17 @@ in {
|
||||
useDHCP = false;
|
||||
ipv4.addresses = [ { address = "10.0.0.1"; prefixLength = 24;}];
|
||||
};
|
||||
nat = {
|
||||
enable = true;
|
||||
internalInterfaces = [ "eth1" ];
|
||||
externalInterface = "eth0";
|
||||
};
|
||||
};
|
||||
users.users.liminix = {
|
||||
isNormalUser = true;
|
||||
uid = 1000;
|
||||
extraGroups = [ "wheel"];
|
||||
extraGroups = [ "wheel" ];
|
||||
openssh.authorizedKeys.keys = cfg.keys;
|
||||
};
|
||||
services.getty.autologinUser = "liminix";
|
||||
};
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
{...}:
|
||||
{ ... }:
|
||||
{
|
||||
bordervm = {
|
||||
# ethernet.pci = { id = "01:00.0"; enable = true; };
|
||||
ethernet.usb = { vendor = "0x0bda"; product = "0x8153"; enable = true; };
|
||||
ethernet.usb = {
|
||||
vendor = "0x0bda";
|
||||
product = "0x8153";
|
||||
enable = true;
|
||||
};
|
||||
l2tp = {
|
||||
host = "l2tp.aa.net.uk";
|
||||
};
|
||||
|
||||
69
ci.nix
69
ci.nix
@@ -1,17 +1,22 @@
|
||||
{
|
||||
nixpkgs
|
||||
, unstable
|
||||
, liminix
|
||||
, ... }:
|
||||
nixpkgs,
|
||||
unstable,
|
||||
liminix,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (builtins) map;
|
||||
pkgs = (import nixpkgs {});
|
||||
borderVmConf = ./bordervm.conf-example.nix;
|
||||
pkgs = (import nixpkgs { });
|
||||
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:
|
||||
@@ -22,33 +27,35 @@ let
|
||||
}).outputs.default;
|
||||
tests = import ./tests/ci.nix;
|
||||
jobs =
|
||||
(genAttrs devices for-device) //
|
||||
tests //
|
||||
{
|
||||
buildEnv = (import liminix {
|
||||
inherit nixpkgs borderVmConf;
|
||||
device = import (liminix + "/devices/qemu");
|
||||
liminix-config = vanilla;
|
||||
}).buildEnv;
|
||||
(genAttrs devices for-device)
|
||||
// tests
|
||||
// {
|
||||
buildEnv =
|
||||
(import liminix {
|
||||
inherit nixpkgs borderVmConf;
|
||||
device = import (liminix + "/devices/qemu");
|
||||
liminix-config = vanilla;
|
||||
}).buildEnv;
|
||||
doc =
|
||||
let json =
|
||||
(import liminix {
|
||||
inherit nixpkgs borderVmConf;
|
||||
device = import (liminix + "/devices/qemu");
|
||||
liminix-config = {...} : {
|
||||
let
|
||||
json =
|
||||
(import liminix {
|
||||
inherit nixpkgs borderVmConf;
|
||||
device = import (liminix + "/devices/qemu");
|
||||
liminix-config =
|
||||
{ ... }:
|
||||
{
|
||||
imports = [ ./modules/all-modules.nix ];
|
||||
};
|
||||
}).outputs.optionsJson;
|
||||
installers = map (f: "system.outputs.${f}") [
|
||||
"vmroot"
|
||||
"mtdimage"
|
||||
"ubimage"
|
||||
];
|
||||
inherit (pkgs.lib) concatStringsSep;
|
||||
in pkgs.stdenv.mkDerivation {
|
||||
}).outputs.optionsJson;
|
||||
in
|
||||
pkgs.stdenv.mkDerivation {
|
||||
name = "liminix-doc";
|
||||
nativeBuildInputs = with pkgs; [
|
||||
gnumake sphinx fennel luaPackages.lyaml
|
||||
gnumake
|
||||
sphinx
|
||||
fennel
|
||||
luaPackages.lyaml
|
||||
];
|
||||
src = ./.;
|
||||
buildPhase = ''
|
||||
|
||||
50
default.nix
50
default.nix
@@ -1,35 +1,47 @@
|
||||
{
|
||||
device
|
||||
, liminix-config ? <liminix-config>
|
||||
, nixpkgs ? <nixpkgs>
|
||||
, borderVmConf ? ./bordervm.conf.nix
|
||||
deviceName ? null,
|
||||
device ? (import ./devices/${deviceName}),
|
||||
liminix-config ? <liminix-config>,
|
||||
nixpkgs ? <nixpkgs>,
|
||||
borderVmConf ? ./bordervm.conf.nix,
|
||||
imageType ? "primary",
|
||||
}:
|
||||
|
||||
let
|
||||
overlay = import ./overlay.nix;
|
||||
pkgs = import nixpkgs (device.system // {
|
||||
overlays = [overlay];
|
||||
config = {
|
||||
allowUnsupportedSystem = true; # mipsel
|
||||
permittedInsecurePackages = [
|
||||
"python-2.7.18.6" # kernel backports needs python <3
|
||||
"python-2.7.18.7"
|
||||
];
|
||||
};
|
||||
});
|
||||
pkgs = import nixpkgs (
|
||||
device.system
|
||||
// {
|
||||
overlays = [ overlay ];
|
||||
config = {
|
||||
allowUnsupportedSystem = true; # mipsel
|
||||
permittedInsecurePackages = [
|
||||
"python-2.7.18.6" # kernel backports needs python <3
|
||||
"python-2.7.18.7"
|
||||
];
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
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;
|
||||
@@ -37,7 +49,14 @@ let
|
||||
borderVm = ((import <nixpkgs/nixos/lib/eval-config.nix>) {
|
||||
system = builtins.currentSystem;
|
||||
modules = [
|
||||
({ ... } : { nixpkgs.overlays = [ overlay ]; })
|
||||
{
|
||||
nixpkgs.overlays = [
|
||||
(final: prev: {
|
||||
go-l2tp = final.callPackage ./pkgs/go-l2tp {};
|
||||
tufted = final.callPackage ./pkgs/tufted {};
|
||||
})
|
||||
];
|
||||
}
|
||||
(import ./bordervm-configuration.nix)
|
||||
borderVmConf
|
||||
];
|
||||
@@ -68,6 +87,7 @@ in {
|
||||
min-copy-closure
|
||||
fennelrepl
|
||||
lzma
|
||||
lua
|
||||
];
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -214,7 +213,6 @@
|
||||
networkInterfaces =
|
||||
let
|
||||
inherit (config.system.service.network) link;
|
||||
inherit (config.system.service) bridge;
|
||||
in rec {
|
||||
wan = link.build { ifname = "wan"; };
|
||||
lan1 = link.build { ifname = "lan1"; };
|
||||
|
||||
@@ -23,12 +23,17 @@
|
||||
VIRTIO_BLK = "y";
|
||||
VIRTIO_NET = "y";
|
||||
};
|
||||
conditionalConfig = {
|
||||
WLAN= {
|
||||
MAC80211_HWSIM = "m";
|
||||
};
|
||||
};
|
||||
};
|
||||
hardware =
|
||||
let
|
||||
mac80211 = pkgs.mac80211.override {
|
||||
drivers = ["mac80211_hwsim"];
|
||||
klibBuild = config.system.outputs.kernel.modulesupport;
|
||||
mac80211 = pkgs.kmodloader.override {
|
||||
inherit (config.system.outputs) kernel;
|
||||
targets = ["mac80211_hwsim"];
|
||||
};
|
||||
in {
|
||||
defaultOutput = "vmroot";
|
||||
|
||||
@@ -92,7 +92,6 @@
|
||||
'';
|
||||
};
|
||||
inherit (pkgs.pseudofile) dir symlink;
|
||||
inherit (pkgs.liminix.networking) interface;
|
||||
in {
|
||||
imports = [
|
||||
../../modules/network
|
||||
@@ -125,8 +124,16 @@
|
||||
networkInterfaces =
|
||||
let inherit (config.system.service.network) link;
|
||||
in {
|
||||
lan = link.build { ifname = "eth0"; };
|
||||
wan = link.build { ifname = "eth1"; };
|
||||
lan = link.build {
|
||||
ifname = "lan";
|
||||
# devpath = "/devices/platform/ahb/19000000.eth";
|
||||
devpath = "/devices/platform/ahb/1a000000.eth";
|
||||
};
|
||||
wan = link.build {
|
||||
ifname = "wan";
|
||||
devpath = "/devices/platform/ahb/19000000.eth";
|
||||
# devpath = "/devices/platform/ahb/1a000000.eth";
|
||||
};
|
||||
wlan = link.build {
|
||||
ifname = "wlan0";
|
||||
dependencies = [ mac80211 ];
|
||||
@@ -149,6 +156,7 @@
|
||||
};
|
||||
boot.tftp = {
|
||||
loadAddress = lim.parseInt "0x00A00000";
|
||||
appendDTB = true;
|
||||
};
|
||||
kernel = {
|
||||
src = pkgs.pkgsBuildBuild.fetchurl {
|
||||
|
||||
@@ -45,7 +45,6 @@
|
||||
|
||||
module = { pkgs, config, lib, lim, ...}:
|
||||
let
|
||||
inherit (pkgs.liminix.networking) interface;
|
||||
inherit (pkgs) openwrt;
|
||||
mac80211 = pkgs.kmodloader.override {
|
||||
targets = ["rt2800soc"];
|
||||
@@ -90,19 +89,6 @@
|
||||
let
|
||||
inherit (config.system.service.network) link;
|
||||
inherit (config.system.service) vlan;
|
||||
inherit (pkgs.liminix.services) oneshot;
|
||||
swconfig = oneshot {
|
||||
name = "swconfig";
|
||||
up = ''
|
||||
PATH=${pkgs.swconfig}/bin:$PATH
|
||||
swconfig dev switch0 set reset
|
||||
swconfig dev switch0 set enable_vlan 1
|
||||
swconfig dev switch0 vlan 1 set ports '1 2 3 4 6t'
|
||||
swconfig dev switch0 vlan 2 set ports '0 6t'
|
||||
swconfig dev switch0 set apply
|
||||
'';
|
||||
down = "${pkgs.swconfig}/bin/swconfig dev switch0 set reset";
|
||||
};
|
||||
in rec {
|
||||
eth = link.build { ifname = "eth0"; };
|
||||
# lan and wan ports are both behind a switch on eth0
|
||||
@@ -110,13 +96,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,7 +110,8 @@
|
||||
};
|
||||
boot.tftp = {
|
||||
loadAddress = lim.parseInt "0x00A00000";
|
||||
};
|
||||
appendDTB = true;
|
||||
};
|
||||
|
||||
kernel = {
|
||||
src = pkgs.fetchurl {
|
||||
@@ -136,6 +121,7 @@
|
||||
};
|
||||
extraPatchPhase = ''
|
||||
${openwrt.applyPatches.ramips}
|
||||
${openwrt.applyPatches.rt2x00}
|
||||
'';
|
||||
config = {
|
||||
|
||||
|
||||
@@ -38,7 +38,6 @@
|
||||
|
||||
module = { pkgs, config, lib, lim, ...}:
|
||||
let
|
||||
inherit (pkgs.liminix.networking) interface;
|
||||
inherit (pkgs.liminix.services) oneshot;
|
||||
inherit (pkgs.pseudofile) dir symlink;
|
||||
inherit (pkgs) openwrt;
|
||||
@@ -97,7 +96,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,6 +121,7 @@
|
||||
# 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 = {
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
# this device is described by the "qemu" device
|
||||
installer = "vmroot";
|
||||
|
||||
module = {pkgs, config, lim, ... }: {
|
||||
module = { config, lim, ... }: {
|
||||
imports = [
|
||||
../../modules/arch/aarch64.nix
|
||||
../families/qemu.nix
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
'';
|
||||
installer = "vmroot";
|
||||
|
||||
module = {pkgs, config, lim, ... }: {
|
||||
module = { config, lim, ... }: {
|
||||
imports = [
|
||||
../../modules/arch/arm.nix
|
||||
../families/qemu.nix
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
in the Development manual.
|
||||
|
||||
'';
|
||||
module = {pkgs, config, lib, lim, ... }: {
|
||||
module = { config, lib, lim, ... }: {
|
||||
imports = [
|
||||
../../modules/arch/mipseb.nix
|
||||
../families/qemu.nix
|
||||
|
||||
@@ -419,7 +419,6 @@
|
||||
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"; };
|
||||
|
||||
@@ -155,8 +155,6 @@
|
||||
|
||||
module = {pkgs, config, lib, lim, ... }:
|
||||
let
|
||||
openwrt = pkgs.openwrt;
|
||||
inherit (lib) mkOption types;
|
||||
inherit (pkgs.liminix.services) oneshot;
|
||||
inherit (pkgs) liminix;
|
||||
mtd_by_name_links = pkgs.liminix.services.oneshot rec {
|
||||
@@ -358,7 +356,6 @@
|
||||
networkInterfaces =
|
||||
let
|
||||
inherit (config.system.service.network) link;
|
||||
inherit (config.system.service) bridge;
|
||||
in rec {
|
||||
en70000 = link.build {
|
||||
# in armada-38x.dtsi this is eth0.
|
||||
|
||||
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";
|
||||
};
|
||||
};
|
||||
365
devices/zyxel-nwa50ax/default.nix
Normal file
365
devices/zyxel-nwa50ax/default.nix
Normal file
@@ -0,0 +1,365 @@
|
||||
{
|
||||
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.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";
|
||||
};
|
||||
};
|
||||
@@ -1,11 +1,9 @@
|
||||
{ eval, lib, pkgs }:
|
||||
let
|
||||
inherit (lib) types;
|
||||
conf = eval.config;
|
||||
rootDir = builtins.toPath ./..;
|
||||
stripAnyPrefixes = lib.flip (lib.fold lib.removePrefix)
|
||||
["${rootDir}/"];
|
||||
optToDoc = name: opt : {
|
||||
stripAnyPrefixes = lib.flip (lib.fold lib.removePrefix) [ "${rootDir}/" ];
|
||||
optToDoc = name: opt: {
|
||||
inherit name;
|
||||
description = opt.description or null;
|
||||
default = opt.default or null;
|
||||
@@ -26,7 +24,6 @@ let
|
||||
let x = lib.mapAttrsToList optToDoc sd.parameters; in x;
|
||||
}
|
||||
else
|
||||
item // { declarations = map stripAnyPrefixes item.declarations; };
|
||||
item // { declarations = map stripAnyPrefixes item.declarations; };
|
||||
in
|
||||
builtins.map spliceServiceDefn
|
||||
(pkgs.lib.optionAttrSetToDocList eval.options)
|
||||
builtins.map spliceServiceDefn (pkgs.lib.optionAttrSetToDocList eval.options)
|
||||
|
||||
@@ -1,24 +1,18 @@
|
||||
with import <nixpkgs> {} ;
|
||||
with import <nixpkgs> { };
|
||||
|
||||
let
|
||||
inherit (builtins) stringLength readDir filter;
|
||||
devices = filter (n: n != "families")
|
||||
(lib.mapAttrsToList (n: t: n) (readDir ../devices));
|
||||
texts = map (n:
|
||||
let d = import ../devices/${n}/default.nix;
|
||||
d' = {
|
||||
description = "${n}\n${substring 0 (stringLength n) "********************************"}\n";
|
||||
} // d;
|
||||
installer =
|
||||
if d ? description && d ? installer
|
||||
then ''
|
||||
|
||||
The default installation route for this device is
|
||||
:ref:`system-outputs-${d.installer}`
|
||||
''
|
||||
else "";
|
||||
in d'.description)
|
||||
devices;
|
||||
devices = filter (n: n != "families") (lib.mapAttrsToList (n: t: n) (readDir ../devices));
|
||||
texts = map (
|
||||
n:
|
||||
let
|
||||
d = import ../devices/${n}/default.nix;
|
||||
d' = {
|
||||
description = "${n}\n${substring 0 (stringLength n) "********************************"}\n";
|
||||
} // d;
|
||||
in
|
||||
d'.description
|
||||
) devices;
|
||||
in
|
||||
writeText "hwdoc" ''
|
||||
Supported hardware
|
||||
|
||||
@@ -11,15 +11,15 @@
|
||||
...
|
||||
}: let
|
||||
secrets = import ./extneder-secrets.nix;
|
||||
inherit (pkgs.liminix.services) oneshot longrun bundle target;
|
||||
inherit (pkgs.liminix.services) oneshot longrun target;
|
||||
inherit (pkgs.pseudofile) dir symlink;
|
||||
inherit (pkgs) writeText dropbear ifwait serviceFns;
|
||||
inherit (pkgs) writeText serviceFns;
|
||||
svc = config.system.service;
|
||||
in rec {
|
||||
boot = {
|
||||
tftp = {
|
||||
serverip = "192.168.8.148";
|
||||
ipaddr = "192.168.8.251";
|
||||
serverip = "10.0.0.1";
|
||||
ipaddr = "10.0.0.8";
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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";
|
||||
};
|
||||
@@ -141,23 +119,37 @@ in rec {
|
||||
secrets_file
|
||||
services.mount_external_disk
|
||||
config.hardware.networkInterfaces.lan
|
||||
] ;
|
||||
];
|
||||
};
|
||||
|
||||
users.root = {
|
||||
passwd = lib.mkForce secrets.root.passwd;
|
||||
# openssh.authorizedKeys.keys = [
|
||||
# (builtins.readFile "/home/dan/.ssh/id_rsa.pub")
|
||||
# ];
|
||||
openssh.authorizedKeys.keys = secrets.root.keys;
|
||||
};
|
||||
|
||||
users.backup = {
|
||||
uid=500; gid=500; gecos="Storage owner"; dir="/srv";
|
||||
shell="/dev/null";
|
||||
uid = 500;
|
||||
gid = 500;
|
||||
gecos = "Storage owner";
|
||||
dir = "/srv";
|
||||
shell = "/dev/null";
|
||||
};
|
||||
groups.backup = {
|
||||
gid=500; usernames = ["backup"];
|
||||
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;
|
||||
};
|
||||
})
|
||||
];
|
||||
}
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
# wherever the text "EDIT" appears - please consult the tutorial
|
||||
# documentation for details.
|
||||
|
||||
{ config, pkgs, lib, ... } :
|
||||
{ config, pkgs, ... }:
|
||||
let
|
||||
inherit (pkgs.liminix.services) bundle oneshot longrun;
|
||||
inherit (pkgs.liminix.services) bundle oneshot;
|
||||
inherit (pkgs) serviceFns;
|
||||
# EDIT: you can pick your preferred RFC1918 address space
|
||||
# for NATted connections, if you don't like this one.
|
||||
@@ -49,31 +49,40 @@ in rec {
|
||||
country_code = "GB";
|
||||
wpa_passphrase = "not a real wifi password";
|
||||
|
||||
hw_mode="g";
|
||||
hw_mode = "g";
|
||||
ieee80211n = 1;
|
||||
auth_algs = 1; # 1=wpa2, 2=wep, 3=both
|
||||
wpa = 2; # 1=wpa, 2=wpa2, 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
|
||||
wpa_pairwise = "TKIP CCMP"; # auth for wpa (may not need this?)
|
||||
rsn_pairwise = "CCMP"; # auth for wpa2
|
||||
wmm_enabled = 1;
|
||||
};
|
||||
};
|
||||
|
||||
services.int = svc.network.address.build {
|
||||
interface = svc.bridge.primary.build { ifname = "int"; };
|
||||
family = "inet"; address = "${ipv4LocalNet}.1"; prefixLength = 16;
|
||||
family = "inet";
|
||||
address = "${ipv4LocalNet}.1";
|
||||
prefixLength = 16;
|
||||
};
|
||||
|
||||
services.bridge = svc.bridge.members.build {
|
||||
services.bridge = svc.bridge.members.build {
|
||||
primary = services.int;
|
||||
members = with config.hardware.networkInterfaces;
|
||||
[ wlan lan ];
|
||||
members = with config.hardware.networkInterfaces; [
|
||||
wlan
|
||||
lan
|
||||
];
|
||||
};
|
||||
|
||||
services.ntp = svc.ntp.build {
|
||||
pools = { "pool.ntp.org" = ["iburst"]; };
|
||||
makestep = { threshold = 1.0; limit = 3; };
|
||||
pools = {
|
||||
"pool.ntp.org" = [ "iburst" ];
|
||||
};
|
||||
makestep = {
|
||||
threshold = 1.0;
|
||||
limit = 3;
|
||||
};
|
||||
};
|
||||
|
||||
services.sshd = svc.ssh.build { };
|
||||
@@ -157,9 +166,7 @@ in rec {
|
||||
interface = services.wan;
|
||||
};
|
||||
|
||||
services.firewall = svc.firewall.build {
|
||||
ruleset = import ./demo-firewall.nix;
|
||||
};
|
||||
services.firewall = svc.firewall.build { };
|
||||
|
||||
services.packet_forwarding = svc.network.forward.build { };
|
||||
|
||||
@@ -196,7 +203,5 @@ in rec {
|
||||
];
|
||||
};
|
||||
|
||||
defaultProfile.packages = with pkgs; [
|
||||
min-collect-garbage
|
||||
];
|
||||
defaultProfile.packages = with pkgs; [ min-collect-garbage ];
|
||||
}
|
||||
|
||||
@@ -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];
|
||||
};
|
||||
|
||||
services.sshd = svc.ssh.build {};
|
||||
users.root.passwd = lib.mkForce secrets.root.passwd;
|
||||
defaultProfile.packages = with pkgs; [nftables strace tcpdump swconfig];
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
{ config, pkgs, lib, ... } :
|
||||
{ config, pkgs, ... } :
|
||||
let
|
||||
inherit (pkgs) serviceFns;
|
||||
svc = config.system.service;
|
||||
|
||||
in rec {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
{ config, pkgs, lib, ... } :
|
||||
{ config, pkgs, ... } :
|
||||
let
|
||||
inherit (pkgs) serviceFns;
|
||||
svc = config.system.service;
|
||||
|
||||
in rec {
|
||||
|
||||
177
examples/l2tp.nix
Normal file
177
examples/l2tp.nix
Normal file
@@ -0,0 +1,177 @@
|
||||
{
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
secrets = import ./extneder-secrets.nix;
|
||||
rsecrets = import ./rotuer-secrets.nix;
|
||||
|
||||
# https://support.aa.net.uk/Category:Incoming_L2TP says:
|
||||
# "Please use the DNS name (l2tp.aa.net.uk) instead of hardcoding an
|
||||
# IP address; IP addresses can and do change. If you have to use an
|
||||
# IP, use 194.4.172.12, but do check the DNS for l2tp.aa.net.uk in
|
||||
# case it changes."
|
||||
|
||||
# but (1) we don't want to use the wwan stick's dns as our main
|
||||
# resolver: it's provided by some mobile ISP and they aren't
|
||||
# necessarily the best at providing unfettered services without
|
||||
# deciding to do something weird; (2) it's not simple to arrange
|
||||
# that xl2tpd gets a different resolver than every other process;
|
||||
# (3) there's no way to specify an lns address to xl2tpd at runtime
|
||||
# except by rewriting its config file. So what we will do is lookup
|
||||
# the lns hostname using the mobile ISP's dns server and then refuse
|
||||
# to start l2tp unless the expected lns address is one of the
|
||||
# addresses returned. I think this satisfies "do check the DNS"
|
||||
|
||||
lns = { hostname = "l2tp.aaisp.net.uk"; address = "194.4.172.12"; };
|
||||
|
||||
inherit (pkgs.liminix.services) oneshot longrun target;
|
||||
inherit (pkgs.pseudofile) dir symlink;
|
||||
inherit (pkgs) serviceFns;
|
||||
svc = config.system.service;
|
||||
in rec {
|
||||
boot = {
|
||||
tftp = {
|
||||
serverip = "10.0.0.1";
|
||||
ipaddr = "10.0.0.8";
|
||||
};
|
||||
};
|
||||
|
||||
imports = [
|
||||
../modules/cdc-ncm
|
||||
../modules/network
|
||||
../modules/vlan
|
||||
../modules/ssh
|
||||
../modules/usb.nix
|
||||
../modules/watchdog
|
||||
../modules/mount
|
||||
../modules/ppp
|
||||
];
|
||||
hostname = "thing";
|
||||
|
||||
services.wwan = svc.wwan.build {
|
||||
apn = "data.uk";
|
||||
username = "user";
|
||||
password = "one2one";
|
||||
authType = "chap";
|
||||
};
|
||||
|
||||
services.wan =
|
||||
let
|
||||
z = final : prev: {
|
||||
controller = longrun rec {
|
||||
name = "wan-switcher";
|
||||
run = ''
|
||||
(in_outputs ${name}
|
||||
${pkgs.s6-rc-round-robin}/bin/s6-rc-round-robin \
|
||||
-p ${final.proxy.name} \
|
||||
${lib.concatStringsSep " "
|
||||
(builtins.map (f: f.name) [final.pppoe final.l2tp])}
|
||||
)
|
||||
'';
|
||||
};
|
||||
pppoe = (svc.pppoe.build {
|
||||
interface = config.hardware.networkInterfaces.wan;
|
||||
|
||||
ppp-options = [
|
||||
"debug" "+ipv6" "noauth"
|
||||
"name" rsecrets.l2tp.name
|
||||
"password" rsecrets.l2tp.password
|
||||
];
|
||||
}).overrideAttrs(o: { inherit (final) controller; });
|
||||
|
||||
l2tp =
|
||||
let
|
||||
check-address = oneshot rec {
|
||||
name = "check-lns-address";
|
||||
up = "grep -Fx ${ lns.address} $(output_path ${services.lns-address} addresses)";
|
||||
dependencies = [ services.lns-address ];
|
||||
};
|
||||
route = svc.network.route.build {
|
||||
via = "$(output ${services.dhcpc} router)";
|
||||
target = lns.address;
|
||||
dependencies = [services.dhcpc check-address];
|
||||
};
|
||||
in (svc.l2tp.build {
|
||||
lns = lns.address;
|
||||
ppp-options = [
|
||||
"debug" "+ipv6" "noauth"
|
||||
"name" rsecrets.l2tp.name
|
||||
"connect-delay" "5000"
|
||||
"password" rsecrets.l2tp.password
|
||||
];
|
||||
dependencies = [config.services.lns-address route check-address];
|
||||
}).overrideAttrs(o: { inherit (final) controller; });
|
||||
proxy = oneshot rec {
|
||||
name = "wan-proxy";
|
||||
inherit (final) controller;
|
||||
buildInputs = with final; [ pppoe l2tp];
|
||||
up = ''
|
||||
echo start proxy ${name}
|
||||
set -x
|
||||
(in_outputs ${name}
|
||||
cp -rv $(output_path ${final.controller} active)/* .
|
||||
)
|
||||
'';
|
||||
};
|
||||
};
|
||||
in (lib.fix (lib.extends z (prev : { }))).proxy;
|
||||
|
||||
services.sshd = svc.ssh.build { };
|
||||
|
||||
services.resolvconf = oneshot rec {
|
||||
dependencies = [ services.wan ];
|
||||
name = "resolvconf";
|
||||
up = ''
|
||||
. ${serviceFns}
|
||||
( in_outputs ${name}
|
||||
for i in ns1 ns2 ; do
|
||||
ns=$(output ${services.wan} $i)
|
||||
echo "nameserver $ns" >> resolv.conf
|
||||
done
|
||||
)
|
||||
'';
|
||||
};
|
||||
filesystem = dir {
|
||||
etc = dir {
|
||||
"resolv.conf" = symlink "${services.resolvconf}/.outputs/resolv.conf";
|
||||
};
|
||||
};
|
||||
|
||||
services.dhcpc = svc.network.dhcp.client.build {
|
||||
interface = config.services.wwan;
|
||||
dependencies = [ config.services.hostname ];
|
||||
};
|
||||
|
||||
services.lns-address = let
|
||||
ns = "$(output_word ${services.dhcpc} dns 1)";
|
||||
route-to-bootstrap-nameserver = svc.network.route.build {
|
||||
via = "$(output ${services.dhcpc} router)";
|
||||
target = ns;
|
||||
dependencies = [services.dhcpc];
|
||||
};
|
||||
in oneshot rec {
|
||||
name = "resolve-l2tp-server";
|
||||
dependencies = [ services.dhcpc route-to-bootstrap-nameserver ];
|
||||
up = ''
|
||||
(in_outputs ${name}
|
||||
DNSCACHEIP="${ns}" ${pkgs.s6-dns}/bin/s6-dnsip4 ${lns.hostname} \
|
||||
> addresses
|
||||
)
|
||||
'';
|
||||
};
|
||||
|
||||
services.defaultroute4 = svc.network.route.build {
|
||||
via = "$(output ${services.wan} peer-address)";
|
||||
target = "default";
|
||||
dependencies = [services.wan];
|
||||
};
|
||||
|
||||
# defaultProfile.packages = [ pkgs.go-l2tp ];
|
||||
|
||||
users.root = {
|
||||
passwd = lib.mkForce secrets.root.passwd;
|
||||
openssh.authorizedKeys.keys = secrets.root.keys;
|
||||
};
|
||||
}
|
||||
119
examples/nwa50ax-ap.nix
Normal file
119
examples/nwa50ax-ap.nix
Normal file
@@ -0,0 +1,119 @@
|
||||
{ config, pkgs, ... } :
|
||||
let
|
||||
inherit (pkgs.liminix.services) target;
|
||||
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 ];
|
||||
}
|
||||
@@ -3,8 +3,8 @@ 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" {} ''
|
||||
inherit (pkgs.liminix.services) oneshot 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
|
||||
@@ -53,7 +53,7 @@ in rec {
|
||||
services.defaultroute4 = svc.network.route.build {
|
||||
via = "$(output ${services.dhcpc} router)";
|
||||
target = "default";
|
||||
dependencies = [services.dhcpc];
|
||||
dependencies = [ services.dhcpc ];
|
||||
};
|
||||
|
||||
services.resolvconf = oneshot rec {
|
||||
|
||||
@@ -8,12 +8,10 @@
|
||||
root = {
|
||||
# mkpasswd -m sha512crypt
|
||||
passwd = "$6$6pt0mpbgcB7kC2RJ$kSBoCYGyi1.qxt7dqmexLj1l8E6oTZJZmfGyJSsMYMW.jlsETxdgQSdv6ptOYDM7DHAwf6vLG0pz3UD31XBfC1";
|
||||
openssh.authorizedKeys.keys = [
|
||||
];
|
||||
openssh.authorizedKeys.keys = [ ];
|
||||
};
|
||||
|
||||
lan = {
|
||||
prefix = "10.8.0";
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -6,23 +6,16 @@
|
||||
# problems.
|
||||
|
||||
|
||||
{ config, pkgs, lib, ... } :
|
||||
{ config, pkgs, lib, modulesPath, ... } :
|
||||
let
|
||||
secrets = {
|
||||
domainName = "fake.liminix.org";
|
||||
firewallRules = {};
|
||||
firewallRules = { };
|
||||
} // (import ./rotuer-secrets.nix);
|
||||
inherit (pkgs.liminix.services) oneshot longrun bundle;
|
||||
inherit (pkgs) serviceFns;
|
||||
svc = config.system.service;
|
||||
wirelessConfig = {
|
||||
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;
|
||||
};
|
||||
|
||||
@@ -36,65 +29,62 @@ in rec {
|
||||
};
|
||||
|
||||
imports = [
|
||||
../modules/wlan.nix
|
||||
../modules/network
|
||||
../modules/ppp
|
||||
../modules/dnsmasq
|
||||
../modules/dhcp6c
|
||||
../modules/firewall
|
||||
../modules/hostapd
|
||||
../modules/bridge
|
||||
../modules/ntp
|
||||
../modules/schnapps
|
||||
../modules/ssh
|
||||
../modules/outputs/btrfs.nix
|
||||
../modules/outputs/extlinux.nix
|
||||
"${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 = secrets.ssid;
|
||||
hw_mode="g";
|
||||
channel = "2";
|
||||
ieee80211n = 1;
|
||||
} // wirelessConfig;
|
||||
};
|
||||
|
||||
services.hostap5 = svc.hostapd.build {
|
||||
interface = config.hardware.networkInterfaces.wlan5;
|
||||
params = rec {
|
||||
ssid = "${secrets.ssid}5";
|
||||
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.int = svc.network.address.build {
|
||||
interface = svc.bridge.primary.build { ifname = "int"; };
|
||||
family = "inet"; address ="${secrets.lan.prefix}.1"; prefixLength = 24;
|
||||
};
|
||||
|
||||
services.bridge = svc.bridge.members.build {
|
||||
primary = services.int;
|
||||
members = with config.hardware.networkInterfaces;
|
||||
[ wlan
|
||||
wlan5
|
||||
lan0
|
||||
lan1
|
||||
lan2
|
||||
lan3
|
||||
lan4
|
||||
];
|
||||
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 {
|
||||
@@ -106,95 +96,6 @@ in rec {
|
||||
|
||||
users.root = secrets.root;
|
||||
|
||||
services.dns =
|
||||
let interface = services.int;
|
||||
in svc.dnsmasq.build {
|
||||
resolvconf = services.resolvconf;
|
||||
inherit interface;
|
||||
ranges = [
|
||||
"${secrets.lan.prefix}.10,${secrets.lan.prefix}.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);
|
||||
upstreams = [ "/${secrets.domainName}/" ];
|
||||
domain = secrets.domainName;
|
||||
};
|
||||
|
||||
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 =
|
||||
let defaults = import ./demo-firewall.nix;
|
||||
in lib.recursiveUpdate defaults secrets.firewallRules;
|
||||
};
|
||||
|
||||
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
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
{ config, pkgs, lib, lim, ... } :
|
||||
{ config, pkgs, lim, ... } :
|
||||
let
|
||||
inherit (pkgs) serviceFns;
|
||||
svc = config.system.service;
|
||||
|
||||
in rec {
|
||||
|
||||
@@ -9,28 +9,29 @@
|
||||
./busybox.nix
|
||||
./dhcp6c
|
||||
./dnsmasq
|
||||
./outputs/ext4fs.nix
|
||||
./firewall
|
||||
./hardware.nix
|
||||
./hostapd
|
||||
./hostname.nix
|
||||
./outputs/initramfs.nix
|
||||
./outputs/jffs2.nix
|
||||
./kernel
|
||||
./outputs/kexecboot.nix
|
||||
./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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{ lib, lim, pkgs, config, ...}:
|
||||
{ lim, pkgs, config, ...}:
|
||||
{
|
||||
config = {
|
||||
kernel.config = {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{ lib, lim, pkgs, config, ...}:
|
||||
{ lim, pkgs, config, ...}:
|
||||
{
|
||||
config = {
|
||||
kernel.config = {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{ lib, pkgs, config, lim, ...}:
|
||||
{ config, lim, ...}:
|
||||
{
|
||||
config = {
|
||||
kernel.config = {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{ lib, pkgs, config, ...}:
|
||||
{ pkgs, config, ...}:
|
||||
{
|
||||
imports = [ ./mips.nix ];
|
||||
config = {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{ lib, pkgs, config, ...}:
|
||||
{ config, ...}:
|
||||
{
|
||||
imports = [ ./mips.nix ];
|
||||
config = {
|
||||
|
||||
@@ -4,17 +4,12 @@
|
||||
|
||||
{ lib, pkgs, config, ...}:
|
||||
let
|
||||
inherit (lib) mkEnableOption mkOption types isDerivation hasAttr ;
|
||||
inherit (lib) mkOption types;
|
||||
inherit (pkgs.pseudofile) dir symlink;
|
||||
inherit (pkgs.liminix.networking) address interface;
|
||||
inherit (pkgs.liminix.services) bundle;
|
||||
|
||||
type_service = pkgs.liminix.lib.types.service;
|
||||
|
||||
in {
|
||||
imports = [
|
||||
./kernel # kernel is a separate module for doc purposes
|
||||
];
|
||||
options = {
|
||||
defaultProfile = {
|
||||
packages = mkOption {
|
||||
@@ -29,6 +24,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 = ''
|
||||
@@ -37,7 +36,7 @@ in {
|
||||
'';
|
||||
# internal = true; # probably a good case to make this internal
|
||||
};
|
||||
rootfsType = mkOption {
|
||||
rootfsType = mkOption {
|
||||
default = "squashfs";
|
||||
type = types.enum [
|
||||
"btrfs"
|
||||
@@ -47,7 +46,7 @@ in {
|
||||
"ubifs"
|
||||
];
|
||||
};
|
||||
rootOptions = mkOption {
|
||||
rootOptions = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
};
|
||||
@@ -55,11 +54,29 @@ in {
|
||||
boot = {
|
||||
commandLine = mkOption {
|
||||
type = types.listOf types.nonEmptyStr;
|
||||
default = [];
|
||||
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"];
|
||||
type = types.enum [
|
||||
"fit"
|
||||
"uimage"
|
||||
];
|
||||
default = "uimage";
|
||||
};
|
||||
tftp = {
|
||||
@@ -75,7 +92,7 @@ in {
|
||||
};
|
||||
# These names match the uboot environment variables. I reserve
|
||||
# the right to change them if I think of better ones.
|
||||
ipaddr = mkOption {
|
||||
ipaddr = mkOption {
|
||||
type = types.str;
|
||||
description = ''
|
||||
Our IP address to use when creating scripts to
|
||||
@@ -102,6 +119,29 @@ in {
|
||||
"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 = dependencies ++ o.dependencies;
|
||||
buildInputs = dependencies ++ o.buildInputs;
|
||||
});
|
||||
};
|
||||
|
||||
users.root = {
|
||||
uid = 0; gid= 0; gecos = "Root of all evaluation";
|
||||
dir = "/home/root/";
|
||||
|
||||
@@ -10,10 +10,11 @@
|
||||
{ lib, pkgs, config, ...}:
|
||||
let
|
||||
inherit (lib) mkOption types;
|
||||
inherit (pkgs.liminix.services) oneshot;
|
||||
inherit (pkgs) liminix;
|
||||
in
|
||||
{
|
||||
imports = [ ../ifwait ];
|
||||
|
||||
options = {
|
||||
system.service.bridge = {
|
||||
primary = mkOption { type = liminix.lib.types.serviceDefn; };
|
||||
@@ -27,7 +28,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";
|
||||
@@ -47,5 +48,5 @@ in
|
||||
# a better way to test for the existence of vlan config:
|
||||
# maybe the module should set an `enabled` attribute?
|
||||
BRIDGE_VLAN_FILTERING = "y";
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,23 +1,28 @@
|
||||
{
|
||||
liminix
|
||||
, ifwait
|
||||
, lib
|
||||
, svc
|
||||
}:
|
||||
{ members, primary } :
|
||||
|
||||
let
|
||||
inherit (liminix.networking) interface;
|
||||
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";
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
{
|
||||
liminix
|
||||
, ifwait
|
||||
, lib
|
||||
}:
|
||||
{ ifname } :
|
||||
let
|
||||
inherit (liminix.services) bundle oneshot;
|
||||
inherit (lib) mkOption types;
|
||||
inherit (liminix.services) oneshot;
|
||||
in oneshot rec {
|
||||
name = "${ifname}.link";
|
||||
up = ''
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
{ lib, pkgs, config, ...}:
|
||||
let
|
||||
inherit (lib) mkOption mkEnableOption types mapAttrsToList;
|
||||
inherit (lib) mkOption types mapAttrsToList;
|
||||
inherit (pkgs.pseudofile) dir symlink;
|
||||
inherit (lib.strings) toUpper;
|
||||
|
||||
@@ -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 = {
|
||||
@@ -87,10 +85,13 @@ in {
|
||||
};
|
||||
};
|
||||
filesystem = dir {
|
||||
bin = dir ({
|
||||
busybox = symlink "${busybox}/bin/busybox";
|
||||
sh = symlink "${busybox}/bin/busybox";
|
||||
} // makeLinks);
|
||||
bin = dir (
|
||||
{
|
||||
busybox = symlink "${busybox}/bin/busybox";
|
||||
sh = symlink "${busybox}/bin/busybox";
|
||||
}
|
||||
// makeLinks
|
||||
);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
31
modules/cdc-ncm/default.nix
Normal file
31
modules/cdc-ncm/default.nix
Normal file
@@ -0,0 +1,31 @@
|
||||
{ config, pkgs, lib, ... }:
|
||||
let
|
||||
inherit (pkgs) liminix;
|
||||
inherit (lib) mkOption types;
|
||||
in {
|
||||
imports = [
|
||||
../service-trigger
|
||||
];
|
||||
|
||||
options = {
|
||||
system.service.wwan = mkOption {
|
||||
type = liminix.lib.types.serviceDefn;
|
||||
};
|
||||
};
|
||||
config = {
|
||||
kernel.config = {
|
||||
USB_NET_HUAWEI_CDC_NCM = "y";
|
||||
USB_USBNET = "y";
|
||||
USB_SERIAL = "y";
|
||||
USB_SERIAL_OPTION = "y";
|
||||
};
|
||||
|
||||
# https://www.0xf8.org/2017/01/flashing-a-huawei-e3372h-4g-lte-stick-from-hilink-to-stick-mode/
|
||||
system.service.wwan = config.system.callService ./wwan.nix {
|
||||
apn = mkOption { type = types.str; };
|
||||
username = mkOption { type = types.str; };
|
||||
password = mkOption { type = types.str; };
|
||||
authType = mkOption { type = types.enum [ "pap" "chap" ]; };
|
||||
};
|
||||
};
|
||||
}
|
||||
67
modules/cdc-ncm/wwan.nix
Normal file
67
modules/cdc-ncm/wwan.nix
Normal file
@@ -0,0 +1,67 @@
|
||||
{
|
||||
liminix
|
||||
, usb-modeswitch
|
||||
, ppp
|
||||
, lib
|
||||
, svc
|
||||
, uevent-watch
|
||||
}:
|
||||
{ apn, username, password, authType }:
|
||||
let
|
||||
inherit (liminix.services) oneshot;
|
||||
authTypeNum = if authType == "pap" then "1" else "2";
|
||||
chat = lib.escapeShellArgs [
|
||||
# Your usb modem thing might present as a tty that you run PPP
|
||||
# over, or as a network device ("ndis" or "ncm"). The latter
|
||||
# kind is to be preferred, at least in principle, because it's
|
||||
# faster. This initialization sequence works for the Huawei
|
||||
# E3372, and took much swearing: the error messages are *awful*
|
||||
"" "AT"
|
||||
"OK" "ATZ"
|
||||
# create PDP context
|
||||
"OK" "AT+CGDCONT=1,\"IP\",\"${apn}\""
|
||||
# activate PDP context
|
||||
"OK" "AT+CGACT=1,1"
|
||||
# setup username and password per requirements of sim provider.
|
||||
# (caret is special to chat, so needs escaping in AT commands)
|
||||
"OK" "AT\\^AUTHDATA=1,${authTypeNum},\"\",\"${password}\",\"${username}\""
|
||||
# start the thing (I am choosing to read this as "NDIS DialUP")
|
||||
"OK" "AT\\^NDISDUP=1,1"
|
||||
"OK"
|
||||
];
|
||||
modeswitch = oneshot rec {
|
||||
name = "modem-modeswitch";
|
||||
controller = (svc.uevent-rule.build {
|
||||
serviceName = name;
|
||||
terms = { devtype = "usb_device"; product = "12d1/14fe/102"; };
|
||||
});
|
||||
up = ''
|
||||
${usb-modeswitch}/bin/usb_modeswitch -v 12d1 -p 14fe --huawei-new-mode
|
||||
'';
|
||||
};
|
||||
atz = oneshot rec {
|
||||
name = "modem-atz";
|
||||
dependencies = [ modeswitch ];
|
||||
controller = (svc.uevent-rule.build {
|
||||
serviceName = name;
|
||||
terms = {
|
||||
subsystem = "tty";
|
||||
attrs = {
|
||||
idVendor = "12d1";
|
||||
idProduct = "1506";
|
||||
};
|
||||
};
|
||||
symlink = "/dev/modem";
|
||||
});
|
||||
up = ''
|
||||
ls -l /dev/modem
|
||||
test -L /dev/modem || exit 1
|
||||
${ppp}/bin/chat -s -v ${chat} 0<>/dev/modem 1>&0
|
||||
'';
|
||||
down = "${ppp}/bin/chat -v '' ATZ OK 0<>/dev/modem 1>&0";
|
||||
};
|
||||
|
||||
in svc.network.link.build {
|
||||
ifname = "wwan0";
|
||||
dependencies = [ atz ];
|
||||
}
|
||||
@@ -2,9 +2,9 @@
|
||||
writeFennel
|
||||
, 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,7 +1,8 @@
|
||||
(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
|
||||
{
|
||||
@@ -47,19 +48,6 @@
|
||||
}
|
||||
)
|
||||
|
||||
(macro expect [assertion]
|
||||
(let [msg (.. "expectation failed: " (view assertion))]
|
||||
`(when (not ,assertion)
|
||||
(assert false ,msg))))
|
||||
|
||||
(macro expect= [actual expected]
|
||||
`(let [ve# (view ,expected)
|
||||
va# (view ,actual)]
|
||||
(when (not (= ve# va#))
|
||||
(assert false
|
||||
(.. "\nexpected " ve# "\ngot " va#)
|
||||
))))
|
||||
|
||||
(fn first-address []
|
||||
(let [deleted
|
||||
(subject.deletions
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
{
|
||||
liminix
|
||||
, lib
|
||||
, callPackage
|
||||
}:
|
||||
{ client, interface } :
|
||||
let
|
||||
inherit (liminix.services) longrun;
|
||||
inherit (lib) mkOption types;
|
||||
name = "dhcp6c.addr.${client.name}.${interface.name}";
|
||||
script = callPackage ./acquire-wan-address.nix { };
|
||||
in longrun {
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
{
|
||||
liminix
|
||||
, lib
|
||||
, odhcp6c
|
||||
, odhcp-script
|
||||
}:
|
||||
{ interface } :
|
||||
let
|
||||
inherit (liminix.services) longrun;
|
||||
inherit (lib) mkOption types;
|
||||
name = "dhcp6c.${interface.name}";
|
||||
in longrun {
|
||||
inherit name;
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
{ lib, pkgs, config, ...}:
|
||||
let
|
||||
inherit (lib) mkOption types;
|
||||
inherit (pkgs.liminix.services) oneshot;
|
||||
inherit (pkgs) liminix;
|
||||
in
|
||||
{
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
{
|
||||
liminix
|
||||
, lib
|
||||
, callPackage
|
||||
}:
|
||||
{ client, interface } :
|
||||
let
|
||||
inherit (liminix.services) longrun;
|
||||
inherit (lib) mkOption types;
|
||||
name = "dhcp6c.prefix.${client.name}.${interface.name}";
|
||||
script = callPackage ./acquire-delegated-prefix.nix { };
|
||||
in longrun {
|
||||
|
||||
@@ -18,7 +18,7 @@ let
|
||||
name = "${interface.name}.dnsmasq";
|
||||
inherit (liminix.services) longrun;
|
||||
inherit (lib) concatStrings concatStringsSep mapAttrsToList;
|
||||
hostOpt = name : { mac, v4, v6, leasetime } @ attrs:
|
||||
hostOpt = name : { mac, v4, v6, leasetime }:
|
||||
let v6s = concatStrings (map (a : ",[${a}]") v6);
|
||||
in "--dhcp-host=${mac},${v4}${v6s},${name},${builtins.toString leasetime}";
|
||||
in
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
let
|
||||
inherit (lib) mkOption types;
|
||||
inherit (pkgs) liminix;
|
||||
inherit (pkgs.liminix.services) oneshot;
|
||||
|
||||
kmodules = pkgs.kmodloader.override {
|
||||
inherit (config.system.outputs) kernel;
|
||||
@@ -56,8 +55,14 @@ 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";
|
||||
};
|
||||
};
|
||||
@@ -68,13 +73,17 @@ in
|
||||
};
|
||||
in svc.build args' ;
|
||||
};
|
||||
|
||||
programs.busybox.applets = [
|
||||
"insmod" "rmmod"
|
||||
];
|
||||
kernel.config = {
|
||||
NETFILTER = "y";
|
||||
NETFILTER_ADVANCED = "y";
|
||||
NETFILTER_NETLINK = "m";
|
||||
NF_CONNTRACK = "m";
|
||||
|
||||
NETLINK_DIAG = "y";
|
||||
|
||||
IP6_NF_IPTABLES= "m";
|
||||
IP_NF_IPTABLES = "m";
|
||||
IP_NF_NAT = "m";
|
||||
|
||||
@@ -4,12 +4,10 @@
|
||||
, 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;
|
||||
|
||||
@@ -5,14 +5,13 @@
|
||||
## you want to run on it, and would usually be set in the "device" file:
|
||||
## :file:`devices/manuf-model/default.nix`
|
||||
|
||||
|
||||
{ lib, pkgs, config, ...}:
|
||||
{ lib, ... }:
|
||||
let
|
||||
inherit (lib) mkEnableOption mkOption types isDerivation hasAttr ;
|
||||
in {
|
||||
inherit (lib) mkOption types;
|
||||
in
|
||||
{
|
||||
options = {
|
||||
boot = {
|
||||
};
|
||||
boot = { };
|
||||
hardware = {
|
||||
dts = {
|
||||
src = mkOption {
|
||||
@@ -26,7 +25,7 @@ in {
|
||||
'';
|
||||
};
|
||||
includes = mkOption {
|
||||
default = [];
|
||||
default = [ ];
|
||||
description = "List of directories to search for DTS includes (.dtsi files)";
|
||||
type = types.listOf types.path;
|
||||
};
|
||||
@@ -67,6 +66,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
|
||||
|
||||
@@ -8,8 +8,6 @@
|
||||
let
|
||||
inherit (liminix.services) longrun;
|
||||
inherit (lib) concatStringsSep mapAttrsToList;
|
||||
inherit (liminix.lib) typeChecked;
|
||||
inherit (lib) mkOption types;
|
||||
|
||||
# This is not a friendly interface to configuring a wireless AP: it
|
||||
# just passes everything straight through to the hostapd config.
|
||||
|
||||
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 ];
|
||||
restart-on-upgrade = true;
|
||||
run = ''
|
||||
${ifwait}/bin/ifwait -s ${service.name} $(output ${interface} ifname) ${state}
|
||||
'';
|
||||
}
|
||||
@@ -5,14 +5,9 @@
|
||||
|
||||
{ lib, pkgs, config, ...}:
|
||||
let
|
||||
inherit (lib) mkEnableOption mkOption types isDerivation hasAttr ;
|
||||
inherit (pkgs.pseudofile) dir symlink;
|
||||
inherit (pkgs.liminix.networking) address interface;
|
||||
inherit (pkgs.liminix.services) bundle;
|
||||
inherit (lib) mkOption types ;
|
||||
inherit (pkgs) liminix;
|
||||
|
||||
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
|
||||
|
||||
30
modules/mdevd.nix
Normal file
30
modules/mdevd.nix
Normal file
@@ -0,0 +1,30 @@
|
||||
{ config, pkgs, ...} :
|
||||
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 = "exec ${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
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -7,11 +7,6 @@
|
||||
let
|
||||
inherit (lib) mkOption types;
|
||||
inherit (pkgs) liminix;
|
||||
mkBoolOption = description : mkOption {
|
||||
type = types.bool;
|
||||
inherit description;
|
||||
default = true;
|
||||
};
|
||||
|
||||
in {
|
||||
options = {
|
||||
@@ -19,28 +14,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 ../service-trigger ];
|
||||
config.system.service.mount =
|
||||
let svc = config.system.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,27 @@
|
||||
{
|
||||
liminix
|
||||
, lib
|
||||
, svc
|
||||
}:
|
||||
{ device, mountpoint, options, fstype }:
|
||||
{ partlabel, mountpoint, options, fstype }:
|
||||
let
|
||||
inherit (liminix.services) oneshot;
|
||||
device = "/dev/disk/by-partlabel/${partlabel}";
|
||||
name = "mount.${lib.strings.sanitizeDerivationName (lib.escapeURL mountpoint)}";
|
||||
options_string =
|
||||
if options == [] then "" else "-o ${lib.concatStringsSep "," options}";
|
||||
controller = svc.uevent-rule.build {
|
||||
serviceName = name;
|
||||
symlink = device;
|
||||
terms = {
|
||||
partname = partlabel;
|
||||
devtype = "partition";
|
||||
};
|
||||
};
|
||||
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 name;
|
||||
timeout-up = 3600;
|
||||
up = "mount -t ${fstype} ${options_string} ${device} ${mountpoint}";
|
||||
down = "umount ${mountpoint}";
|
||||
inherit controller;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
{
|
||||
liminix
|
||||
, ifwait
|
||||
, serviceFns
|
||||
, lib
|
||||
}:
|
||||
|
||||
@@ -17,7 +17,7 @@ let
|
||||
ip address replace $ip/$mask dev $interface
|
||||
(in_outputs ${name}
|
||||
for i in lease mask ip router siaddr dns serverid subnet opt53 interface ; do
|
||||
printenv $i > $i
|
||||
(printenv $i || true) > $i
|
||||
done)
|
||||
}
|
||||
case $action in
|
||||
@@ -40,7 +40,7 @@ let
|
||||
'';
|
||||
in longrun {
|
||||
inherit name;
|
||||
run = "/bin/udhcpc -f -i $(output ${interface} ifname) -x hostname:$(cat /proc/sys/kernel/hostname) -s ${script}";
|
||||
run = "exec /bin/udhcpc -f -i $(output ${interface} ifname) -x hostname:$(cat /proc/sys/kernel/hostname) -s ${script}";
|
||||
notification-fd = 10;
|
||||
dependencies = [ interface ];
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
{
|
||||
liminix
|
||||
, ifwait
|
||||
, serviceFns
|
||||
, lib
|
||||
}:
|
||||
{ enableIPv4, enableIPv6 }:
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
{
|
||||
liminix
|
||||
, ifwait
|
||||
, serviceFns
|
||||
, lib
|
||||
}:
|
||||
{
|
||||
@@ -11,8 +9,7 @@
|
||||
# if devpath is supplied, we rename the interface at that
|
||||
# path to have the specified name.
|
||||
let
|
||||
inherit (liminix.services) longrun oneshot;
|
||||
inherit (lib) concatStringsSep;
|
||||
inherit (liminix.services) oneshot;
|
||||
name = "${ifname}.link";
|
||||
rename = if devpath != null
|
||||
then ''
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
{
|
||||
liminix
|
||||
, ifwait
|
||||
, serviceFns
|
||||
, lib
|
||||
}:
|
||||
{ target, via, interface ? null, metric }:
|
||||
let
|
||||
inherit (liminix.services) oneshot;
|
||||
with_dev = if interface != null then "dev $(output ${interface} ifname)" else "";
|
||||
target_hash = builtins.substring 0 12 (builtins.hashString "sha256" target);
|
||||
via_hash = builtins.substring 0 12 (builtins.hashString "sha256" via);
|
||||
in oneshot {
|
||||
name = "route-${target}-${builtins.substring 0 12 (builtins.hashString "sha256" "${via}-${if interface!=null then interface.name else ""}")}";
|
||||
name = "route-${target_hash}-${builtins.substring 0 12 (builtins.hashString "sha256" "${via_hash}-${if interface!=null then interface.name else ""}")}";
|
||||
up = ''
|
||||
ip route add ${target} via ${via} metric ${toString metric} ${with_dev}
|
||||
'';
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
liminix
|
||||
, chrony
|
||||
, serviceFns
|
||||
, lib
|
||||
, writeText
|
||||
}:
|
||||
@@ -9,10 +8,6 @@ params:
|
||||
let
|
||||
inherit (liminix.services) longrun;
|
||||
inherit (lib) concatStringsSep mapAttrsToList;
|
||||
inherit (liminix.lib) typeChecked;
|
||||
inherit (lib) mkOption types;
|
||||
|
||||
serverOpts = types.listOf types.str;
|
||||
configFile = p:
|
||||
(mapAttrsToList (name: opts: "server ${name} ${concatStringsSep "" opts}")
|
||||
p.servers)
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
{
|
||||
config
|
||||
, pkgs
|
||||
, lib
|
||||
, ...
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkOption types concatStringsSep;
|
||||
inherit (pkgs) liminix callPackage writeText;
|
||||
inherit (pkgs) liminix writeText;
|
||||
o = config.system.outputs;
|
||||
in
|
||||
{
|
||||
@@ -22,7 +22,7 @@ in
|
||||
# but only part of one.
|
||||
kernel = mkOption {
|
||||
type = types.package;
|
||||
internal = true;
|
||||
internal = true;
|
||||
description = ''
|
||||
kernel
|
||||
******
|
||||
@@ -42,7 +42,7 @@ in
|
||||
};
|
||||
dtb = mkOption {
|
||||
type = types.package;
|
||||
internal = true;
|
||||
internal = true;
|
||||
description = ''
|
||||
dtb
|
||||
***
|
||||
@@ -52,7 +52,7 @@ in
|
||||
};
|
||||
uimage = mkOption {
|
||||
type = types.package;
|
||||
internal = true;
|
||||
internal = true;
|
||||
description = ''
|
||||
uimage
|
||||
******
|
||||
@@ -68,7 +68,7 @@ in
|
||||
};
|
||||
manifest = mkOption {
|
||||
type = types.package;
|
||||
internal = true;
|
||||
internal = true;
|
||||
description = ''
|
||||
Debugging aid. JSON rendition of config.filesystem, on
|
||||
which can run "nix-store -q --tree" on it and find
|
||||
@@ -111,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;
|
||||
};
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
, ...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkIf mkOption types;
|
||||
inherit (lib) mkIf;
|
||||
o = config.system.outputs;
|
||||
in
|
||||
{
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
, ...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkIf mkOption types;
|
||||
inherit (lib) mkIf;
|
||||
o = config.system.outputs;
|
||||
in
|
||||
{
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkEnableOption mkOption mkIf types;
|
||||
inherit (pkgs) runCommand callPackage writeText;
|
||||
inherit (pkgs) runCommand;
|
||||
in
|
||||
{
|
||||
options = {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
, ...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkIf mkOption types;
|
||||
inherit (lib) mkIf;
|
||||
o = config.system.outputs;
|
||||
in
|
||||
{
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
, ...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkOption mkForce types concatStringsSep;
|
||||
inherit (lib) mkOption types concatStringsSep;
|
||||
in {
|
||||
imports = [ ../ramdisk.nix ];
|
||||
options.system.outputs = {
|
||||
@@ -42,8 +42,7 @@ in {
|
||||
|
||||
boot-sh =
|
||||
let
|
||||
inherit (pkgs.lib.trivial) toHexString;
|
||||
inherit (config.system.outputs) rootfs kernel;
|
||||
inherit (config.system.outputs) rootfs;
|
||||
cmdline = concatStringsSep " " config.boot.commandLine;
|
||||
in
|
||||
pkgs.buildPackages.runCommand "boot.sh.sh" {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
, ...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkOption types concatStringsSep;
|
||||
inherit (lib) mkOption types;
|
||||
o = config.system.outputs;
|
||||
phram_address = lib.toHexString (config.hardware.ram.startAddress + 256 * 1024 * 1024);
|
||||
in {
|
||||
|
||||
@@ -58,7 +58,6 @@ in {
|
||||
system.outputs = rec {
|
||||
tftpboot =
|
||||
let
|
||||
inherit (pkgs.lib.trivial) toHexString;
|
||||
o = config.system.outputs;
|
||||
image = let choices = {
|
||||
uimage = o.uimage;
|
||||
@@ -122,7 +121,7 @@ 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"
|
||||
|
||||
dtbSize=$(binsize ./dtb )
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
, ...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkOption types concatStringsSep;
|
||||
inherit (lib) mkOption types;
|
||||
o = config.system.outputs;
|
||||
cfg = config.tplink-safeloader;
|
||||
in {
|
||||
|
||||
@@ -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
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
, ...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkIf mkEnableOption mkOption types concatStringsSep;
|
||||
inherit (lib) mkIf mkOption types;
|
||||
cfg = config.boot.tftp;
|
||||
instructions = pkgs.writeText "env.scr" ''
|
||||
setenv serverip ${cfg.serverip}
|
||||
|
||||
90
modules/outputs/ubivolume.nix
Normal file
90
modules/outputs/ubivolume.nix
Normal file
@@ -0,0 +1,90 @@
|
||||
{
|
||||
config
|
||||
, pkgs
|
||||
, lib
|
||||
, ...
|
||||
}:
|
||||
let
|
||||
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 mkOption types;
|
||||
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
|
||||
'';
|
||||
};
|
||||
}
|
||||
@@ -17,6 +17,9 @@ in {
|
||||
system.service.pppoe = mkOption {
|
||||
type = liminix.lib.types.serviceDefn;
|
||||
};
|
||||
system.service.l2tp = mkOption {
|
||||
type = liminix.lib.types.serviceDefn;
|
||||
};
|
||||
};
|
||||
config = {
|
||||
system.service.pppoe = pkgs.liminix.callService ./pppoe.nix {
|
||||
@@ -29,6 +32,16 @@ in {
|
||||
description = "options supplied on ppp command line";
|
||||
};
|
||||
};
|
||||
system.service.l2tp = pkgs.liminix.callService ./l2tp.nix {
|
||||
lns = mkOption {
|
||||
type = types.str;
|
||||
description = "hostname or address of the L2TP network server";
|
||||
};
|
||||
ppp-options = mkOption {
|
||||
type = types.listOf types.str;
|
||||
description = "options supplied on ppp command line";
|
||||
};
|
||||
};
|
||||
kernel = {
|
||||
config = {
|
||||
PPP = "y";
|
||||
@@ -36,6 +49,8 @@ in {
|
||||
PPP_DEFLATE = "y";
|
||||
PPP_ASYNC = "y";
|
||||
PPP_SYNC_TTY = "y";
|
||||
PPPOL2TP = "y";
|
||||
L2TP = "y";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
61
modules/ppp/l2tp.nix
Normal file
61
modules/ppp/l2tp.nix
Normal file
@@ -0,0 +1,61 @@
|
||||
{
|
||||
liminix
|
||||
, writeAshScript
|
||||
, writeText
|
||||
, serviceFns
|
||||
, xl2tpd
|
||||
} :
|
||||
{ lns, ppp-options }:
|
||||
let
|
||||
inherit (liminix.services) longrun;
|
||||
name = "${lns}.l2tp";
|
||||
ip-up = writeAshScript "ip-up" {} ''
|
||||
. ${serviceFns}
|
||||
(in_outputs ${name}
|
||||
echo $1 > ifname
|
||||
echo $2 > tty
|
||||
echo $3 > speed
|
||||
echo $4 > address
|
||||
echo $5 > peer-address
|
||||
echo $DNS1 > ns1
|
||||
echo $DNS2 > ns2
|
||||
)
|
||||
echo >/proc/self/fd/10
|
||||
'';
|
||||
ip6-up = writeAshScript "ip6-up" {} ''
|
||||
. ${serviceFns}
|
||||
(in_outputs ${name}
|
||||
echo $4 > ipv6-address
|
||||
echo $5 > ipv6-peer-address
|
||||
)
|
||||
echo >/proc/self/fd/10
|
||||
'';
|
||||
ppp-options' = ppp-options ++ [
|
||||
"ip-up-script" ip-up
|
||||
"ipv6-up-script" ip6-up
|
||||
"ipparam" name
|
||||
"nodetach"
|
||||
"usepeerdns"
|
||||
"logfd" "2"
|
||||
];
|
||||
conf = writeText "xl2tpd.conf" ''
|
||||
[lac upstream]
|
||||
lns = ${lns}
|
||||
require authentication = no
|
||||
pppoptfile = ${writeText "ppp-options" ppp-options'}
|
||||
autodial = yes
|
||||
redial = no
|
||||
max redials = 1
|
||||
'';
|
||||
control = "/run/xl2tpd/control-${name}";
|
||||
in
|
||||
longrun {
|
||||
inherit name;
|
||||
run = ''
|
||||
mkdir -p /run/xl2tpd
|
||||
touch ${control}
|
||||
exec ${xl2tpd}/bin/xl2tpd -D -p /run/xl2tpd/${name}.pid -c ${conf} -C ${control}
|
||||
'';
|
||||
notification-fd = 10;
|
||||
timeout-up = 40 * 1000;
|
||||
}
|
||||
@@ -9,6 +9,8 @@
|
||||
{ interface, ppp-options }:
|
||||
let
|
||||
inherit (liminix.services) longrun;
|
||||
lcp-echo-interval = 4;
|
||||
lcp-echo-failure = 3;
|
||||
name = "${interface.name}.pppoe";
|
||||
ip-up = writeAshScript "ip-up" {} ''
|
||||
. ${serviceFns}
|
||||
@@ -37,15 +39,19 @@ let
|
||||
"ipparam" name
|
||||
"nodetach"
|
||||
"usepeerdns"
|
||||
"lcp-echo-interval" (builtins.toString lcp-echo-interval)
|
||||
"lcp-echo-failure" (builtins.toString lcp-echo-failure)
|
||||
"logfd" "2"
|
||||
];
|
||||
in
|
||||
longrun {
|
||||
inherit name;
|
||||
run = ''
|
||||
. ${serviceFns}
|
||||
${ppp}/bin/pppd pty "${pppoe}/bin/pppoe -I $(output ${interface} ifname)" ${lib.concatStringsSep " " ppp-options'}
|
||||
. ${serviceFns}
|
||||
echo Starting pppoe, pppd pid is $$
|
||||
exec ${ppp}/bin/pppd pty "${pppoe}/bin/pppoe -T ${builtins.toString (4 * lcp-echo-interval)} -I $(output ${interface} ifname)" ${lib.concatStringsSep " " ppp-options'}
|
||||
'';
|
||||
notification-fd = 10;
|
||||
timeout-up = (10 + lcp-echo-failure * lcp-echo-interval) * 1000;
|
||||
dependencies = [ interface ];
|
||||
}
|
||||
|
||||
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 types;
|
||||
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) mkOption types ;
|
||||
|
||||
inherit (pkgs.liminix.services) oneshot 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";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -1,11 +1,6 @@
|
||||
{
|
||||
config
|
||||
, pkgs
|
||||
, lib
|
||||
, ...
|
||||
}:
|
||||
{ config, lib, ... }:
|
||||
let
|
||||
inherit (lib) mkIf mkEnableOption mkOption; # types concatStringsSep;
|
||||
inherit (lib) mkIf mkEnableOption; # types concatStringsSep;
|
||||
in {
|
||||
options = {
|
||||
boot = {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{ config, pkgs, ... }:
|
||||
{ config, pkgs, lib, ... }:
|
||||
let
|
||||
inherit (pkgs)
|
||||
execline
|
||||
@@ -6,14 +6,50 @@ let
|
||||
s6-init-bin
|
||||
s6-linux-init
|
||||
stdenvNoCC;
|
||||
inherit (lib.lists) unique concatMap;
|
||||
inherit (pkgs.pseudofile) dir symlink;
|
||||
inherit (pkgs.liminix.services) bundle;
|
||||
inherit (pkgs.liminix.services) oneshot bundle;
|
||||
|
||||
s6-rc-db =
|
||||
let
|
||||
# In the default bundle we need to have all the services
|
||||
# in config.services except for controlled services and
|
||||
# anything that depends on one. But we do need the controllers
|
||||
# themselves.
|
||||
|
||||
# So, find all required services and their transitive
|
||||
# dependencies and their controllers. remove all controlled
|
||||
# services and all services that have a controlled service as
|
||||
# dependency
|
||||
|
||||
isControlled = s : s ? controller && s.controller != null;
|
||||
deps = s : s.dependencies ++
|
||||
lib.optional (isControlled s) s.controller;
|
||||
flatDeps = s : [s] ++ concatMap flatDeps (deps s);
|
||||
allServices = unique (concatMap flatDeps (builtins.attrValues config.services));
|
||||
isDependentOnControlled = s :
|
||||
isControlled s ||
|
||||
(lib.lists.any isDependentOnControlled s.dependencies);
|
||||
|
||||
# all controlled services depend on this oneshot, which
|
||||
# makes a list of them so we can identify them at runtime
|
||||
controlled = oneshot {
|
||||
name = "controlled";
|
||||
up = ''
|
||||
mkdir -p /run/services/controlled
|
||||
for s in $(s6-rc-db -d dependencies controlled); do
|
||||
touch /run/services/controlled/$s
|
||||
done
|
||||
'';
|
||||
down = "rm -r /run/services/controlled";
|
||||
};
|
||||
|
||||
defaultStart =
|
||||
builtins.filter
|
||||
(s: !(isDependentOnControlled s)) allServices;
|
||||
defaultDefaultTarget = bundle {
|
||||
name = "default";
|
||||
contents = builtins.attrValues config.services;
|
||||
contents = defaultStart ++ [controlled];
|
||||
};
|
||||
servicesAttrs = {
|
||||
default = defaultDefaultTarget;
|
||||
|
||||
@@ -34,7 +34,7 @@ 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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{ config, pkgs, lib, ... } :
|
||||
{ config, pkgs, ... } :
|
||||
{
|
||||
config = {
|
||||
programs.busybox = {
|
||||
|
||||
37
modules/service-trigger/default.nix
Normal file
37
modules/service-trigger/default.nix
Normal file
@@ -0,0 +1,37 @@
|
||||
# this is unlikely to be the final form or location of this code, it's
|
||||
# an interim module which wraps the uevent-watch command
|
||||
|
||||
{ lib, pkgs, config, ... }:
|
||||
let
|
||||
inherit (lib) mkOption types;
|
||||
inherit (pkgs) liminix;
|
||||
# inherit (pkgs.liminix.services) bundle;
|
||||
in {
|
||||
options = {
|
||||
system.service.uevent-rule = mkOption {
|
||||
description = "a service which starts other services based on device state (sysfs)";
|
||||
type = liminix.lib.types.serviceDefn;
|
||||
};
|
||||
};
|
||||
config = {
|
||||
system.service.uevent-rule = liminix.callService ./rule.nix {
|
||||
serviceName = mkOption {
|
||||
description = "name of the service to run when the rule matches";
|
||||
type = types.str;
|
||||
};
|
||||
terms = mkOption {
|
||||
type = types.attrs;
|
||||
example = {
|
||||
devtype = "usb_device";
|
||||
attrs.idVendor = "8086";
|
||||
};
|
||||
default = {};
|
||||
};
|
||||
symlink = mkOption {
|
||||
description = "create symlink targeted on devpath";
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
23
modules/service-trigger/rule.nix
Normal file
23
modules/service-trigger/rule.nix
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
liminix
|
||||
, uevent-watch
|
||||
, lib }:
|
||||
{
|
||||
serviceName, terms, symlink
|
||||
}:
|
||||
let
|
||||
inherit (liminix.services) longrun;
|
||||
inherit (lib.attrsets) collect mapAttrsRecursive;
|
||||
inherit (lib.strings) concatStringsSep;
|
||||
stringify = attrs :
|
||||
concatStringsSep " "
|
||||
(collect lib.isString
|
||||
(mapAttrsRecursive
|
||||
(path : value : "${concatStringsSep "." path}=${value}")
|
||||
attrs));
|
||||
termsString = stringify terms;
|
||||
in longrun {
|
||||
name = "watch-for-${serviceName}";
|
||||
restart-on-upgrade = true;
|
||||
run = "${uevent-watch}/bin/uevent-watch ${if symlink != null then "-n ${symlink}" else ""} -s ${serviceName} ${termsString}";
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
config
|
||||
, pkgs
|
||||
, lib
|
||||
, ...
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (pkgs) liminix;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
liminix
|
||||
, dropbear
|
||||
, serviceFns
|
||||
, lib
|
||||
}:
|
||||
p :
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# support for USB block devices and the common filesystems
|
||||
# they're likely to provide
|
||||
|
||||
{lib, config, ... }:
|
||||
{ config, ... }:
|
||||
{
|
||||
kernel = {
|
||||
config = {
|
||||
@@ -24,8 +24,6 @@
|
||||
EXT4_FS = "y";
|
||||
EXT4_USE_FOR_EXT2 = "y";
|
||||
FS_ENCRYPTION = "y";
|
||||
|
||||
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||