uqmi: Add proper IPv6 support

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
owl
Steven Barth 2015-09-11 06:46:40 +00:00
parent eb866e413f
commit 8f24ee6382
2 changed files with 148 additions and 61 deletions

View File

@ -1,13 +1,13 @@
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_NAME:=uqmi PKG_NAME:=uqmi
PKG_VERSION:=2014-12-03 PKG_VERSION:=2015-08-13
PKG_RELEASE=$(PKG_SOURCE_VERSION) PKG_RELEASE=$(PKG_SOURCE_VERSION)
PKG_SOURCE_PROTO:=git PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL:=git://nbd.name/uqmi.git PKG_SOURCE_URL:=git://nbd.name/uqmi.git
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) 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_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz
PKG_MAINTAINER:=Matti Laakso <malaakso@elisanet.fi> PKG_MAINTAINER:=Matti Laakso <malaakso@elisanet.fi>
# PKG_MIRROR_MD5SUM:= # PKG_MIRROR_MD5SUM:=

205
package/network/utils/uqmi/files/lib/netifd/proto/qmi.sh Executable file → Normal file
View File

@ -17,28 +17,25 @@ proto_qmi_init_config() {
proto_config_add_string pincode proto_config_add_string pincode
proto_config_add_string delay proto_config_add_string delay
proto_config_add_string modes proto_config_add_string modes
proto_config_add_boolean ipv6
proto_config_add_boolean dhcp
} }
qmi_disconnect() { proto_qmi_setup() {
# 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
uqmi -s -d "$device" --set-client-id wds,"$cid" --release-client-id wds
uci_revert_state network $interface cid
}
_proto_qmi_setup() {
local interface="$1" local interface="$1"
local device apn auth username password pincode delay modes cid pdh local device apn auth username password pincode delay modes ipv6 dhcp
json_get_vars device apn auth username password pincode delay modes 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
ipv4=1
if [ "$ipv6" = 0 ]; then
ipv6=""
else
ipv6=1
fi
[ -n "$ctl_device" ] && device=$ctl_device [ -n "$ctl_device" ] && device=$ctl_device
@ -86,8 +83,6 @@ _proto_qmi_setup() {
return 1 return 1
} }
qmi_disconnect
uqmi -s -d "$device" --set-data-format 802.3 uqmi -s -d "$device" --set-data-format 802.3
uqmi -s -d "$device" --wda-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" [ -n "$modes" ] && uqmi -s -d "$device" --set-network-modes "$modes"
echo "Starting network $apn" 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 ] && { [ $? -ne 0 ] && {
echo "Unable to obtain client ID" echo "Unable to obtain client ID"
proto_notify_error "$interface" NO_CID proto_notify_error "$interface" NO_CID
return 1 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" \ --start-network "$apn" \
${auth:+--auth-type $auth} \ ${auth:+--auth-type $auth} \
${username:+--username $username} \ ${username:+--username $username} \
${password:+--password $password} \ ${password:+--password $password} \
--autoconnect > /dev/null --ip-family ipv4`
[ $? -ne 0 ] && {
echo "Starting DHCP" echo "Unable to connect IPv4"
proto_init_update "$ifname" 1 uqmi -s -d "$device" --set-client-id wds,"$cid_4" --release-client-id wds
proto_send_update "$interface" 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)"
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
_proto_qmi_setup $@
ret=$?
[ "$ret" = 0 ] || {
logger "qmi bringup failed, retry in 15s"
sleep 15
} }
return $rt [ -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
}
[ -z "$ipv4" -a -z "$ipv6" ] && {
echo "Unable to connect"
proto_notify_error "$interface" CALL_FAILED
return 1
}
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() { proto_qmi_teardown() {
local interface="$1" local interface="$1"
local device local device cid_4 pdh_4 cid_6 pdh_6
json_get_vars device json_get_vars device
[ -n "$ctl_device" ] && device=$ctl_device [ -n "$ctl_device" ] && device=$ctl_device
local cid=$(uci_get_state network $interface cid)
echo "Stopping network" 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_init_update "*" 0
proto_send_update "$interface" proto_send_update "$interface"