tftp: introduce an alternative command line for TFTP #8
23 changed files with 384 additions and 61 deletions
|
@ -170,7 +170,7 @@
|
||||||
maxLEBcount = "256";
|
maxLEBcount = "256";
|
||||||
};
|
};
|
||||||
|
|
||||||
flash.eraseBlockSize = 65536;
|
flash.eraseBlockSize = 64 * 1024;
|
||||||
|
|
||||||
# This is a FIT containing a kernel padded and
|
# This is a FIT containing a kernel padded and
|
||||||
# a UBI volume rootfs.
|
# a UBI volume rootfs.
|
||||||
|
@ -181,8 +181,8 @@
|
||||||
# Aligned on 2kb.
|
# Aligned on 2kb.
|
||||||
alignment = 2048;
|
alignment = 2048;
|
||||||
|
|
||||||
rootDevice = "ubi:rootfs";
|
rootDevice = "ubi0:rootfs";
|
||||||
alternativeRootDevice = "ubi:rootfs";
|
alternativeRootDevice = "ubi1:rootfs";
|
||||||
|
|
||||||
# Auto-attach MTD devices: ubi_a then ubi_b.
|
# Auto-attach MTD devices: ubi_a then ubi_b.
|
||||||
ubi.mtds = [ "ubi_a" "ubi_b" ];
|
ubi.mtds = [ "ubi_a" "ubi_b" ];
|
||||||
|
@ -224,6 +224,7 @@
|
||||||
tftp = {
|
tftp = {
|
||||||
# 5MB is nice.
|
# 5MB is nice.
|
||||||
freeSpaceBytes = 5 * 1024 * 1024;
|
freeSpaceBytes = 5 * 1024 * 1024;
|
||||||
|
appendDTB = true;
|
||||||
loadAddress = lim.parseInt "0x2000000";
|
loadAddress = lim.parseInt "0x2000000";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
./bridge
|
./bridge
|
||||||
./busybox.nix
|
./busybox.nix
|
||||||
./dhcp6c
|
./dhcp6c
|
||||||
|
./jitter-rng
|
||||||
./dnsmasq
|
./dnsmasq
|
||||||
./firewall
|
./firewall
|
||||||
./hardware.nix
|
./hardware.nix
|
||||||
|
|
|
@ -14,5 +14,8 @@
|
||||||
boot.commandLine = [
|
boot.commandLine = [
|
||||||
"console=ttyS0,115200" # true of all mips we've yet encountered
|
"console=ttyS0,115200" # true of all mips we've yet encountered
|
||||||
];
|
];
|
||||||
|
boot.tftp.commandLine = [
|
||||||
|
"console=ttyS0,115200" # true of all mips we've yet encountered
|
||||||
|
];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -109,7 +109,13 @@ in {
|
||||||
]
|
]
|
||||||
++ (map (mtd: "ubi.mtd=${mtd}") config.hardware.ubi.mtds)
|
++ (map (mtd: "ubi.mtd=${mtd}") config.hardware.ubi.mtds)
|
||||||
++ lib.optional (config.rootOptions != null) "rootflags=${config.rootOptions}"
|
++ lib.optional (config.rootOptions != null) "rootflags=${config.rootOptions}"
|
||||||
++ lib.optional (config.hardware.alternativeRootDevice != null) "altroot=${config.hardware.alternativeRootDevice}";
|
++ lib.optional (config.hardware.alternativeRootDevice != null) "rootalt=${config.hardware.alternativeRootDevice}";
|
||||||
|
|
||||||
|
boot.tftp.commandLine = [
|
||||||
|
"panic=10 oops=panic init=/bin/init loglevel=8"
|
||||||
|
"fw_devlink=off"
|
||||||
|
"rootfstype=${config.rootfsType}"
|
||||||
|
];
|
||||||
|
|
||||||
system.callService = path : parameters :
|
system.callService = path : parameters :
|
||||||
let
|
let
|
||||||
|
|
|
@ -20,6 +20,7 @@ in
|
||||||
system.service.bridge = {
|
system.service.bridge = {
|
||||||
primary = mkOption { type = liminix.lib.types.serviceDefn; };
|
primary = mkOption { type = liminix.lib.types.serviceDefn; };
|
||||||
members = mkOption { type = liminix.lib.types.serviceDefn; };
|
members = mkOption { type = liminix.lib.types.serviceDefn; };
|
||||||
|
ready = mkOption { type = liminix.lib.types.serviceDefn; };
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
config.system.service.bridge = {
|
config.system.service.bridge = {
|
||||||
|
@ -28,6 +29,12 @@ in
|
||||||
type = types.str;
|
type = types.str;
|
||||||
description = "bridge interface name to create";
|
description = "bridge interface name to create";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
macAddressFromInterface = mkOption {
|
||||||
|
type = types.nullOr liminix.lib.types.service;
|
||||||
|
default = null;
|
||||||
|
description = "reuse mac address from an existing interface service";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
members = config.system.callService ./members.nix {
|
members = config.system.callService ./members.nix {
|
||||||
primary = mkOption {
|
primary = mkOption {
|
||||||
|
@ -40,6 +47,19 @@ in
|
||||||
description = "interfaces to add to the bridge";
|
description = "interfaces to add to the bridge";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# TODO: generalize it outside
|
||||||
|
ready = config.system.callService ./ready.nix {
|
||||||
|
primary = mkOption {
|
||||||
|
type = liminix.lib.types.service;
|
||||||
|
description = "primary bridge interface";
|
||||||
|
};
|
||||||
|
|
||||||
|
members = mkOption {
|
||||||
|
type = liminix.lib.types.service;
|
||||||
|
description = "members service";
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
config.kernel.config = {
|
config.kernel.config = {
|
||||||
BRIDGE = "y";
|
BRIDGE = "y";
|
||||||
|
|
|
@ -10,22 +10,21 @@ let
|
||||||
inherit (liminix.networking) interface;
|
inherit (liminix.networking) interface;
|
||||||
inherit (liminix.services) bundle oneshot;
|
inherit (liminix.services) bundle oneshot;
|
||||||
inherit (lib) mkOption types;
|
inherit (lib) mkOption types;
|
||||||
addif = member :
|
addif = member : oneshot {
|
||||||
# how do we get sight of services from here? maybe we need to
|
name = "${primary.name}.member.${member.name}";
|
||||||
# implement ifwait as a regualr derivation instead of a
|
up = ''
|
||||||
# servicedefinition
|
echo "waiting for bridge $(output ${primary} ifname) to be ready"
|
||||||
svc.ifwait.build {
|
${ifwait}/bin/ifwait -v $(output ${primary} ifname) running
|
||||||
state = "running";
|
echo "attaching $(output ${member} ifname) to $(output ${primary} ifname) bridge"
|
||||||
interface = member;
|
ip link set dev $(output ${member} ifname) master $(output ${primary} ifname)
|
||||||
dependencies = [ primary member ];
|
'';
|
||||||
service = oneshot {
|
down = ''
|
||||||
name = "${primary.name}.member.${member.name}";
|
echo "detaching $(output ${member} ifname) from any bridge"
|
||||||
up = ''
|
ip link set dev $(output ${member} ifname) nomaster
|
||||||
ip link set dev $(output ${member} ifname) master $(output ${primary} ifname)
|
'';
|
||||||
'';
|
|
||||||
down = "ip link set dev $(output ${member} ifname) nomaster";
|
dependencies = [ primary member ];
|
||||||
};
|
};
|
||||||
};
|
|
||||||
in bundle {
|
in bundle {
|
||||||
name = "${primary.name}.members";
|
name = "${primary.name}.members";
|
||||||
contents = map addif members;
|
contents = map addif members;
|
||||||
|
|
|
@ -3,15 +3,24 @@
|
||||||
, ifwait
|
, ifwait
|
||||||
, lib
|
, lib
|
||||||
}:
|
}:
|
||||||
{ ifname } :
|
{ ifname, macAddressFromInterface ? null } :
|
||||||
let
|
let
|
||||||
inherit (liminix.services) bundle oneshot;
|
inherit (liminix.services) bundle oneshot;
|
||||||
inherit (lib) mkOption types;
|
inherit (lib) mkOption types optional;
|
||||||
in oneshot rec {
|
in oneshot rec {
|
||||||
name = "${ifname}.link";
|
name = "${ifname}.link";
|
||||||
up = ''
|
up = ''
|
||||||
ip link add name ${ifname} type bridge
|
${if macAddressFromInterface == null then
|
||||||
${liminix.networking.ifup name ifname}
|
"ip link add name ${ifname} type bridge"
|
||||||
|
else
|
||||||
|
"ip link add name ${ifname} address $(output ${macAddressFromInterface} ether) type bridge"}
|
||||||
|
|
||||||
|
(in_outputs ${name}
|
||||||
|
echo ${ifname} > ifname
|
||||||
|
cat /sys/class/net/${ifname}/address > ether
|
||||||
|
)
|
||||||
'';
|
'';
|
||||||
down = "ip link set down dev ${ifname}";
|
down = "ip link delete ${ifname}";
|
||||||
|
|
||||||
|
dependencies = optional (macAddressFromInterface != null) macAddressFromInterface;
|
||||||
}
|
}
|
||||||
|
|
18
modules/bridge/ready.nix
Normal file
18
modules/bridge/ready.nix
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
liminix
|
||||||
|
, ifwait
|
||||||
|
, lib
|
||||||
|
}:
|
||||||
|
{ primary, members } :
|
||||||
|
let
|
||||||
|
inherit (liminix.services) oneshot;
|
||||||
|
in oneshot {
|
||||||
|
name = "${primary.name}.oper";
|
||||||
|
up = ''
|
||||||
|
ip link set up dev $(output ${primary} ifname)
|
||||||
|
${ifwait}/bin/ifwait -v $(output ${primary} ifname) running
|
||||||
|
'';
|
||||||
|
down = "ip link set down dev $(output ${primary} ifname)";
|
||||||
|
|
||||||
|
dependencies = [ members ];
|
||||||
|
}
|
|
@ -26,6 +26,10 @@ in {
|
||||||
interface = mkOption {
|
interface = mkOption {
|
||||||
type = liminix.lib.types.service;
|
type = liminix.lib.types.service;
|
||||||
};
|
};
|
||||||
|
package = mkOption {
|
||||||
|
type = types.package;
|
||||||
|
default = pkgs.hostapd;
|
||||||
|
};
|
||||||
params = mkOption {
|
params = mkOption {
|
||||||
type = types.attrs;
|
type = types.attrs;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
{
|
{
|
||||||
liminix
|
liminix
|
||||||
, hostapd
|
|
||||||
, writeText
|
, writeText
|
||||||
, lib
|
, lib
|
||||||
}:
|
}:
|
||||||
{ interface, params} :
|
{ package, interface, params } :
|
||||||
let
|
let
|
||||||
inherit (liminix.services) longrun;
|
inherit (liminix.services) longrun;
|
||||||
inherit (lib) concatStringsSep mapAttrsToList;
|
inherit (lib) concatStringsSep mapAttrsToList;
|
||||||
|
@ -35,5 +34,5 @@ let
|
||||||
in longrun {
|
in longrun {
|
||||||
inherit name;
|
inherit name;
|
||||||
dependencies = [ interface ];
|
dependencies = [ interface ];
|
||||||
run = "${hostapd}/bin/hostapd -i $(output ${interface} ifname) -P /run/${name}.pid -S ${conf}";
|
run = "${package}/bin/hostapd -i $(output ${interface} ifname) -P /run/${name}.pid -S ${conf}";
|
||||||
}
|
}
|
||||||
|
|
21
modules/jitter-rng/default.nix
Normal file
21
modules/jitter-rng/default.nix
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
## CPU Jitter RNG
|
||||||
|
## ==============
|
||||||
|
##
|
||||||
|
## CPU Jitter RNG is a random number generator # providing non-physical true
|
||||||
|
## random generation # that works equally for kernel and user-land. It relies
|
||||||
|
## on the availability of a high-resolution timer.
|
||||||
|
{ lib, pkgs, ... }:
|
||||||
|
let
|
||||||
|
inherit (lib) mkOption types;
|
||||||
|
inherit (pkgs) liminix;
|
||||||
|
in {
|
||||||
|
options.system.service.jitter-rng = mkOption {
|
||||||
|
type = liminix.lib.types.serviceDefn;
|
||||||
|
};
|
||||||
|
|
||||||
|
config = {
|
||||||
|
system.service.jitter-rng = pkgs.liminix.callService ./jitter-rng.nix {
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
18
modules/jitter-rng/jitter-rng.nix
Normal file
18
modules/jitter-rng/jitter-rng.nix
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
liminix
|
||||||
|
, lib
|
||||||
|
, jitterentropy-rngd
|
||||||
|
}:
|
||||||
|
{ }:
|
||||||
|
let
|
||||||
|
inherit (liminix.services) longrun;
|
||||||
|
name = "jitterentropy-rngd";
|
||||||
|
in
|
||||||
|
longrun {
|
||||||
|
# Does it need to be unique?
|
||||||
|
inherit name;
|
||||||
|
run = ''
|
||||||
|
mkdir -p /run/jitterentropy-rngd
|
||||||
|
${jitterentropy-rngd}/bin/jitterentropy-rngd -v -p /run/jitterentropy-rngd/${name}.pid
|
||||||
|
'';
|
||||||
|
}
|
|
@ -17,7 +17,7 @@ let
|
||||||
ip address replace $ip/$mask dev $interface
|
ip address replace $ip/$mask dev $interface
|
||||||
(in_outputs ${name}
|
(in_outputs ${name}
|
||||||
for i in lease mask ip router siaddr dns serverid subnet opt53 interface ; do
|
for i in lease mask ip router siaddr dns serverid subnet opt53 interface ; do
|
||||||
printenv $i > $i
|
(printenv $i || true) > $i
|
||||||
done)
|
done)
|
||||||
}
|
}
|
||||||
case $action in
|
case $action in
|
||||||
|
@ -40,7 +40,7 @@ let
|
||||||
'';
|
'';
|
||||||
in longrun {
|
in longrun {
|
||||||
inherit name;
|
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;
|
notification-fd = 10;
|
||||||
dependencies = [ interface ];
|
dependencies = [ interface ];
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,8 @@
|
||||||
, ...
|
, ...
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
inherit (lib) mkIf mkOption types;
|
inherit (pkgs) liminix;
|
||||||
|
inherit (lib) mkIf;
|
||||||
o = config.system.outputs;
|
o = config.system.outputs;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
|
@ -24,17 +25,10 @@ in
|
||||||
};
|
};
|
||||||
boot.initramfs.enable = true;
|
boot.initramfs.enable = true;
|
||||||
system.outputs = {
|
system.outputs = {
|
||||||
rootfs =
|
rootfs = liminix.builders.jffs2 {
|
||||||
let
|
bootableRootDirectory = o.bootablerootdir;
|
||||||
inherit (pkgs.pkgsBuildBuild) runCommand mtdutils;
|
inherit (config.hardware.flash) eraseBlockSize;
|
||||||
endian = if pkgs.stdenv.isBigEndian
|
};
|
||||||
then "--big-endian" else "--little-endian";
|
|
||||||
in runCommand "make-jffs2" {
|
|
||||||
depsBuildBuild = [ mtdutils ];
|
|
||||||
} ''
|
|
||||||
tree=${o.bootablerootdir}
|
|
||||||
(cd $tree && mkfs.jffs2 --compression-mode=size ${endian} -e ${toString config.hardware.flash.eraseBlockSize} --enable-compressor=lzo --pad --root . --output $out --squash --faketime )
|
|
||||||
'';
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
14
modules/outputs/tftpboot-fit.its
Normal file
14
modules/outputs/tftpboot-fit.its
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
description = "Liminix TFTP bootscript";
|
||||||
|
#address-cells = <1>;
|
||||||
|
|
||||||
|
images {
|
||||||
|
bootscript {
|
||||||
|
description = "Bootscript";
|
||||||
|
data = /incbin/("boot.scr");
|
||||||
|
type = "script";
|
||||||
|
compression = "none";
|
||||||
|
};
|
||||||
|
};
|
|
@ -5,10 +5,18 @@
|
||||||
, ...
|
, ...
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
inherit (lib) mkOption types concatStringsSep;
|
inherit (lib) mkOption mkIf types concatStringsSep;
|
||||||
|
inherit (pkgs) liminix;
|
||||||
cfg = config.boot.tftp;
|
cfg = config.boot.tftp;
|
||||||
hw = config.hardware;
|
hw = config.hardware;
|
||||||
arch = pkgs.stdenv.hostPlatform.linuxArch;
|
arch = pkgs.stdenv.hostPlatform.linuxArch;
|
||||||
|
|
||||||
|
# UBI cannot run on the top of phram.
|
||||||
|
needsSquashfs = config.rootfsType == "ubifs";
|
||||||
|
rootfstype = if needsSquashfs then "squashfs" else config.rootfsType;
|
||||||
|
rootfs = if needsSquashfs then
|
||||||
|
liminix.builders.squashfs config.filesystem.contents
|
||||||
|
else config.system.outputs.rootfs;
|
||||||
in {
|
in {
|
||||||
imports = [ ../ramdisk.nix ];
|
imports = [ ../ramdisk.nix ];
|
||||||
options.boot.tftp = {
|
options.boot.tftp = {
|
||||||
|
@ -28,6 +36,14 @@ in {
|
||||||
type = types.bool;
|
type = types.bool;
|
||||||
default = false;
|
default = false;
|
||||||
};
|
};
|
||||||
|
commandLine = mkOption {
|
||||||
|
type = types.listOf types.str;
|
||||||
|
default = config.boot.commandLine;
|
||||||
|
description = ''
|
||||||
|
TFTP-specific command line.
|
||||||
|
Defaults to the classical one if unset.
|
||||||
|
'';
|
||||||
|
};
|
||||||
};
|
};
|
||||||
options.system.outputs = {
|
options.system.outputs = {
|
||||||
tftpboot = mkOption {
|
tftpboot = mkOption {
|
||||||
|
@ -51,11 +67,52 @@ in {
|
||||||
It uses the Linux `phram <https://github.com/torvalds/linux/blob/master/drivers/mtd/devices/phram.c>`_ driver to emulate a flash device using a segment of physical RAM.
|
It uses the Linux `phram <https://github.com/torvalds/linux/blob/master/drivers/mtd/devices/phram.c>`_ driver to emulate a flash device using a segment of physical RAM.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
tftpboot-fit = mkOption {
|
||||||
|
type = types.package;
|
||||||
|
description = ''
|
||||||
|
tftpboot-fit
|
||||||
|
************
|
||||||
|
|
||||||
|
This output is a variant that encloses the `boot.scr` in a FIT
|
||||||
|
if that's simpler to transfer for you.
|
||||||
|
'';
|
||||||
|
};
|
||||||
};
|
};
|
||||||
config = {
|
config = {
|
||||||
boot.ramdisk.enable = true;
|
boot.ramdisk.enable = true;
|
||||||
|
|
||||||
|
kernel.config = mkIf needsSquashfs {
|
||||||
|
SQUASHFS = "y";
|
||||||
|
SQUASHFS_XZ = "y";
|
||||||
|
};
|
||||||
|
|
||||||
system.outputs = rec {
|
system.outputs = rec {
|
||||||
|
tftpboot-fit =
|
||||||
|
let
|
||||||
|
tftpboot-fit = pkgs.writeText "tftpboot.its" ''
|
||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
description = "Liminix TFTP bootscript";
|
||||||
|
#address-cells = <1>;
|
||||||
|
|
||||||
|
images {
|
||||||
|
bootscript {
|
||||||
|
description = "Bootscript";
|
||||||
|
data = /incbin/("${tftpboot}/boot.scr");
|
||||||
|
type = "script";
|
||||||
|
compression = "none";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
'';
|
||||||
|
in
|
||||||
|
pkgs.runCommand "tftpboot-fit" { nativeBuildInputs = with pkgs.pkgsBuildBuild; [ ubootTools ]; } ''
|
||||||
|
mkdir -p $out/
|
||||||
|
cp -rf ${tftpboot}/* $out/
|
||||||
|
mkimage -f ${tftpboot-fit} $out/script.ub
|
||||||
|
'';
|
||||||
tftpboot =
|
tftpboot =
|
||||||
let
|
let
|
||||||
inherit (pkgs.lib.trivial) toHexString;
|
inherit (pkgs.lib.trivial) toHexString;
|
||||||
|
@ -69,7 +126,7 @@ in {
|
||||||
zimage = "bootz";
|
zimage = "bootz";
|
||||||
}; in choices.${cfg.kernelFormat};
|
}; in choices.${cfg.kernelFormat};
|
||||||
|
|
||||||
cmdline = concatStringsSep " " config.boot.commandLine;
|
cmdline = concatStringsSep " " config.boot.tftp.commandLine;
|
||||||
objcopy = "${pkgs.stdenv.cc.bintools.targetPrefix}objcopy";
|
objcopy = "${pkgs.stdenv.cc.bintools.targetPrefix}objcopy";
|
||||||
stripAndZip = ''
|
stripAndZip = ''
|
||||||
${objcopy} -O binary -R .reginfo -R .notes -R .note -R .comment -R .mdebug -R .note.gnu.build-id -S vmlinux.elf vmlinux.bin
|
${objcopy} -O binary -R .reginfo -R .notes -R .note -R .comment -R .mdebug -R .note.gnu.build-id -S vmlinux.elf vmlinux.bin
|
||||||
|
@ -84,7 +141,7 @@ in {
|
||||||
hex() { printf "0x%x" $1; }
|
hex() { printf "0x%x" $1; }
|
||||||
|
|
||||||
rootfsStart=${toString cfg.loadAddress}
|
rootfsStart=${toString cfg.loadAddress}
|
||||||
rootfsSize=$(binsize64k ${o.rootfs} )
|
rootfsSize=$(binsize64k ${rootfs} )
|
||||||
rootfsSize=$(($rootfsSize + ${toString cfg.freeSpaceBytes} ))
|
rootfsSize=$(($rootfsSize + ${toString cfg.freeSpaceBytes} ))
|
||||||
|
|
||||||
ln -s ${o.manifest} manifest
|
ln -s ${o.manifest} manifest
|
||||||
|
@ -98,13 +155,13 @@ in {
|
||||||
dtbStart=$(($rootfsStart + $rootfsSize))
|
dtbStart=$(($rootfsStart + $rootfsSize))
|
||||||
${if cfg.compressRoot
|
${if cfg.compressRoot
|
||||||
then ''
|
then ''
|
||||||
lzma -z9cv ${o.rootfs} > rootfs.lz
|
lzma -z9cv ${rootfs} > rootfs.lz
|
||||||
rootfsLzStart=$dtbStart
|
rootfsLzStart=$dtbStart
|
||||||
rootfsLzSize=$(binsize rootfs.lz)
|
rootfsLzSize=$(binsize rootfs.lz)
|
||||||
dtbStart=$(($dtbStart + $rootfsLzSize))
|
dtbStart=$(($dtbStart + $rootfsLzSize))
|
||||||
''
|
''
|
||||||
else ''
|
else ''
|
||||||
ln -s ${o.rootfs} rootfs
|
ln -s ${rootfs} rootfs
|
||||||
''
|
''
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,7 +178,7 @@ in {
|
||||||
fdtput -p -t s dtb /reserved-memory/$node compatible phram
|
fdtput -p -t s dtb /reserved-memory/$node compatible phram
|
||||||
fdtput -p -t lx dtb /reserved-memory/$node reg $ac_prefix $(hex $rootfsStart) $sz_prefix $(hex $rootfsSize)
|
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";
|
cmd="liminix ${cmdline} mtdparts=phram0:''${rootfsSize}(rootfs) phram.phram=phram0,''${rootfsStart},''${rootfsSize},${toString config.hardware.flash.eraseBlockSize} rootfstype=${rootfstype} root=/dev/mtdblock0";
|
||||||
fdtput -t s dtb /chosen ${config.boot.commandLineDtbNode} "$cmd"
|
fdtput -t s dtb /chosen ${config.boot.commandLineDtbNode} "$cmd"
|
||||||
|
|
||||||
dtbSize=$(binsize ./dtb )
|
dtbSize=$(binsize ./dtb )
|
||||||
|
|
83
modules/pki/default.nix
Normal file
83
modules/pki/default.nix
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
# Inspired from nixpkgs/NixOS.
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
|
||||||
|
let
|
||||||
|
inherit (pkgs.pseudofile) dir symlink;
|
||||||
|
cfg = config.security.pki;
|
||||||
|
|
||||||
|
cacertPackage = pkgs.cacert.override {
|
||||||
|
blacklist = [ ];
|
||||||
|
extraCertificateFiles = cfg.certificateFiles;
|
||||||
|
extraCertificateStrings = cfg.certificates;
|
||||||
|
};
|
||||||
|
caBundleName = "ca-bundle.crt";
|
||||||
|
caBundle = "${cacertPackage}/etc/ssl/certs/${caBundleName}";
|
||||||
|
|
||||||
|
in
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
options = {
|
||||||
|
security.pki.installCACerts = mkEnableOption "installing CA certificates to the system" // {
|
||||||
|
default = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
security.pki.certificateFiles = mkOption {
|
||||||
|
type = types.listOf types.path;
|
||||||
|
default = [];
|
||||||
|
example = literalExpression ''[ "''${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt" ]'';
|
||||||
|
description = ''
|
||||||
|
A list of files containing trusted root certificates in PEM
|
||||||
|
format. These are concatenated to form
|
||||||
|
{file}`/etc/ssl/certs/ca-certificates.crt`, which is
|
||||||
|
used by many programs that use OpenSSL, such as
|
||||||
|
{command}`curl` and {command}`git`.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
security.pki.certificates = mkOption {
|
||||||
|
type = types.listOf types.str;
|
||||||
|
default = [];
|
||||||
|
example = literalExpression ''
|
||||||
|
[ '''
|
||||||
|
NixOS.org
|
||||||
|
=========
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIGUDCCBTigAwIBAgIDD8KWMA0GCSqGSIb3DQEBBQUAMIGMMQswCQYDVQQGEwJJ
|
||||||
|
TDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0
|
||||||
|
...
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
'''
|
||||||
|
]
|
||||||
|
'';
|
||||||
|
description = ''
|
||||||
|
A list of trusted root certificates in PEM format.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf cfg.installCACerts {
|
||||||
|
# NixOS canonical location + Debian/Ubuntu/Arch/Gentoo compatibility.
|
||||||
|
filesystem = dir {
|
||||||
|
etc = dir {
|
||||||
|
ssl = dir {
|
||||||
|
certs = dir {
|
||||||
|
"ca-certificates.crt" = symlink caBundle;
|
||||||
|
"ca-bundle.crt" = symlink caBundle;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# CentOS/Fedora compatibility.
|
||||||
|
pki = dir {
|
||||||
|
certs = dir {
|
||||||
|
"ca-bundle.crt" = symlink caBundle;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
41
overlay.nix
41
overlay.nix
|
@ -143,6 +143,42 @@ extraPkgs // {
|
||||||
});
|
});
|
||||||
in h.override { openssl = null; sqlite = null; };
|
in h.override { openssl = null; sqlite = null; };
|
||||||
|
|
||||||
|
hostapd-radius =
|
||||||
|
let
|
||||||
|
config = [
|
||||||
|
"CONFIG_DRIVER_NL80211=y"
|
||||||
|
"CONFIG_DRIVER_WIRED=y"
|
||||||
|
"CONFIG_EAP=y"
|
||||||
|
"CONFIG_EAP_PEAP=y"
|
||||||
|
"CONFIG_RADIUS_SERVER=y"
|
||||||
|
"CONFIG_FULL_DYNAMIC_VLAN=y"
|
||||||
|
"CONFIG_IAPP=y"
|
||||||
|
"CONFIG_IEEE80211AC=y"
|
||||||
|
"CONFIG_IEEE80211AX=y"
|
||||||
|
"CONFIG_IEEE80211N=y"
|
||||||
|
"CONFIG_IEEE80211W=y"
|
||||||
|
"CONFIG_INTERNAL_LIBTOMMATH=y"
|
||||||
|
"CONFIG_INTERNAL_LIBTOMMATH_FAST=y"
|
||||||
|
"CONFIG_IPV6=y"
|
||||||
|
"CONFIG_LIBNL32=y"
|
||||||
|
"CONFIG_PKCS12=y"
|
||||||
|
"CONFIG_RSN_PREAUTH=y"
|
||||||
|
# Required to read the key material for RADIUS.
|
||||||
|
"CONFIG_TLS=openssl"
|
||||||
|
];
|
||||||
|
h = prev.hostapd.overrideAttrs(o: {
|
||||||
|
extraConfig = "";
|
||||||
|
configurePhase = ''
|
||||||
|
cat > hostapd/defconfig <<EOF
|
||||||
|
${builtins.concatStringsSep "\n" config}
|
||||||
|
EOF
|
||||||
|
${o.configurePhase}
|
||||||
|
'';
|
||||||
|
});
|
||||||
|
in h.override { sqlite = null; };
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
kexec-tools-static = prev.kexec-tools.overrideAttrs(o: {
|
kexec-tools-static = prev.kexec-tools.overrideAttrs(o: {
|
||||||
# For kexecboot we copy kexec into a ramdisk on the system being
|
# For kexecboot we copy kexec into a ramdisk on the system being
|
||||||
# upgraded from. This is more likely to work if kexec is
|
# upgraded from. This is more likely to work if kexec is
|
||||||
|
@ -168,6 +204,11 @@ extraPkgs // {
|
||||||
patches = (if o ? patches then o.patches else []) ++ [
|
patches = (if o ? patches then o.patches else []) ++ [
|
||||||
./pkgs/mtdutils/0001-mkfs.jffs2-add-graft-option.patch
|
./pkgs/mtdutils/0001-mkfs.jffs2-add-graft-option.patch
|
||||||
];
|
];
|
||||||
|
|
||||||
|
postInstall = ''
|
||||||
|
# Testing programs which we don't need. We save a lot of space!
|
||||||
|
rm -rf $out/libexec
|
||||||
|
'';
|
||||||
});
|
});
|
||||||
|
|
||||||
nftables = prev.nftables.overrideAttrs(o: {
|
nftables = prev.nftables.overrideAttrs(o: {
|
||||||
|
|
|
@ -13,6 +13,7 @@ in {
|
||||||
liminix = {
|
liminix = {
|
||||||
builders = {
|
builders = {
|
||||||
squashfs = callPackage ./liminix-tools/builders/squashfs.nix {};
|
squashfs = callPackage ./liminix-tools/builders/squashfs.nix {};
|
||||||
|
jffs2 = callPackage ./liminix-tools/builders/jffs2.nix {};
|
||||||
dtb = callPackage ./kernel/dtb.nix {};
|
dtb = callPackage ./kernel/dtb.nix {};
|
||||||
uimage = callPackage ./kernel/uimage.nix {};
|
uimage = callPackage ./kernel/uimage.nix {};
|
||||||
kernel = callPackage ./kernel {};
|
kernel = callPackage ./kernel {};
|
||||||
|
|
|
@ -19,11 +19,11 @@
|
||||||
(match v
|
(match v
|
||||||
;; - up: Reflects the administrative state of the interface (IFF_UP)
|
;; - up: Reflects the administrative state of the interface (IFF_UP)
|
||||||
;; - running: Reflects the operational state (IFF_RUNNING).
|
;; - running: Reflects the operational state (IFF_RUNNING).
|
||||||
{:event "newlink" :name params.link :up :yes :running :yes}
|
{:event "newlink" :name params.link :up "yes" :running "yes"}
|
||||||
{:present true :up true :running true}
|
{:present true :up true :running true}
|
||||||
|
|
||||||
{:event "newlink" :name params.link :up :yes}
|
{:event "newlink" :name params.link :up "yes"}
|
||||||
{:present :true :up true}
|
{:present true :up true}
|
||||||
|
|
||||||
{:event "newlink" :name params.link}
|
{:event "newlink" :name params.link}
|
||||||
{:present true }
|
{:present true }
|
||||||
|
|
17
pkgs/liminix-tools/builders/jffs2.nix
Normal file
17
pkgs/liminix-tools/builders/jffs2.nix
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
{
|
||||||
|
stdenv
|
||||||
|
, busybox
|
||||||
|
, buildPackages
|
||||||
|
, callPackage
|
||||||
|
, pseudofile
|
||||||
|
, runCommand
|
||||||
|
, writeText
|
||||||
|
} : { eraseBlockSize, bootableRootDirectory }:
|
||||||
|
let
|
||||||
|
endian = if stdenv.isBigEndian then "--big-endian" else "--little-endian";
|
||||||
|
in runCommand "frob-jffs2" {
|
||||||
|
depsBuildBuild = [ buildPackages.mtdutils ];
|
||||||
|
} ''
|
||||||
|
tree=${bootableRootDirectory}
|
||||||
|
(cd $tree && mkfs.jffs2 --compression-mode=size ${endian} -e ${toString eraseBlockSize} --enable-compressor=lzo --pad --root . --output $out --squash --faketime)
|
||||||
|
''
|
|
@ -9,6 +9,7 @@
|
||||||
ip link set up dev ${ifname}
|
ip link set up dev ${ifname}
|
||||||
(in_outputs ${name}
|
(in_outputs ${name}
|
||||||
echo ${ifname} > ifname
|
echo ${ifname} > ifname
|
||||||
|
cat /sys/class/net/${ifname}/address > ether
|
||||||
)
|
)
|
||||||
'';
|
'';
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,13 +65,18 @@ static char * eat_param(char *p, char *param_name, char **out)
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define SCAN_CMDLINE(cmdline, identifier, field) do { \
|
||||||
|
for (char* p = strdup(cmdline); *p; p++) { \
|
||||||
|
p = eat_param(p, identifier, &(opts->field)); \
|
||||||
|
} \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
|
||||||
void parseopts(char * cmdline, struct root_opts *opts) {
|
void parseopts(char * cmdline, struct root_opts *opts) {
|
||||||
for(char *p = cmdline; *p; p++) {
|
SCAN_CMDLINE(cmdline, "root=", device);
|
||||||
p = eat_param(p, "root=", &(opts->device));
|
SCAN_CMDLINE(cmdline, "rootfstype=", fstype);
|
||||||
p = eat_param(p, "rootfstype=", &(opts->fstype));
|
SCAN_CMDLINE(cmdline, "rootflags=", mount_opts);
|
||||||
p = eat_param(p, "rootflags=", &(opts->mount_opts));
|
SCAN_CMDLINE(cmdline, "rootalt=", altdevice);
|
||||||
p = eat_param(p, "altroot=", &(opts->altdevice));
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TESTS
|
#ifdef TESTS
|
||||||
|
@ -85,6 +90,8 @@ void parseopts(char * cmdline, struct root_opts *opts) {
|
||||||
#define S(x) #x
|
#define S(x) #x
|
||||||
#define expect_equal(actual, expected) \
|
#define expect_equal(actual, expected) \
|
||||||
if(!actual || strcmp(actual, expected)) die("%d: expected \"%s\", got \"%s\"", __LINE__, expected, actual);
|
if(!actual || strcmp(actual, expected)) die("%d: expected \"%s\", got \"%s\"", __LINE__, expected, actual);
|
||||||
|
#define expect_null(actual) \
|
||||||
|
if (actual) die("%d: expected null, got \"%s\"", __LINE__, actual);
|
||||||
|
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
|
@ -92,6 +99,7 @@ int main()
|
||||||
struct root_opts opts = {
|
struct root_opts opts = {
|
||||||
.device = "/dev/hda1",
|
.device = "/dev/hda1",
|
||||||
.fstype = "xiafs",
|
.fstype = "xiafs",
|
||||||
|
.altdevice = NULL,
|
||||||
.mount_opts = NULL
|
.mount_opts = NULL
|
||||||
};
|
};
|
||||||
char *buf;
|
char *buf;
|
||||||
|
@ -103,14 +111,22 @@ int main()
|
||||||
expect_equal(opts.fstype, "ubifs");
|
expect_equal(opts.fstype, "ubifs");
|
||||||
expect_equal(opts.mount_opts, "subvol=1");
|
expect_equal(opts.mount_opts, "subvol=1");
|
||||||
|
|
||||||
// finds altroot= options
|
// finds rootalt= options
|
||||||
buf = strdup("liminix console=ttyS0,115200 panic=10 oops=panic init=/bin/init loglevel=8 root=/dev/ubi0_4 rootfstype=ubifs rootflags=subvol=1 fw_devlink=off mtdparts=phram0:18M(rootfs) phram.phram=phram0,0x40400000,18874368,65536 root=/dev/mtdblock0 altroot=/dev/mtdblock6 foo");
|
buf = strdup("liminix console=ttyS0,115200 panic=10 oops=panic init=/bin/init loglevel=8 root=/dev/ubi0_4 rootfstype=ubifs rootflags=subvol=1 fw_devlink=off mtdparts=phram0:18M(rootfs) phram.phram=phram0,0x40400000,18874368,65536 root=/dev/mtdblock0 rootalt=/dev/mtdblock6 foo");
|
||||||
memset(&opts, '\0', sizeof opts); parseopts(buf, &opts);
|
memset(&opts, '\0', sizeof opts); parseopts(buf, &opts);
|
||||||
expect_equal(opts.device, "/dev/mtdblock0");
|
expect_equal(opts.device, "/dev/mtdblock0");
|
||||||
expect_equal(opts.altdevice, "/dev/mtdblock6");
|
expect_equal(opts.altdevice, "/dev/mtdblock6");
|
||||||
expect_equal(opts.fstype, "ubifs");
|
expect_equal(opts.fstype, "ubifs");
|
||||||
expect_equal(opts.mount_opts, "subvol=1");
|
expect_equal(opts.mount_opts, "subvol=1");
|
||||||
|
|
||||||
|
// Ensure that `altdevice` is NULL.
|
||||||
|
buf = strdup("liminix console=ttyS0,115200 panic=10 oops=panic init=/bin/init loglevel=8 fw_devlink=off rootfstype=ubifs mtdparts=phram0:19791872(rootfs) phram.phram=phram0,33554432,19791872,65536 rootfstype=jffs2 root=/dev/mtdblock0");
|
||||||
|
memset(&opts, '\0', sizeof opts); parseopts(buf, &opts);
|
||||||
|
expect_equal(opts.device, "/dev/mtdblock0");
|
||||||
|
expect_null(opts.altdevice);
|
||||||
|
expect_equal(opts.fstype, "jffs2");
|
||||||
|
expect_null(opts.mount_opts);
|
||||||
|
|
||||||
// in case of duplicates, chooses the latter
|
// in case of duplicates, chooses the latter
|
||||||
// also: works if the option is end of string
|
// also: works if the option is end of string
|
||||||
buf = strdup("liminix console=ttyS0,115200 panic=10 oops=panic init=/bin/init loglevel=8 root=/dev/ubi0_4 rootfstype=ubifs fw_devlink=off mtdparts=phram0:18M(rootfs) phram.phram=phram0,0x40400000,18874368,65536 root=/dev/mtdblock0");
|
buf = strdup("liminix console=ttyS0,115200 panic=10 oops=panic init=/bin/init loglevel=8 root=/dev/ubi0_4 rootfstype=ubifs fw_devlink=off mtdparts=phram0:18M(rootfs) phram.phram=phram0,0x40400000,18874368,65536 root=/dev/mtdblock0");
|
||||||
|
@ -146,12 +162,12 @@ int main()
|
||||||
if(opts.altdevice) die("expected null altdevice, got \"%s\"", opts.altdevice);
|
if(opts.altdevice) die("expected null altdevice, got \"%s\"", opts.altdevice);
|
||||||
|
|
||||||
// provides empty strings for empty options
|
// provides empty strings for empty options
|
||||||
buf = strdup("liminix rootfstype= fw_devlink=off root= altroot= /dev/hda1");
|
buf = strdup("liminix rootfstype= fw_devlink=off root= rootalt= /dev/hda1");
|
||||||
memset(&opts, '\0', sizeof opts); parseopts(buf, &opts);
|
memset(&opts, '\0', sizeof opts); parseopts(buf, &opts);
|
||||||
|
|
||||||
if(strlen(opts.fstype)) die("expected empty rootfstype, got \"%s\"", opts.fstype);
|
if(strlen(opts.fstype)) die("expected empty rootfstype, got \"%s\"", opts.fstype);
|
||||||
if(strlen(opts.device)) die("expected empty root, got \"%s\"", opts.device);
|
if(strlen(opts.device)) die("expected empty root, got \"%s\"", opts.device);
|
||||||
if(strlen(opts.altdevice)) die("expected empty altroot, got \"%s\"", opts.altdevice);
|
if(strlen(opts.altdevice)) die("expected empty rootalt, got \"%s\"", opts.altdevice);
|
||||||
|
|
||||||
expect_equal("01", pr_u32(1));
|
expect_equal("01", pr_u32(1));
|
||||||
expect_equal("ab", pr_u32(0xab));
|
expect_equal("ab", pr_u32(0xab));
|
||||||
|
|
Loading…
Reference in a new issue