]> git.ipfire.org Git - people/ms/network.git/blob - src/hooks/ports/wireless-ap
wireless-ap: Add support for WPA3 and rewrite WPA2
[people/ms/network.git] / src / hooks / ports / wireless-ap
1 #!/bin/bash
2 ###############################################################################
3 # #
4 # IPFire.org - A linux based firewall #
5 # Copyright (C) 2010 Michael Tremer & Christian Schmidt #
6 # #
7 # This program is free software: you can redistribute it and/or modify #
8 # it under the terms of the GNU General Public License as published by #
9 # the Free Software Foundation, either version 3 of the License, or #
10 # (at your option) any later version. #
11 # #
12 # This program is distributed in the hope that it will be useful, #
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
15 # GNU General Public License for more details. #
16 # #
17 # You should have received a copy of the GNU General Public License #
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
19 # #
20 ###############################################################################
21
22 . /usr/lib/network/header-port
23
24 HOOK_PORT_PATTERN="${PORT_PATTERN_ACCESSPOINT}"
25
26 HOOK_SETTINGS=(
27 "ADDRESS"
28 "BROADCAST_SSID"
29 "CHANNEL"
30 "CHANNEL_BANDWIDTH"
31 "DFS"
32 "ENVIRONMENT"
33 "MFP"
34 "MODE"
35 "PHY"
36 "SECRET"
37 "SSID"
38 "WPA3_PERSONAL"
39 "WPA2_PERSONAL"
40 )
41
42 # Disable WPA3+2 by default
43 DEFAULT_WPA3_PERSONAL="off"
44 DEFAULT_WPA2_PERSONAL="off"
45
46 # Broadcast SSID by default
47 DEFAULT_BROADCAST_SSID="on"
48
49 # Perform radar detection by default when possible
50 DEFAULT_DFS="on"
51
52 # 802.11w - Management Frame Protection
53 # Disable by default because many clients cannot connect when enabled
54 DEFAULT_MFP="off"
55
56 DEFAULT_ENVIRONMENT="${WIRELESS_DEFAULT_ENVIRONMENT}"
57
58 hook_check_settings() {
59 assert isset ADDRESS
60 assert ismac ADDRESS
61 assert isset BROADCAST_SSID
62 assert isbool BROADCAST_SSID
63 assert isset CHANNEL
64 assert isbool DFS
65 assert isbool MFP
66 assert isset MODE
67 assert isoneof MODE ${HOSTAPD_SUPPORTED_MODES}
68 assert isset PHY
69 assert ismac PHY
70 assert isset SSID
71
72 assert wireless_environment_is_valid "${ENVIRONMENT}"
73 }
74
75 hook_parse_cmdline() {
76 while [ $# -gt 0 ]; do
77 case "${1}" in
78 --broadcast-ssid=*)
79 BROADCAST_SSID=$(cli_get_val "${1}")
80 ;;
81 --channel=*)
82 CHANNEL=$(cli_get_val "${1}")
83 ;;
84 --channel-bandwidth=*)
85 CHANNEL_BANDWIDTH="$(cli_get_val "${1}")"
86 ;;
87 --dfs=*)
88 DFS="$(cli_get_val "${1}")"
89
90 if enabled DFS; then
91 DFS="on"
92 elif disabled DFS; then
93 DFS="off"
94 else
95 error "Invalid value for DFS: ${DFS}"
96 return ${EXIT_ERROR}
97 fi
98 ;;
99 --environment=*)
100 ENVIRONMENT="$(cli_get_val "${1}")"
101
102 if ! wireless_environment_is_valid "${ENVIRONMENT}"; then
103 error "Invalid wireless environment: ${ENVIRONMENT}"
104 return ${EXIT_ERROR}
105 fi
106 ;;
107 --mac=*)
108 ADDRESS=$(cli_get_val "${1}")
109 ;;
110 --mfp=*)
111 MFP="$(cli_get_val "${1}")"
112
113 if enabled MFP; then
114 MFP="on"
115 elif disabled MFP; then
116 MFP="off"
117 else
118 error "Invalid value for --mfp: ${MFP}"
119 return ${EXIT_ERROR}
120 fi
121 ;;
122 --mode=*)
123 MODE=$(cli_get_val "${1}")
124
125 if ! isoneof MODE ${HOSTAPD_SUPPORTED_MODES}; then
126 error "Unsupported mode: ${MODE}"
127 error "Mode must be one of ${HOSTAPD_SUPPORTED_MODES}"
128 return ${EXIT_ERROR}
129 fi
130 ;;
131 --phy=*)
132 PHY=$(cli_get_val "${1}")
133 ;;
134 --secret=*)
135 SECRET="$(cli_get_val "${1}")"
136 ;;
137 --ssid=*)
138 SSID=$(cli_get_val "${1}")
139 ;;
140 --wpa2-personal=*)
141 WPA2_PERSONAL="$(cli_get_bool "${1}")"
142 ;;
143 --wpa3-personal=*)
144 WPA3_PERSONAL="$(cli_get_bool "${1}")"
145 ;;
146 *)
147 warning "Ignoring unknown argument '${1}'"
148 ;;
149 esac
150 shift
151 done
152
153 # Generate a random MAC address if none is set
154 if ! isset ADDRESS; then
155 ADDRESS="$(mac_generate)"
156 fi
157
158 # MODE must be set
159 if ! isset MODE; then
160 error "--mode is not set"
161 return ${EXIT_ERROR}
162 fi
163
164 # Automatically enable ACS if no channel is set and ACS is available
165 if ! isset CHANNEL && phy_supports_acs "${PHY}"; then
166 CHANNEL="0"
167
168 log INFO "Automatic Channel Selection (ACS) enabled"
169 fi
170
171 # Channel bandwidth must match the mode
172 if isset CHANNEL_BANDWIDTH && ! wireless_channel_bandwidth_is_valid "${MODE}" "${CHANNEL_BANDWIDTH}"; then
173 error "Channel Bandwidth '${CHANNEL_BANDWIDTH}' is not supported for ${MODE}"
174 return ${EXIT_ERROR}
175 fi
176
177 # Check if SECRET is set when WPA* is enabled
178 if ! isset SECRET && (enabled WPA3_PERSONAL || enabled WPA2_PERSONAL); then
179 error "Secret is not set when PSK authentication is enabled"
180 return ${EXIT_ERROR}
181 fi
182
183 # Save address of phy do identify it again
184 PHY=$(phy_get ${PHY})
185 PHY=$(phy_get_address ${PHY})
186 }
187
188 hook_edit() {
189 local port=${1}
190 assert isset port
191
192 if ! hook_default_edit "$@"; then
193 return ${EXIT_ERROR}
194 fi
195
196 # To apply all changes, we need to restart the port
197 port_restart "${port}"
198 }
199
200 hook_create() {
201 local port="${1}"
202 assert isset port
203
204 device_exists "${port}" && exit ${EXIT_OK}
205
206 port_settings_read "${port}"
207
208 # Check if the PHY is present.
209 local phy=$(phy_get ${PHY})
210 if ! isset phy; then
211 log DEBUG "phy '${PHY}' is not present"
212 exit ${EXIT_ERROR}
213 fi
214
215 # Create the wireless device
216 wireless_create "${port}" \
217 --phy="${phy}" \
218 --type="ap" \
219 --address="${ADDRESS}"
220
221 exit ${EXIT_OK}
222 }
223
224 hook_remove() {
225 local port="${1}"
226 assert isset port
227
228 # Remove the device if present
229 if device_exists "${port}"; then
230 wireless_remove "${port}"
231 fi
232
233 exit ${EXIT_OK}
234 }
235
236 hook_up() {
237 local port="${1}"
238 assert isset port
239
240 # The port must already exist before
241 # hostapd is started. Otherwise it will
242 # fail horribly over and over again.
243 assert device_exists "${port}"
244
245 hostapd_start "${port}"
246 }
247
248 hook_down() {
249 local port="${1}"
250 assert isset port
251
252 hostapd_stop "${port}"
253 }
254
255 hook_hotplug() {
256 local port="${1}"
257 assert isset port
258
259 case "$(hotplug_action)" in
260 add)
261 # Create the port when the phy is plugged in
262 if hotplug_event_port_uses_phy "${port}"; then
263 hook_create "${port}"
264 fi
265 ;;
266
267 remove)
268 # Stop hostapd
269 if hotplug_event_port_is_interface "${port}"; then
270 hostapd_stop "${port}"
271
272 exit ${EXIT_OK}
273 fi
274 ;;
275 esac
276
277 exit ${EXIT_NOT_HANDLED}
278 }