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