[OpenWrt-Devel] [PATCH 1/2] [packages] add support for Huawei NCM modems

Maarten Deprez deprez.maarten at gmail.com
Sat Mar 28 16:28:50 EDT 2015


Adds support for Huawei NCM modems, which expect ndisdup commands at a
separate cdc-wdm device, supported by kmod-usb-net-huawei-cdc-ncm.
This builds on the work of Oskari Rauta at
https://sites.google.com/site/variousopenwrt/huawei-e3267 . In
particular, i added a lot of resilience. It has provided me with a
stable connection on Huawei E303 and E398 modems during the last few
months.

Signed-off-by: Maarten Deprez <deprez.maarten at gmail.com>


diff --git a/net/huawei-ncm/Makefile b/net/huawei-ncm/Makefile
new file mode 100644
index 0000000..27a0bcc
--- /dev/null
+++ b/net/huawei-ncm/Makefile
@@ -0,0 +1,52 @@
+#
+# Copyright (C) 2015 Maarten Deprez <deprez.maarten at gmail.com
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=huawei-ncm
+PKG_VERSION:=1
+PKG_RELEASE:=0
+PKG_LICENSE:=GPLv2
+
+PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/huawei-ncm
+  SECTION:=net
+  CATEGORY:=Network
+  DEPENDS:=+kmod-usb-net-huawei-cdc-ncm
+  TITLE:=Huawei NCM protocol
+  PKGARCH:=all
+  MAINTAINER:=Maarten Deprez <deprez.maarten at gmail.com>
+endef
+
+define Package/huawei-ncm/description
+ Protocol scripts to make and maintain connections to 3G/4G networks
over huawei NCM modems
+endef
+
+define Build/Prepare
+endef
+
+define Build/Configure
+endef
+
+define Build/Compile
+endef
+
+define Package/huawei-ncm/install
+    $(INSTALL_DIR) $(1)/lib/netifd/proto
+    $(INSTALL_BIN) ./files/lib/netifd/proto/huawei_ncm.sh
$(1)/lib/netifd/proto/huawei_ncm.sh
+    $(INSTALL_DIR) $(1)/usr/bin
+    $(INSTALL_BIN) ./files/usr/bin/* $(1)/usr/bin/
+    $(INSTALL_DIR) $(1)/usr/sbin
+    $(INSTALL_BIN) ./files/usr/sbin/* $(1)/usr/sbin/
+    $(INSTALL_DIR) $(1)/usr/lib/huawei-ncm
+    $(INSTALL_DATA) ./files/usr/lib/huawei-ncm/*.sh $(1)/usr/lib/huawei-ncm/
+endef
+
+$(eval $(call BuildPackage,huawei-ncm))
diff --git a/net/huawei-ncm/files/lib/netifd/proto/huawei_ncm.sh
b/net/huawei-ncm/files/lib/netifd/proto/huawei_ncm.sh
new file mode 100755
index 0000000..a75880c
--- /dev/null
+++ b/net/huawei-ncm/files/lib/netifd/proto/huawei_ncm.sh
@@ -0,0 +1,49 @@
+#!/bin/sh
+
+. /lib/functions.sh
+. ../netifd-proto.sh
+init_proto "$@"
+
+proto_huawei_ncm_init_config() {
+    renew_handler=1
+
+    proto_config_add_string 'pin'
+    proto_config_add_string 'apn'
+    proto_config_add_string 'mode'
+    proto_config_add_string 'freq'
+    proto_config_add_string 'timeout'
+    proto_config_add_string 'interval'
+}
+
+proto_huawei_ncm_setup() {
+    local config="$1"
+    local iface="$2"
+
+    local pin apn mode freq timeout interval
+    json_get_vars pin apn mode freq timeout interval
+
+    proto_export "INTERFACE=$config"
+    proto_run_command "$config" /usr/sbin/huawei-ncm-connect -vvv \
+        -p /var/run/huawei-ncm-$iface.pid \
+        -s /lib/netifd/dhcp.script \
+        -m "${mode:-2,0}" \
+        -f "${freq:-0}" \
+        -n "$pin" \
+        -t "${timeout:-15}" \
+        -i "${interval:-60}" \
+        "$iface" \
+        "$apn"
+
+}
+
+proto_huawei_ncm_renew() {
+    local config="$1"
+    proto_kill_command "$config" SIGHUP
+}
+
+proto_huawei_ncm_teardown() {
+    local config="$1"
+    proto_kill_command "$config"
+}
+
+add_protocol huawei_ncm
diff --git a/net/huawei-ncm/files/usr/bin/huawei-ncm-cells
b/net/huawei-ncm/files/usr/bin/huawei-ncm-cells
new file mode 100755
index 0000000..9443a96
--- /dev/null
+++ b/net/huawei-ncm/files/usr/bin/huawei-ncm-cells
@@ -0,0 +1,33 @@
+#!/bin/sh
+
+VERBOSITY=1
+IFACE="$1"
+
+
+### includes
+
+. /usr/lib/huawei-ncm/error.sh
+. /usr/lib/huawei-ncm/find-modem.sh
+. /usr/lib/huawei-ncm/modem.sh
+
+
+### find and init modem
+
+find_modem
+MODEM="$PCUI"
+init_modem
+
+m=$(modem '^CELLINFO=?') || exit $?
+
+for i in $(echo "$m" | sed -e 's/[()]//g' -e 's/,/\n/g'); do
+
+        n="$(modem "^CELLINFO=$i"
'^[0-9]\+,[0-9]\+,-[0-9]\+,-[0-9]\+$')" || exit $?
+
+        [ -n "$n" ] || continue
+
+        printf '%s [%d dBm / %d dBm]\n' \
+                "$(echo "$n" | cut -d, -f1)" \
+                "$(echo "$n" | cut -d, -f3)" \
+                "$(echo "$n" | cut -d, -f4)"
+
+done
diff --git a/net/huawei-ncm/files/usr/bin/huawei-ncm-info
b/net/huawei-ncm/files/usr/bin/huawei-ncm-info
new file mode 100755
index 0000000..1b358cd
--- /dev/null
+++ b/net/huawei-ncm/files/usr/bin/huawei-ncm-info
@@ -0,0 +1,116 @@
+#!/bin/sh
+
+VERBOSITY=1
+IFACE="$1"
+
+
+### includes
+
+. /usr/lib/huawei-ncm/error.sh
+. /usr/lib/huawei-ncm/find-modem.sh
+. /usr/lib/huawei-ncm/modem.sh
+
+
+### find and init modem
+
+find_modem
+init_modem "$PCUI"
+
+
+### product information
+
+modem I . |
+while read i; do
+
+    case "$i" in
+        Manufacturer:*)
+            echo -n "vendor ";;
+        Model:*)
+            echo -n "model ";;
+        Revision:*)
+            echo -n "firmware ";;
+        IMEI:*)
+            echo -n "imei ";;
+        *) continue;;
+    esac
+
+    echo "$i" | sed 's/^[^:]*: //'
+
+done
+
+
+### network
+
+m="$(modem '+COPS?')" || exit $?
+echo -n "provider "
+echo "$m" | cut -d, -f3 | sed 's/"//g'
+
+
+### mode
+
+m="$(modem '^SYSCFG?')" || exit $?
+echo -n "mode "
+
+case "$(echo "$m" | cut -d, -f1,2)" in
+    2,0) echo "Auto";;
+    2,1) echo "GSM, WCDMA";;
+    2,2) echo "WCDMA, GSM";;
+    13,*) echo "GSM";;
+    14,*) echo "WCDMA";;
+    *) echo "Unknown";;
+esac
+
+
+### data bandwidth
+
+m="$(modem '+CGEQNEG=1')" || exit $?
+printf "uplink %s kbps\n" "$(echo "$m" | cut -d, -f3)"
+printf "downlink %s kbps\n" "$(echo "$m" | cut -d, -f4)"
+
+
+### frequency lock
+
+m="$(modem '^FREQLOCK?')" || exit $?
+echo -n "freqlock "
+echo "$m" | cut -d, -f2
+
+
+### cell
+
+modem '+CREG=2'
+m="$(modem '+CREG?')" || exit $?
+i="$(echo "$m" | cut -d, -f3 | sed 's/"//g')"
+[ -n "$i" ] && printf "lac 0x%x (%d)\n" $((0x$i)) $((0x$i))
+i="$(echo "$m" | cut -d, -f4 | sed 's/"//g')"
+[ -n "$i" ] && printf "ci 0x%x (%d)\n" $((0x$i)) $((0x$i))
+
+
+### cell info
+
+if m="$(modem '^CELLINFO=0' '^[0-9]\+,[0-9]\+,-[0-9]\+,-[0-9]\+$')"; then
+    echo -n "freq "
+    echo "$m" | cut -d, -f1
+fi
+
+
+### network technology
+
+#m="$(modem '^SYSINFOEX')" || exit $?
+#printf "network %s / %s\n" \
+#    "$(echo "$m" | cut -d, -f7 | sed 's/"//g')" \
+#    "$(echo "$m" | cut -d, -f9 | sed 's/"//g')"
+
+
+### reception: csq / rssi
+
+m="$(modem '+CSQ')" || exit $?
+i="$(echo "$m" | cut -d, -f1)"
+[ -n "$i" ] && printf "signal %d%% (%d / 31)\n" $((($i * 100 + 16) / 31)) $i
+[ -n "$i" ] && printf "rssi %d dBm\n" $(($i * 2 - 113))
+
+
+### reception: rcsp / ecio
+
+m="$(modem '^CSNR?')" || exit $?
+printf "rcsp %d dBm\n" "$(echo "$m" | cut -d, -f1)"
+printf "ecio %d dBm\n" "$(echo "$m" | cut -d, -f2)"
diff --git a/net/huawei-ncm/files/usr/lib/huawei-ncm/error.sh
b/net/huawei-ncm/files/usr/lib/huawei-ncm/error.sh
new file mode 100644
index 0000000..9affe46
--- /dev/null
+++ b/net/huawei-ncm/files/usr/lib/huawei-ncm/error.sh
@@ -0,0 +1,14 @@
+### error function
+
+VERBOSITY="${VERBOSITY:-1}"
+
+error () {
+        [ $VERBOSITY -ge 1 ] && echo "$@" >&2
+        exit 1
+}
+
+vecho () {
+        v=$1; shift
+        [ $VERBOSITY -ge $v ] &&
+        echo "$@" >&2
+}
diff --git a/net/huawei-ncm/files/usr/lib/huawei-ncm/find-modem.sh
b/net/huawei-ncm/files/usr/lib/huawei-ncm/find-modem.sh
new file mode 100644
index 0000000..b06df97
--- /dev/null
+++ b/net/huawei-ncm/files/usr/lib/huawei-ncm/find-modem.sh
@@ -0,0 +1,223 @@
+#include error.sh
+
+### load module with checking
+
+# load_module (module, [timeout])
+
+load_module () {
+
+    vecho 2 -n "Loading $1 module... "
+
+    local t=0
+
+    while ! [ -d "/sys/module/$1" ]; do
+
+        if ! [ $((t++)) -lt ${2:-3} ]; then
+            vecho 2 "timeout!" || vecho 1 "timeout loading $1 module"
+            return 1
+        fi
+
+        if ! modprobe "$1"; then
+            vecho 2 "failed!" || vecho 1 "unable to load $1 module"
+            return 1
+        fi
+
+        sleep 1
+
+    done
+
+    vecho 2 "ok!"
+    return 0
+
+}
+
+
+### find huawei modem device
+
+# is_huawei_modem (iface)
+is_huawei_modem () {
+    [ "$(basename "$(readlink "/sys/class/net/$1/device/driver")")" =
huawei_cdc_ncm ]
+}
+
+# find_modem_iface ([iface], [timeout])
+find_modem_iface () {
+
+    vecho 2 -n "Looking for huawei-cdc-ncm modem... "
+
+    local i t=0
+
+    while true; do
+
+        for i in $([ -n "$1" ] && echo "$1" || ls /sys/class/net); do
+            is_huawei_modem "$i" || continue
+            IFACE="$i"; break 2
+        done
+
+        if ! [ $((t++)) -lt ${2:-5} ]; then
+            vecho 2 "failed" || vecho 1 "no huawei-cdc-ncm modem found"
+            return 1
+        fi
+
+        sleep 1
+
+    done
+
+    usbpath="$(readlink -f "/sys/class/net/$IFACE/device")"
+
+    vecho 2 "ok!"
+    return 0
+
+}
+
+
+### find interfaces
+# use AT^SETPORT="FF;1,16,3,2" and restart
+# to enable (only) necessary interfaces
+
+check_interfaces () {
+    [ -c "$MODEM" -a -c "$PCUI" -a -c "$WDM" ]
+}
+
+find_interfaces () {
+
+    vecho 2 -n "Enumerating interfaces on $IFACE... "
+
+    local i
+
+    unset MODEM PCUI DIAG WDM
+
+    for i in /sys/class/net/"$IFACE"/device/../*:*; do
+        case $(cat "$i"/bInterfaceProtocol) in
+            01) MODEM="/dev/$(basename "$i"/tty*)";;
+            02) PCUI="/dev/$(basename "$i"/tty*)";;
+            03) DIAG="/dev/$(basename "$i"/tty*)";;
+            16) WDM="/dev/$(basename "$i/usbmisc"/*)";;
+        esac
+    done
+
+
+    # check if necessary interfaces are present
+
+    if ! check_interfaces; then
+        vecho 1 "missing interfaces from $IFACE:" \
+            "$( [ -c "$MODEM" ] || echo modem )" \
+            "$( [ -c "$PCUI" ] || echo pcui )" \
+            "$( [ -c "$WDM" ] || echo wdm )"
+        return 1
+    fi
+
+    vecho 2 "ok!"
+    return 0
+
+}
+
+
+### usb connection path
+
+cumpath () {
+
+    local p i
+
+    read p
+
+    while read i; do
+        p="$p/$i"
+        echo "$i" | grep -qx "$1" &&
+        echo "$p"
+    done
+
+}
+
+usb_path () {
+    echo "$1" | sed -e 's@\(^.*/usb[0-9]\+\|[^/]\+\)/@\1\n at g' |
+    cumpath '[0-9.-]\+'
+}
+
+
+### reset last usb hub in path
+
+usbpath=
+
+reset_usb () {
+
+    [ -x /usr/bin/usbreset ] || return 1
+    [ -n "$usbpath" ] || return 1
+
+    local dev i
+
+        vecho 2 -n "Trying to recover usb connectivity... "
+
+    usb_path "$usbpath" | tac |
+
+    while read i; do
+
+        vecho 3 -n "($(basename "$i")) "
+
+        [ -d "$i" ] || continue
+        [ -f "$i/busnum" -a -f "$i/devnum" ] || continue
+
+        dev=$(printf '%03d/%03d\n' $(cat "$i/busnum") $(cat "$i/devnum"))
+        vecho 3 -n "--> [$dev] "
+
+        usbreset $dev || break
+
+        vecho 2 "ok!"
+        return 0
+
+    done
+
+    vecho 2 "failed!"
+    return 1
+
+}
+
+
+### reset modem device
+
+reset_modem () {
+
+    [ -c "$MODEM" ] || return 1
+
+    vecho 2 -n "Resetting modem $IFACE... "
+
+    echo -en "AT+CFUN=4\r\n" > "$MODEM"
+    sleep 1
+    echo -en "AT+CFUN=6,0\r\n" > "$MODEM"
+
+    vecho 2 "ok!"
+    return 0
+
+}
+
+
+### find modem
+
+iface="$IFACE"
+
+find_modem () {
+    find_modem_iface "$iface" "${1:-10}" &&
+    find_interfaces
+}
+
+
+### find modem with resilience
+
+find_modem_hard () {
+
+    local t=0
+
+    load_module huawei_cdc_ncm || return 1
+
+    while true; do
+
+        find_modem ${1:-30} && return 0
+
+        [ $((t++)) -lt 2 ] || return 1
+
+        reset_modem ||
+        #reset_usb ||
+        return 1
+
+    done
+
+}
diff --git a/net/huawei-ncm/files/usr/lib/huawei-ncm/modem.sh
b/net/huawei-ncm/files/usr/lib/huawei-ncm/modem.sh
new file mode 100644
index 0000000..0cba57c
--- /dev/null
+++ b/net/huawei-ncm/files/usr/lib/huawei-ncm/modem.sh
@@ -0,0 +1,70 @@
+#include error.sh
+
+### open modem device
+
+modem=
+
+init_modem () {
+    local m="${1:-$MODEM}"
+    [ -c "$m" ] || error "modem $m does not exist"
+    [ $VERBOSITY -ge 4 ] && echo "Opening modem $m" >&2
+    exec 5<> "$m" || error "failed to open modem: $m"
+    echo -en 'ATE0\r\n' >&5
+    while read -rt1 -u5 i; do true; done
+    modem="$m"
+}
+
+
+### send command and read response
+
+modem() {
+
+    [ -n "$modem" ] || error "modem not initialized"
+
+    echo -en "AT$1\r\n" >&5
+
+    if [ -n "$2" ]; then
+        match="$2"
+        select=
+    else
+        match="^$(echo "$1" | grep -o "^\W\w\+"):"
+        select='s/^.*: *//'
+    fi
+
+    err=timeout; t0=$(($(date +%s)+10))
+    while [ $((t=t0-$(date +%s))) -gt 0 ] && read -r -t$t -u5 i; do
+
+        i="$(echo "$i" | sed 's/\r$//')"
+
+        vecho 4 "modem: $1: $i" >&2
+
+        #echo "$i" | grep -q "^AT" && continue
+
+        if echo "$i" | grep -q '^OK'; then
+            err=; break
+        fi
+
+        if echo "$i" | grep -q '^ERROR'; then
+            err="command error"; break
+        fi
+
+        if echo "$i" | grep -q '^CME ERROR:'; then
+            err="cme error ${i#*:}"; break
+        fi
+
+        if echo "$i" | grep -q "$match"; then
+                        echo "$i" | sed "$select"
+                        continue
+                fi
+
+        n=$((n+1))
+
+    done
+
+    if [ -n "$err" ]; then
+        vecho 1 "modem error: $1: $err" >&2
+        return 1
+    fi
+
+    return 0
+}
diff --git a/net/huawei-ncm/files/usr/sbin/huawei-ncm-connect
b/net/huawei-ncm/files/usr/sbin/huawei-ncm-connect
new file mode 100755
index 0000000..90f8152
--- /dev/null
+++ b/net/huawei-ncm/files/usr/sbin/huawei-ncm-connect
@@ -0,0 +1,367 @@
+#!/bin/sh
+
+
+### error handling and logging
+
+. /usr/lib/huawei-ncm/error.sh
+
+
+### interrupt handlers
+
+int=
+run=1
+renew=
+connection=0
+
+sleep=
+
+wsleep () {
+    sleep "$@" & sleep=$!
+    wait $sleep; sleep=
+    [ -n "$run" ]
+}
+
+trap 'run=; [ -n "$sleep" ] && kill $sleep; vecho 2 "interrupt!"' TERM
+trap 'renew=1; [ -n "$sleep" ] && kill $sleep; vecho 2 "renew!"' HUP
+trap 'kill -TERM $$; int=1' INT
+trap '[ -n "$PID" ] && rm -f "$PID"' EXIT
+
+
+### check arguments
+
+PID=
+PIN=
+MODE=
+FREQ=
+SCRIPT=/lib/netifd/dhcp.script
+TIMEOUT=15
+INTERVAL=60
+VERBOSITY=1
+
+usage () {
+
+    if [ $VERBOSITY -ge 1 ]; then
+            echo "Usage: $0 [ options ] <interface> <apn>" >&2
+        echo "Options:" >&2
+        echo "    -p <pidfile>    save PID in <pidfile>" >&2
+        echo "    -m <mode>    set modem to network <mode>" >&2
+        echo "    -f <freq>    lock frequency to <freq>" >&2
+        echo "    -n <pin>    pin code of the card" >&2
+        echo "    -s <script>    use <script> as DHCP script" >&2
+        echo "    -t <timeout>    time to wait for network and data
connection" >&2
+        echo "    -i <interval>    connection checking interval" >&2
+    fi
+
+        exit 2
+}
+
+while getopts ":p:m:f:n:s:t:i:qvh" i; do
+    case $i in
+        p) PID="$OPTARG";;
+        m) MODE="$OPTARG";;
+        f) FREQ="$OPTARG";;
+        n) PIN="$OPTARG";;
+        s) SCRIPT="$OPTARG";;
+        t) TIMEOUT="$OPTARG";;
+        i) INTERVAL="$OPTARG";;
+        q) VERBOSITY=$((VERBOSITY-1));;
+        v) VERBOSITY=$((VERBOSITY+1));;
+        h) usage;;
+        ?) vecho 1 "Invalid option: -$OPTARG"; usage;;
+        :) vecho 1 "Option -$OPTARG needs an argument"; usage;;
+    esac
+done
+
+shift $(($OPTIND-1))
+
+if [ $# -ne 2 ]; then
+    vecho 1 "Expecting two arguments"
+    usage
+fi
+
+IFACE="$1"
+APN="$2"
+
+
+### save pid
+
+if [ -n "$PID" ]; then
+    echo $$ > "$PID"
+fi
+
+
+### include modem functions
+
+. /usr/lib/huawei-ncm/find-modem.sh
+. /usr/lib/huawei-ncm/modem.sh
+
+
+### check pin state
+
+check_pin () {
+
+    vecho 2 -n "Checking PIN... "
+
+    m="$(modem '^CPIN?')" || exit $?
+    pin="$(echo "$m" | cut -d, -f1)"
+    times="$(echo "$m" | cut -d, -f2)"
+
+    case "$pin" in
+
+        READY)
+            vecho 2 "ok!"
+        ;;
+
+        SIM\ PIN)
+
+            ### don't try to unlock in face of failed tries
+            if [ "$times" != 3 ]; then
+                vecho 1 "SIM card locked with non-virgin 'times'
record; won't try to unlock"
+                exit 1
+            fi
+
+            ### check if PIN was given
+            if [ -z "$PIN" ]; then
+                vecho 1 "SIM card locked but no PIN specified"
+                exit 1
+            fi
+
+
+            ### try to unlock
+
+            modem "^CPIN=\"$PIN\"" || exit $?
+
+        ;;
+
+        *)
+            vecho 1 "SIM card locked with $pin code ($m)"
+            exit 1
+        ;;
+    esac
+}
+
+### set mode if requested
+
+set_mode () {
+
+    [ -z "$MODE" ] && return
+
+    vecho 2 -n "Setting mode... "
+
+    ### default: no change
+    mode=16,3
+
+    ### calculate mode
+
+    case "$MODE" in
+        gsm) mode=13,0 ;;
+        wcdma) mode=14,0 ;;
+        gsmfirst) mode=2,1 ;;
+        wcdmafirst) mode=2,2 ;;
+        auto) mode=2,0 ;;
+    esac
+
+    ### set mode
+    modem "^SYSCFG=$mode,3fffffff,2,4" || exit $?
+
+    vecho 2 "ok!"
+}
+
+
+### lock to frequency if requested
+
+lock_frequency () {
+
+    [ -n "$FREQ" ] || return 0
+
+        vecho 2 -n "Locking frequency... "
+
+    if [ "$FREQ" = "0" ]; then
+        modem "^FREQLOCK=0" || exit $?
+    else
+        modem "^FREQLOCK=1,$FREQ" || exit $?
+    fi
+
+    vecho 2 "ok!"
+    return 0
+
+}
+
+
+### wait for network registration
+
+register () {
+
+    vecho 2 -n "Waiting for network... "
+
+    for i in $(seq "$TIMEOUT"); do
+        stat="$(modem '+CREG?' | cut -d, -f2)" || exit $?
+        [ "$stat" == 1 ] && break
+        wsleep 1 || return 1
+        vecho 2 -en "\b. "
+    done
+
+    if [ "$stat" != 1 ]; then
+        vecho 2 "timeout" || vecho 1 "timeout while waiting for network"
+        return 1
+    fi
+
+    vecho 2 "ok!"
+    return 0
+}
+
+
+### check +CGPADDR response
+is_connected () {
+    [ -n "$1" -a "$1" != '"0.0.0.0"' ]
+}
+
+
+### establish data connection
+
+connect () {
+
+    vecho 2 -n "Establishing data connection... "
+
+    echo -en "AT^NDISDUP=1,1,\"$APN\"\r\n" > "$WDM"
+    connection=1
+
+    for i in $(seq "$TIMEOUT"); do
+        ip="$(modem '+CGPADDR=1' | cut -d, -f2)" || exit $?
+        is_connected "$ip" && break
+        wsleep 1 || return 1
+        vecho 2 -en "\b. "
+    done
+
+    if ! is_connected "$ip"; then
+        vecho 2 "timeout" || vecho 1 "timeout waiting for data connection"
+        return 1
+    fi
+
+    vecho 2 "ok"
+    return 0
+
+}
+
+
+### request address
+
+dhcp () {
+
+    vecho 2 -n "Running udhcpc... "
+
+    ifconfig "$IFACE" up &&
+    udhcpc -i "$IFACE" -s "$SCRIPT" -f -t 0 -q
+
+    [ -n "$run" ] || return 1
+
+    if [ $? -gt 0 ]; then
+        vecho 1 "failed to get ip address"
+        return 1
+    fi
+
+    connection=2
+    vecho 2 "ok"
+    return 0
+
+}
+
+### take a break
+
+nap () {
+
+    ### sleep...
+
+    vecho 3 -n "Taking a nap... "
+
+    wsleep "$INTERVAL" || return 1
+    [ -z "$renew" ] || return 1
+
+    vecho 3 "wake up"
+    return 0
+
+}
+
+
+### check connection
+check () {
+
+    [ $connection -ne 2 ] && return 1
+
+    vecho 3 -n "Checking connection... "
+
+    ip="$(modem '+CGPADDR=1' | cut -d, -f2)" || exit $?
+
+    if ! is_connected "$ip"; then
+        connection=0
+        vecho 2 "lost connection"
+        return 1
+    fi
+
+    vecho 3 "ok!"
+    return 0
+
+}
+
+### disconnect
+
+disconnect () {
+
+    [ $connection -ge 1 ] || return
+
+    vecho 2 -n "Disconnecting... "
+
+    echo -en "AT^NDISDUP=1,0\r\n" > "$WDM"
+
+    for i in $(seq "$TIMEOUT"); do
+        ip="$(modem '+CGPADDR=1' | cut -d, -f2)" || exit $?
+        [ -z "$ip" ] && break
+        wsleep 1
+        vecho 2 -en "\b. "
+    done
+
+    if [ -n "$ip" ]; then
+        vecho 2 "timeout" || vecho 1 "timeout waiting for disconnection"
+        return 1
+    fi
+
+    vecho 1 "disconnected"
+    connection=0
+    return 0
+
+}
+
+
+### connection loop
+
+while [ -n "$run" ]; do
+
+    if ! find_modem_hard; then
+        vecho 1 "Couldn't find modem; sleeping 10 minutes"
+        wsleep 600
+        continue
+    fi
+
+    init_modem
+
+    check_pin
+    set_mode
+    lock_frequency
+
+    register &&
+    connect &&
+    dhcp
+
+    renew=
+    while [ -n "$run" ]; do
+        nap && check || break
+    done
+
+    check_interfaces &&
+    disconnect
+
+done
+
+if [ -n "$int" ]; then
+    kill -INT -$$
+fi
_______________________________________________
openwrt-devel mailing list
openwrt-devel at lists.openwrt.org
https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel



More information about the openwrt-devel mailing list