1
0
forked from dan/liminix

Compare commits

..

No commits in common. "d14ee41325841005e3d2c222b30cdcf7f8439e5e" and "83ee488e4c81124380b8bd4ff8183e632f30eb91" have entirely different histories.

58 changed files with 321 additions and 1693 deletions

1
.gitignore vendored
View File

@ -6,4 +6,3 @@ result-*
_build
*-secrets.nix
examples/static-leases.nix
/doc/hardware.rst

47
NEWS
View File

@ -31,52 +31,5 @@ Upstream changes that have led to incompatible Liminix changes are:
* newer U-Boot version
* util-linux can now be built (previously depended on systemd)
2024-01-30
New port! Thanks to Arnout Engelen <arnout@bzzt.net>, Liminix
now runs on the TP-Link Archer AX23
2024-02-12
* We now build wifi drivers (mac80211) from the same kernel source as
the running kernel, instead of using drivers from the linux-backports
project. This may be a regression on some devices that depend on
OpenWrt patches for wireless functionality: if you have a device that
used to work and now doesn't, refer to OpenWrt
package/kernel/mac80211/patches/ to see if there's something in there
that needs to be applied.
* in general, we build kernel modules (e.g. for nftables) at the same
time as the kernel itself instead of expecting to be able to build
them afterwards as though they were "out of tree". Refer to commit
b9c0d93670275e69df24902b05bf4aa4f0fcbe96 for a fuller explanation
of how this simplifies things.
2024-02-13
So that we can be more consistent about services that would like their
state to be preserved across boots (assuming a writable filesystem)
these changes have been made
* /run/service-state has been moved to /run/services/outputs
to better reflect what it's used for
* /run/services/state is either a symlink to /persist/services/state
(if there's a writeable fs on /persist) or a directory (if there
isn't)
The change will lose your ssh host key(s) unless you copy them from
the old location to the new one before rebooting into the new system
mkdir -m 02751 -p /run/services/state/dropbear
cp /persist/secrets/dropbear/* /run/services/state/dropbear
The `output`, `mkoutputs` functions defined by ${serviceFns}
have been updated for the new location.
2024-02-16
New (or at least, previously unreported) port! Liminix now runs on the
Turris Omnia and has been serving my family's internet needs for most
of this week. Thanks to NGI0 Entrust and the NLnet Foundation for
sponsoring this development (and funding the hardware)

View File

@ -33,7 +33,7 @@ functioning version, see [the CI system](https://build.liminix.org/jobset/limini
Documentation is in the [doc](doc/) directory. You can build it
by running
nix-shell -p sphinx --run "make -C doc hardware.rst html"
nix-shell -p sphinx --run "make -C doc html"
Rendered documentation corresponding to the latest commit on `main`
is published to [https://www.liminix.org/doc/](https://www.liminix.org/doc/)

View File

@ -3845,269 +3845,3 @@ store. Also probably it should mkdir $prefix/persist. Also it needs to
create $prefix/boot: it's too late to do that with `activate`
because u-boot will need it to exist in order to load the initramfs
that runs activate
Thu Jan 11 23:36:47 GMT 2024
squashfs rootfsType doesn't rebuild when the kernel config is changed
Mon Jan 22 19:04:45 GMT 2024
setenv serverip 10.0.0.1
setenv ipaddr 10.0.0.8
compraddr=0x01000000
tftpboot ${compraddr} recovery.img.lzma
setexpr writeaddr ${filesize} + $compraddr
lzmadec ${compraddr} $writeaddr
usb start
usb dev 0
wdt dev watchdog@20300
wdt stop
usb write ${writeaddr} 0 ${filesize}
Thu Jan 25 11:55:36 GMT 2024
openwrt:
CONFIG_BROADCOM_PHY=m
CONFIG_FIXED_PHY=y
CONFIG_GENERIC_PHY=y
CONFIG_IP17XX_PHY=m ?
CONFIG_MARVELL_PHY=y
CONFIG_MVSW61XX_PHY=y ?
CONFIG_RTL8366RB_PHY=m ?
CONFIG_RTL8366S_PHY=m ?
CONFIG_RTL8367B_PHY=m ?
CONFIG_SWPHY=y
CONFIG_USB_PHY=y
CONFIG_FIXED_PHY=y
CONFIG_GENERIC_PHY=y
CONFIG_MARVELL_PHY=y
CONFIG_PHY_MVEBU_A3700_COMPHY=y
CONFIG_PHY_MVEBU_A38X_COMPHY=y
CONFIG_SWPHY=y
#
Sat Jan 27 18:14:13 GMT 2024
To make the recovery system (and tftpboot generally) more useful, it
would be good to resize the root fs on boot. Need to do this before
anything that writes to it
Mon Jan 29 21:50:59 GMT 2024
something is corrupted in the uncompressed rootfs
$ head -c $(printf "%d" 0x2be0000) rootfs | sha1sum
142571fe0436c18191727d1d4c2fd32163c1f2e1 -
=> sha1sum 0x1000000 2be0000
sha1 for 01000000 ... 03bdffff ==> 142571fe0436c18191727d1d4c2fd32163c1f2e1
but!
$ head -c $(printf "%d" 0x2bf0000) rootfs | sha1sum
7aa004ba87c6772bade491fbade164e2dfe100f9 -
=> sha1sum 0x1000000 2bf0000
sha1 for 01000000 ... 03beffff ==> 1a0923a94784d0c0b86006c5e6fff1649770dad3
something is trashing something in the range 03be0000 - 03beffff
or else it's not being decompressed properly
pxefile_addr_r=0x1900000
ramdisk_addr_r=0x2200000
scriptaddr=0x1800000
fdt_addr_r=0x2000000
fdtcontroladdr=7fb19b30
fdtfile=armada-385-turris-omnia.dtb
fdt_high=0x10000000
initrd_high=0x10000000
kernel_addr_r=0x1000000
0x1700000;
0x10000000
Sun Feb 4 11:55:00 GMT 2024
restructuredtext headings:
https://devguide.python.org/documentation/markup/#sections
####### chapter (one per filename)
*******
=======
-------
Mon Feb 5 09:57:52 GMT 2024
Before calling the Omnia "done" I'd like to get it to the point that
I can actually use it as a CPE. This means
- writing something down about how we handle static addresses
- hosts that need static ipv6 can configure it themselves as ::n
where n is a small number. this won't clash with slaac
- the `hosts` param to dnsmasq can specify static ipv4
- dealing with port forwards and allowed incoming in the firewall
- would be quite cool to run sniproxy instead of forwarding to
loaclhost (extra credit)
Sat Feb 10 18:23:54 GMT 2024
ARGH KERNEL
You can't define CONFIG_NETFILTER=y in a monolithic kernel and expect
later to separately build some modules that use it, because there are
a bunch of symbols that only get defined if certain other CONFIG
options are set at the time that the monolithic kernel is built.
https://github.com/torvalds/linux/blob/master/net/netfilter/core.c#L689
Another example is
https://github.com/torvalds/linux/blob/master/include/linux/netdevice.h#L160
- if you decide after building the kernel that you're going to build
some wireless modules, you can't do that without rebuilding the kernel
so that it knows to expect them
The moral of the story seems to be: if you have a compiled Linux kernel source tree and you change some symbol from "is not set" to m and then run make modules, you cannot in general expect that newly compiled module to work.
AP advertised VHT without HT, disabling HT/VHT/HE
TODO
- [done] support kernel version as parameter to builder pkgs/kernel/default.nix
- [done] extract the change in how module loading works from omnia device config,
and fix the other thing that uses it
- [axed] wlan module to take 'backported' as a parameter
half of the omnia conditionalConfig can go into the module
- [done] upgrade omnia to kernel v6
- figure out what mdns we need for local hostname resolution
(maybe bridging lan/wlan)?
- [DONE] slow wifi because "AP advertised VHT without HT, disabling HT/VHT/HE"
- [DONE] add local domain to secrets
- run sniproxy instead of forwarding
- [test] forward some port to loaclhost 22 for inbound ipv4 ssh
Mon Feb 12 21:50:35 GMT 2024
# find /run/service-state/dhcp6c.wan.link.pppoe/address/
/run/service-state/dhcp6c.wan.link.pppoe/address/
/run/service-state/dhcp6c.wan.link.pppoe/address/2001-8b0-1111-1111-0-ffff-51bb-4cf2_LFoo015bSsM
/run/service-state/dhcp6c.wan.link.pppoe/address/2001-8b0-1111-1111-0-ffff-51bb-4cf2_LFoo015bSsM/valid
/run/service-state/dhcp6c.wan.link.pppoe/address/2001-8b0-1111-1111-0-ffff-51bb-4cf2_LFoo015bSsM/preferred
/run/service-state/dhcp6c.wan.link.pppoe/address/2001-8b0-1111-1111-0-ffff-51bb-4cf2_LFoo015bSsM/len
/run/service-state/dhcp6c.wan.link.pppoe/address/2001-8b0-1111-1111-0-ffff-51bb-4cf2_LFoo015bSsM/address
#
valid 7199 preferred 3599
Tue Feb 13 19:44:57 GMT 2024
Before we put this back live, would be good to
[done] 1) move the leases file into /persist
I think we'll do /persist/service/<name>/ and change ssh to use the same
scheme.
we could put mkpersist() in serviceFns which would check for /persist
and return a directory in /persist/service/ or /run/service-state
(will something bad happen if we use /run/service-state? it will also
expose the thingy as an output, but whether it's accessible that way
will depend on whether there's a writable fs or not, which is unexpected)
: rename service-state to /run/services/outputs
: on boot
: if /persist
: create /persist/services/state and symlink /run/services/state to it
: else create /run/services/state
[done] 2) maybe change the local domain back to .lan? setting up
systemd-networkd with search domains is an awful faff
[done] 3) work out what to do with incoming ssh from wan
- For noetbook and thinkpad we have a vpn anyway so can expect to
reach loaclhost directly using ipv6
- stop ssh from ever trying to get to our ipv4 address.
- we could get rid of A record for loaclhost.telent.net but
there are a bunch of CNAMES pointing at it for web servers.
- we could reject incoming connections to tcp4 port 22 in firewall
and then there is a clear signal to Dont Do That Then
- for emergency use, dnat ipv4 2200 and 2201 to rotuer and loaclhost
Tue Feb 13 22:31:03 GMT 2024
* the reason we can't reboot is that there is a service to add each
lan device to the bridge which does ifwait $dev running, which doesn't
return until there's something plugged in. So s6-rc hangs indefinitely
until the lan switch is fully populated. This is definitely a "next
milestone" thing.
* another example of "thing that depends on other thing but which it
is actually OK if neither of them happen" might be "mount a
filesystem if there is a usb mass storage device attached"
* I don't know if failover also fits into the model we don't quite
have. LTE route depends on pppoe not being healthy
we can have services (or bundles) that aren't part of the default target,
and plumb them into events of some kind (netlink?) to bring them up/down?
we can use s6-rc instanced services:
https://skarnet.org/software/s6/instances.html
"s6-instance-create and s6-instance-delete are relatively expensive operations, because they have to recursively copy or delete directories and use the synchronization mechanism with the instance supervisor, compared to s6-instance-control which only has to send commands to already existing supervisors. If you are going to turn instances on and off on a regular basis, it is more efficient to keep the instance existing and control it with s6-instance-control than it is to repeatedly create and delete it. "
Probably we need something that reads netlink messages and converts
them to a format that we can use to control services. Is there a
benefit to using services here and not just running commands? it means
the system state change we desire will stay changed.
TODO items not to lose track of
- speed testing (iperf)
- make gl-ar750 tftpboot build again
- finish belkin
- install sniproxy
- is there something simple we can do to make it reboot again?
- turn rotuer,extneder examples into "profiles" that don't embed
hardware specifics
Thu Feb 15 11:50:56 GMT 2024
1) to make tftpboot work with old bootm implementations we need
- compressed root
- uncompressed root
- kernel with dtb
dtb needs to know where uncompressed rootfs is and how big
2) if the image is a zImage (arm32) or an Image (arm64) we have to stick
with the three-arg bootz, and the dtb has to be lower in ram than the kernel
Fri Feb 16 15:43:32 GMT 2024
DHCP6c refresh is still wrong. We get updates for an address that
hasn't changed prefix or length, when the expiry times have changed,
and we can't action that by remove;add because remove will wipe out
any routes through the interface but add won't put them back
We can use "change" for both adds and changes, but we need to know that
a change is not a delete
The "identity" of an address is the address itself: kernel won't
let you add the same address with two different prefixes.
Keeping it simple, we could call "change" on every address in the
new-addresses list and "del" on every address in old-addresses
that is no longer in new-addresses
If the upstream has changed length, "ip addr change" is ignored,
so it needs to be in deleted as well as added/changed

1
ci.nix
View File

@ -11,7 +11,6 @@ let
devices = [
"gl-ar750" "gl-mt300n-v2" "gl-mt300a"
"qemu" "qemu-aarch64" "qemu-armv7l"
"tp-archer-ax23"
];
vanilla = ./vanilla-configuration.nix;
for-device = name:

View File

@ -67,7 +67,6 @@ in {
go-l2tp
min-copy-closure
fennelrepl
lzma
];
};
}

View File

@ -57,8 +57,8 @@
kernel = {
src = pkgs.pkgsBuildBuild.fetchurl {
name = "linux.tar.gz";
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.137.tar.gz";
hash = "sha256-PkdzUKZ0IpBiWe/RS70J76JKnBFzRblWcKlaIFNxnHQ=";
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.71.tar.gz";
hash = "sha256-yhO2cXIeIgUxkSZf/4aAsF11uxyh+UUZu6D1h92vCD8=";
};
extraPatchPhase = ''
${pkgs.openwrt.applyPatches.mediatek}
@ -144,17 +144,6 @@
# SERIAL_8250_NR_UARTS="3";
# SERIAL_8250_RUNTIME_UARTS="3";
SERIAL_OF_PLATFORM="y";
# Must enble hardware watchdog drivers. Else the device reboots after several seconds
WATCHDOG = "y";
MEDIATEK_WATCHDOG = "y";
};
conditionalConfig = {
WLAN= {
MT7615E = "m";
MT7622_WMAC = "y";
MT7915E = "m";
};
};
};
boot = {
@ -176,9 +165,12 @@
hardware =
let
openwrt = pkgs.openwrt;
mac80211 = pkgs.kmodloader.override {
targets = ["mt7615e" "mt7915e"];
inherit (config.system.outputs) kernel;
mac80211 = pkgs.mac80211.override {
drivers = [
"mt7615e"
"mt7915e"
];
klibBuild = config.system.outputs.kernel.modulesupport;
};
in {
ubi = {

View File

@ -7,8 +7,8 @@
kernel = {
src = pkgs.pkgsBuildBuild.fetchurl {
name = "linux.tar.gz";
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.137.tar.gz";
hash = "sha256-PkdzUKZ0IpBiWe/RS70J76JKnBFzRblWcKlaIFNxnHQ=";
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.71.tar.gz";
hash = "sha256-yhO2cXIeIgUxkSZf/4aAsF11uxyh+UUZu6D1h92vCD8=";
};
config = {
MTD = "y";

View File

@ -71,10 +71,9 @@
cp $blobdir/board.bin $out/ath10k/QCA9887/hw1.0/
'';
};
mac80211 = pkgs.kmodloader.override {
targets = ["ath9k" "ath10k_pci"];
inherit (config.system.outputs) kernel;
dependencies = [ ath10k_cal_data ];
mac80211 = pkgs.mac80211.override {
drivers = ["ath9k" "ath10k_pci"];
klibBuild = config.system.outputs.kernel.modulesupport;
};
ath10k_cal_data =
let
@ -133,7 +132,7 @@
};
wlan5 = link.build {
ifname = "wlan1";
dependencies = [ ath10k_cal_data mac80211 ];
dependencies = [ mac80211 ath10k_cal_data ];
};
};
};
@ -153,8 +152,8 @@
kernel = {
src = pkgs.pkgsBuildBuild.fetchurl {
name = "linux.tar.gz";
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.137.tar.gz";
hash = "sha256-PkdzUKZ0IpBiWe/RS70J76JKnBFzRblWcKlaIFNxnHQ=";
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.71.tar.gz";
hash = "sha256-yhO2cXIeIgUxkSZf/4aAsF11uxyh+UUZu6D1h92vCD8=";
};
# Mainline linux 5.19 doesn't have device-tree support for
@ -162,8 +161,6 @@
# OpenWrt kernel patches
extraPatchPhase = ''
${openwrt.applyPatches.ath79}
sed -i.bak -e '\,include <linux/hw_random.h>,a #include <linux/gpio/driver.h>' drivers/net/wireless/ath/ath9k/ath9k.h # context reqd for next patch
patch -p1 < ${openwrt.src}/package/kernel/mac80211/patches/ath9k/552-ath9k-ahb_of.patch
'';
config = {
@ -214,21 +211,14 @@
WATCHDOG = "y";
ATH79_WDT = "y"; # watchdog timer
# this is all copied from nixwrt ath79 config. Clearly not all
# of it is device config, some of it is wifi config or
# installation method config or ...
EARLY_PRINTK = "y";
PRINTK_TIME = "y";
};
conditionalConfig = {
WLAN = {
WLAN_VENDOR_ATH = "y";
ATH_COMMON = "m";
ATH9K = "m";
ATH9K_AHB = "y";
ATH10K = "m";
ATH10K_PCI = "m";
ATH10K_DEBUG = "y";
};
};
};
};
}

View File

@ -47,9 +47,9 @@
let
inherit (pkgs.liminix.networking) interface;
inherit (pkgs) openwrt;
mac80211 = pkgs.kmodloader.override {
targets = ["rt2800soc"];
inherit (config.system.outputs) kernel;
mac80211 = pkgs.mac80211.override {
drivers = ["rt2800soc"];
klibBuild = config.system.outputs.kernel.modulesupport;
};
in {
imports = [
@ -131,8 +131,8 @@
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=";
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.71.tar.gz";
hash = "sha256-yhO2cXIeIgUxkSZf/4aAsF11uxyh+UUZu6D1h92vCD8=";
};
extraPatchPhase = ''
${openwrt.applyPatches.ramips}
@ -178,14 +178,6 @@
} // lib.optionalAttrs (config.system.service ? vlan) {
SWCONFIG = "y";
};
conditionalConfig = {
WLAN = {
WLAN_VENDOR_RALINK = "y";
RT2800SOC = "m";
RT2X00 = "m";
};
};
};
};
}

View File

@ -43,9 +43,9 @@
inherit (pkgs.pseudofile) dir symlink;
inherit (pkgs) openwrt;
mac80211 = pkgs.kmodloader.override {
targets = ["mt7603e"];
inherit (config.system.outputs) kernel;
mac80211 = pkgs.mac80211.override {
drivers = ["mt7603e"];
klibBuild = config.system.outputs.kernel.modulesupport;
};
wlan_firmware = pkgs.fetchurl {
url = "https://github.com/openwrt/mt76/raw/f24b56f935392ca1d35fae5fd6e56ef9deda4aad/firmware/mt7628_e2.bin";
@ -127,8 +127,8 @@
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=";
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.71.tar.gz";
hash = "sha256-yhO2cXIeIgUxkSZf/4aAsF11uxyh+UUZu6D1h92vCD8=";
};
extraPatchPhase = ''
${openwrt.applyPatches.ramips}
@ -185,15 +185,6 @@
RALINK_WDT = "y"; # watchdog
MT7621_WDT = "y"; # or it might be this one
};
conditionalConfig = {
WLAN = {
WLAN_VENDOR_RALINK = "y";
WLAN_VENDOR_MEDIATEK = "y";
MT7603E = "m";
};
};
};
};
}

View File

@ -1,442 +0,0 @@
{
description = ''
TP-Link Archer AX23 / AX1800 Dual Band Wi-Fi 6 Router
*****************************************************
Hardware summary
================
- MediaTek MT7621 (880MHz)
- 16MB Flash
- 128MB RAM
- WLan hardware: Mediatek MT7905, MT7975
Limitations
===========
Status LEDs do not work yet.
Uploading an image via tftp doesn't work yet, because the Archer uboot
version is so old it doesn't support overriding the DTB from the mboot
command. The tftpboot module doesn't support this yet, see
https://gti.telent.net/dan/liminix/pulls/5 for the WiP.
'';
system = {
crossSystem = {
config = "mipsel-unknown-linux-musl";
gcc = {
abi = "32";
# https://openwrt.org/docs/techref/instructionset/mipsel_24kc
arch = "24kc";
};
};
};
module = {pkgs, config, lib, lim, ... }:
let firmware = pkgs.stdenv.mkDerivation {
name = "wlan-firmware";
phases = ["installPhase"];
installPhase = ''
mkdir $out
cp ${pkgs.linux-firmware}/lib/firmware/mediatek/{mt7915,mt7615,mt7622}* $out
'';
};
in {
imports = [
../../modules/arch/mipsel.nix
../../modules/outputs/tftpboot.nix
../../modules/outputs/tplink-safeloader.nix
];
config = {
kernel = {
src = pkgs.pkgsBuildBuild.fetchurl {
name = "linux.tar.gz";
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.137.tar.gz";
hash = "sha256-PkdzUKZ0IpBiWe/RS70J76JKnBFzRblWcKlaIFNxnHQ=";
};
extraPatchPhase = ''
${pkgs.openwrt.applyPatches.ramips}
'';
config = {
# Initially taken from openwrt's ./target/linux/ramips/mt7621/config-5.15,
# then tweaked here and there
ARCH_32BIT_OFF_T="y";
ARCH_HIBERNATION_POSSIBLE="y";
ARCH_KEEP_MEMBLOCK="y";
ARCH_MMAP_RND_BITS_MAX="15";
ARCH_MMAP_RND_COMPAT_BITS_MAX="15";
ARCH_SUSPEND_POSSIBLE="y";
AT803X_PHY="y";
BLK_MQ_PCI="y";
BOARD_SCACHE="y";
CEVT_R4K="y";
CLKSRC_MIPS_GIC="y";
CLK_MT7621="y";
CLOCKSOURCE_WATCHDOG="y";
CLONE_BACKWARDS="y";
CMDLINE_BOOL="y";
COMMON_CLK="y";
COMPAT_32BIT_TIME="y";
CPU_GENERIC_DUMP_TLB="y";
CPU_HAS_DIEI="y";
CPU_HAS_PREFETCH="y";
CPU_HAS_RIXI="y";
CPU_HAS_SYNC="y";
CPU_LITTLE_ENDIAN="y";
CPU_MIPS32="y";
CPU_MIPS32_R2="y";
CPU_MIPSR2="y";
CPU_MIPSR2_IRQ_EI="y";
CPU_MIPSR2_IRQ_VI="y";
CPU_NEEDS_NO_SMARTMIPS_OR_MICROMIPS="y";
CPU_R4K_CACHE_TLB="y";
CPU_RMAP="y";
CPU_SUPPORTS_32BIT_KERNEL="y";
CPU_SUPPORTS_HIGHMEM="y";
CPU_SUPPORTS_MSA="y";
CRC16="y";
CRYPTO_DEFLATE="y";
CRYPTO_HASH_INFO="y";
CRYPTO_LIB_BLAKE2S_GENERIC="y";
CRYPTO_LIB_POLY1305_RSIZE="2";
CRYPTO_LZO="y";
CRYPTO_ZSTD="y";
CSRC_R4K="y";
DIMLIB="y";
DMA_NONCOHERENT="y";
DTB_RT_NONE="y";
DTC="y";
EARLY_PRINTK="y";
FIXED_PHY="y";
FWNODE_MDIO="y";
FW_LOADER_PAGED_BUF="y";
GENERIC_ATOMIC64="y";
GENERIC_CLOCKEVENTS="y";
GENERIC_CMOS_UPDATE="y";
GENERIC_CPU_AUTOPROBE="y";
GENERIC_FIND_FIRST_BIT="y";
GENERIC_GETTIMEOFDAY="y";
GENERIC_IOMAP="y";
GENERIC_IRQ_CHIP="y";
GENERIC_IRQ_EFFECTIVE_AFF_MASK="y";
GENERIC_IRQ_SHOW="y";
GENERIC_LIB_ASHLDI3="y";
GENERIC_LIB_ASHRDI3="y";
GENERIC_LIB_CMPDI2="y";
GENERIC_LIB_LSHRDI3="y";
GENERIC_LIB_UCMPDI2="y";
GENERIC_PCI_IOMAP="y";
GENERIC_PHY="y";
GENERIC_PINCONF="y";
GENERIC_SCHED_CLOCK="y";
GENERIC_SMP_IDLE_THREAD="y";
GENERIC_TIME_VSYSCALL="y";
GLOB="y";
GPIOLIB_IRQCHIP="y";
GPIO_CDEV="y";
GPIO_GENERIC="y";
GPIO_MT7621="y";
GRO_CELLS="y";
HANDLE_DOMAIN_IRQ="y";
HARDWARE_WATCHPOINTS="y";
HAS_DMA="y";
HAS_IOMEM="y";
HAS_IOPORT_MAP="y";
I2C="y";
I2C_ALGOBIT="y";
I2C_BOARDINFO="y";
I2C_CHARDEV="y";
I2C_GPIO="y";
I2C_MT7621="y";
ICPLUS_PHY="y";
IRQCHIP="y";
IRQ_DOMAIN="y";
IRQ_DOMAIN_HIERARCHY="y";
IRQ_FORCED_THREADING="y";
IRQ_MIPS_CPU="y";
IRQ_WORK="y";
LIBFDT="y";
LOCK_DEBUGGING_SUPPORT="y";
LZO_COMPRESS="y";
LZO_DECOMPRESS="y";
MDIO_BUS="y";
MDIO_DEVICE="y";
MDIO_DEVRES="y";
MEDIATEK_GE_PHY="y";
MEMFD_CREATE="y";
MFD_SYSCON="y";
MIGRATION="y";
MIKROTIK="y";
MIKROTIK_RB_SYSFS="y";
MIPS="y";
MIPS_ASID_BITS="8";
MIPS_ASID_SHIFT="0";
MIPS_CLOCK_VSYSCALL="y";
MIPS_CM="y";
MIPS_CPC="y";
MIPS_CPS="y";
MIPS_CPU_SCACHE="y";
MIPS_GIC="y";
MIPS_L1_CACHE_SHIFT="5";
MIPS_LD_CAN_LINK_VDSO="y";
MIPS_MT="y";
MIPS_MT_FPAFF="y";
MIPS_MT_SMP="y";
MIPS_NR_CPU_NR_MAP="4";
MIPS_PERF_SHARED_TC_COUNTERS="y";
MIPS_SPRAM="y";
MODULES_USE_ELF_REL="y";
MTD_CMDLINE_PARTS="y";
MTD_NAND_CORE="y";
MTD_NAND_ECC="y";
MTD_NAND_ECC_SW_HAMMING="y";
MTD_NAND_MT7621="y";
MTD_NAND_MTK_BMT="y";
MTD_RAW_NAND="y";
MTD_ROUTERBOOT_PARTS="y";
MTD_SERCOMM_PARTS="y";
MTD_SPI_NOR="y";
MTD_SPLIT_FIT_FW="y";
MTD_SPLIT_MINOR_FW="y";
MTD_SPLIT_SEAMA_FW="y";
MTD_SPLIT_TPLINK_FW="y";
MTD_SPLIT_TRX_FW="y";
MTD_SPLIT_UIMAGE_FW="y";
MTD_UBI="y";
MTD_UBI_BEB_LIMIT="20";
MTD_UBI_BLOCK="y";
MTD_UBI_WL_THRESHOLD="4096";
MTD_VIRT_CONCAT="y";
NEED_DMA_MAP_STATE="y";
NET_DEVLINK="y";
NET_DSA="y";
NET_DSA_MT7530="y";
NET_DSA_MT7530_MDIO="y";
NET_DSA_TAG_MTK="y";
NET_FLOW_LIMIT="y";
NET_MEDIATEK_SOC="y";
NET_SELFTESTS="y";
NET_SWITCHDEV="y";
NET_VENDOR_MEDIATEK="y";
NO_HZ_COMMON="y";
NO_HZ_IDLE="y";
NR_CPUS="4";
NVMEM="y";
OF="y";
OF_ADDRESS="y";
OF_EARLY_FLATTREE="y";
OF_FLATTREE="y";
OF_GPIO="y";
OF_IRQ="y";
OF_KOBJ="y";
OF_MDIO="y";
PAGE_POOL="y";
PAGE_POOL_STATS="y";
PCI="y";
PCIE_MT7621="y";
PCI_DISABLE_COMMON_QUIRKS="y";
PCI_DOMAINS="y";
PCI_DOMAINS_GENERIC="y";
PCI_DRIVERS_GENERIC="y";
PCS_MTK_LYNXI="y";
PERF_USE_VMALLOC="y";
PGTABLE_LEVELS="2";
PHYLIB="y";
PHYLINK="y";
PHY_MT7621_PCI="y";
PINCTRL="y";
PINCTRL_AW9523="y";
PINCTRL_MT7621="y";
PINCTRL_RALINK="y";
PINCTRL_SX150X="y";
POWER_RESET="y";
POWER_RESET_GPIO="y";
POWER_SUPPLY="y";
PTP_1588_CLOCK_OPTIONAL="y";
QUEUED_RWLOCKS="y";
QUEUED_SPINLOCKS="y";
RALINK="y";
RATIONAL="y";
REGMAP="y";
REGMAP_I2C="y";
REGMAP_MMIO="y";
REGULATOR="y";
REGULATOR_FIXED_VOLTAGE="y";
RESET_CONTROLLER="y";
RFS_ACCEL="y";
RPS="y";
RTC_CLASS="y";
RTC_DRV_BQ32K="y";
RTC_DRV_PCF8563="y";
RTC_I2C_AND_SPI="y";
SCHED_SMT="y";
SERIAL_8250="y";
SERIAL_8250_CONSOLE="y";
SERIAL_8250_NR_UARTS="3";
SERIAL_8250_RUNTIME_UARTS="3";
SERIAL_MCTRL_GPIO="y";
SERIAL_OF_PLATFORM="y";
SGL_ALLOC="y";
SMP="y";
SMP_UP="y";
SOCK_RX_QUEUE_MAPPING="y";
SOC_BUS="y";
SOC_MT7621="y";
SPI="y";
SPI_MASTER="y";
SPI_MEM="y";
SPI_MT7621="y";
SRCU="y";
SWPHY="y";
SYNC_R4K="y";
SYSCTL_EXCEPTION_TRACE="y";
SYS_HAS_CPU_MIPS32_R1="y";
SYS_HAS_CPU_MIPS32_R2="y";
SYS_HAS_EARLY_PRINTK="y";
SYS_SUPPORTS_32BIT_KERNEL="y";
SYS_SUPPORTS_ARBIT_HZ="y";
SYS_SUPPORTS_HIGHMEM="y";
SYS_SUPPORTS_HOTPLUG_CPU="y";
SYS_SUPPORTS_LITTLE_ENDIAN="y";
SYS_SUPPORTS_MIPS16="y";
SYS_SUPPORTS_MIPS_CPS="y";
SYS_SUPPORTS_MULTITHREADING="y";
SYS_SUPPORTS_SCHED_SMT="y";
SYS_SUPPORTS_SMP="y";
SYS_SUPPORTS_ZBOOT="y";
TARGET_ISA_REV="2";
TICK_CPU_ACCOUNTING="y";
TIMER_OF="y";
TIMER_PROBE="y";
TREE_RCU="y";
TREE_SRCU="y";
UBIFS_FS="y";
USB_SUPPORT="y";
USE_OF="y";
WEAK_ORDERING="y";
XPS="y";
XXHASH="y";
ZLIB_DEFLATE="y";
ZLIB_INFLATE="y";
ZSTD_COMPRESS="y";
ZSTD_DECOMPRESS="y";
} // lib.optionalAttrs (config.system.service ? watchdog) {
RALINK_WDT = "y"; # watchdog
MT7621_WDT = "y"; # or it might be this one
};
conditionalConfig = {
WLAN = {
MT7915E = "m";
};
};
};
tplink-safeloader.board = "ARCHER-AX23-V1";
boot = {
commandLine = [ "console=ttyS0,115200" ];
tftp = {
# Should be a segment of free RAM, where the tftp artifact
# can be stored before unpacking it to the 'hardware.loadAddress'
# The 'hardware.loadAddress' is 0x80001000, which suggests the
# RAM would start at 0x8000000 and (being 128MB) go to
# to 0x8800000. Let's put it at the 100MB mark at
# 0x8000000+0x0640000=0x86400000
loadAddress = lim.parseInt "0x86400000";
};
};
filesystem =
let inherit (pkgs.pseudofile) dir symlink;
in
dir {
lib = dir {
firmware = dir {
mediatek = symlink firmware;
};
};
};
hardware =
let
openwrt = pkgs.openwrt;
mac80211 = pkgs.kmodloader.override {
targets = [
"mt7915e"
];
inherit (config.system.outputs) kernel;
};
in {
# from OEM bootlog (openwrt wiki):
# 4 cmdlinepart partitions found on MTD device raspi
# Creating 4 MTD partitions on "raspi":
# 0x000000000000-0x000000040000 : "uboot"
# 0x000000040000-0x000000440000 : "uImage"
# 0x000000440000-0x000000ff0000 : "rootfs"
# 0x000000ff0000-0x000001000000 : "ART"
# from openwrt bootlog (openwrt wiki):
# 5 fixed-partitions partitions found on MTD device spi0.0
# OF: Bad cell count for /palmbus@1e000000/spi@b00/flash@0/partitions
# OF: Bad cell count for /palmbus@1e000000/spi@b00/flash@0/partitions
# OF: Bad cell count for /palmbus@1e000000/spi@b00/flash@0/partitions
# OF: Bad cell count for /palmbus@1e000000/spi@b00/flash@0/partitions
# Creating 5 MTD partitions on "spi0.0":
# 0x000000000000-0x000000040000 : "u-boot"
# 0x000000040000-0x000000fa0000 : "firmware"
# 2 uimage-fw partitions found on MTD device firmware
# Creating 2 MTD partitions on "firmware":
# 0x000000000000-0x0000002c0000 : "kernel"
# 0x0000002c0000-0x000000f60000 : "rootfs"
# mtd: setting mtd3 (rootfs) as root device
# 1 squashfs-split partitions found on MTD device rootfs
# 0x000000640000-0x000000f60000 : "rootfs_data"
# 0x000000fa0000-0x000000fb0000 : "config"
# 0x000000fb0000-0x000000ff0000 : "tplink"
# 0x000000ff0000-0x000001000000 : "radio"
flash = {
# from the OEM bootlog 'Booting image at bc040000'
# (0x40000 from 0xbc000000)
address = lim.parseInt "0xbc040000";
# 0x000000040000-0x000000fa0000
size = lim.parseInt "0xf60000";
# TODO: find in /proc/mtd on a running system
eraseBlockSize = 65536;
};
# since this is mentioned in the partition table as well?
defaultOutput = "tplink-safeloader";
# taken from openwrt sysupgrade image:
# openwrt-23.05.2-ramips-mt7621-tplink_archer-ax23-v1-squashfs-sysupgrade.bin: u-boot legacy uImage, MIPS OpenWrt Linux-5.15.137, Linux/MIPS, OS Kernel Image (lzma), 2797386 bytes, Tue Nov 14 13:38:11 2023, Load Address: 0X80001000, Entry Point: 0X80001000, Header CRC: 0X19F74C5B, Data CRC: 0XF685563C
loadAddress = lim.parseInt "0x80001000";
entryPoint = lim.parseInt "0x80001000";
rootDevice = "/dev/mtdblock3";
dts = {
src = "${openwrt.src}/target/linux/ramips/dts/mt7621_tplink_archer-ax23-v1.dts";
includes = [
"${openwrt.src}/target/linux/ramips/dts"
"${config.system.outputs.kernel.modulesupport}/arch/arm64/boot/dts/mediatek/"
];
};
networkInterfaces =
let
inherit (config.system.service.network) link;
inherit (config.system.service) bridge;
in rec {
lan1 = link.build { ifname = "lan1"; };
lan2 = link.build { ifname = "lan2"; };
lan3 = link.build { ifname = "lan3"; };
lan4 = link.build { ifname = "lan4"; };
wan = link.build { ifname = "wan"; };
wlan = link.build {
ifname = "wlan0";
dependencies = [ mac80211 ];
};
wlan5 = link.build {
ifname = "wlan1";
dependencies = [ mac80211 ];
};
};
};
};
};
}

View File

@ -10,141 +10,19 @@
to work (and provides you an easy rollback if you decide you don't
like Liminix after all).
The install process has two stages, and is intended that you
should not need to open the device and add a serial console
(although it may be handy for visibility, and in case anything
goes wrong). First we build a minimal installation/recovery
system, then we reboot into that recovery image to prepare the
device for the full target install.
The install process is designed so that you should not need to open
the device and add a serial console (although it may be handy
for visibility and in case anything goes wrong). In outline
Installation using a USB stick
==============================
First, build the image for the USB stick. Review
:file:`examples/recovery.nix` in order to change the default
root password (which is ``secret``) and/or the SSH keys, then
build it with
.. code-block:: console
$ nix-build -I liminix-config=./examples/recovery.nix \
--arg device "import ./devices/turris-omnia" \
-A outputs.mbrimage -o mbrimage
$ file -L mbrimage
mbrimage: DOS/MBR boot sector; partition 1 : ID=0x83, active, start-CHS (0x0,0,5), end-CHS (0x6,130,26), startsector 4, 104602 sectors
Next, copy the image from your build machine to a USB storage
medium using :command:`dd` or your other most favoured file copying
tool, which might be a comand something like this:
.. code-block:: console
$ dd if=mbrimage of=/dev/path/to/the/usb/stick \
bs=1M conv=fdatasync status=progress
The Omnia's default boot order only checks USB after it has failed
to boot from eMMC, which is not ideal for our purpose. Unless you
have a serial cable, the easiest way to change this is by booting
to TurrisOS and logging in with ssh:
.. code-block:: console
root@turris:/# fw_printenv boot_targets
boot_targets=mmc0 nvme0 scsi0 usb0 pxe dhcp
root@turris:/# fw_setenv boot_targets usb0 mmc0
root@turris:/# fw_printenv boot_targets
boot_targets=usb0 mmc0
root@turris:/# reboot -f
It should now boot into the recovery image. It expects a network
cable to be plugged into LAN2 with something on the other end of
it that serves DHCP requests. Check your DHCP server logs for a
request from a ``liminix-recovery`` host and figure out what IP
address was assigned.
.. code-block:: console
$ ssh liminix-recovery.lan
You should get a "Busybox" banner and a root prompt. Now you can
start preparing the device to install Liminix on it. First we'll
mount the root filesystem and take a snapshot:
.. code-block:: console
# mkdir /dest && mount /dev/mmcblk0p1 /dest
# schnapps -d /dest create "pre liminix"
# schnapps -d /dest list
ERROR: not a valid btrfs filesystem: /
# | Type | Size | Date | Description
------+-----------+-------------+---------------------------+------------------------------------
1 | single | 16.00KiB | 1970-01-01 00:11:49 +0000 | pre liminix
(``not a valid btrfs filesystem: /`` is not a real error)
then we can remove all the files
.. code-block:: console
# rm -r /dest/@/*
and then it's ready to install the real Liminix system onto. On
your build system, create the Liminix configuration you wish to
install: here we'll use the ``rotuer`` example.
.. code-block:: console
build$ nix-build -I liminix-config=./examples/rotuer.nix \
--arg device "import ./devices/turris-omnia" \
-A outputs.systemConfiguration
and then use :command:`min-copy-closure` to copy it to the device.
.. code-block:: console
build$ nix-shell --run \
"min-copy-closure -r /dest/@ root@liminix-recovery.lan result"
and activate it
.. code-block:: console
build$ ssh root@liminix-recovery.lan \
"/dest/@/$(readlink result)/bin/install /dest/@"
The final steps are performed directly on the device again: add
a symlink so U-Boot can find :file:`/boot`, then restore the
default boot order and reboot into the new configuration.
.. code-block:: console
# cd /dest && ln -s @/boot .
# fw_setenv boot_targets "mmc0 nvme0 scsi0 usb0 pxe dhcp"
# cd / ; umount /dest
# reboot
Installation using a TFTP server and serial console
===================================================
If you have a :ref:`serial` console connection and a TFTP server,
and would rather use them than fiddling with USB sticks, the
:file:`examples/recovery.nix` configuration also works
using the ``tftpboot`` output. So you can do
.. code-block:: console
build$ nix-build -I liminix-config=./examples/recovery.nix \
--arg device "import ./devices/turris-omnia" \
-A outputs.tftpboot
and then paste the generated :file:`result/boot.scr` into
U-Boot, and you will end up with the same system as you would
have had after booting from USB. If you don't have a serial
console connection you could probably even get clever with
elaborate use of :command:`fw_setenv`, but that is left as
an exercise for the reader.
1. build a "recovery" system with useful btrfs tools
2. boot that system using TFTP or a USB stick
3. once booted, mount the real root filesystem on /mnt
4. take a snapshot using schnapps, and then delete everything
5. use min-copy-closure -d /mnt/@ to copy the real configuration
to the device
6. reboot into a fully operational system
Detailed instructions to follow...
'';
system = {
@ -182,10 +60,12 @@
kernel = {
src = pkgs.pkgsBuildBuild.fetchurl {
name = "linux.tar.gz";
url = "https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.7.4.tar.gz";
hash = "sha256-wIrmL0BS63nRwWfm4nw+dRNVPUzGh9M4X7LaHzAn5tU=";
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.71.tar.gz";
hash = "sha256-yhO2cXIeIgUxkSZf/4aAsF11uxyh+UUZu6D1h92vCD8=";
};
version = "6.7.4";
extraPatchPhase = ''
${pkgs.openwrt.applyPatches.mvebu}
'';
config = {
PCI = "y";
OF = "y";
@ -197,27 +77,11 @@
ARCH_MULTI_V7= "y";
PCI_MVEBU = "y";
AHCI_MVEBU = "y";
RTC_CLASS = "y";
RTC_DRV_ARMADA38X = "y"; # this may be useful anyway?
EXPERT = "y";
ALLOW_DEV_COREDUMP = "n";
# dts has a compatible for this but dmesg is not
# showing it
EEPROM_AT24 = "y"; # atmel,24c64
I2C = "y";
I2C_MUX = "y";
I2C_MUX_PCA954x = "y";
MACH_ARMADA_38X = "y";
SMP = "y";
# this is disabled for the moment because it relies on a
# GCC plugin that requires gmp.h to build, and I can't see
# right now how to confgure it to find gmp
# this is disabled for the moment because it relies on a GCC
# plugin that requires gmp.h to build, and I can't see right now
# how to confgure it to find gmp
STACKPROTECTOR_PER_TASK = "n";
NR_CPUS = "4";
VFP = "y";
@ -229,7 +93,7 @@
PSTORE = "y";
PSTORE_RAM = "y";
PSTORE_CONSOLE = "y";
# PSTORE_DEFLATE_COMPRESS = "n";
PSTORE_DEFLATE_COMPRESS = "n";
BLOCK = "y";
MMC="y";
@ -283,22 +147,8 @@
NET_DSA = "y";
NET_DSA_MV88E6XXX = "y"; # depends on PTP_1588_CLOCK_OPTIONAL
};
conditionalConfig = {
USB = {
USB_XHCI_MVEBU = "y";
USB_XHCI_HCD = "y";
};
WLAN = {
WLAN_VENDOR_ATH = "y";
ATH_COMMON = "m";
ATH9K = "m";
ATH9K_PCI = "y";
ATH10K = "m";
ATH10K_PCI = "m";
ATH10K_DEBUG = "y";
};
};
};
boot = {
commandLine = [
"console=ttyS0,115200"
@ -332,15 +182,15 @@
};
boot.tftp = {
loadAddress = lim.parseInt "0x1700000";
loadAddress = lim.parseInt "0x1000000";
kernelFormat = "zimage";
compressRoot = true;
};
hardware = let
mac80211 = pkgs.kmodloader.override {
inherit (config.system.outputs) kernel;
targets = ["ath9k" "ath10k_pci"];
mac80211 = pkgs.mac80211.override {
drivers = ["ath9k_pci" "ath10k_pci"];
klibBuild = config.system.outputs.kernel.modulesupport;
};
in {
defaultOutput = "mtdimage";
@ -349,9 +199,9 @@
rootDevice = "/dev/mmcblk0p1";
dts = {
src = "${config.system.outputs.kernel.modulesupport}/arch/arm/boot/dts/marvell/armada-385-turris-omnia.dts";
src = "${config.system.outputs.kernel.modulesupport}/arch/arm/boot/dts/armada-385-turris-omnia.dts";
includes = [
"${config.system.outputs.kernel.modulesupport}/arch/arm/boot/dts/marvell/"
"${config.system.outputs.kernel.modulesupport}/arch/arm/boot/dts/"
];
};
flash.eraseBlockSize = 65536; # only used for tftpboot

View File

@ -12,13 +12,9 @@ BUILDDIR = _build
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
hardware.rst: hardware.nix
@rm -f hardware.rst || true
@cp $$(nix-build hardware.nix) hardware.rst
.PHONY: help Makefile
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
html: Makefile
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

View File

@ -24,15 +24,6 @@ writeText "hwdoc" ''
Supported hardware
##################
For development, the `GL.iNet GL-MT300A <https://www.gl-inet.com/products/gl-mt300a/>`_
is an attractive choice as it has a builtin "debrick" procedure in the
boot monitor and is also comparatively simple to
attach serial cables to (soldering not required), so it
is lower-risk than some devices.
For a more powerful device, something with an ath10k would be the safe bet,
or the Linksys E8450 which seems popular in the openwrt community.
${lib.concatStringsSep "\n\n" texts}
''

View File

@ -138,8 +138,6 @@ unbrick if necessary.
work here, but you accept the slightly greater bricking
risk if it doesn't.
See :doc:`hardware` for device support status.
You may want to read and inwardly digest the Develoment Manual section
:ref:`serial` when you start working with Liminix on real hardware. You
won't *need* serial access for this example, assuming it works, but it

View File

@ -145,7 +145,7 @@ in rec {
};
users.root = {
passwd = lib.mkForce secrets.root.passwd;
passwd = lib.mkForce secrets.root_password;
# openssh.authorizedKeys.keys = [
# (builtins.readFile "/home/dan/.ssh/id_rsa.pub")
# ];

View File

@ -35,7 +35,6 @@ in {
(drop "icmpv6 type destination-unreachable ct state invalid,untracked")
];
};
forward-ip6 = {
type = "filter";
family = "ip6";
@ -96,23 +95,19 @@ in {
# recognised (outbound-initiated) flow
(accept "oifname \"int\" iifname \"ppp0\" ct state established,related")
(accept "iifname \"int\" oifname \"ppp0\" ")
"log prefix \"DENIED CHAIN=forward-ip6 \""
];
};
input-ip6-lan = {
input-lan = {
type = "filter";
family = "ip6";
rules = [
(accept "udp dport 547") # dhcp, could restrict to daddr ff02::1:2
(accept "udp dport 53") # dns
(accept "tcp dport 22")
];
};
input-ip6-wan = {
input-wan = {
type = "filter";
family = "ip6";
@ -128,8 +123,8 @@ in {
hook = "input";
rules = [
(accept "meta l4proto icmpv6")
"iifname int jump input-ip6-lan"
"iifname ppp0 jump input-ip6-wan"
"iifname int jump input-lan"
"iifname ppp0 jump input-wan"
(if allow-incoming
then accept "oifname \"int\" iifname \"ppp0\""
else "oifname \"int\" iifname \"ppp0\" jump incoming-allowed-ip6"
@ -137,7 +132,6 @@ in {
# how does this even make sense in an input chain?
(accept "oifname \"int\" iifname \"ppp0\" ct state established,related")
(accept "iifname \"int\" oifname \"ppp0\" ")
"log prefix \"DENIED CHAIN=input-ip6 \""
];
};
@ -160,7 +154,6 @@ in {
"oifname \"ppp0\" masquerade"
];
};
nat-rx = {
type = "nat";
hook = "prerouting";
@ -174,71 +167,4 @@ in {
# packet replies. "
];
};
# these chains are for rules that have to be present for things to
# basically work at all: for example, the router won't issue DHCP
# unless it's allowed to receive DHCP requests. For "site policy"
# rules you may prefer to use incoming-allowed-ip[46] instead
input-ip4-lan = {
type = "filter";
family = "ip";
rules = [
(accept "udp dport 67") # dhcp
(accept "udp dport 53") # dns
(accept "tcp dport 22") # ssh
];
};
input-ip4-wan = {
type = "filter";
family = "ip";
rules = [
(accept "udp sport 53")
];
};
input-ip4 = {
type = "filter";
family = "ip";
policy = "drop";
hook = "input";
rules = [
"iifname lo accept"
"icmp type { echo-request, echo-reply } accept"
"iifname int jump input-ip4-lan"
"iifname ppp0 jump input-ip4-wan"
"oifname \"int\" iifname \"ppp0\" jump incoming-allowed-ip4"
"ct state established,related accept"
"log prefix \"DENIED CHAIN=input-ip4 \""
];
};
forward-ip4 = {
type = "filter";
family = "ip";
policy = "drop";
hook = "forward";
rules = [
"iifname \"int\" accept"
"ct state established,related accept"
"oifname \"int\" iifname \"ppp0\" jump incoming-allowed-ip4"
"log prefix \"DENIED CHAIN=forward-ip4 \""
];
};
incoming-allowed-ip4 = {
type = "filter";
family = "ip";
rules = [
# This is where you put permitted incoming connections. If
# you're using NAT and want to forward a port from outside to
# devices on the LAN, then you need a DNAT rule in nat-rx chain
# *and* to accept the packet in this chain (specifying the
# internal (RFC1918) address).
];
};
}

View File

@ -131,6 +131,6 @@ in rec {
dependencies = [services.dhcpc];
};
users.root.passwd = lib.mkForce secrets.root.passwd;
users.root.passwd = lib.mkForce secrets.root_password;
defaultProfile.packages = with pkgs; [nftables strace tcpdump swconfig];
}

View File

@ -4,16 +4,11 @@ let
svc = config.system.service;
inherit (pkgs.pseudofile) dir symlink;
inherit (pkgs.liminix.services) oneshot longrun bundle target;
some-util-linux = pkgs.runCommand "some-util-linux" {} ''
mkdir -p $out/bin
cd ${pkgs.util-linux-small}/bin
cp fdisk sfdisk mkswap $out/bin
'';
in rec {
imports = [
../modules/network
../modules/ssh
../modules/usb.nix
../modules/schnapps
../modules/outputs/mtdimage.nix
../modules/outputs/mbrimage.nix
@ -22,7 +17,6 @@ in rec {
../modules/outputs/ubimage.nix
../modules/outputs/jffs2.nix
../modules/outputs/ext4fs.nix
../modules/outputs/extlinux.nix
];
kernel.config = {
@ -32,11 +26,9 @@ in rec {
boot.tftp = {
ipaddr = "10.0.0.8"; # my address
serverip = "10.0.0.1"; # build machine or other tftp server
freeSpaceBytes = 1024 * 1024 * 4;
};
boot.loader.extlinux.enable = true;
hostname = "liminix-recovery";
hostname = "recovery";
services.dhcpc = svc.network.dhcp.client.build {
interface = config.hardware.networkInterfaces.lan2;
@ -46,16 +38,13 @@ in rec {
dependencies = [ config.services.hostname ];
};
services.sshd = svc.ssh.build {
dependencies = [ config.services.growfs ];
};
services.sshd = svc.ssh.build { };
services.defaultroute4 = svc.network.route.build {
via = "$(output ${services.dhcpc} router)";
target = "default";
dependencies = [services.dhcpc];
};
services.resolvconf = oneshot rec {
dependencies = [ services.dhcpc ];
name = "resolvconf";
@ -68,40 +57,17 @@ in rec {
)
'';
};
services.growfs = let name = "growfs"; in oneshot {
inherit name;
up = ''
. ${serviceFns}
device=$(grep /persist /proc/1/mountinfo | cut -f9 -d' ')
${pkgs.e2fsprogs}/bin/resize2fs $device
'';
};
filesystem = dir {
etc = dir {
"resolv.conf" = symlink "${services.resolvconf}/.outputs/resolv.conf";
};
mnt = dir {};
};
rootfsType = "ext4";
# sda is most likely correct for the boot-from-USB case. For tftp
# it's overridden by the boot.scr anyway, so maybe it all works out
hardware.rootDevice = lib.mkForce "/dev/sda1";
rootfsType = "squashfs";
users.root = {
# the password is "secret". Use mkpasswd -m sha512crypt to
# create this hashed password string
passwd = "$6$y7WZ5hM6l5nriLmo$5AJlmzQZ6WA.7uBC7S8L4o19ESR28Dg25v64/vDvvCN01Ms9QoHeGByj8lGlJ4/b.dbwR9Hq2KXurSnLigt1W1";
openssh.authorizedKeys.keys =
let fromBuild =
(builtins.readFile
((builtins.toPath (builtins.getEnv "HOME")) + "/.ssh/authorized_keys")
);
in lib.splitString "\n" fromBuild;
};
defaultProfile.packages = with pkgs; [
@ -109,7 +75,7 @@ in rec {
btrfs-progs
mtdutils # mtd, jffs2, ubifs
dtc # you never know when you might need device tree stuff
some-util-linux
util-linux-small # fdisk
libubootenv # fw_{set,print}env
pciutils
];

View File

@ -1,6 +1,5 @@
{
rec {
wpa_passphrase = "you bring light in";
ssid = "liminix";
l2tp = {
name = "abcde@a.1";
password = "NotMyIspPassword";
@ -11,9 +10,5 @@
openssh.authorizedKeys.keys = [
];
};
lan = {
prefix = "10.8.0";
};
root_password = root.passwd;
}

View File

@ -8,10 +8,7 @@
{ config, pkgs, lib, ... } :
let
secrets = {
domainName = "fake.liminix.org";
firewallRules = {};
} // (import ./rotuer-secrets.nix);
secrets = import ./rotuer-secrets.nix;
inherit (pkgs.liminix.services) oneshot longrun bundle;
inherit (pkgs) serviceFns;
svc = config.system.service;
@ -45,7 +42,6 @@ in rec {
../modules/hostapd
../modules/bridge
../modules/ntp
../modules/schnapps
../modules/ssh
../modules/outputs/btrfs.nix
../modules/outputs/extlinux.nix
@ -58,7 +54,7 @@ in rec {
services.hostap = svc.hostapd.build {
interface = config.hardware.networkInterfaces.wlan;
params = {
ssid = secrets.ssid;
ssid = "liminix";
hw_mode="g";
channel = "2";
ieee80211n = 1;
@ -68,20 +64,19 @@ in rec {
services.hostap5 = svc.hostapd.build {
interface = config.hardware.networkInterfaces.wlan5;
params = rec {
ssid = "${secrets.ssid}5";
ssid = "liminix_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;
family = "inet"; address ="10.8.0.1"; prefixLength = 16;
};
services.bridge = svc.bridge.members.build {
@ -89,12 +84,7 @@ in rec {
members = with config.hardware.networkInterfaces;
[ wlan
wlan5
lan0
lan1
lan2
lan3
lan4
];
lan ];
};
services.ntp = svc.ntp.build {
@ -112,7 +102,7 @@ in rec {
resolvconf = services.resolvconf;
inherit interface;
ranges = [
"${secrets.lan.prefix}.10,${secrets.lan.prefix}.240"
"10.8.0.10,10.8.0.240"
# ra-stateless: sends router advertisements with the O and A
# bits set, and provides a stateless DHCP service. The client
# will use a SLAAC address, and use DHCP for other
@ -123,8 +113,8 @@ in rec {
# 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;
domain = "fake.liminix.org";
};
services.wan = svc.pppoe.build {
@ -170,9 +160,7 @@ in rec {
};
services.firewall = svc.firewall.build {
ruleset =
let defaults = import ./demo-firewall.nix;
in lib.recursiveUpdate defaults secrets.firewallRules;
ruleset = import ./demo-firewall.nix;
};
services.packet_forwarding = svc.network.forward.build { };
@ -197,18 +185,9 @@ in rec {
defaultProfile.packages = with pkgs; [
min-collect-garbage
nftables
strace
tcpdump
s6
];
programs.busybox = {
applets = [
"fdisk" "sfdisk"
];
options = {
FEATURE_FANCY_TAIL = "y";
};
};
programs.busybox.applets = [
"fdisk" "sfdisk"
];
}

View File

@ -16,7 +16,7 @@
./hostname.nix
./outputs/initramfs.nix
./outputs/jffs2.nix
./kernel
./kernel.nix
./outputs/kexecboot.nix
./mount
./network

View File

@ -13,7 +13,7 @@ let
in {
imports = [
./kernel # kernel is a separate module for doc purposes
./kernel.nix # kernel is a separate module for doc purposes
];
options = {
defaultProfile = {

View File

@ -1,32 +1,31 @@
(local { : system } (require :anoia))
(local svc (require :anoia.svc))
(fn deletions [old-addresses new-addresses]
(let [deleted {}]
(fn changes [old-addresses new-addresses]
(let [added {}
deleted {}]
(each [n address (pairs new-addresses)]
(if (not (. old-addresses n))
(table.insert added address)))
(each [n address (pairs old-addresses)]
(let [now (. new-addresses n)]
(if (or (not now) (not (= now.len address.len)))
(table.insert deleted address))))
deleted))
(if (not (. new-addresses n))
(table.insert deleted address)))
(values added deleted)))
(fn update-prefixes [wan-device addresses new-addresses exec]
(each [_ p (ipairs (deletions addresses new-addresses))]
(exec
(.. "ip address del " p.address "1/" p.len " dev " wan-device)))
(each [_ p (pairs new-addresses)]
(exec
(.. "ip address change " p.address "1/" p.len
" dev " wan-device
" valid_lft " p.valid
" preferred_lft " p.preferred
)))
new-addresses)
(fn update-prefixes [device prefixes new-prefixes]
(let [(added deleted) (changes prefixes new-prefixes)]
(each [_ p (ipairs added)]
(system
(.. "ip address add " p.address "1/" p.len " dev " device)))
(each [_ p (ipairs deleted)]
(system
(.. "ip address del " p.address "1/" p.len " dev " device)))))
(fn run []
(let [[state-directory lan-device] arg
dir (svc.open state-directory)]
(accumulate [addresses []
v (dir:events)]
(update-prefixes lan-device addresses (v:output "prefix") system))))
(update-prefixes lan-device addresses (v:output "prefix")))))
{ : changes : run }

View File

@ -5,45 +5,23 @@
(local a1
{
"2001-ab-cd-ef" {
:address "2001:ab:cd:ef"
:len "64"
:preferred "3600"
:valid "7200"
}
}
)
(local a156
{
"2001-ab-cd-ef" {
:address "2001:ab:cd:ef"
:len "56"
:preferred "3600"
:valid "7200"
}
"2001-ab-cd-ef_hjgKHGhKJH" {
:address "2001:ab:cd:ef"
:len "64"
:preferred "200"
:valid "200"
}
}
)
(local a2
{
"2001-0-1-2-3" {
:address "2001:0:1:2:3"
:len "64"
:preferred "3600"
:valid "7200"
}
}
)
(local a21
{
"2001-0-1-2-3" {
:address "2001:0:1:2:3"
:len "64"
:preferred "1800"
:valid "5400"
}
"2001-0-1-2-3_aNteBnb" {
:address "2001:0:1:2:3"
:len "64"
:preferred "200"
:valid "200"
}
}
)
@ -52,85 +30,39 @@
`(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
(let [(add del)
(subject.changes
{ }
a1
)]
(expect= deleted [])))
(expect (= (# del) 0))
(expect (= (# add) 1))
(let [[first] add]
(expect (= first.address "2001:ab:cd:ef")))))
(fn second-address []
(let [del
(subject.deletions
(let [(add del)
(subject.changes
a1
(merge (dup a1) a2)
)]
(expect= del [])))
(expect (= (# del) 0))
(expect (= (# add) 1))
(let [[first] add] (expect (= first.address "2001:0:1:2:3")))))
(fn old-address-is-deleted []
(let [del
(subject.deletions
(fn less-address []1
(let [(add del)
(subject.changes
(merge (dup a1) a2)
a1
)]
(expect= (. del 1) (. a2 "2001-0-1-2-3"))
))
(expect (= (# add) 0))
(expect (= (# del) 1))
(fn changed-lifetime-not-deleted []
(let [del
(subject.deletions
(merge (dup a1) a2)
(merge (dup a1) a21)
)]
;; when an address lifetime changes, "ip address change"
;; will update that so it need not (should not) be deleted
(expect= del [])))
(let [[first] del] (expect (= first.address "2001:0:1:2:3")))))
(fn changed-prefix-is-deleted []
(let [del
(subject.deletions a1 a156)]
;; when an address prefix changes, "ip address change"
;; ignores that cjhange, so we have to remove the
;; address before reinstating it
(expect= del [(. a1 "2001-ab-cd-ef")])))
(first-address)
(second-address)
(old-address-is-deleted)
(changed-lifetime-not-deleted)
(changed-prefix-is-deleted)
(let [cmds []]
(subject.update-addresses
"ppp0" a1 (merge (dup a1) a2)
(fn [a] (table.insert cmds a)))
(expect=
(doto cmds table.sort)
[
;; order of changes is unimportant
"ip address change 2001:0:1:2:3/64 dev ppp0 valid_lft 7200 preferred_lft 3600"
"ip address change 2001:ab:cd:ef/64 dev ppp0 valid_lft 7200 preferred_lft 3600"
]))
(let [cmds []]
(subject.update-addresses
"ppp0" (merge (dup a1) a2) a1
(fn [a] (table.insert cmds a)))
(expect=
cmds
[
;; deletes are executed before changes
"ip address del 2001:0:1:2:3/64 dev ppp0"
"ip address change 2001:ab:cd:ef/64 dev ppp0 valid_lft 7200 preferred_lft 3600"
]))
(print "OK")
(less-address)

View File

@ -1,32 +1,35 @@
(local { : system } (require :anoia))
(local svc (require :anoia.svc))
(fn deletions [old-addresses new-addresses]
(let [deleted {}]
(each [n address (pairs old-addresses)]
(let [now (. new-addresses n)]
(if (or (not now) (not (= now.len address.len)))
(table.insert deleted address))))
deleted))
;; acquire-delegated-prefix has very similar code: we'd like to move
;; this to anoia.svc when we see what the general form would look like
(fn update-addresses [wan-device addresses new-addresses exec]
(each [_ p (ipairs (deletions addresses new-addresses))]
(exec
(.. "ip address del " p.address "/" p.len " dev " wan-device)))
(each [_ p (pairs new-addresses)]
(exec
(.. "ip address change " p.address "/" p.len
" dev " wan-device
" valid_lft " p.valid
" preferred_lft " p.preferred
)))
new-addresses)
(fn changes [old-addresses new-addresses]
(let [added {}
deleted {}]
(each [n address (pairs new-addresses)]
(if (not (. old-addresses n))
(table.insert added address)))
(each [n address (pairs old-addresses)]
(if (not (. new-addresses n))
(table.insert deleted address)))
(values added deleted)))
(fn update-addresses [wan-device addresses new-addresses]
(let [(added deleted) (changes addresses new-addresses)]
(each [_ p (ipairs added)]
(system
(.. "ip address add " p.address "/" p.len " dev " wan-device)))
(each [_ p (ipairs deleted)]
(system
(.. "ip address del " p.address "/" p.len " dev " wan-device)))
new-addresses))
(fn run []
(let [[state-directory wan-device] arg
dir (svc.open state-directory)]
(accumulate [addresses []
v (dir:events)]
(update-addresses wan-device addresses (v:output "address") system))))
(update-addresses wan-device addresses (v:output "address")))))
{ : update-addresses : deletions : run }
{ : update-addresses : changes : run }

View File

@ -11,6 +11,6 @@ let
script = callPackage ./acquire-wan-address.nix { };
in longrun {
inherit name;
run = "${script} $SERVICE_OUTPUTS/${client.name} $(output ${interface} ifname)";
run = "${script} /run/service-state/${client.name} $(output ${interface} ifname)";
dependencies = [ client interface ];
}

View File

@ -13,7 +13,7 @@ in longrun {
inherit name;
notification-fd = 10;
run = ''
export SERVICE_STATE=$SERVICE_OUTPUTS/${name}
export SERVICE_STATE=/run/service-state/${name}
${odhcp6c}/bin/odhcp6c -s ${odhcp-script} -e -v -p /run/${name}.pid -P0 $(output ${interface} ifname)
)
'';

View File

@ -11,6 +11,6 @@ let
script = callPackage ./acquire-delegated-prefix.nix { };
in longrun {
inherit name;
run = "${script} $SERVICE_OUTPUTS/${client.name} $(output ${interface} ifname)";
run = "${script} /run/service-state/${client.name} $(output ${interface} ifname)";
dependencies = [ client interface ];
}

View File

@ -41,11 +41,10 @@ longrun {
--no-hosts \
--log-dhcp \
--enable-ra \
--log-debug \
--log-queries \
--log-facility=- \
--dhcp-leasefile=$(mkstate ${name})/leases \
--dhcp-leasefile=/run/${name}.leases \
--pid-file=/run/${name}.pid
'';
# --log-debug \
# --log-queries \
}

View File

@ -10,41 +10,34 @@ let
inherit (pkgs) liminix;
inherit (pkgs.liminix.services) oneshot;
kmodules = pkgs.kmodloader.override {
inherit (config.system.outputs) kernel;
kconf = isModule :
# setting isModule false is utterly untested and mostly
# unimplemented: I say this to preempt any "how on earth is this
# even supposed to work?" questions
let yes = if isModule then "m" else "y";
in {
NFT_FIB_IPV4 = yes;
NFT_FIB_IPV6 = yes;
NF_TABLES = yes;
NF_CT_PROTO_DCCP = "y";
NF_CT_PROTO_SCTP = "y";
NF_CT_PROTO_UDPLITE = "y";
# NF_CONNTRACK_FTP = yes;
NFT_CT = yes;
};
kmodules = pkgs.kernel-modules.override {
kernelSrc = config.system.outputs.kernel.src;
modulesupport = config.system.outputs.kernel.modulesupport;
targets = [
"nft_fib_ipv4"
"nft_fib_ipv6"
"nf_log_syslog"
"ip6_tables"
"ip_tables"
"iptable_nat"
"nf_conntrack"
"nf_defrag_ipv4"
"nf_defrag_ipv6"
"nf_log_syslog"
"nf_nat"
"nf_reject_ipv4"
"nf_reject_ipv6"
"nf_tables"
"nft_chain_nat"
"nft_ct"
"nft_fib"
"nft_fib_ipv4"
"nft_fib_ipv6"
"nft_log"
"nft_masq"
"nft_nat"
"nft_reject"
"nft_reject_inet"
"nft_reject_ipv4"
"nft_reject_ipv6"
"x_tables"
"xt_MASQUERADE"
"xt_nat"
"xt_tcpudp"
];
kconfig = kconf true;
};
loadModules = oneshot {
name = "firewall-modules";
up = "sh ${kmodules}/load.sh";
down = "sh ${kmodules}/unload.sh";
};
in
{
@ -62,40 +55,38 @@ in
};
};
in svc // {
build = args :
let args' = args // {
dependencies = (args.dependencies or []) ++ [kmodules];
};
in svc.build args' ;
build = args : (svc.build args) // {
dependencies = [ loadModules ] ++ (svc.dependencies or []);
};
};
# For historical reasons the kernel config is split between
# monolithic options and modules. TODO: go through this list
# and see what can be moved into the "kconf" definiton above
kernel.config = {
NETFILTER_XT_MATCH_CONNTRACK = "y";
IP6_NF_IPTABLES= "y";
IP_NF_IPTABLES= "y";
IP_NF_NAT = "y";
IP_NF_TARGET_MASQUERADE = "y";
NETFILTER = "y";
NETFILTER_ADVANCED = "y";
NETFILTER_NETLINK = "m";
NF_CONNTRACK = "m";
NETFILTER_XTABLES = "y";
IP6_NF_IPTABLES= "m";
IP_NF_IPTABLES = "m";
IP_NF_NAT = "m";
IP_NF_TARGET_MASQUERADE = "m";
NFT_COMPAT = "y";
NFT_CT = "y";
NFT_LOG = "y";
NFT_MASQ = "y";
NFT_NAT = "y";
NFT_REJECT = "y";
NFT_REJECT_INET = "y";
NFT_CT = "m";
NFT_FIB_IPV4 = "m";
NFT_FIB_IPV6 = "m";
NFT_LOG = "m";
NFT_MASQ = "m";
NFT_NAT = "m";
NFT_REJECT = "m";
NFT_REJECT_INET = "m";
NF_CT_PROTO_DCCP = "y";
NF_CT_PROTO_SCTP = "y";
NF_CT_PROTO_UDPLITE = "y";
NF_LOG_SYSLOG = "m";
NF_NAT = "m";
NF_NAT_MASQUERADE = "y";
NF_TABLES = "m";
NF_CONNTRACK = "y";
NF_NAT = "y";
NF_NAT_MASQUERADE = "y";
NF_TABLES= "y";
NF_TABLES_INET = "y";
NF_TABLES_IPV4 = "y";
NF_TABLES_IPV6 = "y";

View File

@ -76,11 +76,7 @@ in {
default = [];
example = ["ath9k" "ath10k"];
};
rootDevice = mkOption {
description = "Full path to preferred root device";
type = types.str;
example = "/dev/mtdblock3";
};
rootDevice = mkOption { };
networkInterfaces = mkOption {
type = types.attrsOf types.anything;
};

View File

@ -13,21 +13,10 @@ let
type_service = pkgs.liminix.lib.types.service;
mergeConditionals = conf : conditions :
# for each key in conditions, if it is present in conf
# then merge the associated value into conf
lib.foldlAttrs
(acc: name: value:
if (conf ? ${name}) && (conf.${name} != "n")
then acc // value
else acc)
conf
conditions;
in {
options = {
kernel = {
src = mkOption { type = types.path; } ;
version = mkOption { type = types.str; default = "5.15.137";} ;
modular = mkOption {
type = types.bool;
default = true;
@ -53,20 +42,6 @@ in {
};
'';
};
conditionalConfig = mkOption {
description = ''
Kernel config options that should only be applied when
some other option is present.
'';
type = types.attrsOf (types.attrsOf types.nonEmptyStr);
default = {};
example = {
USB = {
USB_XHCI_MVEBU = "y";
USB_XHCI_HCD = "y";
};
};
};
makeTargets = mkOption {
type = types.listOf types.str;
};
@ -74,15 +49,10 @@ in {
};
config = {
system.outputs =
let
mergedConfig = mergeConditionals
config.kernel.config
config.kernel.conditionalConfig;
k = liminix.builders.kernel.override {
config = mergedConfig;
inherit (config.kernel) version src extraPatchPhase;
targets = config.kernel.makeTargets;
};
let k = liminix.builders.kernel.override {
inherit (config.kernel) config src extraPatchPhase;
targets = config.kernel.makeTargets;
};
in {
kernel = k.vmlinux;
zimage = k.zImage;

View File

@ -60,9 +60,6 @@ in
Combined kernel and FDT in uImage (U-Boot compatible) format
'';
};
tplink-safeloader = mkOption {
type = types.package;
};
u-boot = mkOption {
type = types.package;
};

View File

@ -24,7 +24,7 @@ in {
cd $out
${if wantsDtb then "cp ${o.dtb} dtb" else "true"}
cp ${o.initramfs} initramfs
cp ${o.zimage} kernel
cp ${o.zimage} kernel
mkdir extlinux
cat > extlinux/extlinux.conf << _EOF
menu title Liminix

View File

@ -7,8 +7,6 @@
let
inherit (lib) mkOption types concatStringsSep;
cfg = config.boot.tftp;
hw = config.hardware;
arch = pkgs.stdenv.hostPlatform.linuxArch;
in {
imports = [ ../ramdisk.nix ];
options.boot.tftp = {
@ -24,10 +22,6 @@ in {
type = types.bool;
default = false;
};
appendDTB = mkOption {
type = types.bool;
default = false;
};
};
options.system.outputs = {
tftpboot = mkOption {
@ -68,46 +62,33 @@ in {
uimage = "bootm";
zimage = "bootz";
}; in choices.${cfg.kernelFormat};
cmdline = concatStringsSep " " config.boot.commandLine;
objcopy = "${pkgs.stdenv.cc.bintools.targetPrefix}objcopy";
stripAndZip = ''
${objcopy} -O binary -R .reginfo -R .notes -R .note -R .comment -R .mdebug -R .note.gnu.build-id -S vmlinux.elf vmlinux.bin
rm -f vmlinux.bin.lzma ; lzma -k -z vmlinux.bin
'';
in
pkgs.runCommand "tftpboot" { nativeBuildInputs = with pkgs.pkgsBuildBuild; [ lzma dtc pkgs.stdenv.cc ubootTools ]; } ''
pkgs.runCommand "tftpboot" { nativeBuildInputs = with pkgs.pkgsBuildBuild; [ lzma dtc ]; } ''
mkdir $out
cd $out
binsize() { local s=$(stat -L -c %s $1); echo $(($s + 0x1000 &(~0xfff))); }
binsize64k() { local s=$(stat -L -c %s $1); echo $(($s + 0x10000 &(~0xffff))); }
hex() { printf "0x%x" $1; }
rootfsStart=${toString cfg.loadAddress}
rootfsSize=$(binsize64k ${o.rootfs} )
rootfsSize=$(($rootfsSize + ${toString cfg.freeSpaceBytes} ))
dtbStart=$(($rootfsStart + $rootfsSize))
dtbSize=$(binsize ${o.dtb} )
imageStart=$(($dtbStart + $dtbSize))
imageSize=$(binsize ${image})
ln -s ${o.manifest} manifest
ln -s ${image} image
ln -s ${o.kernel} vmlinux # handy for gdb
# if we are transferring kernel and dtb separately, the
# dtb has to precede the kernel in ram, because zimage
# decompression code will assume that any memory after the
# end of the kernel is free
dtbStart=$(($rootfsStart + $rootfsSize))
${if cfg.compressRoot
then ''
lzma -z9cv ${o.rootfs} > rootfs.lz
rootfsLzStart=$dtbStart
rootfsLzStart=$(($imageStart + $imageSize))
rootfsLzSize=$(binsize rootfs.lz)
dtbStart=$(($dtbStart + $rootfsLzSize))
''
else ''
ln -s ${o.rootfs} rootfs
''
else "ln -s ${o.rootfs} rootfs"
}
cat ${o.dtb} > dtb
address_cells=$(fdtget dtb / '#address-cells')
size_cells=$(fdtget dtb / '#size-cells')
@ -124,37 +105,20 @@ in {
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"
dtbSize=$(binsize ./dtb )
${if cfg.appendDTB then ''
imageStart=$dtbStart
# re-package image with updated dtb
cat ${o.kernel} > vmlinux.elf
${objcopy} --update-section .appended_dtb=dtb vmlinux.elf
${stripAndZip}
mkimage -A ${arch} -O linux -T kernel -C lzma -a $(hex ${toString hw.loadAddress}) -e $(hex ${toString hw.entryPoint}) -n '${lib.toUpper arch} Liminix Linux tftpboot' -d vmlinux.bin.lzma image
# dtc -I dtb -O dts -o /dev/stdout dtb | grep -A10 chosen ; exit 1
tftpcmd="tftpboot $(hex $imageStart) result/image "
bootcmd="bootm $(hex $imageStart)"
'' else ''
imageStart=$(($dtbStart + $dtbSize))
tftpcmd="tftpboot $(hex $imageStart) result/image; tftpboot $(hex $dtbStart) result/dtb "
ln -s ${image} image
bootcmd="${bootCommand} $(hex $imageStart) - $(hex $dtbStart)"
''}
# dtc -I dtb -O dts -o /dev/stdout dtb | grep -A10 chosen ; exit 1
cat > boot.scr << EOF
setenv serverip ${cfg.serverip}
setenv ipaddr ${cfg.ipaddr}
${
tftpboot $(hex $imageStart) result/image ; ${
if cfg.compressRoot
then "tftpboot $(hex $rootfsLzStart) result/rootfs.lz"
else "tftpboot $(hex $rootfsStart) result/rootfs"
}; $tftpcmd
}; tftpboot $(hex $dtbStart) result/dtb
${if cfg.compressRoot
then "lzmadec $(hex $rootfsLzStart) $(hex $rootfsStart); "
else ""
} $bootcmd
} ${bootCommand} $(hex $imageStart) - $(hex $dtbStart)
EOF
'';

View File

@ -1,61 +0,0 @@
{
config
, pkgs
, lib
, ...
}:
let
inherit (lib) mkOption types concatStringsSep;
o = config.system.outputs;
cfg = config.tplink-safeloader;
in {
options.tplink-safeloader = {
board = mkOption {
type = types.str;
};
};
options.system.outputs = {
tplink-safeloader = mkOption {
type = types.package;
description = ''
tplink-safeloader
*****************
For creating 'safeloader' images for tp-link devices.
These can be flashed to the device using the firmware update feature
in the TP-link web UI or the OEM bootloader recovery: Use something
sharp to hold the 'reset' button while turning on the router until
only the orange LED remains lit. The router will assume IP address
192.168.0.1 and expect you to take 192.168.0.5 on one of the LAN ports.
On NixOS, use something like::
networking.interfaces.enp0s20f0u1c2 = {
ipv4.addresses = [ {
address = "192.168.0.5";
prefixLength = 24;
} ];
};
networking.networkmanager = {
unmanaged = [ "enp0s20f0u1c2" ];
};
This connection is rather somewhat temperamental, it may take a couple
of attempts, possibly re-attaching the USB dongle and running
``systemctl restart network-start.service``. The web interface does not
give accurate feedback (the progress bar is a lie), so you may want
to upload the firmware using ``curl -F firmware=@result http://192.168.0.1/f2.htm``.
After this shows a 'success' JSON, the image still needs to be
transferred from memory to flash, so be patient.
'';
};
};
config = {
system.outputs = rec {
tplink-safeloader =
pkgs.runCommand "tplink" { nativeBuildInputs = with pkgs.pkgsBuildBuild; [ firmware-utils ]; } ''
tplink-safeloader -B "${cfg.board}" -k "${o.uimage}" -r "${o.rootfs}" -o $out
'';
};
};
}

View File

@ -22,15 +22,8 @@ mount -t tmpfs none /tmp
mkdir /dev/pts
mount -t devpts none /dev/pts
mkdir -m 0751 -p /run/services/outputs
chgrp system /run/services/outputs
if test -d /persist; then
mkdir -m 0751 -p /persist/services/state
(cd /run/services && ln -s ../../persist/services/state .)
else
mkdir -m 0751 -p /run/services/state
fi
mkdir -m 0751 /run/service-state
chgrp system /run/service-state
### If your services are managed by s6-rc:
### (replace /run/service with your scandir)

View File

@ -29,12 +29,15 @@ let
in
longrun {
name = "sshd";
# we need /run/dropbear to point to hostkey storage, as that
# pathname is hardcoded into the binary.
# env -i clears the environment so we don't pass anything weird to
# ssh sessions
run = ''
ln -s $(mkstate dropbear) /run
if test -d /persist; then
mkdir -p /persist/secrets/dropbear
ln -s /persist/secrets/dropbear /run
else
mkdir -p /run/dropbear
fi
. /etc/profile # sets PATH but do we need this? it's the same file as ashrc
exec env -i ENV=/etc/ashrc PATH=$PATH ${dropbear}/bin/dropbear ${concatStringsSep " " options}
'';

View File

@ -1,31 +0,0 @@
# support for USB block devices and the common filesystems
# they're likely to provide
{lib, config, ... }:
{
kernel = {
config = {
USB = "y";
USB_EHCI_HCD = "y";
USB_EHCI_HCD_PLATFORM = "y";
USB_OHCI_HCD = "y";
USB_OHCI_HCD_PLATFORM = "y";
USB_SUPPORT = "y";
USB_COMMON = "y";
USB_STORAGE = "y";
USB_STORAGE_DEBUG = "n";
USB_UAS = "y";
USB_ANNOUNCE_NEW_DEVICES = "y";
SCSI = "y";
BLK_DEV_SD = "y";
USB_PRINTER = "y";
MSDOS_PARTITION = "y";
EFI_PARTITION = "y";
EXT4_FS = "y";
EXT4_USE_FOR_EXT2 = "y";
FS_ENCRYPTION = "y";
};
};
}

View File

@ -46,14 +46,6 @@ in {
CRYPTO_SHA1 = "y";
ENCRYPTED_KEYS = "y";
KEYS = "y";
WLAN = "y";
CFG80211 = "m";
MAC80211 = "m";
EXPERT = "y";
CFG80211_CERTIFICATION_ONUS = "y";
CFG80211_REQUIRE_SIGNED_REGDB = "n"; # depends on ONUS
CFG80211_CRDA_SUPPORT = "n";
};
};
};

View File

@ -104,7 +104,6 @@ extraPkgs // {
"CONFIG_DRIVER_NL80211=y"
"CONFIG_IAPP=y"
"CONFIG_IEEE80211AC=y"
"CONFIG_IEEE80211AX=y"
"CONFIG_IEEE80211N=y"
"CONFIG_IEEE80211W=y"
"CONFIG_INTERNAL_LIBTOMMATH=y"

View File

@ -58,15 +58,14 @@ in {
anoia = callPackage ./anoia {};
fennel = callPackage ./fennel {};
fennelrepl = callPackage ./fennelrepl {};
firewallgen = callPackage ./firewallgen {};
firmware-utils = callPackage ./firmware-utils {};
firewallgen = callPackage ./firewallgen {};
gen_init_cpio = callPackage ./gen_init_cpio {};
go-l2tp = callPackage ./go-l2tp {};
hi = callPackage ./hi {};
ifwait = callPackage ./ifwait {};
initramfs-peek = callPackage ./initramfs-peek {};
kernel-backport = callPackage ./kernel-backport {};
kmodloader = callPackage ./kmodloader {};
kernel-modules = callPackage ./kernel-modules {};
levitate = callPackage ./levitate {};
libubootenv = callPackage ./libubootenv {};
linotify = callPackage ./linotify {};

View File

@ -1,24 +0,0 @@
{ stdenv
, fetchFromGitHub
, cmake
, zlib
, openssl
}:
stdenv.mkDerivation {
pname = "firmware-utils";
version = "snapshot";
src = fetchFromGitHub {
owner = "openwrt";
repo = "firmware-utils";
rev = "e87f23849790a7c77b4cd0e8ef0384da188174e5";
hash = "sha256-285Isf9sRuUt5S56SozgqpnS0+LOfnvpxpnWLwuWYUk=";
};
nativeBuildInputs = [
cmake
zlib
openssl
];
}

View File

@ -0,0 +1,3 @@
# obj-m += net/ipv4/netfilter/nft_fib_ipv4.o

View File

@ -0,0 +1,55 @@
{
stdenv
, buildPackages
, kernelSrc ? null
, modulesupport ? null
, targets ? []
, kconfig ? {}
, openssl
, writeText
, lib
}:
let
writeConfig = import ../kernel/write-kconfig.nix { inherit lib writeText; };
arch = if stdenv.isMips
then "mips"
else if stdenv.isAarch64
then "arm64"
else throw "unknown arch";
in stdenv.mkDerivation {
name = "kernel-modules";
nativeBuildInputs = [buildPackages.stdenv.cc] ++
(with buildPackages.pkgs; [
bc bison flex
openssl
cpio
kmod
]);
CC = "${stdenv.cc.bintools.targetPrefix}gcc";
HOST_EXTRACFLAGS = with buildPackages.pkgs;
"-I${buildPackages.openssl.dev}/include -L${buildPackages.openssl.out}/lib";
CROSS_COMPILE = stdenv.cc.bintools.targetPrefix;
ARCH = arch;
KBUILD_BUILD_HOST = "liminix.builder";
buildPhase = ''
cat ${writeConfig "kconfig" kconfig} > .more-config
cat .more-config >> .config
make olddefconfig
for v in $(cat .more-config) ; do grep $v .config || (echo Missing $v && exit 1);done
# grep =m .config
make modules
'';
src = modulesupport;
installPhase = ''
mkdir -p $out/lib/modules/0.0
find . -name \*.ko | cpio --verbose --make-directories -p $out/lib/modules/0.0
depmod -b $out -v 0.0
touch $out/load.sh
for i in ${lib.concatStringsSep " " targets}; do
modprobe -S 0.0 -d $out --show-depends $i >> $out/load.sh
done
tac < $out/load.sh | sed 's/^insmod/rmmod/g' > $out/unload.sh
'';
}

View File

@ -6,7 +6,6 @@
, config
, src
, version ? "0"
, extraPatchPhase ? "echo"
, targets ? ["vmlinux"]
} :
@ -52,9 +51,9 @@ stdenv.mkDerivation rec {
patches = [
./cmdline-cookie.patch
./phram-allow-cached-mappings.patch
./mips-malta-fdt-from-bootloader.patch
] ++ lib.optional (lib.versionOlder version "5.18.0")
./phram-allow-cached-mappings.patch;
];
# this is here to work around what I think is a bug in nixpkgs
# packaging of ncurses: it installs pkg-config data files which
@ -104,7 +103,8 @@ stdenv.mkDerivation rec {
mkdir -p $headers
cp -a include .config $headers/
mkdir -p $modulesupport
make modules
cp modules.* $modulesupport
make clean modules_prepare
cp -a . $modulesupport
'';
}

View File

@ -1,43 +0,0 @@
{
liminix
, lib
, targets ? []
, kernel ? null
, runCommand
, pkgsBuildBuild
, dependencies ? []
} :
let
inherit (liminix.services) oneshot;
inherit (lib) concatStringsSep;
loader = runCommand "modules" {
nativeBuildInputs = with pkgsBuildBuild ;[
kmod cpio gawk
];
} ''
kernel=${kernel.modulesupport}
mkdir -p lib/modules/0.0
(cd $kernel && find . -name \*.ko | cpio --verbose --make-directories -p $NIX_BUILD_TOP/lib/modules/0.0)
cp $kernel/modules.* lib/modules/0.0
depmod -b . 0.0
(for i in ${lib.concatStringsSep " " targets}; do
modprobe -S 0.0 -d $NIX_BUILD_TOP --show-depends $i | sed "s,^insmod $NIX_BUILD_TOP/lib/modules/0.0/,,g"
done) | awk '!a[$0]++' > load-order
mkdir $out
for i in $(cat load-order); do
install -v $NIX_BUILD_TOP/lib/modules/0.0/$i -D $out/$i
done
echo "O=$out" > $out/load.sh
sed "s,^,insmod \$O/,g" < load-order >> $out/load.sh
echo "O=$out" > $out/unload.sh
tac load-order | sed "s,^,rmmod \$O/,g" > $out/unload.sh
'';
in oneshot {
name = "kmodloader-" + (concatStringsSep "-" targets);
up = "sh ${loader}/load.sh";
down = "sh ${loader}/unload.sh";
inherit dependencies;
}

View File

@ -15,6 +15,6 @@ for i in run notification-fd up down consumer-for producer-for pipeline-name ; d
test -n "$(printenv $i)" && (echo "$(printenv $i)" > $out/${name}/$i)
done
( cd $out && ln -s /run/services/outputs/${name} ./.outputs )
( cd $out && ln -s /run/service-state/${name} ./.outputs )
for i in $out/${name}/{down,up,run} ; do test -f $i && chmod +x $i; done
true

View File

@ -9,7 +9,7 @@
}:
let
inherit (builtins) concatStringsSep;
prefix = "/run/services/outputs";
prefix = "/run/service-state";
output = service: name: "${prefix}/${service.name}/${name}";
serviceScript = commands : ''
#!/bin/sh

View File

@ -20,7 +20,7 @@ if toplevel=$(nix-build "$@" -A outputs.systemConfiguration --no-out-link); then
echo systemConfiguration $toplevel
min-copy-closure $target_host $toplevel
$ssh_command $target_host $toplevel/bin/install
$ssh_command $target_host "sync; source /etc/profile; reboot -f"
$ssh_command $target_host "sync; source /etc/profile; reboot"
else
echo Rebuild failed
fi

View File

@ -20,21 +20,23 @@
out))
(let [(address len preferred valid extra)
(string.match str "(.-)/(%d+),(%d+),(%d+)(.*)$")]
(merge {: address : len
:preferred (or preferred "forever")
:valid (or valid "forever")
}
(parse-extra extra))))
(merge {: address : len : preferred : valid} (parse-extra extra))))
(fn write-addresses [prefix addresses]
(each [_ a (ipairs (split " " addresses))]
(let [address (parse-address a)
suffix (base64url (string.pack "n" (hash a)))
;; keydir should be a function of all the address
;; attributes: we want it to change whenever anything changes
;; so that clients can see which addresses are new without
;; deep table comparisons
keydir (..
prefix
(-> address.address
(: :gsub "::$" "")
(: :gsub ":" "-")))]
(: :gsub ":" "-"))
"_"
suffix)]
(mktree (.. state-directory "/" keydir))
(each [k v (pairs address)]
(write-value (.. keydir "/" k) v)))))

View File

@ -7,8 +7,8 @@ let
name = "openwrt-source";
repo = "openwrt";
owner = "openwrt";
rev = "refs/tags/v23.05.2";
hash = "sha256-kP+cSOB6LiOMWs7g+ji7P7ehiDYDwRdmT4R5jSzw6K4=";
rev = "a5265497a4f6da158e95d6a450cb2cb6dc085cab";
hash = "sha256-YYi4gkpLjbOK7bM2MGQjAyEBuXJ9JNXoz/JEmYf8xE8=";
};
doPatch = family : ''
cp -av ${src}/target/linux/generic/files/* .

View File

@ -3,10 +3,9 @@
, fetchFromGitLab
, makeWrapper
, btrfs-progs
, util-linux-small
, lib
}:
let search_path = lib.makeBinPath [btrfs-progs util-linux-small];
let search_path = lib.makeBinPath [btrfs-progs];
in stdenv.mkDerivation {
pname = "schnapps";
version = "2.13.0";

View File

@ -2,15 +2,8 @@
writeText "service-fns.sh" ''
output() { cat $1/.outputs/$2; }
output_path() { echo $(realpath $1/.outputs)/$2; }
SERVICE_OUTPUTS=/run/services/outputs
SERVICE_STATE=/run/services/state
mkoutputs() {
d=$SERVICE_OUTPUTS/$1
mkdir -m 2751 -p $d && chown root:system $d
echo $d
}
mkstate() {
d=$SERVICE_STATE/$1
d=/run/service-state/$1
mkdir -m 2751 -p $d && chown root:system $d
echo $d
}

View File

@ -92,13 +92,10 @@ in attrset:
# case otherwise we will install into a ramfs/rootfs
""
}
if test -d \$dest/persist; then dest=\$dest/persist; fi
if test -d $dest/persist; then dest=$dest/persist; fi
cp -v -fP \$src/bin/* \$src/etc/* \$dest
${if attrset ? boot then ''
(cd \$dest
if test -e boot ; then rm boot ; fi
ln -sf ${lib.strings.removePrefix "/" attrset.boot.target} ./boot
)
(cd \$dest && rm ./boot && ln -sf ${lib.strings.removePrefix "/" attrset.boot.target} ./boot)
'' else ""}
EOF
chmod +x $out/bin/install

View File

@ -12,7 +12,7 @@ let derivation = (import liminix {
img = derivation.outputs.tftpboot;
uboot = derivation.outputs.u-boot;
pkgsBuild = derivation.pkgs.pkgsBuildBuild;
in pkgsBuild.runCommand "check-${deviceName}" {
in pkgsBuild.runCommand "check" {
nativeBuildInputs = with pkgsBuild; [
expect
socat
@ -44,11 +44,4 @@ in {
mipsLz = check "qemu" {
boot.tftp.compressRoot = true;
};
# this works on real hardware but I haven't figured out how
# to make it work on qemu: it says
# "OF: fdt: No chosen node found, continuing without"
# mipsOldUboot = check "qemu" {
# boot.tftp.appendDTB = true;
# };
}