1#!/bin/sh
2
3[ -n "$INCLUDE_ONLY" ] || {
4	. /lib/functions.sh
5	. ../netifd-proto.sh
6	init_proto "$@"
7}
8
9proto_qmi_init_config() {
10	available=1
11	no_device=1
12	proto_config_add_string "device:device"
13	proto_config_add_string apn
14	proto_config_add_string auth
15	proto_config_add_string username
16	proto_config_add_string password
17	proto_config_add_string pincode
18	proto_config_add_string delay
19	proto_config_add_string modes
20	proto_config_add_boolean ipv6
21	proto_config_add_boolean dhcp
22}
23
24proto_qmi_setup() {
25	local interface="$1"
26
27	local device apn auth username password pincode delay modes ipv6 dhcp
28	local cid_4 pdh_4 cid_6 pdh_6 ipv4
29	local ip subnet gateway dns1 dns2 ip_6 ip_prefix_length gateway_6 dns1_6 dns2_6
30	json_get_vars device apn auth username password pincode delay modes ipv6 dhcp
31
32	ipv4=1
33
34	if [ "$ipv6" = 0 ]; then
35		ipv6=""
36	else
37		ipv6=1
38	fi
39
40	[ -n "$ctl_device" ] && device=$ctl_device
41
42	[ -n "$device" ] || {
43		echo "No control device specified"
44		proto_notify_error "$interface" NO_DEVICE
45		proto_set_available "$interface" 0
46		return 1
47	}
48	[ -c "$device" ] || {
49		echo "The specified control device does not exist"
50		proto_notify_error "$interface" NO_DEVICE
51		proto_set_available "$interface" 0
52		return 1
53	}
54
55	devname="$(basename "$device")"
56	devpath="$(readlink -f /sys/class/usbmisc/$devname/device/)"
57	ifname="$( ls "$devpath"/net )"
58	[ -n "$ifname" ] || {
59		echo "The interface could not be found."
60		proto_notify_error "$interface" NO_IFACE
61		proto_set_available "$interface" 0
62		return 1
63	}
64
65	[ -n "$delay" ] && sleep "$delay"
66
67	while uqmi -s -d "$device" --get-pin-status | grep '"UIM uninitialized"' > /dev/null; do
68		sleep 1;
69	done
70
71	[ -n "$pincode" ] && {
72		uqmi -s -d "$device" --verify-pin1 "$pincode" || {
73			echo "Unable to verify PIN"
74			proto_notify_error "$interface" PIN_FAILED
75			proto_block_restart "$interface"
76			return 1
77		}
78	}
79
80	[ -n "$apn" ] || {
81		echo "No APN specified"
82		proto_notify_error "$interface" NO_APN
83		return 1
84	}
85
86	uqmi -s -d "$device" --set-data-format 802.3
87	uqmi -s -d "$device" --wda-set-data-format 802.3
88
89	echo "Waiting for network registration"
90	while uqmi -s -d "$device" --get-serving-system | grep '"searching"' > /dev/null; do
91		sleep 5;
92	done
93
94	[ -n "$modes" ] && uqmi -s -d "$device" --set-network-modes "$modes"
95
96	echo "Starting network $apn"
97
98	cid_4=`uqmi -s -d "$device" --get-client-id wds`
99	[ $? -ne 0 ] && {
100		echo "Unable to obtain client ID"
101		proto_notify_error "$interface" NO_CID
102		return 1
103	}
104
105	pdh_4=`uqmi -s -d "$device" --set-client-id wds,"$cid_4" \
106		--start-network "$apn" \
107		${auth:+--auth-type $auth} \
108		${username:+--username $username} \
109		${password:+--password $password} \
110		--ip-family ipv4`
111	[ $? -ne 0 ] && {
112		echo "Unable to connect IPv4"
113		uqmi -s -d "$device" --set-client-id wds,"$cid_4" --release-client-id wds
114		ipv4=""
115	}
116
117	[ -n "$ipv6" ] && {
118		cid_6=`uqmi -s -d "$device" --get-client-id wds`
119		if [ $? = 0 ]; then
120			pdh_6=`uqmi -s -d "$device" --set-client-id wds,"$cid_6" \
121				--start-network "$apn" \
122				${auth:+--auth-type $auth} \
123				${username:+--username $username} \
124				${password:+--password $password} \
125				--ip-family ipv6`
126			[ $? -ne 0 ] && {
127				echo "Unable to connect IPv6"
128				uqmi -s -d "$device" --set-client-id wds,"$cid_6" --release-client-id wds
129				ipv6=""
130			}
131		else
132			echo "Unable to connect IPv6"
133			ipv6=""
134		fi
135	}
136
137	[ -z "$ipv4" -a -z "$ipv6" ] && {
138		echo "Unable to connect"
139		proto_notify_error "$interface" CALL_FAILED
140		return 1
141	}
142
143	if [ -z "$dhcp" -o "$dhcp" = 0 ]; then
144		echo "Setting up $ifname"
145		[ -n "$ipv4" ] && {
146			json_load "$(uqmi -s -d $device --set-client-id wds,$cid_4 --get-current-settings)"
147			json_select ipv4
148			json_get_vars ip subnet gateway dns1 dns2
149
150			proto_init_update "$ifname" 1
151			proto_set_keep 1
152			proto_add_ipv4_address "$ip" "$subnet"
153			proto_add_dns_server "$dns1"
154			proto_add_dns_server "$dns2"
155			proto_add_ipv4_route "0.0.0.0" 0 "$gateway"
156			proto_add_data
157			json_add_string "cid_4" "$cid_4"
158			json_add_string "pdh_4" "$pdh_4"
159			proto_close_data
160			proto_send_update "$interface"
161		}
162	
163		[ -n "$ipv6" ] && {
164			json_load "$(uqmi -s -d $device --set-client-id wds,$cid_6 --get-current-settings)"
165			json_select ipv6
166			json_get_var ip_6 ip
167			json_get_var gateway_6 gateway
168			json_get_var dns1_6 dns1
169			json_get_var dns2_6 dns2
170			json_get_var ip_prefix_length ip-prefix-length
171
172			proto_init_update "$ifname" 1
173			proto_set_keep 1
174			# RFC 7278: Extend an IPv6 /64 Prefix to LAN
175			proto_add_ipv6_address "$ip_6" "128"
176			proto_add_ipv6_prefix "${ip_6}/${ip_prefix_length}"
177			proto_add_ipv6_route "$gateway_6" "128"
178			proto_add_ipv6_route "::0" 0 "$gateway_6" "" "" "${ip_6}/${ip_prefix_length}"
179			proto_add_dns_server "$dns1_6"
180			proto_add_dns_server "$dns2_6"
181			proto_add_data
182			json_add_string "cid_6" "$cid_6"
183			json_add_string "pdh_6" "$pdh_6"
184			proto_close_data
185			proto_send_update "$interface"
186		}
187	else
188		echo "Starting DHCP on $ifname"
189		proto_init_update "$ifname" 1
190		proto_add_data
191		[ -n "$ipv4" ] && {
192			json_add_string "cid_4" "$cid_4"
193			json_add_string "pdh_4" "$pdh_4"
194		}
195		[ -n "$ipv6" ] && {
196			json_add_string "cid_6" "$cid_6"
197			json_add_string "pdh_6" "$pdh_6"
198		}
199		proto_close_data
200		proto_send_update "$interface"
201
202		[ -n "$ipv4" ] && {
203			json_init
204			json_add_string name "${interface}_4"
205			json_add_string ifname "@$interface"
206			json_add_string proto "dhcp"
207			json_close_object
208			ubus call network add_dynamic "$(json_dump)"
209		}
210
211		[ -n "$ipv6" ] && {
212			json_init
213			json_add_string name "${interface}_6"
214			json_add_string ifname "@$interface"
215			json_add_string proto "dhcpv6"
216			# RFC 7278: Extend an IPv6 /64 Prefix to LAN
217			json_add_string extendprefix 1
218			json_close_object
219			ubus call network add_dynamic "$(json_dump)"
220		}
221	fi
222}
223
224proto_qmi_teardown() {
225	local interface="$1"
226
227	local device cid_4 pdh_4 cid_6 pdh_6
228	json_get_vars device
229
230	[ -n "$ctl_device" ] && device=$ctl_device
231
232	echo "Stopping network"
233
234	json_load "$(ubus call network.interface.$interface status)"
235	json_select data
236	json_get_vars cid_4 pdh_4 cid_6 pdh_6
237
238	[ -n "$cid_4" ] && {
239		[ -n "$pdh_4" ] && {
240			uqmi -s -d "$device" --set-client-id wds,"$cid_4" --stop-network "$pdh_4"
241			uqmi -s -d "$device" --set-client-id wds,"$cid_4" --release-client-id wds
242		}
243	}
244	[ -n "$cid_6" ] && {
245		[ -n "$pdh_6" ] && {
246			uqmi -s -d "$device" --set-client-id wds,"$cid_6" --stop-network "$pdh_6"
247			uqmi -s -d "$device" --set-client-id wds,"$cid_6" --release-client-id wds
248		}
249	}
250
251	proto_init_update "*" 0
252	proto_send_update "$interface"
253}
254
255[ -n "$INCLUDE_ONLY" ] || {
256	add_protocol qmi
257}
258