netifd-wireless.sh 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  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) wpa_cipher="CCMP";;
  191. *tkip) wpa_cipher="TKIP";;
  192. *gcmp256) wpa_cipher="GCMP-256";;
  193. *gcmp) wpa_cipher="GCMP";;
  194. esac
  195. # 802.11n requires CCMP for WPA
  196. [ "$enable_ht:$wpa_cipher" = "1:TKIP" ] && wpa_cipher="CCMP TKIP"
  197. # Examples:
  198. # psk-mixed/tkip => WPA1+2 PSK, TKIP
  199. # wpa-psk2/tkip+aes => WPA2 PSK, CCMP+TKIP
  200. # wpa2/tkip+aes => WPA2 RADIUS, CCMP+TKIP
  201. case "$encryption" in
  202. wpa2*|wpa3*|*psk2*|psk3*|sae*|owe*)
  203. wpa=2
  204. ;;
  205. wpa*mixed*|*psk*mixed*)
  206. wpa=3
  207. ;;
  208. wpa*|*psk*)
  209. wpa=1
  210. ;;
  211. *)
  212. wpa=0
  213. wpa_cipher=
  214. ;;
  215. esac
  216. wpa_pairwise="$wpa_cipher"
  217. case "$encryption" in
  218. owe*)
  219. auth_type=owe
  220. ;;
  221. wpa3-mixed*)
  222. auth_type=eap-eap192
  223. ;;
  224. wpa3*)
  225. auth_type=eap192
  226. ;;
  227. psk3-mixed*|sae-mixed*)
  228. auth_type=psk-sae
  229. ;;
  230. psk3*|sae*)
  231. auth_type=sae
  232. ;;
  233. *psk*)
  234. auth_type=psk
  235. ;;
  236. *wpa*|*8021x*)
  237. auth_type=eap
  238. ;;
  239. *wep*)
  240. auth_type=wep
  241. case "$encryption" in
  242. *shared*)
  243. auth_mode_open=0
  244. auth_mode_shared=1
  245. ;;
  246. *mixed*)
  247. auth_mode_shared=1
  248. ;;
  249. esac
  250. ;;
  251. esac
  252. case "$encryption" in
  253. *osen*)
  254. auth_osen=1
  255. ;;
  256. esac
  257. }
  258. _wireless_set_brsnoop_isolation() {
  259. local multicast_to_unicast="$1"
  260. local isolate
  261. json_get_vars isolate proxy_arp
  262. [ ${isolate:-0} -gt 0 -o -z "$network_bridge" ] && return
  263. [ ${multicast_to_unicast:-1} -gt 0 -o ${proxy_arp:-0} -gt 0 ] && json_add_boolean isolate 1
  264. }
  265. for_each_interface() {
  266. local _w_types="$1"; shift
  267. local _w_ifaces _w_iface
  268. local _w_type
  269. local _w_found
  270. local multicast_to_unicast
  271. json_get_keys _w_ifaces interfaces
  272. json_select interfaces
  273. for _w_iface in $_w_ifaces; do
  274. json_select "$_w_iface"
  275. if [ -n "$_w_types" ]; then
  276. json_get_var network_bridge bridge
  277. json_get_var network_ifname bridge-ifname
  278. json_get_var multicast_to_unicast multicast_to_unicast
  279. json_select config
  280. _wireless_set_brsnoop_isolation "$multicast_to_unicast"
  281. json_get_var _w_type mode
  282. json_select ..
  283. _w_types=" $_w_types "
  284. [[ "${_w_types%$_w_type*}" = "$_w_types" ]] && {
  285. json_select ..
  286. continue
  287. }
  288. fi
  289. "$@" "$_w_iface"
  290. json_select ..
  291. done
  292. json_select ..
  293. }
  294. for_each_vlan() {
  295. local _w_vlans _w_vlan
  296. json_get_keys _w_vlans vlans
  297. json_select vlans
  298. for _w_vlan in $_w_vlans; do
  299. json_select "$_w_vlan"
  300. json_select config
  301. "$@" "$_w_vlan"
  302. json_select ..
  303. json_select ..
  304. done
  305. json_select ..
  306. }
  307. for_each_station() {
  308. local _w_stas _w_sta
  309. json_get_keys _w_stas stas
  310. json_select stas
  311. for _w_sta in $_w_stas; do
  312. json_select "$_w_sta"
  313. json_select config
  314. "$@" "$_w_sta"
  315. json_select ..
  316. json_select ..
  317. done
  318. json_select ..
  319. }
  320. _wdev_common_device_config() {
  321. config_add_string channel hwmode band htmode noscan
  322. }
  323. _wdev_common_iface_config() {
  324. config_add_string mode ssid encryption 'key:wpakey'
  325. }
  326. _wdev_common_vlan_config() {
  327. config_add_string name vid iface
  328. }
  329. _wdev_common_station_config() {
  330. config_add_string mac key vid iface
  331. }
  332. init_wireless_driver() {
  333. name="$1"; shift
  334. cmd="$1"; shift
  335. case "$cmd" in
  336. dump)
  337. add_driver() {
  338. eval "drv_$1_cleanup"
  339. json_init
  340. json_add_string name "$1"
  341. json_add_array device
  342. _wdev_common_device_config
  343. eval "drv_$1_init_device_config"
  344. json_close_array
  345. json_add_array iface
  346. _wdev_common_iface_config
  347. eval "drv_$1_init_iface_config"
  348. json_close_array
  349. json_add_array vlan
  350. _wdev_common_vlan_config
  351. eval "drv_$1_init_vlan_config"
  352. json_close_array
  353. json_add_array station
  354. _wdev_common_station_config
  355. eval "drv_$1_init_station_config"
  356. json_close_array
  357. json_dump
  358. }
  359. ;;
  360. setup|teardown)
  361. interface="$1"; shift
  362. data="$1"; shift
  363. export __netifd_device="$interface"
  364. add_driver() {
  365. [[ "$name" == "$1" ]] || return 0
  366. _wdev_handler "$1" "$cmd"
  367. }
  368. ;;
  369. esac
  370. }