commit da8866a01a71c1297f817d20e2dc5b26b4df67bf
parent 8cff11d0a37020f80ac4a69f86c29b53f940e664
Author: Daniel Barlow <dan@telent.net>
Date: Sat, 1 Oct 2022 18:53:20 +0100
first pass at a hostapd service, rough around the edges
Diffstat:
5 files changed, 129 insertions(+), 0 deletions(-)
diff --git a/pkgs/liminix-tools/networking/default.nix b/pkgs/liminix-tools/networking/default.nix
@@ -28,6 +28,7 @@ in {
};
pppoe = callPackage ./pppoe.nix {};
dnsmasq = callPackage ./dnsmasq.nix {};
+ hostapd = callPackage ./hostapd.nix {};
route = { name, target, via, dependencies }:
oneshot {
inherit name;
diff --git a/pkgs/liminix-tools/networking/hostapd.nix b/pkgs/liminix-tools/networking/hostapd.nix
@@ -0,0 +1,39 @@
+# This is not a friendly interface to configuring a wireless AP: it
+# just passes everything straight through to the hostapd config. When
+# we've worked out what the sensible options are to expose, we'll add
+# them as top-level attributes and rename params to extraParams
+
+{
+ liminix
+, hostapd
+, lib
+, writeText
+}:
+interface:
+{
+ params ? {}
+}:
+let
+ inherit (liminix.services) longrun;
+ inherit (lib) concatStringsSep mapAttrsToList;
+ inherit (builtins) toString;
+
+ name = "${interface.device}.hostapd";
+ defaults = {
+ driver = "nl80211";
+ logger_syslog = "-1";
+ logger_syslog_level = 1;
+ ctrl_interface = "/run/hostapd";
+ ctrl_interface_group = 0;
+ };
+
+ conf = writeText "hostapd.conf"
+ (concatStringsSep
+ "\n"
+ (mapAttrsToList
+ (name: value: "${name}=${toString value}")
+ (defaults // params)));
+in longrun {
+ inherit name;
+ run = "${hostapd}/bin/hostapd -d -i ${interface.device} -P /run/hostapd.pid -S ${conf}";
+}
diff --git a/tests/wlan/configuration.nix b/tests/wlan/configuration.nix
@@ -0,0 +1,43 @@
+{ config, pkgs, lib, ... } :
+let
+ inherit (pkgs.liminix.networking) interface address hostapd route dnsmasq;
+ inherit (pkgs.liminix.services) oneshot longrun bundle target output;
+in rec {
+ services.loopback =
+ let iface = interface { type = "loopback"; device = "lo";};
+ in bundle {
+ name = "loopback";
+ contents = [
+ (address iface { family = "inet4"; address ="127.0.0.1"; prefixLength = 8;})
+ (address iface { family = "inet6"; address ="::1"; prefixLength = 128;})
+ ];
+ };
+
+ services.wlan = interface { type = "hardware"; device = "wlan0"; };
+
+ services.hostap = hostapd (services.wlan) {
+ params = {
+ ssid = "liminix";
+ country_code = "GB";
+ hw_mode="g";
+ channel = "2";
+ wmm_enabled = 1;
+ ieee80211n = 1;
+ wpa_passphrase = "colourless green ideas";
+ auth_algs = 1; # 1=wpa2, 2=wep, 3=both
+ wpa = 2; # 1=wpa, 2=wpa2, 3=both
+ wpa_key_mgmt = "WPA-PSK";
+ wpa_pairwise = "TKIP CCMP"; # auth for wpa (may not need this?)
+ rsn_pairwise = "CCMP"; # auth for wpa2
+ };
+ };
+
+ services.default = target {
+ name = "default";
+ contents = with services; [
+ loopback
+ hostap
+ ];
+ };
+ defaultProfile.packages = with pkgs; [ tcpdump ] ;
+}
diff --git a/tests/wlan/run.sh b/tests/wlan/run.sh
@@ -0,0 +1,25 @@
+#!/usr/bin/env sh
+
+cleanup(){
+ if test -e foo.pid && test -d /proc/`cat foo.pid` ; then
+ echo "killing qemu"
+ kill `cat foo.pid`
+ fi
+}
+trap cleanup EXIT
+fatal(){
+ err=$?
+ echo "FAIL: command $(eval echo $BASH_COMMAND) exited with code $err"
+ exit $err
+}
+trap fatal ERR
+
+NIXPKGS_ALLOW_UNSUPPORTED_SYSTEM=1 nix-build '<liminix>' -I liminix-config=./configuration.nix --arg device "import <liminix/devices/qemu.nix>" -A outputs.default $*
+
+
+
+../../scripts/run-qemu.sh \
+ --background foo.sock \
+ result/vmlinux result/squashfs \
+
+nix-shell -p expect --run "expect wait-for-wlan.expect"
diff --git a/tests/wlan/wait-for-wlan.expect b/tests/wlan/wait-for-wlan.expect
@@ -0,0 +1,21 @@
+set timeout 60
+
+spawn socat unix-connect:foo.sock -
+send "\r\n"
+expect "login:" { send "root\r\n" }
+expect "/ #"
+set FINISHED 0
+set EXIT "1"
+send "ls -l /run/uncaught-logs/current\r\n"
+expect "/ #"
+while { $FINISHED < 10 } {
+ send "grep AP-ENABLED /run/uncaught-logs/current || echo not\r\n"
+
+ expect {
+ "wlan0: AP-ENABLED" { set FINISHED 10; set EXIT 0; }
+ "not" { send_user "waiting ..." ; sleep 5 }
+ }
+ set FINISHED [ expr $FINISHED + 1 ]
+}
+
+exit $EXIT