1{ config, lib, pkgs, ... }: 2 3# TODO: 4# 5# asserts 6# ensure that the nl80211 module is loaded/compiled in the kernel 7# wpa_supplicant and hostapd on the same wireless interface doesn't make any sense 8 9with lib; 10 11let 12 13 cfg = config.services.hostapd; 14 15 configFile = pkgs.writeText "hostapd.conf" '' 16 interface=${cfg.interface} 17 driver=${cfg.driver} 18 ssid=${cfg.ssid} 19 hw_mode=${cfg.hwMode} 20 channel=${toString cfg.channel} 21 22 # logging (debug level) 23 logger_syslog=-1 24 logger_syslog_level=2 25 logger_stdout=-1 26 logger_stdout_level=2 27 28 ctrl_interface=/var/run/hostapd 29 ctrl_interface_group=${cfg.group} 30 31 ${if cfg.wpa then '' 32 wpa=1 33 wpa_passphrase=${cfg.wpaPassphrase} 34 '' else ""} 35 36 ${cfg.extraConfig} 37 '' ; 38 39in 40 41{ 42 ###### interface 43 44 options = { 45 46 services.hostapd = { 47 48 enable = mkOption { 49 default = false; 50 description = '' 51 Enable putting a wireless interface into infrastructure mode, 52 allowing other wireless devices to associate with the wireless 53 interface and do wireless networking. A simple access point will 54 <option>enable hostapd.wpa</option>, 55 <option>hostapd.wpaPassphrase</option>, and 56 <option>hostapd.ssid</option>, as well as DHCP on the wireless 57 interface to provide IP addresses to the associated stations, and 58 NAT (from the wireless interface to an upstream interface). 59 ''; 60 }; 61 62 interface = mkOption { 63 default = ""; 64 example = "wlp2s0"; 65 description = '' 66 The interfaces <command>hostapd</command> will use. 67 ''; 68 }; 69 70 driver = mkOption { 71 default = "nl80211"; 72 example = "hostapd"; 73 type = types.string; 74 description = '' 75 Which driver <command>hostapd</command> will use. 76 Most applications will probably use the default. 77 ''; 78 }; 79 80 ssid = mkOption { 81 default = "nixos"; 82 example = "mySpecialSSID"; 83 type = types.string; 84 description = "SSID to be used in IEEE 802.11 management frames."; 85 }; 86 87 hwMode = mkOption { 88 default = "g"; 89 type = types.string; 90 description = '' 91 Operation mode. 92 (a = IEEE 802.11a, b = IEEE 802.11b, g = IEEE 802.11g). 93 ''; 94 }; 95 96 channel = mkOption { 97 default = 7; 98 example = 11; 99 type = types.int; 100 description = '' 101 Channel number (IEEE 802.11) 102 Please note that some drivers do not use this value from 103 <command>hostapd</command> and the channel will need to be configured 104 separately with <command>iwconfig</command>. 105 ''; 106 }; 107 108 group = mkOption { 109 default = "wheel"; 110 example = "network"; 111 type = types.string; 112 description = '' 113 Members of this group can control <command>hostapd</command>. 114 ''; 115 }; 116 117 wpa = mkOption { 118 default = true; 119 description = '' 120 Enable WPA (IEEE 802.11i/D3.0) to authenticate with the access point. 121 ''; 122 }; 123 124 wpaPassphrase = mkOption { 125 default = "my_sekret"; 126 example = "any_64_char_string"; 127 type = types.string; 128 description = '' 129 WPA-PSK (pre-shared-key) passphrase. Clients will need this 130 passphrase to associate with this access point. 131 Warning: This passphrase will get put into a world-readable file in 132 the Nix store! 133 ''; 134 }; 135 136 extraConfig = mkOption { 137 default = ""; 138 example = '' 139 auth_algo=0 140 ieee80211n=1 141 ht_capab=[HT40-][SHORT-GI-40][DSSS_CCK-40] 142 ''; 143 type = types.string; 144 description = "Extra configuration options to put in hostapd.conf."; 145 }; 146 }; 147 }; 148 149 150 ###### implementation 151 152 config = mkIf cfg.enable { 153 154 assertions = [ 155 { assertion = (cfg.hwMode == "a" || cfg.hwMode == "b" || cfg.hwMode == "g"); 156 message = "hwMode must be a/b/g"; 157 } 158 { assertion = (cfg.channel >= 1 && cfg.channel <= 13); 159 message = "channel must be between 1 and 13"; 160 }]; 161 162 environment.systemPackages = [ pkgs.hostapd ]; 163 164 systemd.services.hostapd = 165 { description = "hostapd wireless AP"; 166 167 path = [ pkgs.hostapd ]; 168 wantedBy = [ "network.target" ]; 169 170 after = [ "${cfg.interface}-cfg.service" "nat.service" "bind.service" "dhcpd.service"]; 171 172 serviceConfig = 173 { ExecStart = "${pkgs.hostapd}/bin/hostapd ${configFile}"; 174 Restart = "always"; 175 }; 176 }; 177 }; 178}