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