diff --git a/net/travelmate/Makefile b/net/travelmate/Makefile index ec41e0940..48f12ba56 100644 --- a/net/travelmate/Makefile +++ b/net/travelmate/Makefile @@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=travelmate -PKG_VERSION:=0.2.7 +PKG_VERSION:=0.3.0 PKG_RELEASE:=1 PKG_LICENSE:=GPL-3.0+ PKG_MAINTAINER:=Dirk Brenken diff --git a/net/travelmate/files/README.md b/net/travelmate/files/README.md index 2f8084a2e..eefe8886f 100644 --- a/net/travelmate/files/README.md +++ b/net/travelmate/files/README.md @@ -3,15 +3,15 @@ ## Description If you’re planning an upcoming vacation or a business trip, taking your laptop, tablet or smartphone give you the ability to connect with friends or complete work on the go. But many hotels don’t have a secure wireless network setup or you’re limited on using a single device at once. Investing in a portable, mini travel router is a great way to connect all of your devices at once while having total control over your own personalized wireless network. A logical combination of AP+STA mode on one physical radio allows most of OpenWrt/LEDE supported router devices to connect to a wireless hotspot/station (STA) and provide a wireless access point (AP) from that hotspot at the same time. Downside of this solution: whenever the STA interface looses the connection it will go into an active scan cycle which renders the radio unusable for AP mode operation, therefore the AP is taken down if the STA looses its association. -To avoid these kind of deadlocks, travelmate set all station interfaces in an "always off" mode, connects automatically to available hotspots and monitor & change these uplink connections automatically if required. +To avoid these kind of deadlocks, travelmate set all station interfaces in an "always off" mode and connects automatically to available/configured hotspots. ## Main Features * STA interfaces operating in an "always off" mode, to make sure that the AP is always accessible +* zero-conf like automatic installation & setup, usually no manual changes needed * fast uplink connections -* reliable connection tracking -* easy setup within normal OpenWrt/LEDE environment -* status & debug logging to syslog * procd init system support +* procd based hotplug support, the travelmate start will be triggered by interface triggers +* status & debug logging to syslog ## Prerequisites * [OpenWrt](https://openwrt.org) or [LEDE](https://www.lede-project.org) trunk @@ -22,7 +22,7 @@ To avoid these kind of deadlocks, travelmate set all station interfaces in an "a * install 'travelmate' (_opkg install travelmate_) * configure your network to support (multiple) wlan uplinks and set travelmate config options (details see below) * set 'trm\_enabled' option in travelmate config to '1' -* travelmate starts automatically during boot, triggered by procd as soon as the wireless subsystem is up & running +* travelmate starts automatically during boot and will be triggered by procd interface triggers ## LuCI travelmate companion package * download the package [here](https://downloads.lede-project.org/snapshots/packages/x86_64/luci) @@ -37,14 +37,13 @@ To avoid these kind of deadlocks, travelmate set all station interfaces in an "a * install the packages as described above ## Travelmate config options -* mandatory config options: +* travelmate config options: * trm\_enabled => main switch to enable/disable the travelmate service (default: '0', disabled) - * trm\_loop => loop timeout in seconds for wlan monitoring (default: '30') - * trm\_maxretry => how many times should travelmate try to connect to a certain uplink, to disable this check at all set it to '0' (default: '3') -* optional config options: * trm\_debug => enable/disable debug logging (default: '0', disabled) - * trm\_device => limit travelmate to a dedicated radio, i.e 'radio0' (default: use all radios) + * trm\_maxwait => how long (in seconds) should travelmate wait for wlan interface reload action (default: '20') + * trm\_maxretry => how many times should travelmate try to find an uplink after a trigger event (default: '3') * trm\_iw => set this option to '0' to use iwinfo for wlan scanning (default: '1', use iw) + * trm\_iface => restrict the procd interface trigger to a (list of) certain wan interface(s) or disable it at all (default: not set, disabled) ## Setup **1. configure a wwan interface in /etc/config/network:** @@ -117,16 +116,6 @@ config wifi-iface /etc/init.d/travelmate start -**Common runtime outputs (visible via logread)** - -**Success:** Sun Oct 9 17:02:21 2016 user.notice root: travelmate-0.2.1[712] info : wlan interface "wwan06" connected to uplink "blackhole.nl" - -**Disabled service:** Sun Oct 9 18:06:32 2016 user.notice root: travelmate-0.2.1[2379] info : travelmate is currently disabled, please set 'trm_enabled' to use this service - -**Misconfigured/broken uplink:** Sun Oct 9 18:56:42 2016 user.notice root: travelmate-0.2.1[2435] info : uplink "blackhole.nl" disabled due to permanent connection failures - -**Uplink disappeared:** Sun Oct 9 19:00:28 2016 user.notice root: travelmate-0.2.1[3876] info : uplink "Neffos C5L" get lost - ## Support Please join the travelmate discussion in this [forum thread](https://forum.openwrt.org/viewtopic.php?id=67697) or contact me by [mail](mailto:dev@brenken.org) diff --git a/net/travelmate/files/travelmate.conf b/net/travelmate/files/travelmate.conf index e413a8cfe..c63000f38 100644 --- a/net/travelmate/files/travelmate.conf +++ b/net/travelmate/files/travelmate.conf @@ -3,5 +3,7 @@ config travelmate 'global' option trm_enabled '0' - option trm_loop '30' + option trm_debug '0' + option trm_maxwait '20' option trm_maxretry '3' + option trm_iw '1' diff --git a/net/travelmate/files/travelmate.init b/net/travelmate/files/travelmate.init index fc3e9ed9e..9529cd18a 100755 --- a/net/travelmate/files/travelmate.init +++ b/net/travelmate/files/travelmate.init @@ -3,23 +3,37 @@ START=85 USE_PROCD=1 -exec 2>/dev/null trm_script="/usr/bin/travelmate.sh" +trm_iface="$(uci -q get travelmate.global.trm_iface)" + +boot() +{ + ubus -t 30 wait_for network.interface + rc_procd start_service +} start_service() { - ubus -t 30 wait_for network.wireless - if [ $(($?)) -eq 0 ] - then - procd_open_instance - procd_set_param command "${trm_script}" - procd_close_instance - else - logger -s "travelmate [procd]:" "no wlan devices found, travelmate startup canceled" - fi + procd_open_instance "travelmate" + procd_set_param env trm_procd="true" + procd_set_param command "${trm_script}" "${@}" + procd_set_param stdout 1 + procd_set_param stderr 1 + procd_close_instance } service_triggers() { - procd_add_reload_trigger "travelmate" + local iface + + procd_add_config_trigger "config.change" "travelmate" /etc/init.d/travelmate start + if [ -z "${trm_iface}" ] + then + procd_add_raw_trigger "interface.*.down" 1000 /etc/init.d/travelmate start + else + for iface in ${trm_iface} + do + procd_add_interface_trigger "interface.*.down" "${iface}" /etc/init.d/travelmate start + done + fi } diff --git a/net/travelmate/files/travelmate.sh b/net/travelmate/files/travelmate.sh index fa0d7ae8f..726fd951d 100755 --- a/net/travelmate/files/travelmate.sh +++ b/net/travelmate/files/travelmate.sh @@ -10,144 +10,96 @@ # LC_ALL=C PATH="/usr/sbin:/usr/bin:/sbin:/bin" -trm_pid="${$}" -trm_ver="0.2.7" +trm_ver="0.3.0" +trm_enabled=1 trm_debug=0 -trm_loop=30 +trm_maxwait=20 trm_maxretry=3 trm_iw=1 -trm_device="" -# function to prepare all relevant AP and STA interfaces -# -f_prepare() +f_envload() { - local config="${1}" - local mode="$(uci -q get wireless."${config}".mode)" - local device="$(uci -q get wireless."${config}".device)" - local network="$(uci -q get wireless."${config}".network)" - local disabled="$(uci -q get wireless."${config}".disabled)" - - if [ "${mode}" = "ap" ] && [ -n "${network}" ] && - ([ -z "${trm_device}" ] || [ "${trm_device}" = "${device}" ]) + # source required system libraries + # + if [ -r "/lib/functions.sh" ] then - f_ifname "${device}" - if [ -z "${disabled}" ] || [ "${disabled}" = "1" ] - then - f_set "none" "${config}" "${network}" "up" - fi - elif [ "${mode}" = "sta" ] && [ -n "${network}" ] - then - trm_stalist="${trm_stalist} ${config}_${network}" - if [ -z "${disabled}" ] || [ "${disabled}" = "0" ] - then - f_set "none" "${config}" "${network}" "down" - fi + . "/lib/functions.sh" + else + f_log "error" "required system library not found" fi -} -# function to set different wlan interface status -# -f_set() -{ - local change="${1}" - local config="${2}" - local interface="${3}" - local command="${4}" - - if [ "${command}" = "up" ] - then - uci -q set wireless."${config}".disabled=0 - ubus call network.interface."${interface}" "${command}" - trm_checklist="${trm_checklist} ${interface}" - elif [ "${command}" = "down" ] + # load uci config and check 'enabled' option + # + option_cb() + { + local option="${1}" + local value="${2}" + eval "${option}=\"${value}\"" + } + config_load travelmate + + if [ ${trm_enabled} -ne 1 ] then - uci -q set wireless."${config}".disabled=1 - ubus call network.interface."${interface}" "${command}" + f_log "info " "status ::: travelmate is currently disabled, please set 'trm_enabled' to '1' to use this service" + exit 0 fi - f_log "debug" "set ::: change: ${change}, config: ${config}, interface: ${interface}, command: ${command}, checklist: ${trm_checklist}, uci-changes: $(uci -q changes wireless)" - if [ -n "$(uci -q changes wireless)" ] + # check for preferred wireless tool + # + if [ ${trm_iw} -eq 1 ] then - if [ "${change}" = "commit" ] - then - uci -q commit wireless - ubus call network reload - f_check - elif [ "${change}" = "partial" ] - then - ubus call network reload - f_check - elif [ "${change}" = "defer" ] - then - uci -q revert wireless - elif [ "${change}" = "revert" ] - then - uci -q revert wireless - ubus call network reload - f_check - fi + trm_scanner="$(which iw)" + else + trm_scanner="$(which iwinfo)" + fi + if [ -z "${trm_scanner}" ] + then + f_log "error" "status ::: no wireless tool for wlan scanning found, please install 'iw' or 'iwinfo'" fi } -# function to get ap ifnames by ubus call +# function to bring down all STA interfaces # -f_ifname() +f_prepare() { - local device="${1}" - local name cfg + local config="${1}" + local mode="$(uci -q get wireless."${config}".mode)" + local network="$(uci -q get wireless."${config}".network)" + local disabled="$(uci -q get wireless."${config}".disabled)" - json_load "$(ubus -S call network.wireless status)" - json_select "${device}" - json_get_keys if_list interfaces - json_select interfaces - for iface in ${if_list} - do - json_select "${iface}" - json_get_var name ifname - json_select "config" - json_get_var cfg mode - if [ -n "${name}" ] && [ "${cfg}" = "ap" ] + if [ "${mode}" = "sta" ] && [ -n "${network}" ] + then + trm_stalist="${trm_stalist} ${config}_${network}" + if [ -z "${disabled}" ] || [ "${disabled}" = "0" ] then - trm_aplist="${trm_aplist} ${name}" + uci -q set wireless."${config}".disabled=1 + f_log "debug" "prepare ::: config: ${config}, interface: ${network}" fi - done + fi } -# function to check interface status on "up" event -# f_check() { - local interface value - local cnt=0 + local ifname cnt=0 mode="${1}" + trm_ifstatus="false" - for interface in ${trm_checklist} + while [ ${cnt} -lt ${trm_maxwait} ] do - while [ $((cnt)) -lt 15 ] - do - json_load "$(ubus -S call network.interface."${interface}" status)" - json_get_var trm_status up - if [ "${trm_status}" = "1" ] || [ -n "${trm_uplink}" ] - then - f_log "debug" "check::: interface: ${interface}, status: ${trm_status}, uplink-cfg: ${trm_uplink}, uplink-ssid: ${trm_ssid}, loop-cnt: ${cnt}, error-cnt: $((trm_count_${trm_config}))" - json_cleanup - break - fi - cnt=$((cnt+1)) - sleep 1 - done + ifname="$(ubus -S call network.wireless status | jsonfilter -l 1 -e "@.*.interfaces[@.config.mode=\"${mode}\"].ifname")" + if [ "${mode}" = "sta" ] + then + trm_ifstatus="$(ubus -S call network.interface dump | jsonfilter -e "@.interface[@.device=\"${ifname}\"].up")" + else + trm_ifstatus="$(ubus -S call network.wireless status | jsonfilter -l1 -e '@.*.up')" + fi + if [ "${trm_ifstatus}" = "true" ] + then + break + fi + cnt=$((cnt+1)) + sleep 1 done - if [ -n "${trm_uplink}" ] && [ "${trm_status}" = "0" ] - then - ubus call network reload - eval "trm_count_${trm_uplink}=\$((trm_count_${trm_uplink}+1))" - trm_checklist="" - trm_uplink="" - f_log "info" "uplink ${trm_ssid} get lost" - elif [ -z "${trm_uplink}" ] && [ -n "${trm_checklist}" ] - then - trm_checklist="" - fi + f_log "debug" "check ::: name: ${ifname}, status: ${trm_ifstatus}, count: ${cnt}" } # function to write to syslog @@ -157,125 +109,79 @@ f_log() local class="${1}" local log_msg="${2}" - if [ -n "${log_msg}" ] && ([ "${class}" != "debug" ] || ([ "${class}" = "debug" ] && [ $((trm_debug)) -eq 1 ])) + if [ -n "${log_msg}" ] && ([ "${class}" != "debug" ] || [ ${trm_debug} -eq 1 ]) then - logger -t "travelmate-${trm_ver}[${trm_pid}] ${class}" "${log_msg}" 2>&1 + logger -t "travelmate-[${trm_ver}] ${class}" "${log_msg}" + if [ "${class}" = "error" ] + then + exit 255 + fi fi } -# source required system libraries -# -if [ -r "/lib/functions.sh" ] && [ -r "/usr/share/libubox/jshn.sh" ] -then - . "/lib/functions.sh" - . "/usr/share/libubox/jshn.sh" - json_init -else - f_log "error" "required system libraries not found" - exit 255 -fi - -# load uci config and check 'enabled' option -# -option_cb() +f_main() { - local option="${1}" - local value="${2}" - eval "${option}=\"${value}\"" -} - -config_load travelmate - -if [ "${trm_enabled}" != "1" ] -then - f_log "info" "travelmate is currently disabled, please set 'trm_enabled' to '1' to use this service" - exit 0 -fi + local ap_list ssid_list config network ssid cnt=0 -# check for preferred wireless tool -# -if [ $((trm_iw)) -eq 1 ] -then - trm_scanner="$(which iw)" -else - trm_scanner="$(which iwinfo)" -fi - -if [ -z "${trm_scanner}" ] -then - f_log "error" "no wireless tool for wlan scanning found, please install 'iw' or 'iwinfo'" - exit 1 -fi - -# infinitive loop to establish and track STA uplink connections -# -while true -do - if [ -z "${trm_uplink}" ] || [ "${trm_status}" = "0" ] + f_check "sta" + if [ "${trm_ifstatus}" != "true" ] then - trm_aplist="" - trm_stalist="" config_load wireless config_foreach f_prepare wifi-iface - f_set "commit" - if [ -z "${trm_aplist}" ] + if [ -n "$(uci -q changes wireless)" ] then - f_log "error" "no usable AP configuration found, please check '/etc/config/wireless'" - exit 1 + uci -q commit wireless + ubus call network reload fi - for ap in ${trm_aplist} + f_check "ap" + ap_list="$(ubus -S call network.wireless status | jsonfilter -e '@.*.interfaces[@.config.mode="ap"].ifname')" + f_log "debug" "main ::: ap-list: ${ap_list}, sta-list: ${trm_stalist}" + if [ -z "${ap_list}" ] || [ -z "${trm_stalist}" ] + then + f_log "error" "main ::: no usable AP/STA configuration found" + fi + for ap in ${ap_list} do - ubus -t 10 wait_for hostapd."${ap}" - if [ $((trm_iw)) -eq 1 ] - then - trm_ssidlist="$(${trm_scanner} dev "${ap}" scan 2>/dev/null | awk '/SSID: /{if(!seen[$0]++){printf "\"";for(i=2; i<=NF; i++)if(i==2)printf $i;else printf " "$i;printf "\" "}}')" - else - trm_ssidlist="$(${trm_scanner} "${ap}" scan | awk '/ESSID: ".*"/{ORS=" ";if (!seen[$0]++) for(i=2; i<=NF; i++) print $i}')" - fi - f_log "debug" "main ::: scan-tool: ${trm_scanner}, aplist: ${trm_aplist}, ssidlist: ${trm_ssidlist}" - if [ -n "${trm_ssidlist}" ] - then - if [ -z "${trm_stalist}" ] + while [ ${cnt} -lt ${trm_maxretry} ] + do + if [ ${trm_iw} -eq 1 ] then - f_log "error" "no usable STA configuration found, please check '/etc/config/wireless'" - exit 1 + ssid_list="$(${trm_scanner} dev "${ap}" scan 2>/dev/null | \ + awk '/SSID: /{if(!seen[$0]++){printf "\"";for(i=2; i<=NF; i++)if(i==2)printf $i;else printf " "$i;printf "\" "}}')" + else + ssid_list="$(${trm_scanner} "${ap}" scan | \ + awk '/ESSID: ".*"/{ORS=" ";if (!seen[$0]++) for(i=2; i<=NF; i++) print $i}')" fi - for sta in ${trm_stalist} - do - trm_config="${sta%%_*}" - trm_network="${sta##*_}" - trm_ssid="\"$(uci -q get wireless."${trm_config}".ssid)\"" - if [ $((trm_count_${trm_config})) -lt $((trm_maxretry)) ] || [ $((trm_maxretry)) -eq 0 ] - then - if [ -n "$(printf "${trm_ssidlist}" | grep -Fo "${trm_ssid}")" ] + f_log "debug" "main ::: scan-tool: ${trm_scanner}, ssidlist: ${ssid_list}" + if [ -n "${ssid_list}" ] + then + for sta in ${trm_stalist} + do + config="${sta%%_*}" + network="${sta##*_}" + ssid="\"$(uci -q get wireless."${config}".ssid)\"" + if [ -n "$(printf "${ssid_list}" | grep -Fo "${ssid}")" ] then - f_set "partial" "${trm_config}" "${trm_network}" "up" - if [ "${trm_status}" = "1" ] - then - trm_checklist="${trm_network}" - trm_uplink="${trm_config}" - f_set "defer" - f_log "info" "wwan interface connected to uplink ${trm_ssid}" - break 2 - else - f_set "revert" - eval "trm_count_${trm_config}=\$((trm_count_${trm_config}+1))" - fi + uci -q set wireless."${config}".disabled=0 + uci -q commit wireless + ubus call network.interface."${network}" up + ubus call network reload + f_log "info " "main ::: wwan interface connected to uplink ${ssid}" + return 0 fi - elif [ $((trm_count_${trm_config})) -eq $((trm_maxretry)) ] && [ $((trm_maxretry)) -ne 0 ] - then - eval "trm_count_${trm_config}=\$((trm_count_${trm_config}+1))" - f_log "info" "uplink ${trm_ssid} disabled due to permanent connection failures" - fi - done - fi - sleep 5 + done + fi + cnt=$((cnt+1)) + sleep 5 + done done - else - f_check - if [ -n "${trm_uplink}" ] - then - sleep ${trm_loop} - fi + f_log "info " "main ::: no wwan uplink found" fi -done +} + +if [ "${trm_procd}" = "true" ] +then + f_envload + f_main +fi +exit 0 \ No newline at end of file