This patch adds more user friendly support for 3g/lte modems using NCM network interface. This work I did, can easily be ported to variants like QMI, etc.. This adds support to /etc/config/network so one can define there usage of a such dongle, and then WAN connection can be automaticly established without hacky scripts. This patch also creates 3 other packages than just basic support for NCM: 1) support for Huawei E3672 dongle (initially no other dongles supported) 2) ncm protocol support for luci. Easy/simple/fast to set up in LuCI. 3) status page for luci reporting dongles: hardware, carrier, cell and signal.
Better description and screenshots from LuCI from this forum post: https://forum.openwrt.org/viewtopic.php?pid=218745#p218745 Signed-off-by: Oskari Rauta <oskari.ra...@gmail.com> Patch starts: diff --git a/package/network/services/ncm/Makefile b/package/network/services/ncm/Makefile new file mode 100644 index 0000000..a37e3ed --- /dev/null +++ b/package/network/services/ncm/Makefile @@ -0,0 +1,151 @@ +# +# Copyright (C) 2007-2013 OpenWrt.org +# Copyright (C) 2010 Vertical Communications +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=ncm +PKG_VERSION:=1.0 +PKG_RELEASE:=1 +PKG_MAINTAINER:=Oskari Rauta <oskari.ra...@gmail.com> +PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)-$(PKG_RELEASE) + +include $(INCLUDE_DIR)/package.mk + +define Package/ncm/Default + VERSION:=$(PKG_VERSION)-$(PKG_RELEASE) + URL:=http://openwrt.org/ + MAINTAINER:=Oskari Rauta <oskari.ra...@gmail.com> +endef + +define Package/ncm +$(call Package/ncm/Default) + SECTION:=net + CATEGORY:=Network + TITLE:=Protocol support for NCM + DEPENDS:=+netifd +comgt +kmod-usb-net-cdc-ncm +kmod-usb-serial +endef + +define Package/ncm/description + This package contains protocol support for NCM. +endef + +define Package/ncm-huawei-e3276 +$(call Package/ncm/Default) + SECTION:=net + CATEGORY:=Network + TITLE:=Huawei E3276 support for NCM protocol + DEPENDS:=+ncm +comgt +kmod-usb-serial +endef + +define Package/ncm-huawei-e3276/description + This package contains communication scripts for Huawei E3276 +endef + +define Package/luci-proto-ncm +$(call Package/ncm/Default) + SECTION:=luci + CATEGORY:=LuCI + SUBMENU:=6. Protocols + TITLE:=Support for NCM + DEPENDS:=+ncm +endef + +define Package/luci-proto-ncm/description + This package contains LuCI support for NCM +endef + +define Package/luci-mod-ncm-status +$(call Package/ncm/Default) + SECTION:=luci + CATEGORY:=LuCI + SUBMENU:=2. Modules + TITLE:=LuCI NCM Status Module + DEPENDS:=+luci-mod-admin-core +ncm +comgt +kmod-usb-serial +endef + +define Package/luci-mod-ncm-status/description + LuCI NCM Status Module +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) +endef + +define Build/Configure +endef + +define Build/Compile/Default +endef + +Build/Compile = $(Build/Compile/Default) + +define Package/ncm/install + $(INSTALL_DIR) $(1)/lib + $(INSTALL_DIR) $(1)/lib/netifd + $(INSTALL_DIR) $(1)/lib/netifd/proto + $(INSTALL_DIR) $(1)/etc + $(INSTALL_DIR) $(1)/etc/gcom + $(INSTALL_DIR) $(1)/etc/gcom/ncm + $(INSTALL_DIR) $(1)/etc/gcom/ncm/signal + $(INSTALL_DIR) $(1)/etc/gcom/ncm/carrier + $(INSTALL_DIR) $(1)/etc/gcom/ncm/setmode + $(INSTALL_DIR) $(1)/etc/gcom/ncm/connect + $(INSTALL_DIR) $(1)/etc/gcom/ncm/initscripts + $(INSTALL_BIN) ./files/lib/netifd/proto/ncm.sh $(1)/lib/netifd/proto/ + $(INSTALL_DATA) ./files/etc/gcom/ncm/getcardinfo.gcom $(1)/etc/gcom/ncm/ +endef + +define Package/ncm-huawei-e3276/install + $(INSTALL_DIR) $(1)/etc + $(INSTALL_DIR) $(1)/etc/gcom + $(INSTALL_DIR) $(1)/etc/gcom/ncm + $(INSTALL_DIR) $(1)/etc/gcom/ncm/signal + $(INSTALL_DIR) $(1)/etc/gcom/ncm/carrier + $(INSTALL_DIR) $(1)/etc/gcom/ncm/setmode + $(INSTALL_DIR) $(1)/etc/gcom/ncm/connect + $(INSTALL_DIR) $(1)/etc/gcom/ncm/initscripts + $(INSTALL_DATA) ./files/etc/gcom/ncm/signal/huawei_e3276.gcom $(1)/etc/gcom/ncm/signal/ + $(INSTALL_DATA) ./files/etc/gcom/ncm/carrier/huawei_e3276.gcom $(1)/etc/gcom/ncm/carrier/ + $(INSTALL_DATA) ./files/etc/gcom/ncm/setmode/huawei_e3276.gcom $(1)/etc/gcom/ncm/setmode/ + $(INSTALL_DATA) ./files/etc/gcom/ncm/connect/huawei_e3276.gcom $(1)/etc/gcom/ncm/connect/ + $(INSTALL_DATA) ./files/etc/gcom/ncm/initscripts/huawei_e3276.gcom $(1)/etc/gcom/ncm/initscripts/ +endef + +define Package/luci-proto-ncm/install + $(INSTALL_DIR) $(1)/usr + $(INSTALL_DIR) $(1)/usr/lib + $(INSTALL_DIR) $(1)/usr/lib/lua + $(INSTALL_DIR) $(1)/usr/lib/lua/luci + $(INSTALL_DIR) $(1)/usr/lib/lua/luci/model + $(INSTALL_DIR) $(1)/usr/lib/lua/luci/model/network + $(INSTALL_DIR) $(1)/usr/lib/lua/luci/model/cbi + $(INSTALL_DIR) $(1)/usr/lib/lua/luci/model/cbi/admin_network + $(INSTALL_DATA) ./files/usr/lib/lua/luci/model/network/proto_ncm.lua $(1)/usr/lib/lua/luci/model/network/ + $(INSTALL_DATA) ./files/usr/lib/lua/luci/model/cbi/admin_network/proto_ncm.lua $(1)/usr/lib/lua/luci/model/cbi/admin_network/ +endef + +define Package/luci-mod-ncm-status/install + $(INSTALL_DIR) $(1)/usr + $(INSTALL_DIR) $(1)/usr/lib + $(INSTALL_DIR) $(1)/usr/lib/lua + $(INSTALL_DIR) $(1)/usr/lib/lua/luci + $(INSTALL_DIR) $(1)/usr/lib/lua/luci/view + $(INSTALL_DIR) $(1)/usr/lib/lua/luci/view/ncm + $(INSTALL_DIR) $(1)/usr/lib/lua/luci/controller + $(INSTALL_DIR) $(1)/www + $(INSTALL_DIR) $(1)/www/luci-static + $(INSTALL_DIR) $(1)/www/luci-static/resources + $(INSTALL_DATA) ./files/usr/lib/lua/luci/view/ncm/status.htm $(1)/usr/lib/lua/luci/view/ncm/ + $(INSTALL_DATA) ./files/usr/lib/lua/luci/controller/ncmstatus.lua $(1)/usr/lib/lua/luci/controller/ + $(INSTALL_DATA) ./files/www/luci-static/resources/ncm_xhr.js $(1)/www/luci-static/resources/ +endef + +$(eval $(call BuildPackage,ncm)) +$(eval $(call BuildPackage,ncm-huawei-e3276)) +$(eval $(call BuildPackage,luci-proto-ncm)) +$(eval $(call BuildPackage,luci-mod-ncm-status)) diff --git a/package/network/services/ncm/files/etc/gcom/ncm/carrier/huawei_e3276.gcom b/package/network/services/ncm/files/etc/gcom/ncm/carrier/huawei_e3276.gcom new file mode 100644 index 0000000..58684fd --- /dev/null +++ b/package/network/services/ncm/files/etc/gcom/ncm/carrier/huawei_e3276.gcom @@ -0,0 +1,56 @@ +opengt +set com 115200n81 +set comecho off +set senddelay 0.02 +waitquiet 0.2 0.2 +flash 0.1 + +:getprovider + send "AT+COPS?^m" + let $r="+COPS:" + gosub readresult + system "echo \""+$x+"\" | awk -F\"[:,]\" '{print \"provider \\x27\" $4 \"\\x27\"}'" + +:getmode + send "AT^^SYSCFGEX?^m" + let $r="^^SYSCFGEX:" + gosub readresult + system "echo \""+$x+"\" | awk -F\"[:,]\" '{ \\ + if ( $2 == \"01\" ) print \"mode \\x27\" \"2G\\x27\"; \\ + else if ( $2 == \"02\" ) print \"mode \\x27\" \"3G\\x27\"; \\ + else if ( $2 == \"03\" ) print \"mode \\x27\" \"LTE\\x27\"; \\ + else if ( $2 == \"0201\" ) print \"mode \\x27\" \"3G Preferred\\x27\"; \\ + else if ( $2 == \"030201\" ) print \"mode \\x27\" \"LTE Preferred\\x27\"; \\ + else if (( $2 == \"00\" ) or ( $2 == \"0\" )) print \"mode \\x27\" \"Automatic/Any\\x27\"; \\ + else print \"mode \\x27\" \"Unknown\\x27\";}'" + +:getrate + send "AT+CGEQNEG=1^m" + let $r="+CGEQNEG:" + gosub readresult + system "echo \""+$x+"\" | awk -F\"[:,]\" '{ print \"downlink \\x27\" int($5) \"kbps\\x27\"; print \"uplink \\x27\" int($4) \"kbps\\x27\"; }'" + goto done + +:readresult + let i=5 + let $x="" +:loop + get 1 "^m" $s + let l=len($r) + if len($s) < l goto loop1 + if $mid($s,1,l) <> $r goto loop1 + let $x=$mid($s,1,len($s)-1) + return +:loop1 + if len($s) < 2 goto loop2 + if $mid($s,1,2) = "ER" return + if $mid($s,1,2) = "CO" return +:loop2 + if i = 0 return + let i=i-1 + sleep 0.25 + goto loop + +:done + exit 0 +^@^@ diff --git a/package/network/services/ncm/files/etc/gcom/ncm/connect/huawei_e3276.gcom b/package/network/services/ncm/files/etc/gcom/ncm/connect/huawei_e3276.gcom new file mode 100644 index 0000000..d7a604c --- /dev/null +++ b/package/network/services/ncm/files/etc/gcom/ncm/connect/huawei_e3276.gcom @@ -0,0 +1,63 @@ +opengt +set com 115200n81 +set comecho off +set senddelay 0.05 +waitquiet 1 0.2 + +:start + if $env("USE_DISCONNECT")="1" goto disconnect + send "AT^^NDISDUP=1,1,\"" + send $env("USE_APN") + + if $env("USE_AUTHTYPE")="-1" goto noauth + else goto auth + +:noauth + send "\"^m" + goto result + +:auth + send "\",\"" + send $env("USE_USERID") + send "\",\"" + send $env("USE_PASSWORD") + send "\"," + send $env("USE_AUTHTYPE") + send "^m" + goto result + +:result + waitfor 5 "OK","ERR","ERROR" + if % = 0 goto connok + if % = 1 goto connerr + if % = 2 goto connerr + +:connok + print "WWAN connection established.\r\n" + goto done + +:connerr + print "WWAN error. Connection failed.\r\n" + exit 1 + +:disconnect + send "AT^^NDISDUP=1,0,\"" + send $env("USE_APN") + send "\"^m" + + waitfor 5 "OK","ERR","ERROR" + if % = 0 goto disconnok + if % = 1 goto disconnerr + if % = 2 goto disconnerr + +:disconnok + print "WWAN connection disconnected.\r\n" + goto done + +:disconnerr + print "WWAN disconnection error.\r\n" + exit 1 + +:done + exit 0 +^@^@ diff --git a/package/network/services/ncm/files/etc/gcom/ncm/getcardinfo.gcom b/package/network/services/ncm/files/etc/gcom/ncm/getcardinfo.gcom new file mode 100644 index 0000000..79bea16 --- /dev/null +++ b/package/network/services/ncm/files/etc/gcom/ncm/getcardinfo.gcom @@ -0,0 +1,38 @@ +opengt + set com 115200n81 + set comecho on + set senddelay 0.02 + waitquiet 0.2 0.2 + flash 0.1 + +:start + let i=0 + +:waitfordevice + waitquiet 2 0.5 + inc i + send "AT^m" + waitfor 4 "OK","ERR","ERROR" + if % = 0 goto detect + if i < 5 goto waitfordevice + print "Error: Dongle not responding." + exit 1 + +:detect + send "ATI^m" + waitfor 1 "ATI^m" + get 1 "OK" $s + +:output + system "echo \""+$s+"\" | grep \"Manufacturer:\" | awk '{print \"vendor \\x27\" $2 \"\\x27\"; }'" + system "echo \""+$s+"\" | grep \"Model:\" | awk '{print \"model \\x27\" $2 \"\\x27\"; }'" + system "echo \""+$s+"\" | grep \"Revision:\" | awk '{print \"firmware \\x27\" $2 \"\\x27\"; }'" + system "echo \""+$s+"\" | grep \"IMEI:\" | awk '{print \"imei \\x27\" $2 \"\\x27\"; }'" + system "echo \""+$s+"\" | egrep -i '^^Manufacturer|^^Model' | cut -d ' ' -f 2 | tr -d '\r' | tr '\n' '_' | sed \"s/\\(.*\\)_$/\\'\\1\\'\\n/\" | awk '{ gsub(\"\\x27\", \"\"); \\ + if ( $1 == \"huawei_E3276\" ) print \"driver \\x27huawei_e3276\\x27\"; \\ + else print \"driver \\x27-\\x27\";}'" + + goto continue + +:continue + exit 0 diff --git a/package/network/services/ncm/files/etc/gcom/ncm/initscripts/huawei_e3276.gcom b/package/network/services/ncm/files/etc/gcom/ncm/initscripts/huawei_e3276.gcom new file mode 100644 index 0000000..7d60abd --- /dev/null +++ b/package/network/services/ncm/files/etc/gcom/ncm/initscripts/huawei_e3276.gcom @@ -0,0 +1,31 @@ +opengt +set com 115200n81 +set comecho off +set senddelay 0.02 +waitquiet 0.2 0.2 +flash 0.1 + +:start + send "AT^m" + waitfor 4 "OK","ERR","ERROR" + if % = 1 goto initerror + if % = 2 goto initerror + + send "ATZ^m" + waitfor 4 "OK","ERR","ERROR" + if % = 1 goto initerror + if % = 2 goto initerror + + send "ATQ V1 E1 S0=0^m" + waitfor 4 "OK","ERR","ERROR" + if % = 0 goto continue + if % = 1 goto initerror + if % = 2 goto initerror + +:modeerror + print "Error while initializing dongle.\n" + exit 1 + +:continue + print "Dongle initialization complete.\n" + exit 0 diff --git a/package/network/services/ncm/files/etc/gcom/ncm/setmode/huawei_e3276.gcom b/package/network/services/ncm/files/etc/gcom/ncm/setmode/huawei_e3276.gcom new file mode 100644 index 0000000..275cca4 --- /dev/null +++ b/package/network/services/ncm/files/etc/gcom/ncm/setmode/huawei_e3276.gcom @@ -0,0 +1,56 @@ +# set wwan mode from environment +opengt + set com 115200n81 + set senddelay 0.02 + waitquiet 1 0.2 + flash 0.1 + +:start + if $env("MODE")="2g" goto 2g + if $env("MODE")="3g" goto 3g + if $env("MODE")="lte" goto lte + if $env("MODE")="prefer3g" goto prefer3g + if $env("MODE")="preferlte" goto preferlte + goto auto + +:auto + send "AT^^SYSCFGEX=\"00\",3FFFFFFF,2,4,7FFFFFFFFFFFFFFF,,^m" + goto result + +:2g + send "AT^^SYSCFGEX=\"01\",3FFFFFFF,2,4,7FFFFFFFFFFFFFFF,,^m" + goto result + +:3g + send "AT^^SYSCFGEX=\"02\",3FFFFFFF,2,4,7FFFFFFFFFFFFFFF,,^m" + goto result + +:lte + send "AT^^SYSCFGEX=\"03\",3FFFFFFF,2,4,7FFFFFFFFFFFFFFF,,^m" + goto result + +:prefer3g + send "AT^^SYSCFGEX=\"0201\",3FFFFFFF,2,4,7FFFFFFFFFFFFFFF,,^m" + goto result + +:preferlte + send "AT^^SYSCFGEX=\"030201\",3FFFFFFF,2,4,7FFFFFFFFFFFFFFF,,^m" + goto result + +:result + waitfor 8 "OK","ERR","ERROR" + if % = 0 goto continue + if % = 1 goto modeerror + if % = 2 goto modeerror + print "Timeout setting WWAN mode!\n" + exit 1 + +:modeerror + print "Error setting WWAN mode!\n" + exit 1 + +:continue + print "WWAN mode set to '" + print $env("MODE") + print "'\r\n" + exit 0 diff --git a/package/network/services/ncm/files/etc/gcom/ncm/signal/huawei_e3276.gcom b/package/network/services/ncm/files/etc/gcom/ncm/signal/huawei_e3276.gcom new file mode 100644 index 0000000..a2ddb61 --- /dev/null +++ b/package/network/services/ncm/files/etc/gcom/ncm/signal/huawei_e3276.gcom @@ -0,0 +1,61 @@ +opengt +set com 115200n81 +set comecho off +set senddelay 0.02 +waitquiet 0.2 0.2 +flash 0.1 + +:getcell + send "AT+CREG=2^m" + let $r="OK" + gosub readresult + if $r <> $x goto getnetwork + + send "AT+CREG?^m" + let $r="+CREG:" + gosub readresult + system "echo \""+$x+"\" | awk -F\"[:,]\" '{print \"cellid \\x27\" \"0x\" $5 \" (\" (\"0x\"$5)+0 \")\\x27\"; print \"lac \\x27\" \"0x\" $4 \" (\" (\"0x\"$4)+0 \")\\x27\";}'" + +:getnetwork + send "AT^^SYSINFOEX^m" + let $r="^^SYSINFOEX:" + gosub readresult + system "echo \""+$x+"\" | awk -F\"[:,]\" '{print \"network \\x27\" $8 \" / \" $10 \"\\x27\";}'" + +:getsignalstrength + send "AT+CSQ^m" + let $r="+CSQ:" + gosub readresult + system "echo \""+$x+"\" | awk -F\"[:,]\" '{ print \"signal \\x27\" int(($2 * 100 / 31)+0.5) \"%\\x27\"; print \"rssi \\x27\" int(2 * $2 - 113) \"dBm\\x27\"; print \"csq \\x27\" int($2) \"\\x27\"; }'" + +:getnoicelevels + send "AT^^CSNR?^m" + let $r="^^CSNR:" + gosub readresult + system "echo \""+$x+"\" | awk -F\"[:,]\" '{ print \"rcsp \\x27\" int($2) \"dBm\\x27\"; print \"ecio \\x27\" int($3) \"dB\\x27\";}'" + + goto done + +:readresult + let i=5 + let $x="" +:loop + get 1 "^m" $s + let l=len($r) + if len($s) < l goto loop1 + if $mid($s,1,l) <> $r goto loop1 + let $x=$mid($s,1,len($s)-1) + return +:loop1 + if len($s) < 2 goto loop2 + if $mid($s,1,2) = "ER" return + if $mid($s,1,2) = "CO" return +:loop2 + if i = 0 return + let i=i-1 + sleep 0.25 + goto loop + +:done + exit 0 +^@^@ diff --git a/package/network/services/ncm/files/lib/netifd/proto/ncm.sh b/package/network/services/ncm/files/lib/netifd/proto/ncm.sh new file mode 100755 index 0000000..62b00b8 --- /dev/null +++ b/package/network/services/ncm/files/lib/netifd/proto/ncm.sh @@ -0,0 +1,137 @@ +#!/bin/sh + +. /lib/functions.sh +. ../netifd-proto.sh +init_proto "$@" + +proto_ncm_init_config() { + proto_config_add_string "device" + proto_config_add_string "mode" + proto_config_add_string "apn" + proto_config_add_string "pincode" + proto_config_add_string "authtype" + proto_config_add_string "delay" + proto_config_add_string "username" + proto_config_add_string "password" + proto_config_add_string "ipaddr" + proto_config_add_string "netmask" + proto_config_add_string "hostname" + proto_config_add_string "clientid" + proto_config_add_string "vendorid" + proto_config_add_boolean "broadcast" + proto_config_add_string "reqopts" + proto_config_add_string "iface6rd" + proto_config_add_string "sendopts" +} + +proto_ncm_setup() { + local config="$1" + local iface="$2" + + local device mode apn pincode authtype delay username password + local ipaddr hostname clientid vendorid broadcast reqopts iface6rd sendopts + local cardinfo brand model driver + local dialupscript modescript initscript + + json_get_vars device mode apn pincode delay authtype username password + json_get_vars ipaddr hostname clientid vendorid broadcast reqopts iface6rd sendopts + + [ -e "$device" ] || { + proto_set_available "$interface" 0 + return 1 + } + + cardinfo=$(gcom -d "$device" -s /etc/gcom/ncm/getcardinfo.gcom) + brand=$(echo "$cardinfo" | grep "vendor '" | awk '{ gsub("\x27", ""); print $2; }') + model=$(echo "$cardinfo" | grep "model '" | awk '{ gsub("\x27", ""); print $2; }') + driver=$(echo "$cardinfo" | grep "driver '" | awk '{ gsub("\x27", ""); print $2; }') + + [ "$driver" = "-" ] && { + logger Detected $brand $model. Device is not supported. + proto_notify_error "$interface" UNSUPPORTED_DEVICE + proto_block_restart "$interface" + return 1 + } + + initscript="/etc/gcom/ncm/initscripts/$driver.gcom" + modescript="/etc/gcom/ncm/setmode/$driver.gcom" + dialupscript="/etc/gcom/ncm/connect/$driver.gcom" + + logger Detected $brand $model. Using driver $driver. + + if [ -n "$pincode" ]; then + PINCODE="$pincode" gcom -d "$device" -s /etc/gcom/setpin.gcom || { + proto_notify_error "$interface" PIN_FAILED + proto_block_restart "$interface" + return 1 + } + fi + + [ -e "$initscript" ] && + gcom -d "$device" -s "$initscript" + + [ "$authtype" = "pap" ] && authtype=1 || { + [ "$authtype" = "chap" ] && authtype=2 || { + [ "$authtype" = "cleartext" ] && authtype=0 || + authtype=-1 + } + } + + [ -e "$modescript" ] && + MODE="$mode" gcom -d "$device" -s "$modescript" + + [ -e "$dialupscript" ] || { + logger Dial-up script for driver $driver is missing. + proto_notify_error "$interface" SCRIPT_MISSING + proto_block_restart "$interface" + return 1 + } + + USE_DISCONNECT="0" USE_APN="$apn" USE_AUTHTYPE="$authtype" USE_USERID="$username" USE_PASSWORD="$password" \ + gcom -d "$device" -s "$dialupscript" + + [ ! -z "${delay##*[!0-9]*}" ] && [ "$delay" != "0" ] && /bin/sleep $delay + + local opt dhcpopts + for opt in $reqopts; do + append dhcpopts "-O $opt" + done + + for opt in $sendopts; do + append dhcpopts "-x $opt" + done + + [ "$broadcast" = 1 ] && broadcast="-B" || broadcast= + [ -n "$clientid" ] && clientid="-x 0x3d:${clientid//:/}" || clientid="-C" + [ -n "$iface6rd" ] && proto_export "IFACE6RD=$iface6rd" + + proto_export "INTERFACE=$config" + proto_run_command "$config" udhcpc \ + -p /var/run/udhcpc-$iface.pid \ + -s /lib/netifd/dhcp.script \ + -f -t 0 -i "$iface" \ + ${ipaddr:+-r $ipaddr} \ + ${hostname:+-H $hostname} \ + ${vendorid:+-V $vendorid} \ + $clientid $broadcast $dhcpopts +} + +proto_ncm_teardown() { + local interface="$1" + local device apn cardinfo driver dialupscript + + json_get_vars device apn + + cardinfo=$(gcom -d "$device" -s /etc/gcom/ncm/getcardinfo.gcom) + driver=$(echo "$cardinfo" | grep "driver '" | awk '{ gsub("\x27", ""); print $2; }') + dialupscript="/etc/gcom/ncm/connect/$driver.gcom" + + [ "$driver" == "-" ] || + [ -e "$device" ] && + [ -e "$dialupscript" ] && + USE_DISCONNECT="1" USE_APN="$apn" gcom -d "$device" -s "$dialupscript" + + proto_kill_command "$interface" +} + +add_protocol ncm diff --git a/package/network/services/ncm/files/usr/lib/lua/luci/controller/ncmstatus.lua b/package/network/services/ncm/files/usr/lib/lua/luci/controller/ncmstatus.lua new file mode 100755 index 0000000..cfb6b20 --- /dev/null +++ b/package/network/services/ncm/files/usr/lib/lua/luci/controller/ncmstatus.lua @@ -0,0 +1,8 @@ +module("luci.controller.ncmstatus", package.seeall) + +function index() + local page + + page = entry({"admin", "status", "ncm"}, template("ncm/status"), _("Ncm status")) + page.dependent = true +end diff --git a/package/network/services/ncm/files/usr/lib/lua/luci/model/cbi/admin_network/proto_ncm.lua b/package/network/services/ncm/files/usr/lib/lua/luci/model/cbi/admin_network/proto_ncm.lua new file mode 100644 index 0000000..dfaa02e --- /dev/null +++ b/package/network/services/ncm/files/usr/lib/lua/luci/model/cbi/admin_network/proto_ncm.lua @@ -0,0 +1,120 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2011 Jo-Philipp Wich <x...@subsignal.org> + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 +]]-- + +local map, section, net = ... + +local device, apn, mode, pincode, authtype, username, password +local delay, bcast, defaultroute, peerdns, dns, metric, clientid, vendorclass + + +device = section:taboption("general", Value, "device", translate("Modem device")) +device.rmempty = false + +local device_suggestions = nixio.fs.glob("/dev/tty[A-Z]*") + or nixio.fs.glob("/dev/tts/*") + +if device_suggestions then + local node + for node in device_suggestions do + device:value(node) + end +end + +mode = section:taboption("general", ListValue, "mode", translate("Service mode")) +mode:value("2g", translate("2G only")) +mode:value("3g", translate("3G only")) +mode:value("lte", translate("LTE only")) +mode:value("prefer3g", translate("Prefer 3G")) +mode:value("preferlte", translate("Prefer LTE")) +mode:value("auto", translate("Automatic / Any")) +mode.rmempty = false +mode.default = "auto" + + +apn = section:taboption("general", Value, "apn", translate("APN")) + + +pincode = section:taboption("general", Value, "pincode", translate("PIN")) + + +authtype = section:taboption("general", ListValue, "authtype", translate("Authentication type")) +authtype:value("none", translate("None")) +authtype:value("cleartext", translate("Clear text")) +authtype:value("pap", translate("PAP")) +authtype:value("chap", translate("CHAP")) +authtype.rmempty = false +authtype.default = "none" + + +username = section:taboption("general", Value, "username", translate("PAP/CHAP username")) + + +password = section:taboption("general", Value, "password", translate("PAP/CHAP password")) +password.password = true + + +bcast = section:taboption("advanced", Flag, "broadcast", + translate("Use broadcast flag"), + translate("Required for certain ISPs, e.g. Charter with DOCSIS 3")) + +bcast.default = bcast.disabled + + +defaultroute = section:taboption("advanced", Flag, "defaultroute", + translate("Use default gateway"), + translate("If unchecked, no default route is configured")) + +defaultroute.default = defaultroute.enabled + + +peerdns = section:taboption("advanced", Flag, "peerdns", + translate("Use DNS servers advertised by peer"), + translate("If unchecked, the advertised DNS server addresses are ignored")) + +peerdns.default = peerdns.enabled + + +dns = section:taboption("advanced", DynamicList, "dns", + translate("Use custom DNS servers")) + +dns:depends("peerdns", "") +dns.datatype = "ipaddr" +dns.cast = "string" + + +delay = section:taboption("advanced", Value, "delay", + translate("Dongle connection delay")) +delay.default = "20" +delay.placeholder = translate("seconds") +delay.datatype = "uinteger" + + +metric = section:taboption("advanced", Value, "metric", + translate("Use gateway metric")) + +metric.placeholder = "0" +metric.datatype = "uinteger" + +clientid = section:taboption("advanced", Value, "clientid", + translate("Client ID to send when requesting DHCP")) + + +vendorclass = section:taboption("advanced", Value, "vendorid", + translate("Vendor Class to send when requesting DHCP")) + + +luci.tools.proto.opt_macaddr(section, ifc, translate("Override MAC address")) + + +mtu = section:taboption("advanced", Value, "mtu", translate("Override MTU")) +mtu.placeholder = "1492" +mtu.datatype = "max(9200)" diff --git a/package/network/services/ncm/files/usr/lib/lua/luci/model/network/proto_ncm.lua b/package/network/services/ncm/files/usr/lib/lua/luci/model/network/proto_ncm.lua new file mode 100644 index 0000000..dd8dbe4 --- /dev/null +++ b/package/network/services/ncm/files/usr/lib/lua/luci/model/network/proto_ncm.lua @@ -0,0 +1,60 @@ +--[[ +LuCI - Network model - 3G, PPP, PPtP, PPPoE and PPPoA protocol extension + +Copyright 2011 Jo-Philipp Wich <x...@subsignal.org> + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +]]-- + +local netmod = luci.model.network + +local _, p +for _, p in ipairs({"ncm"}) do + + local proto = netmod:register_protocol(p) + + function proto.get_i18n(self) + return luci.i18n.translate("NCM") + end + + function proto.ifname(self) + return p .. "-" .. self.sid + end + + function proto.opkg_package(self) + return "kmod-usb-net-cdc-ncm" + end + + function proto.is_installed(self) + return nixio.fs.access("/lib/netifd/proto/ncm.sh") + end + + function proto.is_floating(self) + return false + end + + function proto.is_virtual(self) + return false + end + + function proto.get_interfaces(self) + return netmod.protocol.get_interfaces(self) + end + + function proto.contains_interface(self, ifc) + return netmod.protocol.contains_interface(self, ifc) + end + + netmod:register_pattern_virtual("^%s-%%w" % p) +end diff --git a/package/network/services/ncm/files/usr/lib/lua/luci/view/ncm/status.htm b/package/network/services/ncm/files/usr/lib/lua/luci/view/ncm/status.htm new file mode 100644 index 0000000..5568b7f --- /dev/null +++ b/package/network/services/ncm/files/usr/lib/lua/luci/view/ncm/status.htm @@ -0,0 +1,283 @@ +<%# +LuCI - Lua Configuration Interface +Copyright 2008 Steven Barth <ste...@midlink.org> +Copyright 2008-2011 Jo-Philipp Wich <x...@subsignal.org> + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +-%> + +<% + require "luci.sys" + require "luci.fs" + + local rv = { + gothw = "0", + gotcarrier = "0", + gotsignal = "0", + hwrefresh = "0", + modemdev = "", + driver = "", + vendor = "", + model = "", + notification = "", + firmware = "", + imei = "", + provider = "", + mode = "", + downlink = "", + uplink = "", + cellid = "", + lac = "", + network = "", + signal = "", + rssi = "", + csq = "", + rcsp = "", + ecio = "" + } + + if luci.http.formvalue("gothw") == "1" then + rv["gothw"] = luci.http.formvalue("gothw") or "0" + rv["modemdev"] = luci.http.formvalue("modemdev") + rv["driver"] = luci.http.formvalue("driver") + rv["gotcarrier"] = luci.http.formvalue("gotcarrier") or "0" + rv["gotsignal"] = luci.http.formvalue("gotsignal") or "0" + rv["hwrefresh"] = luci.http.formvalue("hwrefresh") or "0" + else + local uci = require "luci.model.uci".cursor() + if uci:get("network", "wan", "proto") == "ncm" then + rv["modemdev"] = uci:get("network", "wan", "device") or "0" + else + if luci.http.formvalue("status") == "1" then + + rv["notification"] = "[ WAN is not using NCM protocol ]" + rv["hwrefresh"] = "0" + rv["gothw"] = "0" + rv["driver"] = "-" + + luci.http.prepare_content("application/json") + luci.http.write_json(rv) + + return + end + + end + + end + + if ( luci.http.formvalue("status") == "1" and rv["driver"] ~= "-" ) then + + if luci.fs.access(rv["modemdev"]) then + + if rv["gothw"] == "0" then + + local modemhw = luci.sys.exec(table.concat({"/usr/bin/gcom -d ", rv["modemdev"], " -s /etc/gcom/ncm/getcardinfo.gcom"}, "")) + + for k, v in string.gmatch(modemhw, "(%w+) '(.-)'") do + rv[k] = v + end + + if rv["driver"] == "" then + rv["driver"] = "-" + end + + if ( rv["vendor"] == "" or rv["model"] == "" or rv["firmware"] == "" or rv["imei"] == "" or rv["driver"] == "" ) then + rv["gothw"] = "0" + elseif (rv["driver"] ~= "-" and + luci.fs.access(table.concat({"/etc/gcom/ncm/carrier/",rv["driver"], ".gcom"}, "")) and + luci.fs.access(table.concat({"/etc/gcom/ncm/signal/", rv["driver"], ".gcom"}, ""))) then + rv['gothw'] = "1" + else + rv["notification"] = " [ Unsupported dongle ]"; + rv["driver"] = "-" + rv["gothw"] = "0" + rv["hwrefresh"] = "1" + end + + elseif rv["gotcarrier"] == "0" then + + if rv["driver"] ~= "-" then + + local modemcarrier = luci.sys.exec(table.concat({"/usr/bin/gcom -d ", rv["modemdev"], " -s /etc/gcom/ncm/carrier/", rv["driver"], ".gcom"}, "")) + + for k, v in string.gmatch(modemcarrier, "(%w+) '(.-)'") do + rv[k] = v + end + + if ( rv["provider"] == "" or rv["downlink"] == "" or rv["uplink"] == "" or rv["mode"] == "" ) then + rv["gotcarrier"] = "0" + else + rv["gotcarrier"] = "1" + end + + else + rv["gotcarrier"] = "1" + end + + else + + if rv["driver"] ~= "-" then + + local modemsignal = luci.sys.exec(table.concat({"/usr/bin/gcom -d ", rv["modemdev"], " -s /etc/gcom/ncm/signal/", rv["driver"], ".gcom"}, "")) + + for k, v in string.gmatch(modemsignal, "(%w+) '(.-)'") do + rv[k] = v + end + rv["gotsignal"] = "1" + end + + end + else + + rv["notification"] = table.concat({"[ ", rv["modemdev"], ": Device not present. ]"}, "") + + end + + end + + if ( luci.http.formvalue("status") == "1" ) then + + luci.http.prepare_content("application/json") + luci.http.write_json(rv) + + return + + end + +-%> + +<%+header%> + +<script type="text/javascript" src="<%=resource%>/cbi.js"></script> +<script type="text/javascript" src="<%=resource%>/ncm_xhr.js"></script> +<script type="text/javascript">//<![CDATA[ + + function capitalize(s) + { + return s.toLowerCase().replace( /\b./g, function(a){ return a.toUpperCase(); } ); + }; + + XHR2.poll(5, '<%=REQUEST_URI%>', { status: 1 }, + function(x, info) + { + + var e; + + if (e = document.getElementById('notification')) + e.innerHTML = info.notification; + + if (( gothwD == "0" && info.gothw == "1" ) || ( info.hwrefresh == "1" )) { + + if (e = document.getElementById('name')) + e.innerHTML = capitalize(info.vendor) + " " + capitalize(info.model); + + if (e = document.getElementById('firmware')) + e.innerHTML = info.firmware; + + if (e = document.getElementById('imei')) + e.innerHTML = info.imei; + } + + if ( gotcarrierD == "0" && info.gotcarrier == "1" ) { + + if (e = document.getElementById('provider')) + e.innerHTML = info.provider; + + if (e = document.getElementById('linkspeed')) + if ( info.downlink != "" && info.uplink != "" ) + e.innerHTML = info.downlink + " / " + info.uplink ; + + if (e = document.getElementById('mode')) + e.innerHTML = info.mode; + + } + + if ( info.gotsignal == "1" ) { + + if (e = document.getElementById('cellid')) + e.innerHTML = info.cellid; + + if (e = document.getElementById('lac')) + e.innerHTML = info.lac; + + if (e = document.getElementById('network')) + e.innerHTML = info.network; + + if (e = document.getElementById('signal')) + e.innerHTML = info.signal; + + if (e = document.getElementById('csq')) + e.innerHTML = info.csq; + + if (e = document.getElementById('rssi')) + e.innerHTML = info.rssi; + + if (e = document.getElementById('rcsp')) + e.innerHTML = info.rcsp; + + if (e = document.getElementById('ecio')) + e.innerHTML = info.ecio; + + } + + modemdevD = info.modemdev; + driverD = info.driver; + gothwD = info.gothw; + gotcarrierD = info.gotcarrier; + hwrefreshD = info.hwrefresh; + gotsignalD = info.gotsignal; + + } + ); + +//]]></script> + +<h2><a id="content" name="content"><%:NCM Status%></a></h2> +<small style="color: #777;" id="notification"></small> + +<fieldset class="cbi-section"> + <legend id="name"><%:Detecting dongle%></legend> + + <table width="100%" cellspacing="10"> + <tr><td width="33%"><%:Firmware version%></td><td id="firmware"></td></tr> + <tr><td width="33%"><%:IMEI%></td><td id="imei"></td></tr> + </table> +</fieldset> + +<fieldset class="cbi-section"> + <legend><%:Network%></legend> + + <table width="100%" cellspacing="10"> + <tr><td width="33%"><%:Provider%></td><td id="provider"></td></tr> + <tr><td width="33%"><%:Downlink/Uplink%></td><td id="linkspeed"></td></tr> + <tr><td width="33%"><%:Mode%></td><td id="mode"></td></tr> + </table> +</fieldset> + +<fieldset class="cbi-section"> + <legend><%:Cell%></legend> + + <table width="100%" cellspacing="10"> + <tr><td width="33%"><%:Location Area Code%></td><td id="lac"></td></tr> + <tr><td width="33%"><%:Cell ID%></td><td id="cellid"></td></tr> + </table> +</fieldset> + +<fieldset class="cbi-section"> + <legend><%:Signal level%></legend> + + <table width="100%" cellspacing="10"> + <tr><td width="33%"><%:Network%></td><td id="network"></td></tr> + <tr><td width="33%"><%:Signal strength%></td><td id="signal"></td></tr> + <tr><td width="33%"><%:CSQ%></td><td id="csq"></td></tr> + <tr><td width="33%"><%:RSSI%></td><td id="rssi"></td></tr> + <tr><td width="33%"><%:RCSP%></td><td id="rcsp"></td></tr> + <tr><td width="33%"><%:ECIO%></td><td id="ecio"></td></tr> + </table> +</fieldset> +<%+footer%> diff --git a/package/network/services/ncm/files/www/luci-static/resources/ncm_xhr.js b/package/network/services/ncm/files/www/luci-static/resources/ncm_xhr.js new file mode 100644 index 0000000..c01e8ac --- /dev/null +++ b/package/network/services/ncm/files/www/luci-static/resources/ncm_xhr.js @@ -0,0 +1,254 @@ +/* + * xhr.js - XMLHttpRequest helper class + * (c) 2008-2010 Jo-Philipp Wich + */ + +var gothwD = "0"; +var gotcarrierD = "0"; +var gotsignalD = "0"; +var hwrefreshD = "0"; +var modemdevD = "" +var driverD = "" + +XHR2 = function() +{ + this.reinit = function() + { + if (window.XMLHttpRequest) { + this._xmlHttp = new XMLHttpRequest(); + } + else if (window.ActiveXObject) { + this._xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); + } + else { + alert("dongle_xhr.js: XMLHttpRequest is not supported by this browser!"); + } + } + + this.busy = function() { + if (!this._xmlHttp) + return false; + + switch (this._xmlHttp.readyState) + { + case 1: + case 2: + case 3: + return true; + + default: + return false; + } + } + + this.abort = function() { + if (this.busy()) + this._xmlHttp.abort(); + } + + this.get = function(url,data,callback) + { + this.reinit(); + + var xhr2 = this._xmlHttp; + var code = this._encode(data); + + url = location.protocol + '//' + location.host + url; + + if (code) + if (url.substr(url.length-1,1) == '&') + url += code; + else + url += '?' + code; + + xhr2.open('GET', url, true); + + xhr2.onreadystatechange = function() + { + if (xhr2.readyState == 4) { + var json = null; + if (xhr2.getResponseHeader("Content-Type") == "application/json") { + try { + json = eval('(' + xhr2.responseText + ')'); + } + catch(e) { + json = null; + } + } + + callback(xhr2, json); + } + } + + xhr2.send(null); + } + + this.post = function(url,data,callback) + { + this.reinit(); + + var xhr2 = this._xmlHttp; + var code = this._encode(data); + + xhr2.onreadystatechange = function() + { + if (xhr2.readyState == 4) + callback(xhr2); + } + + xhr2.open('POST', url, true); + xhr2.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); + xhr2.setRequestHeader('Content-length', code.length); + xhr2.setRequestHeader('Connection', 'close'); + xhr2.send(code); + } + + this.cancel = function() + { + this._xmlHttp.onreadystatechange = function(){}; + this._xmlHttp.abort(); + } + + this.send_form = function(form,callback,extra_values) + { + var code = ''; + + for (var i = 0; i < form.elements.length; i++) + { + var e = form.elements[i]; + + if (e.options) + { + code += (code ? '&' : '') + + form.elements[i].name + '=' + encodeURIComponent( + e.options[e.selectedIndex].value + ); + } + else if (e.length) + { + for (var j = 0; j < e.length; j++) + if (e[j].name) { + code += (code ? '&' : '') + + e[j].name + '=' + encodeURIComponent(e[j].value); + } + } + else + { + code += (code ? '&' : '') + + e.name + '=' + encodeURIComponent(e.value); + } + } + + if (typeof extra_values == 'object') + for (var key in extra_values) + code += (code ? '&' : '') + + key + '=' + encodeURIComponent(extra_values[key]); + + return( + (form.method == 'get') + ? this.get(form.getAttribute('action'), code, callback) + : this.post(form.getAttribute('action'), code, callback) + ); + } + + this._encode = function(obj) + { + obj = obj ? obj : { }; + obj['gothw'] = gothwD; + obj['gotcarrier'] = gotcarrierD; + obj['gotsignal'] = gotsignalD; + obj['hwrefresh'] = hwrefreshD; + obj['modemdev'] = modemdevD; + obj['driver'] = driverD; + obj['_'] = Math.random(); + + if (typeof obj == 'object') + { + var code = ''; + var self = this; + + for (var k in obj) + code += (code ? '&' : '') + + k + '=' + encodeURIComponent(obj[k]); + + return code; + } + + return obj; + } +} + +XHR2.get = function(url, data, callback) +{ + (new XHR2()).get(url, data, callback); +} + +XHR2.poll = function(interval, url, data, callback) +{ + if (isNaN(interval) || interval < 1) + interval = 5; + + if (!XHR2._q) + { + XHR2._t = 0; + XHR2._q = [ ]; + XHR2._r = function() { + for (var i = 0, e = XHR2._q[0]; i < XHR2._q.length; e = XHR2._q[++i]) + { + if (!(XHR2._t % e.interval) && !e.xhr2.busy()) + e.xhr2.get(e.url, e.data, e.callback); + } + + XHR2._t++; + }; + } + + XHR2._q.push({ + interval: interval, + callback: callback, + url: url, + data: data, + xhr2: new XHR2() + }); + + XHR2.run(); +} + +XHR2.halt = function() +{ + if (XHR2._i) + { + /* show & set poll indicator */ + try { + document.getElementById('xhr_poll_status').style.display = ''; + document.getElementById('xhr_poll_status_on').style.display = 'none'; + document.getElementById('xhr_poll_status_off').style.display = ''; + } catch(e) { } + + window.clearInterval(XHR2._i); + XHR2._i = null; + } +} + +XHR2.run = function() +{ + if (XHR2._r && !XHR2._i) + { + /* show & set poll indicator */ + try { + document.getElementById('xhr_poll_status').style.display = ''; + document.getElementById('xhr_poll_status_on').style.display = ''; + document.getElementById('xhr_poll_status_off').style.display = 'none'; + } catch(e) { } + + /* kick first round manually to prevent one second lag when setting up + * the poll interval */ + XHR2._r(); + XHR2._i = window.setInterval(XHR2._r, 1000); + } +} + +XHR2.running = function() +{ + return !!(XHR2._r && XHR2._i); +} _______________________________________________ openwrt-devel mailing list openwrt-devel@lists.openwrt.org https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel