From 487f719203626235facae64d8499258a00de952d Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 28 May 2014 19:45:20 +0000 Subject: [PATCH] uqmi: Add support for QMI-based mobile broadband modems Many of the 4G/LTE and 3G modems utilize the QMI-protocol to control the modem. At the moment there is no support for them in OpenWrt. This patch adds support for them in the form of a netifd script and a control utility. Tested with Huawei E398 and ZTE MF820D (which requires a delay of ~30 s before responding to QMI commands). I put myself up as the maintainer, feel free to change this if you desire. Signed-off-by: Matti Laakso SVN-Revision: 40868 --- package/network/utils/uqmi/Makefile | 48 ++++++ .../utils/uqmi/files/lib/netifd/proto/qmi.sh | 137 ++++++++++++++++++ 2 files changed, 185 insertions(+) create mode 100644 package/network/utils/uqmi/Makefile create mode 100755 package/network/utils/uqmi/files/lib/netifd/proto/qmi.sh diff --git a/package/network/utils/uqmi/Makefile b/package/network/utils/uqmi/Makefile new file mode 100644 index 0000000000..18e0954ad2 --- /dev/null +++ b/package/network/utils/uqmi/Makefile @@ -0,0 +1,48 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=uqmi +PKG_VERSION:=2014-05-27 +PKG_RELEASE=$(PKG_SOURCE_VERSION) + +PKG_SOURCE_PROTO:=git +PKG_SOURCE_URL:=git://nbd.name/uqmi.git +PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) +PKG_SOURCE_VERSION:=d7a56cad6d6ef3c2a5602fc604e31999eb9e78fa +PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz +PKG_MAINTAINER:=Matti Laakso +# PKG_MIRROR_MD5SUM:= +# CMAKE_INSTALL:=1 + +PKG_LICENSE:=GPLv2 +PKG_LICENSE_FILES:= + +PKG_BUILD_PARALLEL:=1 + +include $(INCLUDE_DIR)/package.mk +include $(INCLUDE_DIR)/cmake.mk + +define Package/uqmi + SECTION:=net + CATEGORY:=Network + DEPENDS:=+libubox +libblobmsg-json + TITLE:=Control utility for mobile broadband modems +endef + +define Package/uqmi/description + uqmi is a command line tool for controlling mobile broadband modems using + the QMI-protocol. +endef + +TARGET_CFLAGS += \ + -I$(STAGING_DIR)/usr/include + +CMAKE_OPTIONS += \ + -DDEBUG=1 + +define Package/uqmi/install + $(INSTALL_DIR) $(1)/sbin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/uqmi $(1)/sbin/ + $(CP) ./files/* $(1)/ +endef + +$(eval $(call BuildPackage,uqmi)) diff --git a/package/network/utils/uqmi/files/lib/netifd/proto/qmi.sh b/package/network/utils/uqmi/files/lib/netifd/proto/qmi.sh new file mode 100755 index 0000000000..693fd6c115 --- /dev/null +++ b/package/network/utils/uqmi/files/lib/netifd/proto/qmi.sh @@ -0,0 +1,137 @@ +#!/bin/sh + +. /lib/functions.sh +. ../netifd-proto.sh +init_proto "$@" + +proto_qmi_init_config() { + proto_config_add_string "device:device" + 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 modes +} + +proto_qmi_setup() { + local interface="$1" + + local device apn auth username password pincode delay modes cid pdh + json_get_vars device apn auth username password pincode delay modes + + [ -n "$device" ] || { + logger -p daemon.err -t "qmi[$$]" "No control device specified" + proto_notify_error "$interface" NO_DEVICE + proto_block_restart "$interface" + return 1 + } + [ -c "$device" ] || { + logger -p daemon.err -t "qmi[$$]" "The specified control device does not exist" + proto_notify_error "$interface" NO_DEVICE + proto_block_restart "$interface" + return 1 + } + + [ -n "$delay" ] && sleep "$delay" + + while uqmi -s -d "$device" --get-pin-status | grep '"UIM uninitialized"' > /dev/null; do + sleep 1; + done + + [ -n "$pincode" ] && { + uqmi -s -d "$device" --verify-pin1 "$pincode" || { + logger -p daemon.err -t "qmi[$$]" "Unable to verify PIN" + proto_notify_error "$interface" PIN_FAILED + proto_block_restart "$interface" + return 1 + } + } + + [ -n "$apn" ] || { + logger -p daemon.err -t "qmi[$$]" "No APN specified" + proto_notify_error "$interface" NO_APN + proto_block_restart "$interface" + return 1 + } + + logger -p daemon.info -t "qmi[$$]" "Waiting for network registration" + while uqmi -s -d "$device" --get-serving-system | grep '"searching"' > /dev/null; do + sleep 5; + done + + [ -n "$modes" ] && uqmi -s -d "$device" --set-network-modes "$modes" + + logger -p daemon.info -t "qmi[$$]" "Starting network $apn" + cid=`uqmi -s -d "$device" --get-client-id wds` + [ $? -ne 0 ] && { + logger -p daemon.err -t "qmi[$$]" "Unable to obtain client ID" + proto_notify_error "$interface" NO_CID + proto_block_restart "$interface" + return 1 + } + uci_set_state network $interface cid "$cid" + + pdh=`uqmi -s -d "$device" --set-client-id wds,"$cid" --start-network "$apn" \ + ${auth:+--auth-type $auth} \ + ${username:+--username $username} \ + ${password:+--password $password}` + [ $? -ne 0 ] && { + logger -p daemon.err -t "qmi[$$]" "Unable to connect, check APN and authentication" + proto_notify_error "$interface" NO_PDH + proto_block_restart "$interface" + return 1 + } + uci_set_state network $interface pdh "$pdh" + + if ! uqmi -s -d "$device" --get-data-status | grep '"connected"' > /dev/null; then + logger -p daemon.err -t "qmi[$$]" "Connection lost" + proto_notify_error "$interface" NOT_CONNECTED + proto_block_restart "$interface" + return 1 + fi + + logger -p daemon.info -t "qmi[$$]" "Connected, starting DHCP" + proto_init_update "*" 1 + proto_send_update "$interface" + + json_init + json_add_string name "${interface}_dhcp" + json_add_string ifname "@$interface" + json_add_string proto "dhcp" + json_close_object + ubus call network add_dynamic "$(json_dump)" + + json_init + json_add_string name "${interface}_dhcpv6" + json_add_string ifname "@$interface" + json_add_string proto "dhcpv6" + json_close_object + ubus call network add_dynamic "$(json_dump)" +} + +proto_qmi_teardown() { + local interface="$1" + + local device + json_get_vars device + local cid=$(uci_get_state network $interface cid) + local pdh=$(uci_get_state network $interface pdh) + + logger -p daemon.info -t "qmi[$$]" "Stopping network" + [ -n "$cid" ] && { + [ -n "$pdh" ] && { + uqmi -s -d "$device" --set-client-id wds,"$cid" --stop-network "$pdh" + uci_revert_state network $interface pdh + } + uqmi -s -d "$device" --set-client-id wds,"$cid" --release-client-id wds + uci_revert_state network $interface cid + } + + proto_init_update "*" 0 + proto_send_update "$interface" +} + +add_protocol qmi +