From 77d9425e33212e3c1cf62e1229a302d6dad11afc Mon Sep 17 00:00:00 2001 From: Dirk Brenken Date: Sun, 16 Oct 2016 17:54:48 +0200 Subject: [PATCH] travelmate: new package, release 0.2.2 * a connection manager for travel router (see readme.md for details) Signed-off-by: Dirk Brenken --- net/travelmate/Makefile | 54 ++++++ net/travelmate/files/README.md | 125 ++++++++++++++ net/travelmate/files/travelmate.conf | 7 + net/travelmate/files/travelmate.init | 25 +++ net/travelmate/files/travelmate.sh | 243 +++++++++++++++++++++++++++ 5 files changed, 454 insertions(+) create mode 100644 net/travelmate/Makefile create mode 100644 net/travelmate/files/README.md create mode 100644 net/travelmate/files/travelmate.conf create mode 100755 net/travelmate/files/travelmate.init create mode 100755 net/travelmate/files/travelmate.sh diff --git a/net/travelmate/Makefile b/net/travelmate/Makefile new file mode 100644 index 000000000..6406566a8 --- /dev/null +++ b/net/travelmate/Makefile @@ -0,0 +1,54 @@ +# +# Copyright (C) 2016 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v3. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=travelmate +PKG_VERSION:=0.2.2 +PKG_RELEASE:=1 +PKG_LICENSE:=GPL-3.0+ +PKG_MAINTAINER:=Dirk Brenken + +include $(INCLUDE_DIR)/package.mk + +define Package/$(PKG_NAME) + SECTION:=net + CATEGORY:=Network + TITLE:=A wlan connection manager for travel router + PKGARCH:=all +endef + +define Package/$(PKG_NAME)/description +A wlan connection manager for travel router. +Please see https://github.com/openwrt/packages/blob/master/net/travelmate/files/README.md for further information. + +endef + +define Package/$(PKG_NAME)/conffiles +/etc/config/travelmate +endef + +define Build/Prepare +endef + +define Build/Configure +endef + +define Build/Compile +endef + +define Package/$(PKG_NAME)/install + $(INSTALL_DIR) $(1)/usr/bin + $(INSTALL_BIN) ./files/travelmate.sh $(1)/usr/bin/ + + $(INSTALL_DIR) $(1)/etc/init.d + $(INSTALL_BIN) ./files/travelmate.init $(1)/etc/init.d/travelmate + + $(INSTALL_DIR) $(1)/etc/config + $(INSTALL_CONF) ./files/travelmate.conf $(1)/etc/config/travelmate +endef + +$(eval $(call BuildPackage,$(PKG_NAME))) diff --git a/net/travelmate/files/README.md b/net/travelmate/files/README.md new file mode 100644 index 000000000..61acdc675 --- /dev/null +++ b/net/travelmate/files/README.md @@ -0,0 +1,125 @@ +# travelmate, a connection manager for travel router + +## 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. + +## Main Features +* STA interfaces operating in an "always off" mode, to make sure that the AP is always accessible +* fast uplink connections +* reliable connection tracking +* easy setup within normal OpenWrt/LEDE environment +* status & debug logging to syslog +* procd init system support + +## Prerequisites +* [OpenWrt](https://openwrt.org) or [LEDE](https://www.lede-project.org) trunk +* iw (default) or iwinfo for wlan scanning + +## OpenWrt / LEDE trunk Installation & Usage +* install 'travelmate' (_opkg install travelmate_) +* configure your network to support (multiple) wlan uplinks and set travelmate config options (details see below) +* travelmate starts automatically during boot, triggered by procd as soon as the wireless subsystem is up & running + +## Chaos Calmer installation notes +* 'travelmate' is _not_ available as an ipk package in the Chaos Calmer download repository +* download the package from a development snapshot package directory: + * for 'travelmate' look [here](https://downloads.lede-project.org/snapshots/packages/x86_64/packages/) +* manually transfer the package to your routers temp directory (with tools like _sshfs_ or _winscp_) +* install the package as described above + +## Travelmate config options +* mandatory 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 uplink xyz (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\_iw => force travelmate to use iwinfo (even if iw is installed) set this option to 'none' (default: '', use iw if found) + +## Setup +**1. configure (multiple) wwan interfaces in /etc/config/network:** +

+[...]
+config interface 'wwan01'
+        option proto 'dhcp'
+config interface 'wwan02'
+        option proto 'dhcp'
+config interface 'wwan03'
+        option proto 'dhcp'
+[...]
+
+ +**2. add these interfaces to your firewall configuration in /etc/config/firewall:** +

