uqmi: Add proper IPv6 support
authorSteven Barth <cyrus@openwrt.org>
Fri, 11 Sep 2015 06:46:40 +0000 (06:46 +0000)
committerSteven Barth <cyrus@openwrt.org>
Fri, 11 Sep 2015 06:46:40 +0000 (06:46 +0000)
Use the new --ip-family option to start both IPv4 and IPv6 sessions
by default. Autoconnect can't be used when starting two sessions,
so revert back to using the client IDs and packet data handles for
handling the network connection.

Some modem firmwares do not implement a RA server, therefore by
default use outband IP configuration and static addressing. Some
other firmwares report bogus IP configuration with the WDS get
current settings command. In this case inband configuration with
DHCP/RA can be optionally enabled by setting option dhcp to 1.

Per 3GPP standard a /64 prefix is served to all clients, which is
extended to LAN as specified in RFC 7278.

v2: Restrict the IPv6 gateway route source address
Signed-off-by: Matti Laakso <malaakso@elisanet.fi>
SVN-Revision: 46843

package/network/utils/uqmi/Makefile
package/network/utils/uqmi/files/lib/netifd/proto/qmi.sh [changed mode: 0755->0644]

index 8ca7b85..16e7fea 100644 (file)
@@ -1,13 +1,13 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=uqmi
-PKG_VERSION:=2014-12-03
+PKG_VERSION:=2015-08-13
 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:=86bcdb8cca652676a78b2df8b5e3fb27a40c60a4
+PKG_SOURCE_VERSION:=8a97586e9445a60e355dea13aa87885ab3dcb277
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz
 PKG_MAINTAINER:=Matti Laakso <malaakso@elisanet.fi>
 # PKG_MIRROR_MD5SUM:=
old mode 100755 (executable)
new mode 100644 (file)
index b416da6..8ee7dbd
@@ -17,28 +17,25 @@ proto_qmi_init_config() {
        proto_config_add_string pincode
        proto_config_add_string delay
        proto_config_add_string modes
+       proto_config_add_boolean ipv6
+       proto_config_add_boolean dhcp
 }
 
