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