at 21.11-pre 10 kB view raw
1{ config, lib, pkgs, utils, ... }: 2 3with lib; 4 5let 6 package = if cfg.allowAuxiliaryImperativeNetworks 7 then pkgs.wpa_supplicant_ro_ssids 8 else pkgs.wpa_supplicant; 9 10 cfg = config.networking.wireless; 11 configFile = if cfg.networks != {} || cfg.extraConfig != "" || cfg.userControlled.enable then pkgs.writeText "wpa_supplicant.conf" '' 12 ${optionalString cfg.userControlled.enable '' 13 ctrl_interface=DIR=/run/wpa_supplicant GROUP=${cfg.userControlled.group} 14 update_config=1''} 15 ${cfg.extraConfig} 16 ${concatStringsSep "\n" (mapAttrsToList (ssid: config: with config; let 17 key = if psk != null 18 then ''"${psk}"'' 19 else pskRaw; 20 baseAuth = if key != null 21 then "psk=${key}" 22 else "key_mgmt=NONE"; 23 in '' 24 network={ 25 ssid="${ssid}" 26 ${optionalString (priority != null) ''priority=${toString priority}''} 27 ${optionalString hidden "scan_ssid=1"} 28 ${if (auth != null) then auth else baseAuth} 29 ${extraConfig} 30 } 31 '') cfg.networks)} 32 '' else "/etc/wpa_supplicant.conf"; 33in { 34 options = { 35 networking.wireless = { 36 enable = mkEnableOption "wpa_supplicant"; 37 38 interfaces = mkOption { 39 type = types.listOf types.str; 40 default = []; 41 example = [ "wlan0" "wlan1" ]; 42 description = '' 43 The interfaces <command>wpa_supplicant</command> will use. If empty, it will 44 automatically use all wireless interfaces. 45 ''; 46 }; 47 48 driver = mkOption { 49 type = types.str; 50 default = "nl80211,wext"; 51 description = "Force a specific wpa_supplicant driver."; 52 }; 53 54 allowAuxiliaryImperativeNetworks = mkEnableOption "support for imperative & declarative networks" // { 55 description = '' 56 Whether to allow configuring networks "imperatively" (e.g. via 57 <package>wpa_supplicant_gui</package>) and declaratively via 58 <xref linkend="opt-networking.wireless.networks" />. 59 60 Please note that this adds a custom patch to <package>wpa_supplicant</package>. 61 ''; 62 }; 63 64 networks = mkOption { 65 type = types.attrsOf (types.submodule { 66 options = { 67 psk = mkOption { 68 type = types.nullOr types.str; 69 default = null; 70 description = '' 71 The network's pre-shared key in plaintext defaulting 72 to being a network without any authentication. 73 74 Be aware that these will be written to the nix store 75 in plaintext! 76 77 Mutually exclusive with <varname>pskRaw</varname>. 78 ''; 79 }; 80 81 pskRaw = mkOption { 82 type = types.nullOr types.str; 83 default = null; 84 description = '' 85 The network's pre-shared key in hex defaulting 86 to being a network without any authentication. 87 88 Mutually exclusive with <varname>psk</varname>. 89 ''; 90 }; 91 92 auth = mkOption { 93 type = types.nullOr types.str; 94 default = null; 95 example = '' 96 key_mgmt=WPA-EAP 97 eap=PEAP 98 identity="user@example.com" 99 password="secret" 100 ''; 101 description = '' 102 Use this option to configure advanced authentication methods like EAP. 103 See 104 <citerefentry> 105 <refentrytitle>wpa_supplicant.conf</refentrytitle> 106 <manvolnum>5</manvolnum> 107 </citerefentry> 108 for example configurations. 109 110 Mutually exclusive with <varname>psk</varname> and <varname>pskRaw</varname>. 111 ''; 112 }; 113 114 hidden = mkOption { 115 type = types.bool; 116 default = false; 117 description = '' 118 Set this to <literal>true</literal> if the SSID of the network is hidden. 119 ''; 120 example = literalExample '' 121 { echelon = { 122 hidden = true; 123 psk = "abcdefgh"; 124 }; 125 } 126 ''; 127 }; 128 129 priority = mkOption { 130 type = types.nullOr types.int; 131 default = null; 132 description = '' 133 By default, all networks will get same priority group (0). If some of the 134 networks are more desirable, this field can be used to change the order in 135 which wpa_supplicant goes through the networks when selecting a BSS. The 136 priority groups will be iterated in decreasing priority (i.e., the larger the 137 priority value, the sooner the network is matched against the scan results). 138 Within each priority group, networks will be selected based on security 139 policy, signal strength, etc. 140 ''; 141 }; 142 143 extraConfig = mkOption { 144 type = types.str; 145 default = ""; 146 example = '' 147 bssid_blacklist=02:11:22:33:44:55 02:22:aa:44:55:66 148 ''; 149 description = '' 150 Extra configuration lines appended to the network block. 151 See 152 <citerefentry> 153 <refentrytitle>wpa_supplicant.conf</refentrytitle> 154 <manvolnum>5</manvolnum> 155 </citerefentry> 156 for available options. 157 ''; 158 }; 159 160 }; 161 }); 162 description = '' 163 The network definitions to automatically connect to when 164 <command>wpa_supplicant</command> is running. If this 165 parameter is left empty wpa_supplicant will use 166 /etc/wpa_supplicant.conf as the configuration file. 167 ''; 168 default = {}; 169 example = literalExample '' 170 { echelon = { # SSID with no spaces or special characters 171 psk = "abcdefgh"; 172 }; 173 "echelon's AP" = { # SSID with spaces and/or special characters 174 psk = "ijklmnop"; 175 }; 176 "free.wifi" = {}; # Public wireless network 177 } 178 ''; 179 }; 180 181 userControlled = { 182 enable = mkOption { 183 type = types.bool; 184 default = false; 185 description = '' 186 Allow normal users to control wpa_supplicant through wpa_gui or wpa_cli. 187 This is useful for laptop users that switch networks a lot and don't want 188 to depend on a large package such as NetworkManager just to pick nearby 189 access points. 190 191 When using a declarative network specification you cannot persist any 192 settings via wpa_gui or wpa_cli. 193 ''; 194 }; 195 196 group = mkOption { 197 type = types.str; 198 default = "wheel"; 199 example = "network"; 200 description = "Members of this group can control wpa_supplicant."; 201 }; 202 }; 203 extraConfig = mkOption { 204 type = types.str; 205 default = ""; 206 example = '' 207 p2p_disabled=1 208 ''; 209 description = '' 210 Extra lines appended to the configuration file. 211 See 212 <citerefentry> 213 <refentrytitle>wpa_supplicant.conf</refentrytitle> 214 <manvolnum>5</manvolnum> 215 </citerefentry> 216 for available options. 217 ''; 218 }; 219 }; 220 }; 221 222 config = mkIf cfg.enable { 223 assertions = flip mapAttrsToList cfg.networks (name: cfg: { 224 assertion = with cfg; count (x: x != null) [ psk pskRaw auth ] <= 1; 225 message = ''options networking.wireless."${name}".{psk,pskRaw,auth} are mutually exclusive''; 226 }); 227 228 environment.systemPackages = [ package ]; 229 230 services.dbus.packages = [ package ]; 231 services.udev.packages = [ pkgs.crda ]; 232 233 # FIXME: start a separate wpa_supplicant instance per interface. 234 systemd.services.wpa_supplicant = let 235 ifaces = cfg.interfaces; 236 deviceUnit = interface: [ "sys-subsystem-net-devices-${utils.escapeSystemdPath interface}.device" ]; 237 in { 238 description = "WPA Supplicant"; 239 240 after = lib.concatMap deviceUnit ifaces; 241 before = [ "network.target" ]; 242 wants = [ "network.target" ]; 243 requires = lib.concatMap deviceUnit ifaces; 244 wantedBy = [ "multi-user.target" ]; 245 stopIfChanged = false; 246 247 path = [ package ]; 248 249 script = let 250 configStr = if cfg.allowAuxiliaryImperativeNetworks 251 then "-c /etc/wpa_supplicant.conf -I ${configFile}" 252 else "-c ${configFile}"; 253 in '' 254 if [ -f /etc/wpa_supplicant.conf -a "/etc/wpa_supplicant.conf" != "${configFile}" ] 255 then echo >&2 "<3>/etc/wpa_supplicant.conf present but ignored. Generated ${configFile} is used instead." 256 fi 257 iface_args="-s -u -D${cfg.driver} ${configStr}" 258 ${if ifaces == [] then '' 259 for i in $(cd /sys/class/net && echo *); do 260 DEVTYPE= 261 UEVENT_PATH=/sys/class/net/$i/uevent 262 if [ -e "$UEVENT_PATH" ]; then 263 source "$UEVENT_PATH" 264 if [ "$DEVTYPE" = "wlan" -o -e /sys/class/net/$i/wireless ]; then 265 args+="''${args:+ -N} -i$i $iface_args" 266 fi 267 fi 268 done 269 '' else '' 270 args="${concatMapStringsSep " -N " (i: "-i${i} $iface_args") ifaces}" 271 ''} 272 exec wpa_supplicant $args 273 ''; 274 }; 275 276 powerManagement.resumeCommands = '' 277 /run/current-system/systemd/bin/systemctl try-restart wpa_supplicant 278 ''; 279 280 # Restart wpa_supplicant when a wlan device appears or disappears. 281 services.udev.extraRules = '' 282 ACTION=="add|remove", SUBSYSTEM=="net", ENV{DEVTYPE}=="wlan", RUN+="/run/current-system/systemd/bin/systemctl try-restart wpa_supplicant.service" 283 ''; 284 }; 285 286 meta.maintainers = with lib.maintainers; [ globin ]; 287}