-qmi_disconnect() {
-       # disable previous autoconnect state using the global handle
-       # do not reuse previous wds client id to prevent hangs caused by stale data
-       uqmi -s -d "$device" \
-               --stop-network 0xffffffff \
-               --autoconnect > /dev/null
-}
-
-qmi_wds_release() {
-       [ -n "$cid" ] || return 0
+proto_qmi_setup() {
+       local interface="$1"
 
-       uqmi -s -d "$device" --set-client-id wds,"$cid" --release-client-id wds
-       uci_revert_state network $interface cid
-}
+       local device apn auth username password pincode delay modes ipv6 dhcp
+       local cid_4 pdh_4 cid_6 pdh_6 ipv4
+       local ip subnet gateway dns1 dns2 ip_6 ip_prefix_length gateway_6 dns1_6 dns2_6
+       json_get_vars device apn auth username password pincode delay modes ipv6 dhcp
 
-_proto_qmi_setup() {
-       local interface="$1"
+       ipv4=1
 
-       local device apn auth username password pincode delay modes cid pdh
-       json_get_vars device apn auth username password pincode delay modes
+       if [ "$ipv6" = 0 ]; then
+               ipv6=""
+       else
+               ipv6=1
+       fi
 
        [ -n "$ctl_device" ] && device=$ctl_device
 
@@ -86,8 +83,6 @@ _proto_qmi_setup() {
                return 1
        }
 
-       qmi_disconnect
-
        uqmi -s -d "$device" --set-data-format 802.3
        uqmi -s -d "$device" --wda-set-data-format 802.3
 
@@ -99,67 +94,159 @@ _proto_qmi_setup() {
        [ -n "$modes" ] && uqmi -s -d "$device" --set-network-modes "$modes"
 
        echo "Starting network $apn"
-       cid=`uqmi -s -d "$device" --get-client-id wds`
+
+       cid_4=`uqmi -s -d "$device" --get-client-id wds`
        [ $? -ne 0 ] && {
                echo "Unable to obtain client ID"
                proto_notify_error "$interface" NO_CID
                return 1
        }
 
-       uqmi -s -d "$device" --set-client-id wds,"$cid" \
+       pdh_4=`uqmi -s -d "$device" --set-client-id wds,"$cid_4" \
                --start-network "$apn" \
                ${auth:+--auth-type $auth} \
                ${username:+--username $username} \
                ${password:+--password $password} \
-               --autoconnect > /dev/null
-
-       echo "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"
-       json_close_object
-       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
-       json_close_object
-       ubus call network add_dynamic "$(json_dump)"
-}
-
-proto_qmi_setup() {
-       local ret
+               --ip-family ipv4`
+       [ $? -ne 0 ] && {
+               echo "Unable to connect IPv4"
+               uqmi -s -d "$device" --set-client-id wds,"$cid_4" --release-client-id wds
+               ipv4=""
+       }
 
-       _proto_qmi_setup $@
-       ret=$?
+       [ -n "$ipv6" ] && {
+               cid_6=`uqmi -s -d "$device" --get-client-id wds`
+               if [ $? = 0 ]; then
+                       pdh_6=`uqmi -s -d "$device" --set-client-id wds,"$cid_6" \
+                               --start-network "$apn" \
+                               ${auth:+--auth-type $auth} \
+                               ${username:+--username $username} \
+                               ${password:+--password $password} \
+                               --ip-family ipv6`
+                       [ $? -ne 0 ] && {
+                               echo "Unable to connect IPv6"
+                               uqmi -s -d "$device" --set-client-id wds,"$cid_6" --release-client-id wds
+                               ipv6=""
+                       }
+               else
+                       echo "Unable to connect IPv6"
+                       ipv6=""
+               fi
+       }
 
-       [ "$ret" = 0 ] || {
-               logger "qmi bringup failed, retry in 15s"
-               sleep 15
+       [ -z "$ipv4" -a -z "$ipv6" ] && {
+               echo "Unable to connect"
+               proto_notify_error "$interface" CALL_FAILED
+               return 1
        }
 
-       return $rt
+       if [ -z "$dhcp" ]; then
+               echo "Setting up $ifname"
+               [ -n "$ipv4" ] && {
+                       json_load "$(uqmi -s -d $device --set-client-id wds,$cid_4 --get-current-settings)"
+                       json_select ipv4
+                       json_get_vars ip subnet gateway dns1 dns2
+
+                       proto_init_update "$ifname" 1
+                       proto_set_keep 1
+                       proto_add_ipv4_address "$ip" "$subnet"
+                       proto_add_dns_server "$dns1"
+                       proto_add_dns_server "$dns2"
+                       proto_add_ipv4_route "0.0.0.0" 0 "$gateway"
+                       proto_add_data
+                       json_add_string "cid_4" "$cid_4"
+                       json_add_string "pdh_4" "$pdh_4"
+                       proto_close_data
+                       proto_send_update "$interface"
+               }
+       
+               [ -n "$ipv6" ] && {
+                       json_load "$(uqmi -s -d $device --set-client-id wds,$cid_6 --get-current-settings)"
+                       json_select ipv6
+                       json_get_var ip_6 ip
+                       json_get_var gateway_6 gateway
+                       json_get_var dns1_6 dns1
+                       json_get_var dns2_6 dns2
+                       json_get_var ip_prefix_length ip-prefix-length
+
+                       proto_init_update "$ifname" 1
+                       proto_set_keep 1
+                       # RFC 7278: Extend an IPv6 /64 Prefix to LAN
+                       proto_add_ipv6_address "$ip_6" "128"
+                       proto_add_ipv6_prefix "${ip_6}/${ip_prefix_length}"
+                       proto_add_ipv6_route "$gateway_6" "128"
+                       proto_add_ipv6_route "::0" 0 "$gateway_6" "" "" "${ip_6}/${ip_prefix_length}"
+                       proto_add_dns_server "$dns1_6"
+                       proto_add_dns_server "$dns2_6"
+                       proto_add_data
+                       json_add_string "cid_6" "$cid_6"
+                       json_add_string "pdh_6" "$pdh_6"
+                       proto_close_data
+                       proto_send_update "$interface"
+               }
+       else
+               echo "Starting DHCP on $ifname"
+               proto_init_update "$ifname" 1
+               proto_add_data
+               [ -n "$ipv4" ] && {
+                       json_add_string "cid_4" "$cid_4"
+                       json_add_string "pdh_4" "$pdh_4"
+               }
+               [ -n "$ipv6" ] && {
+                       json_add_string "cid_6" "$cid_6"
+                       json_add_string "pdh_6" "$pdh_6"
+               }
+               proto_close_data
+               proto_send_update "$interface"
+
+               [ -n "$ipv4" ] && {
+                       json_init
+                       json_add_string name "${interface}_4"
+                       json_add_string ifname "@$interface"
+                       json_add_string proto "dhcp"
+                       json_close_object
+                       ubus call network add_dynamic "$(json_dump)"
+               }
+
+               [ -n "$ipv6" ] && {
+                       json_init
+                       json_add_string name "${interface}_6"
+                       json_add_string ifname "@$interface"
+                       json_add_string proto "dhcpv6"
+                       # RFC 7278: Extend an IPv6 /64 Prefix to LAN
+                       json_add_string extendprefix 1
+                       json_close_object
+                       ubus call network add_dynamic "$(json_dump)"
+               }
+       fi
 }
 
 proto_qmi_teardown() {
        local interface="$1"
 
-       local device
+       local device cid_4 pdh_4 cid_6 pdh_6
        json_get_vars device
 
        [ -n "$ctl_device" ] && device=$ctl_device
 
-       local cid=$(uci_get_state network $interface cid)
-
        echo "Stopping network"
-       qmi_disconnect
-       qmi_wds_release
+
+       json_load "$(ubus call network.interface.$interface status)"
+       json_select data
+       json_get_vars cid_4 pdh_4 cid_6 pdh_6
+
+       [ -n "$cid_4" ] && {
+               [ -n "$pdh_4" ] && {
+                       uqmi -s -d "$device" --set-client-id wds,"$cid_4" --stop-network "$pdh_4"
+                       uqmi -s -d "$device" --set-client-id wds,"$cid_4" --release-client-id wds
+               }
+       }
+       [ -n "$cid_6" ] && {
+               [ -n "$pdh_6" ] && {
+                       uqmi -s -d "$device" --set-client-id wds,"$cid_6" --stop-network "$pdh_6"
+                       uqmi -s -d "$device" --set-client-id wds,"$cid_6" --release-client-id wds
+               }
+       }
 
        proto_init_update "*" 0
        proto_send_update "$interface"