uqmi: inherit firewall zone membership to virtual sub interfaces
[oweals/openwrt.git] / package / network / utils / uqmi / files / lib / netifd / proto / qmi.sh
1 #!/bin/sh
2
3 [ -n "$INCLUDE_ONLY" ] || {
4         . /lib/functions.sh
5         . ../netifd-proto.sh
6         init_proto "$@"
7 }
8
9 proto_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_int delay
19         proto_config_add_string modes
20         proto_config_add_string pdptype
21         proto_config_add_int profile
22         proto_config_add_boolean dhcpv6
23         proto_config_add_boolean autoconnect
24         proto_config_add_int plmn
25         proto_config_add_int timeout
26         proto_config_add_defaults
27 }
28
29 proto_qmi_setup() {
30         local interface="$1"
31         local dataformat connstat
32         local device apn auth username password pincode delay modes pdptype profile dhcpv6 autoconnect plmn timeout $PROTO_DEFAULT_OPTIONS
33         local ip4table ip6table
34         local cid_4 pdh_4 cid_6 pdh_6
35         local ip_6 ip_prefix_length gateway_6 dns1_6 dns2_6
36         json_get_vars device apn auth username password pincode delay modes pdptype profile dhcpv6 autoconnect plmn ip4table ip6table timeout $PROTO_DEFAULT_OPTIONS
37
38         [ "$timeout" = "" ] && timeout="10"
39
40         [ "$metric" = "" ] && metric="0"
41
42         [ -n "$ctl_device" ] && device=$ctl_device
43
44         [ -n "$device" ] || {
45                 echo "No control device specified"
46                 proto_notify_error "$interface" NO_DEVICE
47                 proto_set_available "$interface" 0
48                 return 1
49         }
50
51         [ -n "$delay" ] && sleep "$delay"
52
53         device="$(readlink -f $device)"
54         [ -c "$device" ] || {
55                 echo "The specified control device does not exist"
56                 proto_notify_error "$interface" NO_DEVICE
57                 proto_set_available "$interface" 0
58                 return 1
59         }
60
61         devname="$(basename "$device")"
62         devpath="$(readlink -f /sys/class/usbmisc/$devname/device/)"
63         ifname="$( ls "$devpath"/net )"
64         [ -n "$ifname" ] || {
65                 echo "The interface could not be found."
66                 proto_notify_error "$interface" NO_IFACE
67                 proto_set_available "$interface" 0
68                 return 1
69         }
70
71         echo "Waiting for SIM initialization"
72         local uninitialized_timeout=0
73         while uqmi -s -d "$device" --get-pin-status | grep '"UIM uninitialized"' > /dev/null; do
74                 [ -e "$device" ] || return 1
75                 if [ "$uninitialized_timeout" -lt "$timeout" ]; then
76                         let uninitialized_timeout++
77                         sleep 1;
78                 else
79                         echo "SIM not initialized"
80                         proto_notify_error "$interface" SIM_NOT_INITIALIZED
81                         proto_block_restart "$interface"
82                         return 1
83                 fi
84         done
85
86         if uqmi -s -d "$device" --get-pin-status | grep '"Not supported"\|"Invalid QMI command"' > /dev/null; then
87                 [ -n "$pincode" ] && {
88                         uqmi -s -d "$device" --verify-pin1 "$pincode" > /dev/null || uqmi -s -d "$device" --uim-verify-pin1 "$pincode" > /dev/null || {
89                                 echo "Unable to verify PIN"
90                                 proto_notify_error "$interface" PIN_FAILED
91                                 proto_block_restart "$interface"
92                                 return 1
93                         }
94                 }
95         else
96                 . /usr/share/libubox/jshn.sh
97                 json_load "$(uqmi -s -d "$device" --get-pin-status)"
98                 json_get_var pin1_status pin1_status
99                 json_get_var pin1_verify_tries pin1_verify_tries
100
101                 case "$pin1_status" in
102                         disabled)
103                                 echo "PIN verification is disabled"
104                                 ;;
105                         blocked)
106                                 echo "SIM locked PUK required"
107                                 proto_notify_error "$interface" PUK_NEEDED
108                                 proto_block_restart "$interface"
109                                 return 1
110                                 ;;
111                         not_verified)
112                                 [ "$pin1_verify_tries" -lt "3" ] && {
113                                         echo "PIN verify count value is $pin1_verify_tries this is below the limit of 3"
114                                         proto_notify_error "$interface" PIN_TRIES_BELOW_LIMIT
115                                         proto_block_restart "$interface"
116                                         return 1
117                                 }
118                                 if [ -n "$pincode" ]; then
119                                         uqmi -s -d "$device" --verify-pin1 "$pincode" > /dev/null 2>&1 || uqmi -s -d "$device" --uim-verify-pin1 "$pincode" > /dev/null 2>&1 || {
120                                                 echo "Unable to verify PIN"
121                                                 proto_notify_error "$interface" PIN_FAILED
122                                                 proto_block_restart "$interface"
123                                                 return 1
124                                         }
125                                 else
126                                         echo "PIN not specified but required"
127                                         proto_notify_error "$interface" PIN_NOT_SPECIFIED
128                                         proto_block_restart "$interface"
129                                         return 1
130                                 fi
131                                 ;;
132                         verified)
133                                 echo "PIN already verified"
134                                 ;;
135                         *)
136                                 echo "PIN status failed ($pin1_status)"
137                                 proto_notify_error "$interface" PIN_STATUS_FAILED
138                                 proto_block_restart "$interface"
139                                 return 1
140                         ;;
141                 esac
142         fi
143
144         [ -n "$plmn" ] && {
145                 local mcc mnc
146                 if [ "$plmn" = 0 ]; then
147                         mcc=0
148                         mnc=0
149                         echo "Setting PLMN to auto"
150                 else
151                         mcc=${plmn:0:3}
152                         mnc=${plmn:3}
153                         echo "Setting PLMN to $plmn"
154                 fi
155                 uqmi -s -d "$device" --set-plmn --mcc "$mcc" --mnc "$mnc" > /dev/null 2>&1 || {
156                         echo "Unable to set PLMN"
157                         proto_notify_error "$interface" PLMN_FAILED
158                         proto_block_restart "$interface"
159                         return 1
160                 }
161         }
162
163         # Cleanup current state if any
164         uqmi -s -d "$device" --stop-network 0xffffffff --autoconnect > /dev/null 2>&1
165
166         # Set IP format
167         uqmi -s -d "$device" --set-data-format 802.3 > /dev/null 2>&1
168         uqmi -s -d "$device" --wda-set-data-format 802.3 > /dev/null 2>&1
169         dataformat="$(uqmi -s -d "$device" --wda-get-data-format)"
170
171         if [ "$dataformat" = '"raw-ip"' ]; then
172
173                 [ -f /sys/class/net/$ifname/qmi/raw_ip ] || {
174                         echo "Device only supports raw-ip mode but is missing this required driver attribute: /sys/class/net/$ifname/qmi/raw_ip"
175                         return 1
176                 }
177
178                 echo "Device does not support 802.3 mode. Informing driver of raw-ip only for $ifname .."
179                 echo "Y" > /sys/class/net/$ifname/qmi/raw_ip
180         fi
181
182         uqmi -s -d "$device" --sync > /dev/null 2>&1
183
184         echo "Waiting for network registration"
185         local registration_timeout=0
186         while uqmi -s -d "$device" --get-serving-system | grep '"searching"' > /dev/null; do
187                 [ -e "$device" ] || return 1
188                 if [ "$registration_timeout" -lt "$timeout" ]; then
189                         let registration_timeout++
190                         sleep 1;
191                 else
192                         echo "Network registration failed"
193                         proto_notify_error "$interface" NETWORK_REGISTRATION_FAILED
194                         proto_block_restart "$interface"
195                         return 1
196                 fi
197         done
198
199         [ -n "$modes" ] && uqmi -s -d "$device" --set-network-modes "$modes" > /dev/null 2>&1
200
201         echo "Starting network $interface"
202
203         pdptype=$(echo "$pdptype" | awk '{print tolower($0)}')
204         [ "$pdptype" = "ip" -o "$pdptype" = "ipv6" -o "$pdptype" = "ipv4v6" ] || pdptype="ip"
205
206         if [ "$pdptype" = "ip" ]; then
207                 [ -z "$autoconnect" ] && autoconnect=1
208                 [ "$autoconnect" = 0 ] && autoconnect=""
209         else
210                 [ "$autoconnect" = 1 ] || autoconnect=""
211         fi
212
213         [ "$pdptype" = "ip" -o "$pdptype" = "ipv4v6" ] && {
214                 cid_4=$(uqmi -s -d "$device" --get-client-id wds)
215                 if ! [ "$cid_4" -eq "$cid_4" ] 2> /dev/null; then
216                         echo "Unable to obtain client ID"
217                         proto_notify_error "$interface" NO_CID
218                         return 1
219                 fi
220
221                 uqmi -s -d "$device" --set-client-id wds,"$cid_4" --set-ip-family ipv4 > /dev/null 2>&1
222
223                 pdh_4=$(uqmi -s -d "$device" --set-client-id wds,"$cid_4" \
224                         --start-network \
225                         ${apn:+--apn $apn} \
226                         ${profile:+--profile $profile} \
227                         ${auth:+--auth-type $auth} \
228                         ${username:+--username $username} \
229                         ${password:+--password $password} \
230                         ${autoconnect:+--autoconnect})
231
232                 # pdh_4 is a numeric value on success
233                 if ! [ "$pdh_4" -eq "$pdh_4" ] 2> /dev/null; then
234                         echo "Unable to connect IPv4"
235                         uqmi -s -d "$device" --set-client-id wds,"$cid_4" --release-client-id wds > /dev/null 2>&1
236                         proto_notify_error "$interface" CALL_FAILED
237                         return 1
238                 fi
239
240                 # Check data connection state
241                 connstat=$(uqmi -s -d "$device" --get-data-status)
242                 [ "$connstat" == '"connected"' ] || {
243                         echo "No data link!"
244                         uqmi -s -d "$device" --set-client-id wds,"$cid_4" --release-client-id wds > /dev/null 2>&1
245                         proto_notify_error "$interface" CALL_FAILED
246                         return 1
247                 }
248         }
249
250         [ "$pdptype" = "ipv6" -o "$pdptype" = "ipv4v6" ] && {
251                 cid_6=$(uqmi -s -d "$device" --get-client-id wds)
252                 if ! [ "$cid_6" -eq "$cid_6" ] 2> /dev/null; then
253                         echo "Unable to obtain client ID"
254                         proto_notify_error "$interface" NO_CID
255                         return 1
256                 fi
257
258                 uqmi -s -d "$device" --set-client-id wds,"$cid_6" --set-ip-family ipv6 > /dev/null 2>&1
259
260                 pdh_6=$(uqmi -s -d "$device" --set-client-id wds,"$cid_6" \
261                         --start-network \
262                         ${apn:+--apn $apn} \
263                         ${profile:+--profile $profile} \
264                         ${auth:+--auth-type $auth} \
265                         ${username:+--username $username} \
266                         ${password:+--password $password} \
267                         ${autoconnect:+--autoconnect})
268
269                 # pdh_6 is a numeric value on success
270                 if ! [ "$pdh_6" -eq "$pdh_6" ] 2> /dev/null; then
271                         echo "Unable to connect IPv6"
272                         uqmi -s -d "$device" --set-client-id wds,"$cid_6" --release-client-id wds > /dev/null 2>&1
273                         proto_notify_error "$interface" CALL_FAILED
274                         return 1
275                 fi
276
277                 # Check data connection state
278                 connstat=$(uqmi -s -d "$device" --get-data-status)
279                 [ "$connstat" == '"connected"' ] || {
280                         echo "No data link!"
281                         uqmi -s -d "$device" --set-client-id wds,"$cid_6" --release-client-id wds > /dev/null 2>&1
282                         proto_notify_error "$interface" CALL_FAILED
283                         return 1
284                 }
285         }
286
287         echo "Setting up $ifname"
288         proto_init_update "$ifname" 1
289         proto_set_keep 1
290         proto_add_data
291         [ -n "$pdh_4" ] && {
292                 json_add_string "cid_4" "$cid_4"
293                 json_add_string "pdh_4" "$pdh_4"
294         }
295         [ -n "$pdh_6" ] && {
296                 json_add_string "cid_6" "$cid_6"
297                 json_add_string "pdh_6" "$pdh_6"
298         }
299         proto_close_data
300         proto_send_update "$interface"
301
302         local zone="$(fw3 -q network "$interface" 2>/dev/null)"
303
304         [ -n "$pdh_6" ] && {
305                 if [ -z "$dhcpv6" -o "$dhcpv6" = 0 ]; then
306                         json_load "$(uqmi -s -d $device --set-client-id wds,$cid_6 --get-current-settings)"
307                         json_select ipv6
308                         json_get_var ip_6 ip
309                         json_get_var gateway_6 gateway
310                         json_get_var dns1_6 dns1
311                         json_get_var dns2_6 dns2
312                         json_get_var ip_prefix_length ip-prefix-length
313
314                         proto_init_update "$ifname" 1
315                         proto_set_keep 1
316                         proto_add_ipv6_address "$ip_6" "128"
317                         proto_add_ipv6_prefix "${ip_6}/${ip_prefix_length}"
318                         proto_add_ipv6_route "$gateway_6" "128"
319                         [ "$defaultroute" = 0 ] || proto_add_ipv6_route "::0" 0 "$gateway_6" "" "" "${ip_6}/${ip_prefix_length}"
320                         [ "$peerdns" = 0 ] || {
321                                 proto_add_dns_server "$dns1_6"
322                                 proto_add_dns_server "$dns2_6"
323                         }
324                         [ -n "$zone" ] && {
325                                 proto_add_data
326                                 json_add_string zone "$zone"
327                                 proto_close_data
328                         }
329                         proto_send_update "$interface"
330                 else
331                         json_init
332                         json_add_string name "${interface}_6"
333                         json_add_string ifname "@$interface"
334                         json_add_string proto "dhcpv6"
335                         [ -n "$ip6table" ] && json_add_string ip6table "$ip6table"
336                         proto_add_dynamic_defaults
337                         # RFC 7278: Extend an IPv6 /64 Prefix to LAN
338                         json_add_string extendprefix 1
339                         [ -n "$zone" ] && json_add_string zone "$zone"
340                         json_close_object
341                         ubus call network add_dynamic "$(json_dump)"
342                 fi
343         }
344
345         [ -n "$pdh_4" ] && {
346                 json_init
347                 json_add_string name "${interface}_4"
348                 json_add_string ifname "@$interface"
349                 json_add_string proto "dhcp"
350                 [ -n "$ip4table" ] && json_add_string ip4table "$ip4table"
351                 proto_add_dynamic_defaults
352                 [ -n "$zone" ] && json_add_string zone "$zone"
353                 json_close_object
354                 ubus call network add_dynamic "$(json_dump)"
355         }
356 }
357
358 qmi_wds_stop() {
359         local cid="$1"
360         local pdh="$2"
361
362         [ -n "$cid" ] || return
363
364         uqmi -s -d "$device" --set-client-id wds,"$cid" \
365                 --stop-network 0xffffffff \
366                 --autoconnect > /dev/null 2>&1
367
368         [ -n "$pdh" ] && {
369                 uqmi -s -d "$device" --set-client-id wds,"$cid" \
370                         --stop-network "$pdh" > /dev/null 2>&1
371         }
372
373         uqmi -s -d "$device" --set-client-id wds,"$cid" \
374                 --release-client-id wds > /dev/null 2>&1
375 }
376
377 proto_qmi_teardown() {
378         local interface="$1"
379
380         local device cid_4 pdh_4 cid_6 pdh_6
381         json_get_vars device
382
383         [ -n "$ctl_device" ] && device=$ctl_device
384
385         echo "Stopping network $interface"
386
387         json_load "$(ubus call network.interface.$interface status)"
388         json_select data
389         json_get_vars cid_4 pdh_4 cid_6 pdh_6
390
391         qmi_wds_stop "$cid_4" "$pdh_4"
392         qmi_wds_stop "$cid_6" "$pdh_6"
393
394         proto_init_update "*" 0
395         proto_send_update "$interface"
396 }
397
398 [ -n "$INCLUDE_ONLY" ] || {
399         add_protocol qmi
400 }