CMake: bump the minimum required CMake version to 3.5
[project/netifd.git] / scripts / netifd-wireless.sh
1 NETIFD_MAIN_DIR="${NETIFD_MAIN_DIR:-/lib/netifd}"
2
3 . /usr/share/libubox/jshn.sh
4 . $NETIFD_MAIN_DIR/utils.sh
5
6 CMD_UP=0
7 CMD_SET_DATA=1
8 CMD_PROCESS_ADD=2
9 CMD_PROCESS_KILL_ALL=3
10 CMD_SET_RETRY=4
11
12 add_driver() {
13 return
14 }
15
16 wireless_setup_vif_failed() {
17 local error="$1"
18 echo "Interface $_w_iface setup failed: $error"
19 }
20
21 wireless_setup_failed() {
22 local error="$1"
23
24 echo "Device setup failed: $error"
25 wireless_set_retry 0
26 }
27
28 prepare_key_wep() {
29 local key="$1"
30 local hex=1
31
32 echo -n "$key" | grep -qE "[^a-fA-F0-9]" && hex=0
33 [ "${#key}" -eq 10 -a $hex -eq 1 ] || \
34 [ "${#key}" -eq 26 -a $hex -eq 1 ] || {
35 [ "${key:0:2}" = "s:" ] && key="${key#s:}"
36 key="$(echo -n "$key" | hexdump -ve '1/1 "%02x" ""')"
37 }
38 echo "$key"
39 }
40
41 _wdev_prepare_channel() {
42 json_get_vars channel band hwmode
43
44 auto_channel=0
45 enable_ht=0
46 htmode=
47 hwmode="${hwmode##11}"
48
49 case "$channel" in
50 ""|0|auto)
51 channel=0
52 auto_channel=1
53 ;;
54 [0-9]*) ;;
55 *)
56 wireless_setup_failed "INVALID_CHANNEL"
57 ;;
58 esac
59
60 case "$hwmode" in
61 a|b|g|ad) ;;
62 *)
63 if [ "$channel" -gt 14 ]; then
64 hwmode=a
65 else
66 hwmode=g
67 fi
68 ;;
69 esac
70
71 case "$band" in
72 2g) hwmode=g;;
73 5g|6g) hwmode=a;;
74 60g) hwmode=ad;;
75 *)
76 case "$hwmode" in
77 *a) band=5g;;
78 *ad) band=60g;;
79 *b|*g) band=2g;;
80 esac
81 ;;
82 esac
83 }
84
85 _wdev_handler() {
86 json_load "$data"
87
88 json_select config
89 _wdev_prepare_channel
90 json_select ..
91
92 eval "drv_$1_$2 \"$interface\""
93 }
94
95 _wdev_msg_call() {
96 local old_cb
97
98 json_set_namespace wdev old_cb
99 "$@"
100 json_set_namespace $old_cb
101 }
102
103 _wdev_wrapper() {
104 while [ -n "$1" ]; do
105 eval "$1() { _wdev_msg_call _$1 \"\$@\"; }"
106 shift
107 done
108 }
109
110 _wdev_notify_init() {
111 local command="$1"; shift;
112
113 json_init
114 json_add_int "command" "$command"
115 json_add_string "device" "$__netifd_device"
116 while [ -n "$1" ]; do
117 local name="$1"; shift
118 local value="$1"; shift
119 json_add_string "$name" "$value"
120 done
121 json_add_object "data"
122 }
123
124 _wdev_notify() {
125 local options="$1"
126
127 json_close_object
128 ubus $options call network.wireless notify "$(json_dump)"
129 }
130
131 _wdev_add_variables() {
132 while [ -n "$1" ]; do
133 local var="${1%%=*}"
134 local val="$1"
135 shift
136 [[ "$var" = "$val" ]] && continue
137 val="${val#*=}"
138 json_add_string "$var" "$val"
139 done
140 }
141
142 _wireless_add_vif() {
143 local name="$1"; shift
144 local ifname="$1"; shift
145
146 _wdev_notify_init $CMD_SET_DATA "interface" "$name"
147 json_add_string "ifname" "$ifname"
148 _wdev_add_variables "$@"
149 _wdev_notify
150 }
151
152 _wireless_add_vlan() {
153 local name="$1"; shift
154 local ifname="$1"; shift
155
156 _wdev_notify_init $CMD_SET_DATA interface "$__cur_interface" "vlan" "$name"
157 json_add_string "ifname" "$ifname"
158 _wdev_add_variables "$@"
159 _wdev_notify
160 }
161
162 _wireless_set_up() {
163 _wdev_notify_init $CMD_UP
164 _wdev_notify
165 }
166
167 _wireless_set_data() {
168 _wdev_notify_init $CMD_SET_DATA
169 _wdev_add_variables "$@"
170 _wdev_notify
171 }
172
173 _wireless_add_process() {
174 _wdev_notify_init $CMD_PROCESS_ADD
175 local exe="$2"
176 [ -L "$exe" ] && exe="$(readlink -f "$exe")"
177 json_add_int pid "$1"
178 json_add_string exe "$exe"
179 [ -n "$3" ] && json_add_boolean required 1
180 [ -n "$4" ] && json_add_boolean keep 1
181 exe2="$(readlink -f /proc/$1/exe)"
182 [ "$exe" != "$exe2" ] && echo "WARNING (wireless_add_process): executable path $exe does not match process $1 path ($exe2)"
183 _wdev_notify
184 }
185
186 _wireless_process_kill_all() {
187 _wdev_notify_init $CMD_PROCESS_KILL_ALL
188 [ -n "$1" ] && json_add_int signal "$1"
189 _wdev_notify
190 }
191
192 _wireless_set_retry() {
193 _wdev_notify_init $CMD_SET_RETRY
194 json_add_int retry "$1"
195 _wdev_notify
196 }
197
198 _wdev_wrapper \
199 wireless_add_vif \
200 wireless_add_vlan \
201 wireless_set_up \
202 wireless_set_data \
203 wireless_add_process \
204 wireless_process_kill_all \
205 wireless_set_retry \
206
207 wireless_vif_parse_encryption() {
208 json_get_vars encryption
209 set_default encryption none
210
211 auth_mode_open=1
212 auth_mode_shared=0
213 auth_type=none
214
215 if [ "$hwmode" = "ad" ]; then
216 wpa_cipher="GCMP"
217 else
218 wpa_cipher="CCMP"
219 fi
220
221 case "$encryption" in
222 *tkip+aes|*tkip+ccmp|*aes+tkip|*ccmp+tkip) wpa_cipher="CCMP TKIP";;
223 *ccmp256) wpa_cipher="CCMP-256";;
224 *aes|*ccmp) wpa_cipher="CCMP";;
225 *tkip) wpa_cipher="TKIP";;
226 *gcmp256) wpa_cipher="GCMP-256";;
227 *gcmp) wpa_cipher="GCMP";;
228 wpa3-192*) wpa_cipher="GCMP-256";;
229 esac
230
231 # 802.11n requires CCMP for WPA
232 [ "$enable_ht:$wpa_cipher" = "1:TKIP" ] && wpa_cipher="CCMP TKIP"
233
234 # Examples:
235 # psk-mixed/tkip => WPA1+2 PSK, TKIP
236 # wpa-psk2/tkip+aes => WPA2 PSK, CCMP+TKIP
237 # wpa2/tkip+aes => WPA2 RADIUS, CCMP+TKIP
238
239 case "$encryption" in
240 wpa2*|wpa3*|*psk2*|psk3*|sae*|owe*)
241 wpa=2
242 ;;
243 wpa*mixed*|*psk*mixed*)
244 wpa=3
245 ;;
246 wpa*|*psk*)
247 wpa=1
248 ;;
249 *)
250 wpa=0
251 wpa_cipher=
252 ;;
253 esac
254 wpa_pairwise="$wpa_cipher"
255
256 case "$encryption" in
257 owe*)
258 auth_type=owe
259 ;;
260 wpa3-192*)
261 auth_type=eap192
262 ;;
263 wpa3-mixed*)
264 auth_type=eap-eap2
265 ;;
266 wpa3*)
267 auth_type=eap2
268 ;;
269 psk3-mixed*|sae-mixed*)
270 auth_type=psk-sae
271 ;;
272 psk3*|sae*)
273 auth_type=sae
274 ;;
275 *psk*)
276 auth_type=psk
277 ;;
278 *wpa*|*8021x*)
279 auth_type=eap
280 ;;
281 *wep*)
282 auth_type=wep
283 case "$encryption" in
284 *shared*)
285 auth_mode_open=0
286 auth_mode_shared=1
287 ;;
288 *mixed*)
289 auth_mode_shared=1
290 ;;
291 esac
292 ;;
293 esac
294
295 case "$encryption" in
296 *osen*)
297 auth_osen=1
298 ;;
299 esac
300 }
301
302 _wireless_set_brsnoop_isolation() {
303 local multicast_to_unicast="$1"
304 local isolate
305
306 json_get_vars isolate proxy_arp
307
308 [ ${isolate:-0} -gt 0 -o -z "$network_bridge" ] && return
309 [ ${multicast_to_unicast:-1} -gt 0 -o ${proxy_arp:-0} -gt 0 ] && json_add_boolean isolate 1
310 }
311
312 for_each_interface() {
313 local _w_types="$1"; shift
314 local _w_ifaces _w_iface
315 local _w_type
316 local _w_found
317
318 local multicast_to_unicast
319
320 json_get_keys _w_ifaces interfaces
321 json_select interfaces
322 for _w_iface in $_w_ifaces; do
323 json_select "$_w_iface"
324 if [ -n "$_w_types" ]; then
325 json_get_var network_bridge bridge
326 json_get_var network_ifname bridge-ifname
327 json_get_var multicast_to_unicast multicast_to_unicast
328 json_select config
329 _wireless_set_brsnoop_isolation "$multicast_to_unicast"
330 json_get_var _w_type mode
331 json_select ..
332 _w_types=" $_w_types "
333 [[ "${_w_types%$_w_type*}" = "$_w_types" ]] && {
334 json_select ..
335 continue
336 }
337 fi
338 __cur_interface="$_w_iface"
339 "$@" "$_w_iface"
340 json_select ..
341 done
342 json_select ..
343 }
344
345 for_each_vlan() {
346 local _w_vlans _w_vlan
347
348 json_get_keys _w_vlans vlans
349 json_select vlans
350 for _w_vlan in $_w_vlans; do
351 json_select "$_w_vlan"
352 json_select config
353 "$@" "$_w_vlan"
354 json_select ..
355 json_select ..
356 done
357 json_select ..
358 }
359
360 for_each_station() {
361 local _w_stas _w_sta
362
363 json_get_keys _w_stas stas
364 json_select stas
365 for _w_sta in $_w_stas; do
366 json_select "$_w_sta"
367 json_select config
368 "$@" "$_w_sta"
369 json_select ..
370 json_select ..
371 done
372 json_select ..
373 }
374
375 _wdev_common_device_config() {
376 config_add_string channel hwmode band htmode noscan
377 }
378
379 _wdev_common_iface_config() {
380 config_add_string mode ssid encryption 'key:wpakey'
381 config_add_boolean bridge_isolate
382 }
383
384 _wdev_common_vlan_config() {
385 config_add_string name vid iface
386 config_add_boolean bridge_isolate
387 }
388
389 _wdev_common_station_config() {
390 config_add_string mac key vid iface
391 }
392
393 init_wireless_driver() {
394 name="$1"; shift
395 cmd="$1"; shift
396
397 case "$cmd" in
398 dump)
399 add_driver() {
400 eval "drv_$1_cleanup"
401
402 json_init
403 json_add_string name "$1"
404
405 json_add_array device
406 _wdev_common_device_config
407 eval "drv_$1_init_device_config"
408 json_close_array
409
410 json_add_array iface
411 _wdev_common_iface_config
412 eval "drv_$1_init_iface_config"
413 json_close_array
414
415 json_add_array vlan
416 _wdev_common_vlan_config
417 eval "drv_$1_init_vlan_config"
418 json_close_array
419
420 json_add_array station
421 _wdev_common_station_config
422 eval "drv_$1_init_station_config"
423 json_close_array
424
425 json_dump
426 }
427 ;;
428 setup|teardown)
429 interface="$1"; shift
430 data="$1"; shift
431 export __netifd_device="$interface"
432
433 add_driver() {
434 [[ "$name" == "$1" ]] || return 0
435 _wdev_handler "$1" "$cmd"
436 }
437 ;;
438 esac
439 }