1{ config, lib, pkgs, ... }:
2
3with lib;
4
5let
6
7 cfg = config.networking.wireless;
8 configFile = "/etc/wpa_supplicant.conf";
9
10 ifaces =
11 cfg.interfaces ++
12 optional (config.networking.WLANInterface != "") config.networking.WLANInterface;
13
14in
15
16{
17
18 ###### interface
19
20 options = {
21
22 networking.WLANInterface = mkOption {
23 default = "";
24 description = "Obsolete. Use <option>networking.wireless.interfaces</option> instead.";
25 };
26
27 networking.wireless = {
28 enable = mkOption {
29 type = types.bool;
30 default = false;
31 description = ''
32 Whether to start <command>wpa_supplicant</command> to scan for
33 and associate with wireless networks. Note: NixOS currently
34 does not manage <command>wpa_supplicant</command>'s
35 configuration file, <filename>${configFile}</filename>. You
36 should edit this file yourself to define wireless networks,
37 WPA keys and so on (see
38 <citerefentry><refentrytitle>wpa_supplicant.conf</refentrytitle>
39 <manvolnum>5</manvolnum></citerefentry>), or use
40 networking.wireless.userControlled.* to allow users to add entries
41 through <command>wpa_cli</command> and <command>wpa_gui</command>.
42 '';
43 };
44
45 interfaces = mkOption {
46 type = types.listOf types.str;
47 default = [];
48 example = [ "wlan0" "wlan1" ];
49 description = ''
50 The interfaces <command>wpa_supplicant</command> will use. If empty, it will
51 automatically use all wireless interfaces.
52 '';
53 };
54
55 driver = mkOption {
56 type = types.str;
57 default = "nl80211,wext";
58 description = "Force a specific wpa_supplicant driver.";
59 };
60
61 userControlled = {
62 enable = mkOption {
63 type = types.bool;
64 default = false;
65 description = ''
66 Allow normal users to control wpa_supplicant through wpa_gui or wpa_cli.
67 This is useful for laptop users that switch networks a lot and don't want
68 to depend on a large package such as NetworkManager just to pick nearby
69 access points.
70
71 When you want to use this, make sure ${configFile} doesn't exist.
72 It will be created for you.
73
74 Currently it is also necessary to explicitly specify networking.wireless.interfaces.
75 '';
76 };
77
78 group = mkOption {
79 type = types.str;
80 default = "wheel";
81 example = "network";
82 description = "Members of this group can control wpa_supplicant.";
83 };
84 };
85 };
86 };
87
88
89 ###### implementation
90
91 config = mkIf cfg.enable {
92
93 environment.systemPackages = [ pkgs.wpa_supplicant ];
94
95 services.dbus.packages = [ pkgs.wpa_supplicant ];
96
97 # FIXME: start a separate wpa_supplicant instance per interface.
98 jobs.wpa_supplicant =
99 { description = "WPA Supplicant";
100
101 wantedBy = [ "network.target" ];
102
103 path = [ pkgs.wpa_supplicant ];
104
105 preStart = ''
106 touch -a ${configFile}
107 chmod 600 ${configFile}
108 '' + optionalString cfg.userControlled.enable ''
109 if [ ! -s ${configFile} ]; then
110 echo "ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=${cfg.userControlled.group}" >> ${configFile}
111 echo "update_config=1" >> ${configFile}
112 fi
113 '';
114
115 script =
116 ''
117 ${if ifaces == [] then ''
118 for i in $(cd /sys/class/net && echo *); do
119 DEVTYPE=
120 source /sys/class/net/$i/uevent
121 if [ "$DEVTYPE" = "wlan" -o -e /sys/class/net/$i/wireless ]; then
122 ifaces="$ifaces''${ifaces:+ -N} -i$i"
123 fi
124 done
125 '' else ''
126 ifaces="${concatStringsSep " -N " (map (i: "-i${i}") ifaces)}"
127 ''}
128 exec wpa_supplicant -s -u -D${cfg.driver} -c ${configFile} $ifaces
129 '';
130 };
131
132 powerManagement.resumeCommands =
133 ''
134 ${config.systemd.package}/bin/systemctl try-restart wpa_supplicant
135 '';
136
137 assertions = [{ assertion = !cfg.userControlled.enable || cfg.interfaces != [];
138 message = "user controlled wpa_supplicant needs explicit networking.wireless.interfaces";}];
139
140 # Restart wpa_supplicant when a wlan device appears or disappears.
141 services.udev.extraRules =
142 ''
143 ACTION=="add|remove", SUBSYSTEM=="net", ENV{DEVTYPE}=="wlan", RUN+="${config.systemd.package}/bin/systemctl try-restart wpa_supplicant.service"
144 '';
145
146 };
147
148}