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