You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

326 lines
8.4 KiB

  1. #!/bin/sh
  2. # Copyright (c) 2016, prpl Foundation
  3. #
  4. # Permission to use, copy, modify, and/or distribute this software for any purpose with or without
  5. # fee is hereby granted, provided that the above copyright notice and this permission notice appear
  6. # in all copies.
  7. #
  8. # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
  9. # INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE
  10. # FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. # LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  12. # ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  13. #
  14. # Author: Nils Koenig <openwrt@newk.it>
  15. SCRIPT=$0
  16. LOCKFILE=/tmp/wifi_schedule.lock
  17. LOGFILE=/tmp/log/wifi_schedule.log
  18. LOGGING=0 #default is off
  19. PACKAGE=wifi_schedule
  20. GLOBAL=${PACKAGE}.@global[0]
  21. _log()
  22. {
  23. if [ ${LOGGING} -eq 1 ]; then
  24. local ts=$(date)
  25. echo "$ts $@" >> ${LOGFILE}
  26. fi
  27. }
  28. _exit()
  29. {
  30. local rc=$1
  31. lock -u ${LOCKFILE}
  32. exit ${rc}
  33. }
  34. _cron_restart()
  35. {
  36. /etc/init.d/cron restart > /dev/null
  37. }
  38. _add_cron_script()
  39. {
  40. (crontab -l ; echo "$1") | sort | uniq | crontab -
  41. _cron_restart
  42. }
  43. _rm_cron_script()
  44. {
  45. crontab -l | grep -v "$1" | sort | uniq | crontab -
  46. _cron_restart
  47. }
  48. _get_uci_value_raw()
  49. {
  50. local value
  51. value=$(uci get $1 2> /dev/null)
  52. local rc=$?
  53. echo ${value}
  54. return ${rc}
  55. }
  56. _get_uci_value()
  57. {
  58. local value
  59. value=$(_get_uci_value_raw $1)
  60. local rc=$?
  61. if [ ${rc} -ne 0 ]; then
  62. _log "Could not determine UCI value $1"
  63. return 1
  64. fi
  65. echo ${value}
  66. }
  67. _format_dow_list()
  68. {
  69. local dow=$1
  70. local flist=""
  71. local day
  72. for day in ${dow}
  73. do
  74. if [ ! -z ${flist} ]; then
  75. flist="${flist},"
  76. fi
  77. flist="${flist}${day:0:3}"
  78. done
  79. echo ${flist}
  80. }
  81. _enable_wifi_schedule()
  82. {
  83. local entry=$1
  84. local starttime
  85. local stoptime
  86. starttime=$(_get_uci_value ${PACKAGE}.${entry}.starttime) || _exit 1
  87. stoptime=$(_get_uci_value ${PACKAGE}.${entry}.stoptime) || _exit 1
  88. local dow
  89. dow=$(_get_uci_value_raw ${PACKAGE}.${entry}.daysofweek) || _exit 1
  90. local fdow=$(_format_dow_list "$dow")
  91. local forcewifidown
  92. forcewifidown=$(_get_uci_value ${PACKAGE}.${entry}.forcewifidown)
  93. local stopmode="stop"
  94. if [ $forcewifidown -eq 1 ]; then
  95. stopmode="forcestop"
  96. fi
  97. local stop_cron_entry="$(echo ${stoptime} | awk -F':' '{print $2, $1}') * * ${fdow} ${SCRIPT} ${stopmode}" # ${entry}"
  98. _add_cron_script "${stop_cron_entry}"
  99. if [[ $starttime != $stoptime ]]
  100. then
  101. local start_cron_entry="$(echo ${starttime} | awk -F':' '{print $2, $1}') * * ${fdow} ${SCRIPT} start" # ${entry}"
  102. _add_cron_script "${start_cron_entry}"
  103. fi
  104. return 0
  105. }
  106. _get_wireless_interfaces()
  107. {
  108. local n=$(cat /proc/net/wireless | wc -l)
  109. cat /proc/net/wireless | tail -n $(($n - 2))|awk -F':' '{print $1}'| sed 's/ //'
  110. }
  111. get_module_list()
  112. {
  113. local mod_list
  114. local _if
  115. for _if in $(_get_wireless_interfaces)
  116. do
  117. local mod=$(basename $(readlink -f /sys/class/net/${_if}/device/driver))
  118. local mod_dep=$(modinfo ${mod} | awk '{if ($1 ~ /depends/) print $2}')
  119. mod_list=$(echo -e "${mod_list}\n${mod},${mod_dep}" | sort | uniq)
  120. done
  121. echo $mod_list | tr ',' ' '
  122. }
  123. save_module_list_uci()
  124. {
  125. local list=$(get_module_list)
  126. uci set ${GLOBAL}.modules="${list}"
  127. uci commit ${PACKAGE}
  128. }
  129. _unload_modules()
  130. {
  131. local list=$(_get_uci_value ${GLOBAL}.modules)
  132. local retries
  133. retries=$(_get_uci_value ${GLOBAL}.modules_retries) || _exit 1
  134. _log "unload_modules ${list} (retries: ${retries})"
  135. local i=0
  136. while [[ ${i} -lt ${retries} && "${list}" != "" ]]
  137. do
  138. i=$(($i+1))
  139. local mod
  140. local first=0
  141. for mod in ${list}
  142. do
  143. if [ $first -eq 0 ]; then
  144. list=""
  145. first=1
  146. fi
  147. rmmod ${mod} > /dev/null 2>&1
  148. if [ $? -ne 0 ]; then
  149. list="$list $mod"
  150. fi
  151. done
  152. done
  153. }
  154. _load_modules()
  155. {
  156. local list=$(_get_uci_value ${GLOBAL}.modules)
  157. local retries
  158. retries=$(_get_uci_value ${GLOBAL}.modules_retries) || _exit 1
  159. _log "load_modules ${list} (retries: ${retries})"
  160. local i=0
  161. while [[ ${i} -lt ${retries} && "${list}" != "" ]]
  162. do
  163. i=$(($i+1))
  164. local mod
  165. local first=0
  166. for mod in ${list}
  167. do
  168. if [ $first -eq 0 ]; then
  169. list=""
  170. first=1
  171. fi
  172. modprobe ${mod} > /dev/null 2>&1
  173. rc=$?
  174. if [ $rc -ne 255 ]; then
  175. list="$list $mod"
  176. fi
  177. done
  178. done
  179. }
  180. _create_cron_entries()
  181. {
  182. local entries=$(uci show ${PACKAGE} 2> /dev/null | awk -F'.' '{print $2}' | grep -v '=' | grep -v '@global\[0\]' | uniq | sort)
  183. local _entry
  184. for entry in ${entries}
  185. do
  186. local status
  187. status=$(_get_uci_value ${PACKAGE}.${entry}.enabled) || _exit 1
  188. if [ ${status} -eq 1 ]
  189. then
  190. _enable_wifi_schedule ${entry}
  191. fi
  192. done
  193. }
  194. check_cron_status()
  195. {
  196. local global_enabled
  197. global_enabled=$(_get_uci_value ${GLOBAL}.enabled) || _exit 1
  198. _rm_cron_script "${SCRIPT}"
  199. if [ ${global_enabled} -eq 1 ]; then
  200. _create_cron_entries
  201. fi
  202. }
  203. disable_wifi()
  204. {
  205. _rm_cron_script "${SCRIPT} recheck"
  206. /sbin/wifi down
  207. local unload_modules
  208. unload_modules=$(_get_uci_value_raw ${GLOBAL}.unload_modules) || _exit 1
  209. if [[ "${unload_modules}" == "1" ]]; then
  210. _unload_modules
  211. fi
  212. }
  213. soft_disable_wifi()
  214. {
  215. local _disable_wifi=1
  216. local iwinfo=/usr/bin/iwinfo
  217. if [ ! -e ${iwinfo} ]; then
  218. _log "${iwinfo} not available, skipping"
  219. return 1
  220. fi
  221. local ignore_stations=$(_get_uci_value_raw ${GLOBAL}.ignore_stations)
  222. [ -n "${ignore_stations}" ] && _log "Ignoring station(s) ${ignore_stations}"
  223. # check if no stations are associated
  224. local _if
  225. for _if in $(_get_wireless_interfaces)
  226. do
  227. local stations=$(${iwinfo} ${_if} assoclist | grep -o -E '([[:xdigit:]]{1,2}:){5}[[:xdigit:]]{1,2}')
  228. if [ -n "${ignore_stations}" ]; then
  229. stations=$(echo "${stations}" | grep -vwi -E "${ignore_stations// /|}")
  230. fi
  231. if [ -n "${stations}" ]; then
  232. _disable_wifi=0
  233. _log "Station(s) $(echo ${stations}) associated on ${_if}"
  234. fi
  235. done
  236. if [ ${_disable_wifi} -eq 1 ]; then
  237. _log "No stations associated, disable wifi."
  238. disable_wifi
  239. else
  240. _log "Could not disable wifi due to associated stations, retrying..."
  241. local recheck_interval=$(_get_uci_value ${GLOBAL}.recheck_interval)
  242. _add_cron_script "*/${recheck_interval} * * * * ${SCRIPT} recheck"
  243. fi
  244. }
  245. enable_wifi()
  246. {
  247. _rm_cron_script "${SCRIPT} recheck"
  248. local unload_modules
  249. unload_modules=$(_get_uci_value_raw ${GLOBAL}.unload_modules) || _exit 1
  250. if [[ "${unload_modules}" == "1" ]]; then
  251. _load_modules
  252. fi
  253. /sbin/wifi
  254. }
  255. usage()
  256. {
  257. echo ""
  258. echo "$0 cron|start|stop|forcestop|recheck|getmodules|savemodules|help"
  259. echo ""
  260. echo " UCI Config File: /etc/config/${PACKAGE}"
  261. echo ""
  262. echo " cron: Create cronjob entries."
  263. echo " start: Start wifi."
  264. echo " stop: Stop wifi gracefully, i.e. check if there are stations associated and if so keep retrying."
  265. echo " forcestop: Stop wifi immediately."
  266. echo " recheck: Recheck if wifi can be disabled now."
  267. echo " getmodules: Returns a list of modules used by the wireless driver(s)"
  268. echo " savemodules: Saves a list of automatic determined modules to UCI"
  269. echo " help: This description."
  270. echo ""
  271. }
  272. ###############################################################################
  273. # MAIN
  274. ###############################################################################
  275. LOGGING=$(_get_uci_value ${GLOBAL}.logging) || _exit 1
  276. _log ${SCRIPT} $1 $2
  277. lock ${LOCKFILE}
  278. case "$1" in
  279. cron) check_cron_status ;;
  280. start) enable_wifi ;;
  281. forcestop) disable_wifi ;;
  282. stop) soft_disable_wifi ;;
  283. recheck) soft_disable_wifi ;;
  284. getmodules) get_module_list ;;
  285. savemodules) save_module_list_uci ;;
  286. help|--help|-h|*) usage ;;
  287. esac
  288. _exit 0