From 1da6186814c94512c1cbc41f2dfd3b4ac7b2e44f Mon Sep 17 00:00:00 2001 From: tv Date: Wed, 18 Jan 2023 17:14:27 +0100 Subject: tv.wwan: init --- tv/3modules/wwan.nix | 163 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100644 tv/3modules/wwan.nix (limited to 'tv/3modules/wwan.nix') diff --git a/tv/3modules/wwan.nix b/tv/3modules/wwan.nix new file mode 100644 index 000000000..703a903c9 --- /dev/null +++ b/tv/3modules/wwan.nix @@ -0,0 +1,163 @@ +with import ./lib; +{ config, pkgs, ... }: { + options = { + tv.wwan.enable = mkEnableOption "tv.wwan"; + tv.wwan.apn = mkOption { + type = with types; filename; + }; + tv.wwan.device = mkOption { + type = with types; pathname; + default = "/dev/cdc-wdm0"; + }; + tv.wwan.interface = mkOption { + type = with types; nullOr filename; + default = null; + }; + tv.wwan.operators = mkOption { + type = with types; listOf username; + default = []; + }; + tv.wwan.secrets = mkOption { + type = with types; pathname; + default = toString ; + # format: {"pin1":number} + }; + }; + config = let + cfg = config.tv.wwan; + in mkIf cfg.enable { + systemd.services.wwan = { + environment = { + DEVICE = cfg.device; + SECRETS = "%d/secrets"; + }; + path = [ + pkgs.busybox + pkgs.coreutils + pkgs.iproute2 + pkgs.jq + (pkgs.symlinkJoin { + name = "uqmi-wrapper"; + paths = [ + (pkgs.writeDashBin "uqmi" '' + set -efu + exec ${pkgs.uqmi}/bin/uqmi --device="$DEVICE" "$@" + '') + pkgs.uqmi + ]; + }) + (pkgs.writeDashBin "get-interface" ( + if cfg.interface != null then /* sh */ '' + echo ${cfg.interface} + '' else /* sh */ '' + exec ${pkgs.libqmi}/bin/qmicli -d "$DEVICE" -p --get-wwan-iface + '' + )) + ]; + serviceConfig = { + LoadCredential = [ + "secrets:${cfg.secrets}" + ]; + Type = "oneshot"; + RemainAfterExit = true; + SyslogIdentifier = "wwan"; + ExecStart = pkgs.writeDash "tv.wwan.start.sh" '' + set -efu + + interface=$(get-interface) + + pin1_status=$( + uqmi --uim-get-sim-state | + jq -r '"\(.pin1_status)/\(.pin1_verify_tries)"' + ) + case $pin1_status in + verified/*) + : + ;; + not_verified/3) + pin1=$(jq .pin1 "$SECRETS") + echo "verifying PIN1" >&2 + if ! uqmi --uim-verify-pin1 "$pin1"; then + echo "error: failed to verify PIN1" >&2 + exit 1 + fi + ;; + not_verified/*) + echo "error: not trying to verify PIN1: not enough tries left" >&2 + echo \ + "please check your configuration in ${cfg.secrets}" \ + " and verify if manually using:" \ + " ${pkgs.uqmi}/bin/uqmi -d $device --uim-veriy-pin1 XXXX" \ + >&2 + exit 1 + esac + + raw_ip_path=/sys/class/net/$interface/qmi/raw_ip + raw_ip=$(cat "$raw_ip_path") + if [ "$raw_ip" != Y ]; then + echo "enabling raw-ip" >&2 + if ! echo Y > "$raw_ip_path"; then + echo "error: failed to enable raw-ip" >&2 + exit 1 + fi + fi + + operating_mode=$(uqmi --get-device-operating-mode | tr -d \") + case $operating_mode in + online) + : + ;; + persistent_low_power|low_power) + echo "settings device operating mode to online" >&2 + uqmi --set-device-operating-mode online + operating_mode=$(uqmi --get-device-operating-mode | tr -d \") + if test "$operating_mode" != online; then + echo "error: failed to set device operating mode to online" >&2 + exit 1 + fi + ;; + *) + echo "error: don't know how to change device operating mode to online: $operating_mode" >&2 + exit 1 + esac + + ip link set dev "$interface" up + + data_status=$(uqmi --get-data-status | tr -d \") + case $data_status in + connected) + : + ;; + disconnected) + echo "starting network (APN=${cfg.apn})" >&2 + sleep 1 + uqmi \ + --start-network \ + --autoconnect \ + --apn ${cfg.apn} \ + --ip-family ipv4 + sleep 1 + ;; + *) + echo "error: unsupported data status: $data_status" >&2 + exit 1 + esac + + udhcpc -q -f -n -i "$interface" + ''; + Restart = "on-failure"; + ExecStop = pkgs.writeDash "tv.wwan.stop.sh" '' + set -efu + + interface=$(get-interface) + + ip link set dev "$interface" down + uqmi --stop-network 0xFFFFFFFF --autoconnect + uqmi --sync + uqmi --set-device-operating-mode persistent_low_power + ''; + }; + }; + tv.systemd.services.wwan.operators = cfg.operators; + }; +} -- cgit v1.2.3 From 3e5c82d968b571fe3ebd03dcef5d7021c277c01e Mon Sep 17 00:00:00 2001 From: tv Date: Thu, 19 Jan 2023 14:07:23 +0100 Subject: tv wwan: make uqmi-wrapper available to root --- tv/3modules/wwan.nix | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) (limited to 'tv/3modules/wwan.nix') diff --git a/tv/3modules/wwan.nix b/tv/3modules/wwan.nix index 703a903c9..a60d314fd 100644 --- a/tv/3modules/wwan.nix +++ b/tv/3modules/wwan.nix @@ -26,9 +26,19 @@ with import ./lib; config = let cfg = config.tv.wwan; in mkIf cfg.enable { + nixpkgs.overlays = singleton (self: super: { + uqmi-wrapper = pkgs.symlinkJoin { + name = "uqmi-wrapper"; + paths = [ + (pkgs.writeDashBin "uqmi" '' + exec ${pkgs.uqmi}/bin/uqmi --device=${cfg.device} "$@" + '') + pkgs.uqmi + ]; + }; + }); systemd.services.wwan = { environment = { - DEVICE = cfg.device; SECRETS = "%d/secrets"; }; path = [ @@ -36,21 +46,12 @@ with import ./lib; pkgs.coreutils pkgs.iproute2 pkgs.jq - (pkgs.symlinkJoin { - name = "uqmi-wrapper"; - paths = [ - (pkgs.writeDashBin "uqmi" '' - set -efu - exec ${pkgs.uqmi}/bin/uqmi --device="$DEVICE" "$@" - '') - pkgs.uqmi - ]; - }) + pkgs.uqmi-wrapper (pkgs.writeDashBin "get-interface" ( if cfg.interface != null then /* sh */ '' echo ${cfg.interface} '' else /* sh */ '' - exec ${pkgs.libqmi}/bin/qmicli -d "$DEVICE" -p --get-wwan-iface + exec ${pkgs.libqmi}/bin/qmicli -d ${cfg.device} -p --get-wwan-iface '' )) ]; @@ -158,6 +159,9 @@ with import ./lib; ''; }; }; + users.users.root.packages = [ + pkgs.uqmi-wrapper + ]; tv.systemd.services.wwan.operators = cfg.operators; }; } -- cgit v1.2.3 From 57abca263fe86259807e5597d1c8f11c3c3acd44 Mon Sep 17 00:00:00 2001 From: tv Date: Thu, 19 Jan 2023 14:08:01 +0100 Subject: tv wwan: add uqmi bash-completion --- tv/3modules/wwan.nix | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'tv/3modules/wwan.nix') diff --git a/tv/3modules/wwan.nix b/tv/3modules/wwan.nix index a60d314fd..03cd512e4 100644 --- a/tv/3modules/wwan.nix +++ b/tv/3modules/wwan.nix @@ -33,6 +33,20 @@ with import ./lib; (pkgs.writeDashBin "uqmi" '' exec ${pkgs.uqmi}/bin/uqmi --device=${cfg.device} "$@" '') + (pkgs.writeTextDir "share/bash-completion/completions/uqmi" /* sh */'' + _uqmi_complete() { + case ''${#COMP_WORDS[@]} in + 2) + COMPREPLY=($(compgen -W "$( + ${pkgs.uqmi}/bin/uqmi --help 2>&1 | + ${pkgs.coreutils}/bin/tr , \\n | + ${pkgs.gnused}/bin/sed -nr 's/^ *(-[a-z-]+).*/\1/p' + )" -- "''${COMP_WORDS[1]}")) + ;; + esac + } + complete -F _uqmi_complete uqmi + '') pkgs.uqmi ]; }; -- cgit v1.2.3