proto-shell: add helpers for generic options in proto handlers
[project/netifd.git] / scripts / netifd-proto.sh
1 NETIFD_MAIN_DIR="${NETIFD_MAIN_DIR:-/lib/netifd}"
2 PROTO_DEFAULT_OPTIONS="defaultroute peerdns metric"
3
4 . /usr/share/libubox/jshn.sh
5 . $NETIFD_MAIN_DIR/utils.sh
6
7 proto_config_add_int() {
8         config_add_int "$@"
9 }
10
11 proto_config_add_string() {
12         config_add_string "$@"
13 }
14
15 proto_config_add_boolean() {
16         config_add_boolean "$@"
17 }
18
19 proto_config_add_defaults() {
20         proto_config_add_boolean "defaultroute"
21         proto_config_add_boolean "peerdns"
22         proto_config_add_int "metric"
23 }
24
25 proto_add_dynamic_defaults() {
26         [ -n "$defaultroute" ] && json_add_boolean defaultroute "$defaultroute"
27         [ -n "$peerdns" ] && json_add_boolean peerdns "$peerdns"
28         [ -n "$metric" ] && json_add_int metric "$metric"
29 }
30
31 _proto_do_teardown() {
32         json_load "$data"
33         eval "proto_$1_teardown \"$interface\" \"$ifname\""
34 }
35
36 _proto_do_renew() {
37         json_load "$data"
38         eval "proto_$1_renew \"$interface\" \"$ifname\""
39 }
40
41 _proto_do_setup() {
42         json_load "$data"
43         _EXPORT_VAR=0
44         _EXPORT_VARS=
45         eval "proto_$1_setup \"$interface\" \"$ifname\""
46 }
47
48 proto_init_update() {
49         local ifname="$1"
50         local up="$2"
51         local external="$3"
52
53         PROTO_KEEP=0
54         PROTO_INIT=1
55         PROTO_TUNNEL_OPEN=
56         PROTO_IPADDR=
57         PROTO_IP6ADDR=
58         PROTO_ROUTE=
59         PROTO_ROUTE6=
60         PROTO_PREFIX6=
61         PROTO_DNS=
62         PROTO_DNS_SEARCH=
63         json_init
64         json_add_int action 0
65         [ -n "$ifname" -a "*" != "$ifname" ] && json_add_string "ifname" "$ifname"
66         json_add_boolean "link-up" "$up"
67         [ -n "$3" ] && json_add_boolean "address-external" "$external"
68 }
69
70 proto_set_keep() {
71         PROTO_KEEP="$1"
72 }
73
74 proto_close_nested() {
75         [ -n "$PROTO_NESTED_OPEN" ] && json_close_object
76         PROTO_NESTED_OPEN=
77 }
78
79 proto_add_nested() {
80         PROTO_NESTED_OPEN=1
81         json_add_object "$1"
82 }
83
84 proto_add_tunnel() {
85         proto_add_nested "tunnel"
86 }
87
88 proto_close_tunnel() {
89         proto_close_nested
90 }
91
92 proto_add_data() {
93         proto_add_nested "data"
94 }
95
96 proto_close_data() {
97         proto_close_nested
98 }
99
100 proto_add_dns_server() {
101         local address="$1"
102
103         append PROTO_DNS "$address"
104 }
105
106 proto_add_dns_search() {
107         local address="$1"
108
109         append PROTO_DNS_SEARCH "$address"
110 }
111
112 proto_add_ipv4_address() {
113         local address="$1"
114         local mask="$2"
115         local broadcast="$3"
116         local ptp="$4"
117
118         append PROTO_IPADDR "$address/$mask/$broadcast/$ptp"
119 }
120
121 proto_add_ipv6_address() {
122         local address="$1"
123         local mask="$2"
124         local preferred="$3"
125         local valid="$4"
126         local offlink="$5"
127         local class="$6"
128
129         append PROTO_IP6ADDR "$address/$mask/$preferred/$valid/$offlink/$class"
130 }
131
132 proto_add_ipv4_route() {
133         local target="$1"
134         local mask="$2"
135         local gw="$3"
136         local source="$4"
137         local metric="$5"
138
139         append PROTO_ROUTE "$target/$mask/$gw/$metric///$source"
140 }
141
142 proto_add_ipv6_route() {
143         local target="$1"
144         local mask="$2"
145         local gw="$3"
146         local metric="$4"
147         local valid="$5"
148         local source="$6"
149         local table="$7"
150
151         append PROTO_ROUTE6 "$target/$mask/$gw/$metric/$valid/$table/$source"
152 }
153
154 proto_add_ipv6_prefix() {
155         local prefix="$1"
156         local valid="$2"
157         local preferred="$3"
158
159         if [ -z "$valid" ]; then
160                 append PROTO_PREFIX6 "$prefix"
161         else
162                 [ -z "$preferred" ] && preferred="$valid"
163                 append PROTO_PREFIX6 "$prefix,$valid,$preferred"
164         fi
165 }
166
167 _proto_push_ipv4_addr() {
168         local str="$1"
169         local address mask broadcast ptp
170
171         address="${str%%/*}"
172         str="${str#*/}"
173         mask="${str%%/*}"
174         str="${str#*/}"
175         broadcast="${str%%/*}"
176         str="${str#*/}"
177         ptp="$str"
178
179         json_add_object ""
180         json_add_string ipaddr "$address"
181         [ -n "$mask" ] && json_add_string mask "$mask"
182         [ -n "$broadcast" ] && json_add_string broadcast "$broadcast"
183         [ -n "$ptp" ] && json_add_string ptp "$ptp"
184         json_close_object
185 }
186
187 _proto_push_ipv6_addr() {
188         local str="$1"
189         local address mask preferred valid offlink
190
191         address="${str%%/*}"
192         str="${str#*/}"
193         mask="${str%%/*}"
194         str="${str#*/}"
195         preferred="${str%%/*}"
196         str="${str#*/}"
197         valid="${str%%/*}"
198         str="${str#*/}"
199         offlink="${str%%/*}"
200         str="${str#*/}"
201         class="${str%%/*}"
202
203         json_add_object ""
204         json_add_string ipaddr "$address"
205         [ -n "$mask" ] && json_add_string mask "$mask"
206         [ -n "$preferred" ] && json_add_int preferred "$preferred"
207         [ -n "$valid" ] && json_add_int valid "$valid"
208         [ -n "$offlink" ] && json_add_boolean offlink "$offlink"
209         [ -n "$class" ] && json_add_string class "$class"
210         json_close_object
211 }
212
213 _proto_push_string() {
214         json_add_string "" "$1"
215 }
216
217 _proto_push_route() {
218         local str="$1";
219         local target="${str%%/*}"
220         str="${str#*/}"
221         local mask="${str%%/*}"
222         str="${str#*/}"
223         local gw="${str%%/*}"
224         str="${str#*/}"
225         local metric="${str%%/*}"
226         str="${str#*/}"
227         local valid="${str%%/*}"
228         str="${str#*/}"
229         local table="${str%%/*}"
230         str="${str#*/}"
231         local source="${str}"
232
233         json_add_object ""
234         json_add_string target "$target"
235         json_add_string netmask "$mask"
236         [ -n "$gw" ] && json_add_string gateway "$gw"
237         [ -n "$metric" ] && json_add_int metric "$metric"
238         [ -n "$valid" ] && json_add_int valid "$valid"
239         [ -n "$source" ] && json_add_string source "$source"
240         [ -n "$table" ] && json_add_string table "$table"
241         json_close_object
242 }
243
244 _proto_push_array() {
245         local name="$1"
246         local val="$2"
247         local cb="$3"
248
249         [ -n "$val" ] || return 0
250         json_add_array "$name"
251         for item in $val; do
252                 eval "$cb \"\$item\""
253         done
254         json_close_array
255 }
256
257 _proto_notify() {
258         local interface="$1"
259         local options="$2"
260         json_add_string "interface" "$interface"
261         ubus $options call network.interface notify_proto "$(json_dump)"
262 }
263
264 proto_send_update() {
265         local interface="$1"
266
267         proto_close_nested
268         json_add_boolean keep "$PROTO_KEEP"
269         _proto_push_array "ipaddr" "$PROTO_IPADDR" _proto_push_ipv4_addr
270         _proto_push_array "ip6addr" "$PROTO_IP6ADDR" _proto_push_ipv6_addr
271         _proto_push_array "routes" "$PROTO_ROUTE" _proto_push_route
272         _proto_push_array "routes6" "$PROTO_ROUTE6" _proto_push_route
273         _proto_push_array "ip6prefix" "$PROTO_PREFIX6" _proto_push_string
274         _proto_push_array "dns" "$PROTO_DNS" _proto_push_string
275         _proto_push_array "dns_search" "$PROTO_DNS_SEARCH" _proto_push_string
276         _proto_notify "$interface"
277 }
278
279 proto_export() {
280         local var="VAR${_EXPORT_VAR}"
281         _EXPORT_VAR="$(($_EXPORT_VAR + 1))"
282         export -- "$var=$1"
283         append _EXPORT_VARS "$var"
284 }
285
286 proto_run_command() {
287         local interface="$1"; shift
288
289         json_init
290         json_add_int action 1
291         json_add_array command
292         while [ $# -gt 0 ]; do
293                 json_add_string "" "$1"
294                 shift
295         done
296         json_close_array
297         [ -n "$_EXPORT_VARS" ] && {
298                 json_add_array env
299                 for var in $_EXPORT_VARS; do
300                         eval "json_add_string \"\" \"\${$var}\""
301                 done
302                 json_close_array
303         }
304         _proto_notify "$interface"
305 }
306
307 proto_kill_command() {
308         local interface="$1"; shift
309
310         json_init
311         json_add_int action 2
312         [ -n "$1" ] && json_add_int signal "$1"
313         _proto_notify "$interface"
314 }
315
316 proto_notify_error() {
317         local interface="$1"; shift
318
319         json_init
320         json_add_int action 3
321         json_add_array error
322         while [ $# -gt 0 ]; do
323                 json_add_string "" "$1"
324                 shift
325         done
326         json_close_array
327         _proto_notify "$interface"
328 }
329
330 proto_block_restart() {
331         local interface="$1"; shift
332
333         json_init
334         json_add_int action 4
335         _proto_notify "$interface"
336 }
337
338 proto_set_available() {
339         local interface="$1"
340         local state="$2"
341         json_init
342         json_add_int action 5
343         json_add_boolean available "$state"
344         _proto_notify "$interface"
345 }
346
347 proto_add_host_dependency() {
348         local interface="$1"
349         local host="$2"
350         local ifname="$3"
351
352         # execute in subshell to not taint callers env
353         # see tickets #11046, #11545, #11570
354         (
355                 json_init
356                 json_add_int action 6
357                 json_add_string host "$host"
358                 [ -n "$ifname" ] && json_add_string ifname "$ifname"
359                 _proto_notify "$interface" -S
360         )
361 }
362
363 proto_setup_failed() {
364         local interface="$1"
365         json_init
366         json_add_int action 7
367         _proto_notify "$interface"
368 }
369
370 init_proto() {
371         proto="$1"; shift
372         cmd="$1"; shift
373
374         case "$cmd" in
375                 dump)
376                         add_protocol() {
377                                 no_device=0
378                                 no_proto_task=0
379                                 available=0
380                                 renew_handler=0
381                                 teardown_on_l3_link_down=0
382
383                                 add_default_handler "proto_$1_init_config"
384
385                                 json_init
386                                 json_add_string "name" "$1"
387                                 json_add_array "config"
388                                 eval "proto_$1_init_config"
389                                 json_close_array
390                                 json_add_boolean no-device "$no_device"
391                                 json_add_boolean no-proto-task "$no_proto_task"
392                                 json_add_boolean available "$available"
393                                 json_add_boolean renew-handler "$renew_handler"
394                                 json_add_boolean lasterror "$lasterror"
395                                 json_add_boolean teardown-on-l3-link-down "$teardown_on_l3_link_down"
396                                 json_dump
397                         }
398                 ;;
399                 setup|teardown|renew)
400                         interface="$1"; shift
401                         data="$1"; shift
402                         ifname="$1"; shift
403
404                         add_protocol() {
405                                 [[ "$proto" == "$1" ]] || return 0
406
407                                 case "$cmd" in
408                                         setup) _proto_do_setup "$1";;
409                                         teardown) _proto_do_teardown "$1" ;;
410                                         renew) _proto_do_renew "$1" ;;
411                                         *) return 1 ;;
412                                 esac
413                         }
414                 ;;
415         esac
416 }