netifd-wireless.sh 7.9 KB

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