ASR_BASE

Change-Id: Icf3719cc0afe3eeb3edc7fa80a2eb5199ca9dda1
diff --git a/package/network/utils/comgt/files/3g.chat b/package/network/utils/comgt/files/3g.chat
new file mode 100644
index 0000000..6656240
--- /dev/null
+++ b/package/network/utils/comgt/files/3g.chat
@@ -0,0 +1,12 @@
+ABORT   BUSY
+ABORT   'NO CARRIER'
+ABORT   ERROR
+REPORT  CONNECT
+TIMEOUT 10
+""      "AT&F"
+OK      "ATE1"
+OK      'AT+CGDCONT=1,"IP","$USE_APN"'
+SAY     "Calling UMTS/GPRS"
+TIMEOUT 30
+OK      "ATD$DIALNUMBER"
+CONNECT ' '
diff --git a/package/network/utils/comgt/files/3g.sh b/package/network/utils/comgt/files/3g.sh
new file mode 100644
index 0000000..42ba894
--- /dev/null
+++ b/package/network/utils/comgt/files/3g.sh
@@ -0,0 +1,118 @@
+#!/bin/sh
+
+[ -n "$INCLUDE_ONLY" ] || {
+	NOT_INCLUDED=1
+	INCLUDE_ONLY=1
+
+	. ../netifd-proto.sh
+	. ./ppp.sh
+	init_proto "$@"
+}
+
+proto_3g_init_config() {
+	no_device=1
+	available=1
+	ppp_generic_init_config
+	proto_config_add_string "device:device"
+	proto_config_add_string "apn"
+	proto_config_add_string "service"
+	proto_config_add_string "pincode"
+	proto_config_add_string "delay"
+	proto_config_add_string "dialnumber"
+}
+
+proto_3g_setup() {
+	local interface="$1"
+	local chat
+
+	json_get_var device device
+	json_get_var apn apn
+	json_get_var service service
+	json_get_var pincode pincode
+	json_get_var dialnumber dialnumber
+	json_get_var delay delay
+
+	[ -n "$dat_device" ] && device=$dat_device
+
+	device="$(readlink -f $device)"
+	[ -e "$device" ] || {
+		proto_set_available "$interface" 0
+		return 1
+	}
+
+	[ -n "$delay" ] && sleep "$delay"
+
+	case "$service" in
+		cdma|evdo)
+			chat="/etc/chatscripts/evdo.chat"
+		;;
+		*)
+			chat="/etc/chatscripts/3g.chat"
+			cardinfo=$(gcom -d "$device" -s /etc/gcom/getcardinfo.gcom)
+			if echo "$cardinfo" | grep -q Novatel; then
+				case "$service" in
+					umts_only) CODE=2;;
+					gprs_only) CODE=1;;
+					*) CODE=0;;
+				esac
+				export MODE="AT\$NWRAT=${CODE},2"
+			elif echo "$cardinfo" | grep -q Option; then
+				case "$service" in
+					umts_only) CODE=1;;
+					gprs_only) CODE=0;;
+					*) CODE=3;;
+				esac
+				export MODE="AT_OPSYS=${CODE}"
+			elif echo "$cardinfo" | grep -q "Sierra Wireless"; then
+				SIERRA=1
+			elif echo "$cardinfo" | grep -qi huawei; then
+				case "$service" in
+					umts_only) CODE="14,2";;
+					gprs_only) CODE="13,1";;
+					*) CODE="2,2";;
+				esac
+				export MODE="AT^SYSCFG=${CODE},3FFFFFFF,2,4"
+			elif echo "$cardinfo" | grep -q "MikroTik"; then
+				COMMAND="AT+CFUN=1" gcom -d "$device" -s /etc/gcom/runcommand.gcom || return 1
+			fi
+
+			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
+			[ -n "$MODE" ] && gcom -d "$device" -s /etc/gcom/setmode.gcom
+
+			# wait for carrier to avoid firmware stability bugs
+			[ -n "$SIERRA" ] && {
+				gcom -d "$device" -s /etc/gcom/getcarrier.gcom || return 1
+			}
+
+			if [ -z "$dialnumber" ]; then
+				dialnumber="*99***1#"
+			fi
+
+		;;
+	esac
+
+	connect="${apn:+USE_APN=$apn }DIALNUMBER=$dialnumber /usr/sbin/chat -t5 -v -E -f $chat"
+	ppp_generic_setup "$interface" \
+		noaccomp \
+		nopcomp \
+		novj \
+		nobsdcomp \
+		noauth \
+		set EXTENDPREFIX=1 \
+		lock \
+		crtscts \
+		115200 "$device"
+	return 0
+}
+
+proto_3g_teardown() {
+	proto_kill_command "$interface"
+}
+
+[ -z "$NOT_INCLUDED" ] || add_protocol 3g
diff --git a/package/network/utils/comgt/files/3g.usb b/package/network/utils/comgt/files/3g.usb
new file mode 100644
index 0000000..9c7d07a
--- /dev/null
+++ b/package/network/utils/comgt/files/3g.usb
@@ -0,0 +1,35 @@
+#!/bin/sh
+. /lib/functions.sh
+. /lib/netifd/netifd-proto.sh
+
+find_3g_iface() {
+	local cfg="$1"
+	local tty="$2"
+
+	local proto
+	config_get proto "$cfg" proto
+	[ "$proto" = 3g ] || [ "$proto" = ncm ] || return 0
+
+	# bypass state vars here because 00-netstate could clobber .device
+	local dev=$(uci_get network "$cfg" device)
+
+	if [ "${dev##*/}" = "${tty##*/}" ]; then
+		if [ "$ACTION" = add ]; then
+			proto_set_available "$cfg" 1
+		fi
+		if [ "$ACTION" = remove ]; then
+			proto_set_available "$cfg" 0
+		fi
+	fi
+}
+
+[ "$ACTION" = add ] || [ "$ACTION" = remove ] || exit 0
+
+case "$DEVICENAME" in
+	tty*)
+		[ -e "/dev/$DEVICENAME" ] || [ "$ACTION" = remove ] || exit 0
+		config_load network
+		config_foreach find_3g_iface interface "/dev/$DEVICENAME"
+	;;
+esac
+
diff --git a/package/network/utils/comgt/files/directip-stop.gcom b/package/network/utils/comgt/files/directip-stop.gcom
new file mode 100644
index 0000000..1c14863
--- /dev/null
+++ b/package/network/utils/comgt/files/directip-stop.gcom
@@ -0,0 +1,16 @@
+opengt
+set com 115200n81
+set comecho off
+set senddelay 0.05
+waitquiet 1 0.2
+
+:start
+ send "AT!SCACT=0,3^m"
+ waitfor 5 "OK"
+ if % = 0 goto hangupok
+ print "WWAN error. Hangup failed.\r\n"
+ exit 1
+
+:hangupok
+ print "WWAN connection established.\r\n"
+ exit 0
diff --git a/package/network/utils/comgt/files/directip.gcom b/package/network/utils/comgt/files/directip.gcom
new file mode 100644
index 0000000..9a772a9
--- /dev/null
+++ b/package/network/utils/comgt/files/directip.gcom
@@ -0,0 +1,55 @@
+opengt
+set com 115200n81
+set comecho off
+set senddelay 0.05
+waitquiet 1 0.2
+
+:start
+ if $env("USE_AUTH") = "0" goto connect
+ send "AT$QCPDPP=3,"
+ send $env("USE_AUTH")
+ send ",\""
+ if $env("USE_USER") <> "" send $env("USE_USER")
+ send "\",\""
+ if $env("USE_PASS") <> "" send $env("USE_PASS")
+ send "\"^m"
+ waitfor 5 "OK"
+ if % = 0 goto connect
+ print "WWAN error. Auth failed.\r\n"
+ exit 1
+
+:connect
+ send "AT+CFUN=1^m"
+ send "AT+CGDCONT=3,\"IP\",\""
+ send $env("USE_APN")
+ send "\"^m"
+ waitfor 5 "OK"
+ if % = 0 goto connok
+ print "WWAN error. Connection failed.\r\n"
+ exit 1
+
+:connok
+ let c=1
+:loop
+ sleep 2
+ send "AT+CGATT?^m"
+ waitfor 5 "+CGATT: 1"
+ if % = 0 goto carrierok
+ if c > 10 goto carriererr
+ inc c
+ goto loop
+
+:carriererr
+ print "WWAN error. No carrier.\r\n"
+ exit 1
+
+:carrierok
+ send "AT!SCACT=1,3^m"
+ waitfor 5 "OK"
+ if % = 0 goto dialok
+ print "WWAN error. Dialing failed.\r\n"
+ exit 1
+
+:dialok
+ print "WWAN connection established.\r\n"
+ exit 0
diff --git a/package/network/utils/comgt/files/directip.sh b/package/network/utils/comgt/files/directip.sh
new file mode 100644
index 0000000..6535de9
--- /dev/null
+++ b/package/network/utils/comgt/files/directip.sh
@@ -0,0 +1,118 @@
+#!/bin/sh
+
+[ -n "$INCLUDE_ONLY" ] || {
+	. /lib/functions.sh
+	. ../netifd-proto.sh
+	init_proto "$@"
+}
+
+proto_directip_init_config() {
+	available=1
+	no_device=1
+	proto_config_add_string "device:device"
+	proto_config_add_string "apn"
+	proto_config_add_string "pincode"
+	proto_config_add_string "auth"
+	proto_config_add_string "username"
+	proto_config_add_string "password"
+	proto_config_add_boolean sourcefilter
+	proto_config_add_boolean delegate
+	proto_config_add_defaults
+}
+
+proto_directip_setup() {
+	local interface="$1"
+	local chat devpath devname
+
+	local device apn pincode ifname auth username password sourcefilter delegate $PROTO_DEFAULT_OPTIONS
+	json_get_vars device apn pincode auth username password sourcefilter delegate $PROTO_DEFAULT_OPTIONS
+
+	[ -n "$ctl_device" ] && device=$ctl_device
+
+	device="$(readlink -f $device)"
+	[ -e "$device" ] || {
+		proto_notify_error "$interface" NO_DEVICE
+		proto_set_available "$interface" 0
+		return 1
+	}
+
+	devname="$(basename "$device")"
+	devpath="$(readlink -f /sys/class/tty/$devname/device)"
+	ifname="$( ls "$devpath"/../../*/net )"
+
+	[ -n "$ifname" ] || {
+		proto_notify_error "$interface" NO_IFNAME
+		proto_set_available "$interface" 0
+		return 1
+	}
+
+	gcom -d "$device" -s /etc/gcom/getcardinfo.gcom | grep -q "Sierra Wireless" || {
+		proto_notify_error "$interface" BAD_DEVICE
+		proto_block_restart "$interface"
+		return 1
+	}
+
+	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
+	# wait for carrier to avoid firmware stability bugs
+	gcom -d "$device" -s /etc/gcom/getcarrier.gcom || return 1
+
+	local auth_type=0
+	case $auth in
+	pap) auth_type=1;;
+	chap) auth_type=2;;
+	esac
+
+	USE_APN="$apn" USE_USER="$username" USE_PASS="$password" USE_AUTH="$auth_type" \
+			gcom -d "$device" -s /etc/gcom/directip.gcom || {
+		proto_notify_error "$interface" CONNECT_FAILED
+		proto_block_restart "$interface"
+		return 1
+	}
+
+	logger -p daemon.info -t "directip[$$]" "Connected, starting DHCP"
+	proto_init_update "$ifname" 1
+	proto_send_update "$interface"
+
+	json_init
+	json_add_string name "${interface}_4"
+	json_add_string ifname "@$interface"
+	json_add_string proto "dhcp"
+	proto_add_dynamic_defaults
+	ubus call network add_dynamic "$(json_dump)"
+
+	json_init
+	json_add_string name "${interface}_6"
+	json_add_string ifname "@$interface"
+	json_add_string proto "dhcpv6"
+	json_add_string extendprefix 1
+	[ "$delegate" = "0" ] && json_add_boolean delegate "0"
+	[ "$sourcefilter" = "0" ] && json_add_boolean sourcefilter "0"
+	proto_add_dynamic_defaults
+	ubus call network add_dynamic "$(json_dump)"
+
+	return 0
+}
+
+proto_directip_teardown() {
+	local interface="$1"
+
+	local device
+	json_get_vars device
+
+	[ -n "$ctl_device" ] && device=$ctl_device
+
+	gcom -d "$device" -s /etc/gcom/directip-stop.gcom || proto_notify_error "$interface" CONNECT_FAILED
+
+	proto_init_update "*" 0
+	proto_send_update "$interface"
+}
+
+[ -n "$INCLUDE_ONLY" ] || {
+	add_protocol directip
+}
diff --git a/package/network/utils/comgt/files/evdo.chat b/package/network/utils/comgt/files/evdo.chat
new file mode 100644
index 0000000..de49e41
--- /dev/null
+++ b/package/network/utils/comgt/files/evdo.chat
@@ -0,0 +1,17 @@
+# This is a simple chat script based off of the one provided by Sierra Wireless
+# for CDMA connections.  It should work for both Sprint and Verizon networks.
+
+ABORT	BUSY
+ABORT 	'NO CARRIER'
+ABORT	ERROR
+ABORT 	'NO DIAL TONE'
+ABORT 	'NO ANSWER'
+ABORT 	DELAYED
+REPORT	CONNECT
+TIMEOUT	10
+'' 		AT
+OK 		ATZ
+SAY     'Calling CDMA/EVDO'
+TIMEOUT	30
+OK		ATDT#777
+CONNECT	''
diff --git a/package/network/utils/comgt/files/getcardinfo.gcom b/package/network/utils/comgt/files/getcardinfo.gcom
new file mode 100644
index 0000000..f91665f
--- /dev/null
+++ b/package/network/utils/comgt/files/getcardinfo.gcom
@@ -0,0 +1,14 @@
+opengt
+ set com 115200n81
+ set comecho off
+ set senddelay 0.02
+ waitquiet 0.2 0.2
+ flash 0.1
+
+:start
+ send "AT+CGMI^m"
+ get 1 "" $s
+ print $s
+
+:continue
+ exit 0
diff --git a/package/network/utils/comgt/files/getcarrier.gcom b/package/network/utils/comgt/files/getcarrier.gcom
new file mode 100644
index 0000000..1e0216d
--- /dev/null
+++ b/package/network/utils/comgt/files/getcarrier.gcom
@@ -0,0 +1,20 @@
+opengt
+  set senddelay 0.05
+  waitquiet 1 0.2
+  let c=1
+ :loop
+    inc c
+    send "AT+CGATT?^m"
+    waitfor 5 "+CGATT: 1","+CGATT: 0"
+    print "\n."
+    if % = -1 goto error
+    if c > 10 goto toolong
+    if % = 0 goto out
+    sleep 2
+    if % = 1 goto loop
+  :toolong
+  exit 1
+  :error
+  exit 0
+  :out
+ exit 0
diff --git a/package/network/utils/comgt/files/getcnum.gcom b/package/network/utils/comgt/files/getcnum.gcom
new file mode 100644
index 0000000..450cf8c
--- /dev/null
+++ b/package/network/utils/comgt/files/getcnum.gcom
@@ -0,0 +1,20 @@
+opengt
+ set com 115200n81
+ set comecho off
+ set senddelay 0.02
+ waitquiet 0.2 0.2
+ flash 0.1
+
+:start
+ send "AT+CNUM^m"
+ get 1 "^m" $n
+ get 1 ":" $n
+ get 1 "\"" $n
+ get 1 "\"" $n
+ get 1 "\"" $n
+ get 1 "\"" $n
+ let n = len($n)
+ if n<1 goto continue
+ print $n
+:continue
+ exit 0
diff --git a/package/network/utils/comgt/files/getimsi.gcom b/package/network/utils/comgt/files/getimsi.gcom
new file mode 100644
index 0000000..0485456
--- /dev/null
+++ b/package/network/utils/comgt/files/getimsi.gcom
@@ -0,0 +1,17 @@
+opengt
+ set com 115200n81
+ set comecho off
+ set senddelay 0.02
+ waitquiet 0.2 0.2
+ flash 0.1
+
+:start
+ send "AT+CIMI^m"
+ get 1 "^m" $s
+ get 1 "^m" $s
+ let x = len($s)
+ if x<2 goto continue
+ let $s = $right($s, x-1)
+ print $s
+:continue
+ exit 0
diff --git a/package/network/utils/comgt/files/getstrength.gcom b/package/network/utils/comgt/files/getstrength.gcom
new file mode 100644
index 0000000..2886285
--- /dev/null
+++ b/package/network/utils/comgt/files/getstrength.gcom
@@ -0,0 +1,14 @@
+opengt
+ set com 115200n81
+ set comecho off
+ set senddelay 0.02
+ waitquiet 0.2 0.2
+ flash 0.1
+
+:start
+ send "AT+CSQ^m"
+ get 1 "" $s
+ print $s
+
+:continue
+ exit 0
diff --git a/package/network/utils/comgt/files/ncm.json b/package/network/utils/comgt/files/ncm.json
new file mode 100644
index 0000000..5f68b13
--- /dev/null
+++ b/package/network/utils/comgt/files/ncm.json
@@ -0,0 +1,140 @@
+{
+	"huawei": {
+		"initialize": [
+			"AT",
+			"ATZ",
+			"ATQ0",
+			"ATV1",
+			"ATE1",
+			"ATS0=0",
+			"AT+CGDCONT=${profile},\\\"${pdptype}\\\"${apn:+,\\\"$apn\\\"}"
+		],
+		"modes": {
+			"preferlte": "AT^SYSCFGEX=\\\"030201\\\",3fffffff,2,4,7fffffffffffffff,,",
+			"preferumts": "AT^SYSCFGEX=\\\"0201\\\",3fffffff,2,4,7fffffffffffffff,,",
+			"lte": "AT^SYSCFGEX=\\\"03\\\",3fffffff,2,4,7fffffffffffffff,,",
+			"umts": "AT^SYSCFGEX=\\\"02\\\",3fffffff,2,4,7fffffffffffffff,,",
+			"gsm": "AT^SYSCFGEX=\\\"01\\\",3fffffff,2,4,7fffffffffffffff,,",
+			"auto": "AT^SYSCFGEX=\\\"00\\\",3fffffff,2,4,7fffffffffffffff,,"
+		},
+		"connect": "AT^NDISDUP=${profile},1${apn:+,\\\"$apn\\\"}${username:+,\\\"$username\\\"}${password:+,\\\"$password\\\"}${auth:+,$auth}",
+		"disconnect": "AT^NDISDUP=${profile},0"
+	},
+	"samsung": {
+		"initialize": [
+			"AT",
+			"AT+CGREG=2",
+			"AT+CFUN=5",
+			"AT+MODESELECT=3",
+			"AT+CGDCONT=${profile},\\\"${pdptype}\\\"${apn:+,\\\"$apn\\\"}"
+		],
+		"modes": {
+			"umts": "AT+CHANGEALLPATH=1"
+		},
+		"connect": "AT+CGATT=1",
+		"disconnect": "AT+CGATT=0"
+	},
+	"sierra": {
+		"initialize": [
+			"AT+CFUN=1",
+			"AT+CGDCONT=${profile},\\\"${pdptype}\\\"${apn:+,\\\"$apn\\\"}",
+			"AT$QCPDPP=${profile},${auth:-0}${password:+,\\\"$password\\\"}${username:+,\\\"$username\\\"}"
+		],
+		"modes": {
+			"preferlte": "AT!SELRAT=07",
+			"preferumts": "AT!SELRAT=05",
+			"lte": "AT!SELRAT=06",
+			"umts": "AT!SELRAT=01",
+			"gsm": "AT!SELRAT=02",
+			"auto": "AT!SELRAT=00"
+		},
+		"connect": "AT!SCACT=1,${profile}",
+		"disconnect": "AT!SCACT=0,${profile}"
+	},
+	"sony": {
+		"initialize": [
+			"AT+CFUN=1",
+			"AT+CGDCONT=${profile},\\\"${pdptype}\\\"${apn:+,\\\"$apn\\\"}",
+			"AT*EIAAUW=${profile},1,\\\"${username}\\\",\\\"${password}\\\",${auth:-00111}"
+		],
+		"modes": {
+			"umts": "AT+CFUN=6",
+			"gsm": "AT+CFUN=5"
+		},
+		"connect": "AT*ENAP=1,${profile}",
+		"disconnect": "AT*ENAP=0"
+	},
+	"mtk1": {
+		"initialize": [
+			"AT+CFUN=1"
+		],
+		"configure": [
+			"AT+CGDCONT=${profile},\\\"${pdptype}\\\",\\\"${apn}\\\",0,0"
+		],
+		"connect": "AT+CGACT=1,${profile}",
+		"finalize": "AT+CGDATA=\\\"M-MBIM\\\",${profile},1",
+		"disconnect": "AT+CGACT=0,${profile}"
+	},
+	"quectel": {
+		"initialize": [
+			"AT+CFUN=1"
+		],
+		"configure": [
+			"at+qicsgp=${profile},${context_type},\\\"${apn}\\\",\\\"${username}\\\",\\\"${password}\\\",0"
+		],
+		"modes": {
+			"lte": "AT+QCFG=\\\"nwscanmode\\\",3",
+			"umts": "AT+QCFG=\\\"nwscanmode\\\",2",
+			"gsm": "AT+QCFG=\\\"nwscanmode\\\",1",
+			"auto": "AT+QCFG=\\\"nwscanmode\\\",0"
+		},
+		"connect": "AT+qnetdevctl=1,${profile},1",
+		"disconnect": "AT+qnetdevctl=0,${profile},0"
+	},
+	"\"zte": {
+		"initialize": [
+			"AT+CFUN=1"
+		],
+		"configure": [
+			"AT+ZGDCONT=${profile},\\\"${pdptype}\\\",\\\"${apn}\\\",\\\"\\\",0,0",
+			"AT+ZGPCOAUTH=${profile},\\\"${username}\\\",\\\"${password}\\\",0"
+		],
+		"connect": "AT+ZGACT=1,${profile}",
+		"disconnect": "AT+ZGACT=0,${profile}"
+	},
+	"\"marvell\"": {
+		"initialize": [
+			"AT+CFUN=1"
+		],
+		"configure": [
+			"AT+ZGDCONT=${profile},\\\"${pdptype}\\\",\\\"${apn}\\\",\\\"\\\",0,0",
+			"AT+ZGPCOAUTH=${profile},\\\"${username}\\\",\\\"${password}\\\",0"
+		],
+		"connect": "AT+ZGACT=1,${profile}",
+		"disconnect": "AT+ZGACT=0,${profile}"
+	},
+	"\"mikrotik\"": {
+		"configure": [
+			"AT+CFUN=4",
+			"AT+ZGDCONT=${profile},\\\"${pdptype}\\\",\\\"${apn}\\\",0",
+			"AT+ZDHCPLEASE=10",
+			"AT+CFUN=1"
+		],
+		"waitforconnect": "\\\"+ZCONSTAT: 1,${context_type}\\\",\\\"+ZGIPDNS: ${context_type}\\\"",
+		"connect": "AT+ZGACT=1,${context_type}",
+		"finalize": "AT+ZDHCPLEASE=0",
+		"disconnect": "AT+ZGACT=0,1"
+	},
+	"spreadtrum": {
+		"initialize": [
+			"AT+CFUN=1",
+			"AT+CCED=2,8",
+			"AT+SPTTYROUTER=1"
+		],
+		"configure": [
+			"AT+CGDCONT=${profile},\\\"${pdptype}\\\"${apn:+,\\\"$apn\\\"}"
+		],
+		"connect": "AT+SPTZCMD=\\\"Y29ubm1hbmN0bCBuZGlzZGlhbCBBVF5ORElTRFVOPSJ1c2IwIiwxLDE=\\\"",
+		"disconnect": "AT+SPTZCMD=\\\"Y29ubm1hbmN0bCBuZGlzZGlhbCBBVF5ORElTRFVOPSJ1c2IwIiwwLDE=\\\""
+	}
+}
diff --git a/package/network/utils/comgt/files/ncm.sh b/package/network/utils/comgt/files/ncm.sh
new file mode 100644
index 0000000..e9412b2
--- /dev/null
+++ b/package/network/utils/comgt/files/ncm.sh
@@ -0,0 +1,289 @@
+#!/bin/sh
+
+[ -n "$INCLUDE_ONLY" ] || {
+	. /lib/functions.sh
+	. ../netifd-proto.sh
+	init_proto "$@"
+}
+
+proto_ncm_init_config() {
+	no_device=1
+	available=1
+	proto_config_add_string "device:device"
+	proto_config_add_string ifname
+	proto_config_add_string apn
+	proto_config_add_string auth
+	proto_config_add_string username
+	proto_config_add_string password
+	proto_config_add_string pincode
+	proto_config_add_string delay
+	proto_config_add_string mode
+	proto_config_add_string pdptype
+	proto_config_add_boolean sourcefilter
+	proto_config_add_boolean delegate
+	proto_config_add_int profile
+	proto_config_add_defaults
+}
+
+proto_ncm_setup() {
+	local interface="$1"
+
+	local manufacturer initialize setmode connect finalize devname devpath ifpath
+
+	local device ifname  apn auth username password pincode delay mode pdptype profile $PROTO_DEFAULT_OPTIONS
+	json_get_vars device ifname apn auth username password pincode delay mode pdptype sourcefilter delegate profile $PROTO_DEFAULT_OPTIONS
+
+	local context_type
+
+	[ "$metric" = "" ] && metric="0"
+
+	[ -n "$profile" ] || profile=1
+
+	pdptype=$(echo "$pdptype" | awk '{print toupper($0)}')
+	[ "$pdptype" = "IP" -o "$pdptype" = "IPV6" -o "$pdptype" = "IPV4V6" ] || pdptype="IP"
+
+	[ "$pdptype" = "IPV4V6" ] && context_type=3
+	[ -z "$context_type" -a "$pdptype" = "IPV6" ] && context_type=2
+	[ -n "$context_type" ] || context_type=1
+
+	[ -n "$ctl_device" ] && device=$ctl_device
+
+	[ -n "$device" ] || {
+		echo "No control device specified"
+		proto_notify_error "$interface" NO_DEVICE
+		proto_set_available "$interface" 0
+		return 1
+	}
+
+	device="$(readlink -f $device)"
+	[ -e "$device" ] || {
+		echo "Control device not valid"
+		proto_set_available "$interface" 0
+		return 1
+	}
+
+	[ -z "$ifname" ] && {
+		devname="$(basename "$device")"
+		case "$devname" in
+		'ttyACM'*)
+			devpath="$(readlink -f /sys/class/tty/$devname/device)"
+			ifpath="$devpath/../*/net"
+			;;
+		'tty'*)
+			devpath="$(readlink -f /sys/class/tty/$devname/device)"
+			ifpath="$devpath/../../*/net"
+			;;
+		*)
+			devpath="$(readlink -f /sys/class/usbmisc/$devname/device/)"
+			ifpath="$devpath/net"
+			;;
+		esac
+		ifname="$(ls $(ls -1 -d $ifpath | head -n 1))"
+	}
+
+	[ -n "$ifname" ] || {
+		echo "The interface could not be found."
+		proto_notify_error "$interface" NO_IFACE
+		proto_set_available "$interface" 0
+		return 1
+	}
+
+	start=$(date +%s)
+	while true; do
+		manufacturer=$(gcom -d "$device" -s /etc/gcom/getcardinfo.gcom | awk 'NF && $0 !~ /AT\+CGMI/ { sub(/\+CGMI: /,""); print tolower($1); exit; }')
+		[ "$manufacturer" = "error" ] && {
+			manufacturer=""
+		}
+		[ -n "$manufacturer" ] && {
+			break
+		}
+		[ -z "$delay" ] && {
+			break
+		}
+		sleep 1
+		elapsed=$(($(date +%s) - start))
+		[ "$elapsed" -gt "$delay" ] && {
+			break
+		}
+	done
+	[ -z "$manufacturer" ] && {
+		echo "Failed to get modem information"
+		proto_notify_error "$interface" GETINFO_FAILED
+		return 1
+	}
+
+	json_load "$(cat /etc/gcom/ncm.json)"
+	json_select "$manufacturer"
+	[ $? -ne 0 ] && {
+		echo "Unsupported modem"
+		proto_notify_error "$interface" UNSUPPORTED_MODEM
+		proto_set_available "$interface" 0
+		return 1
+	}
+
+	json_get_values initialize initialize
+	for i in $initialize; do
+		eval COMMAND="$i" gcom -d "$device" -s /etc/gcom/runcommand.gcom || {
+			echo "Failed to initialize modem"
+			proto_notify_error "$interface" INITIALIZE_FAILED
+			return 1
+		}
+	done
+
+	[ -n "$pincode" ] && {
+		PINCODE="$pincode" gcom -d "$device" -s /etc/gcom/setpin.gcom || {
+			echo "Unable to verify PIN"
+			proto_notify_error "$interface" PIN_FAILED
+			proto_block_restart "$interface"
+			return 1
+		}
+	}
+
+	json_get_values configure configure
+	echo "Configuring modem"
+	for i in $configure; do
+		eval COMMAND="$i" gcom -d "$device" -s /etc/gcom/runcommand.gcom || {
+			echo "Failed to configure modem"
+			proto_notify_error "$interface" CONFIGURE_FAILED
+			return 1
+		}
+	done
+
+	[ -n "$mode" ] && {
+		json_select modes
+		json_get_var setmode "$mode"
+		[ -n "$setmode" ] && {
+			echo "Setting mode"
+			eval COMMAND="$setmode" gcom -d "$device" -s /etc/gcom/runcommand.gcom || {
+				echo "Failed to set operating mode"
+				proto_notify_error "$interface" SETMODE_FAILED
+				return 1
+			}
+		}
+		json_select ..
+	}
+
+	echo "Starting network $interface"
+	json_get_vars connect
+	[ -n "$connect" ] && {
+		echo "Connecting modem"
+		eval COMMAND="$connect" gcom -d "$device" -s /etc/gcom/runcommand.gcom || {
+			echo "Failed to connect"
+			proto_notify_error "$interface" CONNECT_FAILED
+			return 1
+		}
+	}
+
+	json_get_vars finalize
+
+	echo "Setting up $ifname"
+	proto_init_update "$ifname" 1
+	proto_add_data
+	json_add_string "manufacturer" "$manufacturer"
+	proto_close_data
+	proto_send_update "$interface"
+
+	local zone="$(fw3 -q network "$interface" 2>/dev/null)"
+
+	[ "$pdptype" = "IP" -o "$pdptype" = "IPV4V6" ] && {
+		json_init
+		json_add_string name "${interface}_4"
+		json_add_string ifname "@$interface"
+		json_add_string proto "dhcp"
+		proto_add_dynamic_defaults
+		[ -n "$zone" ] && {
+			json_add_string zone "$zone"
+		}
+		json_close_object
+		ubus call network add_dynamic "$(json_dump)"
+	}
+
+	[ "$pdptype" = "IPV6" -o "$pdptype" = "IPV4V6" ] && {
+		json_init
+		json_add_string name "${interface}_6"
+		json_add_string ifname "@$interface"
+		json_add_string proto "dhcpv6"
+		json_add_string extendprefix 1
+		[ "$delegate" = "0" ] && json_add_boolean delegate "0"
+		[ "$sourcefilter" = "0" ] && json_add_boolean sourcefilter "0"
+		proto_add_dynamic_defaults
+		[ -n "$zone" ] && {
+			json_add_string zone "$zone"
+		}
+		json_close_object
+		ubus call network add_dynamic "$(json_dump)"
+	}
+
+	[ -n "$finalize" ] && {
+		eval COMMAND="$finalize" gcom -d "$device" -s /etc/gcom/runcommand.gcom || {
+			echo "Failed to configure modem"
+			proto_notify_error "$interface" FINALIZE_FAILED
+			return 1
+		}
+	}
+}
+
+proto_ncm_teardown() {
+	local interface="$1"
+
+	local manufacturer disconnect
+
+	local device profile
+	json_get_vars device profile
+
+	[ -n "$ctl_device" ] && device=$ctl_device
+
+	[ -n "$device" ] || {
+		echo "No control device specified"
+		proto_notify_error "$interface" NO_DEVICE
+		proto_set_available "$interface" 0
+		return 1
+	}
+
+	device="$(readlink -f $device)"
+	[ -e "$device" ] || {
+		echo "Control device not valid"
+		proto_set_available "$interface" 0
+		return 1
+	}
+
+	[ -n "$profile" ] || profile=1
+
+	echo "Stopping network $interface"
+
+	json_load "$(ubus call network.interface.$interface status)"
+	json_select data
+	json_get_vars manufacturer
+	[ $? -ne 0 -o -z "$manufacturer" ] && {
+		# Fallback to direct detect, for proper handle device replug.
+		manufacturer=$(gcom -d "$device" -s /etc/gcom/getcardinfo.gcom | awk 'NF && $0 !~ /AT\+CGMI/ { sub(/\+CGMI: /,""); print tolower($1); exit; }')
+		[ $? -ne 0 -o -z "$manufacturer" ] && {
+			echo "Failed to get modem information"
+			proto_notify_error "$interface" GETINFO_FAILED
+			return 1
+		}
+		json_add_string "manufacturer" "$manufacturer"
+	}
+
+	json_load "$(cat /etc/gcom/ncm.json)"
+	json_select "$manufacturer" || {
+		echo "Unsupported modem"
+		proto_notify_error "$interface" UNSUPPORTED_MODEM
+		return 1
+	}
+
+	json_get_vars disconnect
+	[ -n "$disconnect" ] && {
+		eval COMMAND="$disconnect" gcom -d "$device" -s /etc/gcom/runcommand.gcom || {
+			echo "Failed to disconnect"
+			proto_notify_error "$interface" DISCONNECT_FAILED
+			return 1
+		}
+	}
+
+	proto_init_update "*" 0
+	proto_send_update "$interface"
+}
+[ -n "$INCLUDE_ONLY" ] || {
+	add_protocol ncm
+}
diff --git a/package/network/utils/comgt/files/runcommand.gcom b/package/network/utils/comgt/files/runcommand.gcom
new file mode 100644
index 0000000..88a9d29
--- /dev/null
+++ b/package/network/utils/comgt/files/runcommand.gcom
@@ -0,0 +1,31 @@
+# run AT-command from environment
+opengt
+ set com 115200n81
+ set senddelay 0.02
+ waitquiet 1 0.2
+ flash 0.1
+
+:start
+ print "sending -> ",$env("COMMAND"),"\n"
+ send $env("COMMAND")
+ send "^m"
+
+ waitfor 25 "OK","ERR","ERROR","COMMAND NOT SUPPORT"
+ if % = 0 goto continue
+ if % = 1 goto error
+ if % = 2 goto error
+ if % = 3 goto notsupported
+
+ print "Timeout running AT-command\n"
+ exit 1
+
+:error
+ print "Error running AT-command\n"
+ exit 1
+
+:notsupported
+ print "AT-command not supported\n"
+ exit 1
+
+:continue
+ exit 0
diff --git a/package/network/utils/comgt/files/setmode.gcom b/package/network/utils/comgt/files/setmode.gcom
new file mode 100644
index 0000000..4ce0b5f
--- /dev/null
+++ b/package/network/utils/comgt/files/setmode.gcom
@@ -0,0 +1,26 @@
+# set wwan mode from environment
+opengt
+ set com 115200n81
+ set senddelay 0.02
+ waitquiet 1 0.2
+ flash 0.1
+
+:start
+ print "Trying to set mode\n"
+ send $env("MODE")
+ send "^m"
+
+ waitfor 15 "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
+ exit 0
diff --git a/package/network/utils/comgt/files/setpin.gcom b/package/network/utils/comgt/files/setpin.gcom
new file mode 100644
index 0000000..a3f3402
--- /dev/null
+++ b/package/network/utils/comgt/files/setpin.gcom
@@ -0,0 +1,56 @@
+# set pin code from evnironment "$PINCODE"
+opengt
+ set com 115200n81
+ set senddelay 0.05
+ waitquiet 3 0.5
+ flash 0.1
+
+ let c=0
+:start
+ send "AT+CFUN=1^m"
+ send "AT+CPIN?^m"
+ waitfor 15 "SIM PUK","SIM PIN","READY","ERROR","ERR"
+ if % = -1 goto timeout
+ if % = 0 goto ready
+ if % = 1 goto setpin
+ if % = 2 goto ready
+ if % = 3 goto checkrepeat
+ if % = 4 goto checkrepeat
+
+:checkrepeat
+ inc c
+ if c>3 goto pinerror
+ waitquiet 12 0.5
+ goto start
+
+:timeout
+ print "timeout checking for PIN."
+ exit 1
+
+:ready
+ print "SIM ready\n"
+ goto continue
+ exit 0
+
+:setpin
+ # check if output was "SIM PIN2", that's ok.
+ waitfor 1 "2"
+ if % = 0 goto ready
+
+ print "Trying to set PIN\n"
+ send "AT+CPIN=\""
+ send $env("PINCODE")
+ send "\"^m"
+
+ waitfor 20 "OK","ERR"
+ if % = -1 goto pinerror
+ if % = 0 goto continue
+ if % = 1 goto pinerror
+
+:pinerror
+ print "Error setting PIN, check card manually\n"
+ exit 1
+
+:continue
+ print "PIN set successfully\n"
+ exit 0
diff --git a/package/network/utils/comgt/files/ussd.gcom b/package/network/utils/comgt/files/ussd.gcom
new file mode 100644
index 0000000..c5be80b
--- /dev/null
+++ b/package/network/utils/comgt/files/ussd.gcom
@@ -0,0 +1,21 @@
+opengt
+ set com 115200n81
+ set comecho off
+ set senddelay 0.02
+ waitquiet 0.2 0.2
+ flash 0.1
+
+:start
+ send "AT+CUSD=1,"
+ send $env("ussd")
+ send ",15"
+ send "^m"
+ waitfor 120 "+CUSD:"
+ if % = -1 goto timeout
+ get 1 "^m" $s
+ print $s
+ exit 0
+
+:timeout
+ print "ERROR: no USSD response, timeout.\n"
+ exit 1