at 25.11-pre 6.5 kB view raw
1{ 2 config, 3 lib, 4 pkgs, 5 ... 6}: 7 8let 9 inherit (lib.modules) mkIf mkMerge; 10 inherit (lib.options) mkOption mkPackageOption mkEnableOption; 11 inherit (lib.lists) optional optionals; 12 inherit (lib.strings) 13 hasSuffix 14 escapeShellArgs 15 ; 16 inherit (lib) types; 17 cfg = config.services.vwifi; 18in 19{ 20 options = { 21 services.vwifi = 22 let 23 mkOptionalPort = 24 name: 25 mkOption { 26 description = '' 27 The ${name} port. Set to null if we should leave it unset. 28 ''; 29 type = with types; nullOr port; 30 default = null; 31 }; 32 in 33 { 34 package = mkPackageOption pkgs "vwifi" { }; 35 module = { 36 enable = mkEnableOption "mac80211_hwsim module"; 37 numRadios = mkOption { 38 description = "The number of virtual radio interfaces to create."; 39 type = types.int; 40 default = 1; 41 }; 42 macPrefix = mkOption { 43 description = '' 44 The prefix for MAC addresses to use, without the trailing ':'. 45 If one radio is created, you can specify the whole MAC address here. 46 The default is defined in vwifi/src/config.h. 47 ''; 48 type = types.strMatching "^(([0-9A-Fa-f]{2}:){0,5}[0-9A-Fa-f]{2})$"; 49 default = "74:F8:F6"; 50 }; 51 }; 52 client = { 53 enable = mkEnableOption "vwifi client"; 54 spy = mkEnableOption "spy mode, useful for wireless monitors"; 55 serverAddress = mkOption { 56 description = '' 57 The address of the server. If set to null, will try to use the vsock protocol. 58 Note that this assumes that the server is spawned on the host and passed through to 59 QEMU, with something like: 60 61 -device vhost-vsock-pci,id=vwifi0,guest-cid=42 62 ''; 63 type = with types; nullOr str; 64 default = null; 65 }; 66 serverPort = mkOptionalPort "server port"; 67 extraArgs = mkOption { 68 description = '' 69 Extra arguments to pass to vwifi-client. You can use this if you want to bring 70 the radios up using vwifi-client instead of at boot. 71 ''; 72 type = with types; listOf str; 73 default = [ ]; 74 example = [ 75 "--number" 76 "3" 77 ]; 78 }; 79 }; 80 server = { 81 enable = mkEnableOption "vwifi server"; 82 vsock.enable = mkEnableOption "vsock kernel module"; 83 ports = { 84 vhost = mkOptionalPort "vhost"; 85 tcp = mkOptionalPort "TCP server"; 86 spy = mkOptionalPort "spy interface"; 87 control = mkOptionalPort "control interface"; 88 }; 89 openFirewall = mkEnableOption "opening the firewall for the TCP and spy ports"; 90 extraArgs = mkOption { 91 description = '' 92 Extra arguments to pass to vwifi-server. You can use this for things including 93 changing the ports or inducing packet loss. 94 ''; 95 type = with types; listOf str; 96 default = [ ]; 97 example = [ "--lost-packets" ]; 98 }; 99 }; 100 }; 101 }; 102 103 config = mkMerge [ 104 (mkIf cfg.module.enable { 105 boot.kernelModules = [ 106 "mac80211_hwsim" 107 ]; 108 boot.extraModprobeConfig = '' 109 # We'll add more radios using vwifi-add-interfaces in the systemd unit. 110 options mac80211_hwsim radios=0 111 ''; 112 systemd.services.vwifi-add-interfaces = mkIf (cfg.module.numRadios > 0) { 113 description = "vwifi interface bringup"; 114 wantedBy = [ "network-pre.target" ]; 115 serviceConfig = { 116 Type = "oneshot"; 117 ExecStart = 118 let 119 args = [ 120 (toString cfg.module.numRadios) 121 cfg.module.macPrefix 122 ]; 123 in 124 "${cfg.package}/bin/vwifi-add-interfaces ${escapeShellArgs args}"; 125 }; 126 }; 127 assertions = [ 128 { 129 assertion = !(hasSuffix ":" cfg.module.macPrefix); 130 message = '' 131 services.vwifi.module.macPrefix should not have a trailing ":". 132 ''; 133 } 134 ]; 135 }) 136 (mkIf cfg.client.enable { 137 systemd.services.vwifi-client = 138 let 139 clientArgs = 140 optional cfg.client.spy "--spy" 141 ++ optional (cfg.client.serverAddress != null) cfg.client.serverAddress 142 ++ optionals (cfg.client.serverPort != null) [ 143 "--port" 144 cfg.client.serverPort 145 ] 146 ++ cfg.client.extraArgs; 147 in 148 rec { 149 description = "vwifi client"; 150 wantedBy = [ "multi-user.target" ]; 151 after = [ "network.target" ]; 152 requires = after; 153 serviceConfig = { 154 ExecStart = "${cfg.package}/bin/vwifi-client ${escapeShellArgs clientArgs}"; 155 }; 156 }; 157 }) 158 (mkIf cfg.server.enable { 159 boot.kernelModules = mkIf cfg.server.vsock.enable [ 160 "vhost_vsock" 161 ]; 162 networking.firewall.allowedTCPPorts = mkIf cfg.server.openFirewall ( 163 optional (cfg.server.ports.tcp != null) cfg.server.ports.tcp 164 ++ optional (cfg.server.ports.spy != null) cfg.server.ports.spy 165 ); 166 systemd.services.vwifi-server = 167 let 168 serverArgs = 169 optionals (cfg.server.ports.vhost != null) [ 170 "--port-vhost" 171 (toString cfg.server.ports.vhost) 172 ] 173 ++ optionals (cfg.server.ports.tcp != null) [ 174 "--port-tcp" 175 (toString cfg.server.ports.tcp) 176 ] 177 ++ optionals (cfg.server.ports.spy != null) [ 178 "--port-spy" 179 (toString cfg.server.ports.spy) 180 ] 181 ++ optionals (cfg.server.ports.control != null) [ 182 "--port-ctrl" 183 (toString cfg.server.ports.control) 184 ] 185 ++ cfg.server.extraArgs; 186 in 187 rec { 188 description = "vwifi server"; 189 wantedBy = [ "multi-user.target" ]; 190 after = [ "network.target" ]; 191 requires = after; 192 serviceConfig = { 193 ExecStart = "${cfg.package}/bin/vwifi-server ${escapeShellArgs serverArgs}"; 194 }; 195 }; 196 }) 197 ]; 198 199 meta.maintainers = with lib.maintainers; [ numinit ]; 200}