+[...]
+config zone
+        option name 'wan'
+        option input 'REJECT'
+        option output 'ACCEPT'
+        option forward 'REJECT'
+        option masq '1'
+        option mtu_fix '1'
+        option network 'wan wan6 wwan01 wwan02 wwan03 [...]'
+[...]
+
+ +**3. add required station interfaces to your wireless configuration in etc/config/wireless:** +

+[...]
+config wifi-iface
+        option device 'radio0'
+        option network 'wwan01'
+        option mode 'sta'
+        option ssid 'example_01'
+        option ifname 'wlan1'
+        option encryption 'psk2+ccmp'
+        option key 'abc'
+        option disabled '1'
+config wifi-iface
+        option device 'radio0'
+        option network 'wwan02'
+        option mode 'sta'
+        option ssid 'example_02'
+        option ifname 'wlan2'
+        option encryption 'psk2+ccmp'
+        option key 'xyz'
+        option disabled '1'
+config wifi-iface
+        option device 'radio0'
+        option network 'wwan03'
+        option mode 'sta'
+        option ssid 'Telekom_ICE'
+        option ifname 'wlan3'
+        option encryption 'none'
+        option disabled '1'
+[...]
+
+ +**4. configure & start travelmate:** +

+/etc/init.d/network reload
+/etc/init.d/travelmate start
+
+ +**Common runtime outputs** + +**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) + +## Removal +* stop the travelmate daemon with _/etc/init.d/travelmate stop_ +* optional: remove the travelmate package (_opkg remove travelmate_) + +Have fun! +Dirk diff --git a/net/travelmate/files/travelmate.conf b/net/travelmate/files/travelmate.conf new file mode 100644 index 000000000..e413a8cfe --- /dev/null +++ b/net/travelmate/files/travelmate.conf @@ -0,0 +1,7 @@ +# travelmate configuration, for further information +# see 'https://github.com/openwrt/packages/blob/master/net/travelmate/files/README.md' + +config travelmate 'global' + option trm_enabled '0' + option trm_loop '30' + option trm_maxretry '3' diff --git a/net/travelmate/files/travelmate.init b/net/travelmate/files/travelmate.init new file mode 100755 index 000000000..fc3e9ed9e --- /dev/null +++ b/net/travelmate/files/travelmate.init @@ -0,0 +1,25 @@ +#!/bin/sh /etc/rc.common + +START=85 +USE_PROCD=1 + +exec 2>/dev/null +trm_script="/usr/bin/travelmate.sh" + +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 +} + +service_triggers() +{ + procd_add_reload_trigger "travelmate" +} diff --git a/net/travelmate/files/travelmate.sh b/net/travelmate/files/travelmate.sh new file mode 100755 index 000000000..01fae5aef --- /dev/null +++ b/net/travelmate/files/travelmate.sh @@ -0,0 +1,243 @@ +#!/bin/sh +# travelmate, a wlan connection manager for travel router +# written by Dirk Brenken (dev@brenken.org) + +# This is free software, licensed under the GNU General Public License v3. +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# prepare environment +# +LC_ALL=C +PATH="/usr/sbin:/usr/bin:/sbin:/bin" +trm_debug="0" +trm_pid="${$}" +trm_ver="0.2.2" +trm_loop=30 +trm_maxretry=3 +trm_device="" +trm_iw="$(which iw)" + +# function to prepare all relevant AP and STA interfaces +# +trm_prepare() +{ + local config="${1}" + local device="$(uci -q get wireless."${config}".device)" + local mode="$(uci -q get wireless."${config}".mode)" + local network="$(uci -q get wireless."${config}".network)" + local disabled="$(uci -q get wireless."${config}".disabled)" + + if [ "${mode}" = "ap" ] && + ([ -z "${trm_device}" ] || [ "${trm_device}" = "${device}" ]) + then + ifname="$(uci -q get wireless."${config}".ifname)" + trm_aplist="${trm_aplist} ${ifname}" + if [ -z "${disabled}" ] || [ "${disabled}" = "1" ] + then + trm_set "none" "${config}" "${network}" "up" + fi + elif [ "${mode}" = "sta" ] + then + trm_stalist="${trm_stalist} ${config}_${network}" + if [ -z "${disabled}" ] || [ "${disabled}" = "0" ] + then + trm_set "none" "${config}" "${network}" "down" + fi + fi +} + +# function to set different wlan interface states +# +trm_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" ] + then + uci -q set wireless."${config}".disabled=1 + ubus call network.interface."${interface}" "${command}" + fi + + trm_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)" ] + then + if [ "${change}" = "commit" ] + then + uci -q commit wireless + ubus call network reload + trm_check + elif [ "${change}" = "partial" ] + then + ubus call network reload + trm_check + elif [ "${change}" = "defer" ] + then + uci -q revert wireless + elif [ "${change}" = "revert" ] + then + uci -q revert wireless + ubus call network reload + trm_check + fi + fi +} + +# function to check interface state on "up" event +# +trm_check() +{ + local interface value + local cnt=0 + + for interface in ${trm_checklist} + do + while [ $((cnt)) -lt 15 ] + do + json_load "$(ubus -S call network.interface."${interface}" status)" + json_get_var trm_state up + if [ "${trm_state}" = "1" ] || [ -n "${trm_uplink}" ] + then + trm_log "debug" "check::: interface: ${interface}, status: ${trm_state}, uplink: ${trm_uplink}, count: ${cnt}" + json_cleanup + break + fi + cnt=$((cnt+1)) + sleep 1 + done + done + if [ -n "${trm_uplink}" ] && [ "${trm_state}" = "0" ] + then + ubus call network reload + trm_checklist="" + trm_log "info" "uplink ${ssid} get lost" + elif [ -z "${trm_uplink}" ] && [ -n "${trm_checklist}" ] + then + trm_checklist="" + fi +} + +# function to write to syslog +# +trm_log() +{ + local class="${1}" + local log_msg="${2}" + + if [ -n "${log_msg}" ] && ([ "${class}" != "debug" ] || ([ "${class}" = "debug" ] && [ "${trm_debug}" = "1" ])) + then + logger -t "travelmate-${trm_ver}[${trm_pid}] ${class}" "${log_msg}" 2>&1 + 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 + trm_log "error" "required system libraries not found" + exit 255 +fi + +# load uci config and check 'enabled' option +# +option_cb() +{ + local option="${1}" + local value="${2}" + eval "${option}=\"${value}\"" +} +config_load travelmate +if [ "${trm_enabled}" != "1" ] +then + trm_log "info" "travelmate is currently disabled, please set 'trm_enabled' to '1' to use this service" + exit 0 +fi + +# check for preferred wireless tool +# +if [ ! -f "${trm_iw}" ] +then + trm_iwinfo="$(which iwinfo)" + if [ ! -f "${trm_iwinfo}" ] + then + trm_log "error" "no wireless tool for scanning found, please install 'iw' or 'iwinfo'" + exit 255 + fi +fi + +# infinitive loop to establish and track STA uplink connections +# +while true +do + if [ -z "${trm_uplink}" ] || [ "${trm_state}" = "0" ] + then + trm_uplink="" + trm_aplist="" + trm_stalist="" + config_load wireless + config_foreach trm_prepare wifi-iface + trm_set "commit" + for ap in ${trm_aplist} + do + ubus -t 10 wait_for hostapd."${ap}" + if [ -f "${trm_iw}" ] + then + trm_ssidlist="$(${trm_iw} 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_iwinfo} "${ap}" scan | awk '/ESSID: ".*"/{ORS=" ";if (!seen[$0]++) for(i=2; i<=NF; i++) print $i}')" + fi + trm_log "debug" "main ::: iw: ${trm_iw}, iwinfo: ${trm_iwinfo}, ssidlist: ${trm_ssidlist}" + if [ -n "${trm_ssidlist}" ] + then + for sta in ${trm_stalist} + do + config="${sta%%_*}" + network="${sta##*_}" + ssid="\"$(uci -q get wireless."${config}".ssid)\"" + if [ $((trm_count_${network})) -lt $((trm_maxretry)) ] + then + if [ -n "$(printf "${trm_ssidlist}" | grep -Fo "${ssid}")" ] + then + trm_set "partial" "${config}" "${network}" "up" + if [ "${trm_state}" = "1" ] + then + trm_uplink="${network}" + trm_checklist="${trm_uplink}" + trm_set "defer" + trm_log "info" "wlan interface \"${network}\" connected to uplink ${ssid}" + break 2 + else + trm_set "revert" + eval "trm_count_${network}=\$((trm_count_${network}+1))" + fi + fi + elif [ $((trm_count_${network})) -eq $((trm_maxretry)) ] + then + eval "trm_count_${network}=\$((trm_count_${network}+1))" + trm_log "info" "uplink ${ssid} disabled due to permanent connection failures" + fi + done + fi + sleep 1 + done + sleep 5 + else + trm_check + if [ -n "${trm_checklist}" ] + then + sleep ${trm_loop} + fi + fi +done