fixes OLSR 6and4 mode does not work if HNA entries are configured, closes #4803
[packages.git] / net / olsrd / files / olsrd.init
1 #!/bin/sh /etc/rc.common
2 # Copyright (C) 2008  Alina Friedrichsen <x-alina@gmx.net>
3 # Special thanks to bittorf wireless ))
4 START=65
5
6 OLSRD_OLSRD_SCHEMA='ignore:internal config_file:internal DebugLevel=0 IpVersion=4 AllowNoInt:bool=1 Pollrate=0.025 TcRedundancy=2 MprCoverage=3 LinkQualityFishEye=1 LinkQualityWinSize=100 LinkQualityDijkstraLimit=0+9.0 LinkQualityLevel=2 UseHysteresis:bool=0 FIBMetric=flat ClearScreen:bool=1 Willingness=3 LinkQualityAging=0.1 LinkQualityAlgorithm=etx_fpm'
7 OLSRD_IPCCONNECT_SCHEMA='ignore:internal Host:list Net:list2'
8 OLSRD_LOADPLUGIN_SCHEMA='ignore:internal library:internal Host4:list Net4:list2 Host:list Net:list2 Host6:list Net6:list2 Ping:list redistribute:list NonOlsrIf:list name:list lat lon latlon_infile HNA:list2 hosts:list2'
9 OLSRD_INTERFACE_SCHEMA='ignore:internal interface:internal AutoDetectChanges:bool Ip4Broadcast=255.255.255.255 HelloInterval=2.0 HelloValidityTime=40.0 TcInterval=5.0 TcValidityTime=100.0 MidInterval=18.0 MidValidityTime=324.0 HnaInterval=18.0 HnaValidityTime=108.0'
10
11 T='     '
12 N='
13 '
14
15 validate_varname() {
16         local varname="$1"
17         [ -z "$varname" -o "$varname" != "${varname%%[!A-Za-z0-9_]*}" ] && return 1
18         return 0
19 }
20
21 validate_ifname() {
22         local ifname="$1"
23         [ -z "$ifname" -o "$ifname" != "${ifname%%[!A-Za-z0-9.:_-]*}" ] && return 1
24         return 0
25 }
26
27 validate_olsrd_option() {
28         local str="$1"
29         [ -z "$str" -o "$str" != "${str%%[!     0-9A-Za-z./|:_-]*}" ] && return 1
30         return 0
31 }
32
33 get_ifname() {
34         IFNAME=
35         local interface="$1"
36         validate_varname "$interface" || return 1
37         local ifname
38
39         config_get ifname "$interface" ifname
40         validate_ifname "$ifname" || return 1
41         IFNAME="$ifname"
42
43         return 0
44 }
45
46 system_config() {
47         local cfg="$1"
48         local cfgt
49         local hostname
50         local latlon
51
52         config_get cfgt "$cfg" TYPE
53
54         if [ "$cfgt" = "system" ]; then
55                 config_get hostname "$cfg" hostname
56                 hostname="${hostname:-OpenWrt}"
57                 SYSTEM_HOSTNAME="$hostname"
58         fi
59
60         if [ -z "$SYSTEM_LAT" -o -z "$SYSTEM_LON" ]; then
61                 config_get latlon "$cfg" latlon
62                 IFS=" ${T}${N},"
63                 set -- $latlon
64                 unset IFS
65                 SYSTEM_LAT="$1"
66                 SYSTEM_LON="$2"
67         fi
68
69         if [ -z "$SYSTEM_LAT" -o -z "$SYSTEM_LON" ]; then
70                 config_get latlon "$cfg" latitude
71                 SYSTEM_LAT="$latlon"
72                 config_get latlon "$cfg" longitude
73                 SYSTEM_LON="$latlon"
74         fi
75 }
76
77 olsrd_find_config_file() {
78         local cfg="$1"
79         validate_varname "$cfg" || return 0
80
81         config_get_bool ignore "$cfg" ignore 0
82         [ "$ignore" -ne 0 ] && return 0
83         config_get OLSRD_CONFIG_FILE "$cfg" config_file
84
85         return 0
86 }
87
88 warning_invalid_value() {
89         local package="$1"
90         validate_varname "$package" || package=
91         local config="$2"
92         validate_varname "$config" || config=
93         local option="$3"
94         validate_varname "$option" || option=
95
96         echo -n "Warning: Invalid value" 1>&2
97
98         if [ -n "$package" -a -n "$config" ]; then
99                 echo -n " in option '$package.$config${option:+.}$option'" 1>&2
100         fi
101
102         echo ", skipped" 1>&2
103
104         return 0
105 }
106
107 olsrd_write_option() {
108         local param="$1"
109         local cfg="$2"
110         validate_varname "$cfg" || return 1
111         local option="$3"
112         validate_varname "$option" || return 1
113         local value="$4"
114         local option_type="$5"
115
116         if [ "$option_type" = bool ]; then
117                 case "$value" in
118                         1|on|true|enabled|yes) value=yes;;
119                         0|off|false|disabled|no) value=no;;
120                         *) warning_invalid_value olsrd "$cfg" "$option"; return 1;;
121                 esac
122         fi
123
124         if ! validate_olsrd_option "$value"; then
125                 warning_invalid_value olsrd "$cfg" "$option"
126                 return 1
127         fi
128
129         if [ "$value" != "${value%%[G-Zg-z_-]*}" ]; then
130                 if [ "$option" != "Ip6AddrType" -a "$value" != "yes" -a "$value" != "no" ]; then
131                         value="\"$value\""
132                 fi
133         fi
134
135         echo -n "${N}$param$option $value"
136
137         return 0
138 }
139
140 olsrd_write_plparam() {
141         local param="$1"
142         local cfg="$2"
143         validate_varname "$cfg" || return 1
144         local option="$3"
145         validate_varname "$option" || return 1
146         local value="$4"
147         local option_type="$5"
148         local _option
149
150         if [ "$option_type" = bool ]; then
151                 case "$value" in
152                         1|on|true|enabled|yes) value=yes;;
153                         0|off|false|disabled|no) value=no;;
154                         *) warning_invalid_value olsrd "$cfg" "$option"; return 1;;
155                 esac
156         fi
157
158         if ! validate_olsrd_option "$value"; then
159                 warning_invalid_value olsrd "$cfg" "$option"
160                 return 1
161         fi
162
163         IFS='-_'
164         set -- $option
165         option="$*"
166         unset IFS
167         _option="$option"
168         if [ "$option" = 'hosts' ]; then
169                 set -- $value
170                 option="$1"
171                 shift
172                 value="$*"
173         fi
174
175         echo -n "${N}${param}PlParam \"$option\" \"$value\""
176
177         return 0
178 }
179
180 config_update_schema() {
181         unset IFS
182         local schema_varname="$1"
183         validate_varname "$schema_varname" || return 1
184         local command="$2"
185         validate_varname "$command" || return 1
186         local option="$3"
187         validate_varname "$option" || return 1
188         local value="$4"
189         local schema
190         local cur_option
191
192         case "$varname" in
193                 *_LENGTH) return 0;;
194                 *_ITEM*) return 0;;
195         esac
196
197         eval "export -n -- \"schema=\${$schema_varname}\""
198
199         for cur_option in $schema; do
200                 [ "${cur_option%%[:=]*}" = "$option" ] && return 0
201         done
202
203         if [ "$command" = list ]; then
204                 set -- $value
205                 if [ "$#" -ge "3" ]; then
206                         schema_entry="$option:list3"
207                 elif [ "$#" -ge "2" ]; then
208                         schema_entry="$option:list2"
209                 else
210                         schema_entry="$option:list"
211                 fi
212         else
213                 schema_entry="$option"
214         fi
215
216         append "$schema_varname" "$schema_entry"
217
218         return 0
219 }
220
221 config_write_options() {
222         unset IFS
223         local schema="$1"
224         local cfg="$2"
225         validate_varname "$cfg" || return 1
226         local write_func="$3"
227         [ -z "$write_func" ] && output_func=echo
228         local write_param="$4"
229         local schema_entry
230         local option
231         local option_length
232         local option_type
233         local default
234         local value
235         local list_size
236         local list_item
237         local list_value
238         local i
239         local position
240
241         for schema_entry in $schema; do
242                 default="${schema_entry#*[=]}"
243                 [ "$default" = "$schema_entry" ] && default=
244                 option="${schema_entry%%[=]*}"
245                 IFS=':'
246                 set -- $option
247                 unset IFS
248                 option="$1"
249                 option_type="$2"
250                 validate_varname "$option" || continue
251                 [ -z "$option_type" ] || validate_varname "$option_type" || continue
252                 [ "$option_type" = internal ] && continue
253                 config_get value "$cfg" "$option"
254
255                 if [ -z "$value" ]; then
256                         IFS='+'
257                         set -- $default
258                         unset IFS
259                         value=$*
260                 elif [ "$value" = '-' -a -n "$default" ]; then
261                         continue
262                 fi
263
264                 [ -z "$value" ] && continue
265
266                 case "$option_type" in
267                         list) list_size=1;;
268                         list2) list_size=2;;
269                         list3) list_size=3;;
270                         *) list_size=0;;
271                 esac
272
273                 if [ "$list_size" -gt 0 ]; then
274                         config_get option_length "$cfg" "${option}_LENGTH"
275                         if [ -n "$option_length" ]; then
276                                 i=1
277                                 while [ "$i" -le "$option_length" ]; do
278                                         config_get list_value "$cfg" "${option}_ITEM$i"
279                                         "$write_func" "$write_param" "$cfg" "$option" "$list_value" "$option_type" || break
280                                         i=$((i + 1))
281                                 done
282                         else
283                                 list_value=
284                                 i=0
285                                 for list_item in $value; do
286                                         append "list_value" "$list_item"
287                                         i=$((i + 1))
288                                         position=$((i % list_size))
289                                         if [ "$position" -eq 0 ]; then
290                                                 "$write_func" "$write_param" "$cfg" "$option" "$list_value" "$option_type" || break
291                                                 list_value=
292                                         fi
293                                 done
294                                 [ "$position" -ne 0 ] && "$write_func" "$write_param" "$cfg" "$option" "$list_value" "$option_type"
295                         fi
296                 else
297                         "$write_func" "$write_param" "$cfg" "$option" "$value" "$option_type"
298                 fi
299         done
300
301         return 0
302 }
303
304 olsrd_write_olsrd() {
305         local cfg="$1"
306         validate_varname "$cfg" || return 0
307         local ignore
308         local ipversion
309
310         config_get_bool ignore "$cfg" ignore 0
311         [ "$ignore" -ne 0 ] && return 0
312
313         [ "$OLSRD_COUNT" -gt 0 ] && return 0
314
315         config_get ipversion "$cfg" IpVersion
316         if [ "$ipversion" = "6and4" ]; then
317                 OLSRD_IPVERSION_6AND4=1
318                 config_set "$cfg" IpVersion '6'
319         fi
320
321         config_write_options "$OLSRD_OLSRD_SCHEMA" "$cfg" olsrd_write_option
322         echo
323         OLSRD_COUNT=$((OLSRD_COUNT + 1))
324
325         return 0
326 }
327
328 olsrd_write_ipcconnect() {
329         local cfg="$1"
330         validate_varname "$cfg" || return 0
331         local ignore
332
333         config_get_bool ignore "$cfg" ignore 0
334         [ "$ignore" -ne 0 ] && return 0
335
336         [ "$IPCCONNECT_COUNT" -gt 0 ] && return 0
337
338         echo -n "${N}IpcConnect${N}{"
339         config_write_options "$OLSRD_IPCCONNECT_SCHEMA" "$cfg" olsrd_write_option "${T}"
340         echo "${N}}"
341         IPCCONNECT_COUNT=$((IPCCONNECT_COUNT + 1))
342
343         return 0
344 }
345
346 olsrd_write_hna4() {
347         local cfg="$1"
348         validate_varname "$cfg" || return 0
349         local ignore
350
351         config_get_bool ignore "$cfg" ignore 0
352         [ "$ignore" -ne 0 ] && return 0
353
354         config_get netaddr "$cfg" netaddr
355         if ! validate_olsrd_option "$netaddr"; then
356                 warning_invalid_value olsrd "$cfg" "netaddr"
357                 return 0
358         fi
359
360         config_get netmask "$cfg" netmask
361         if ! validate_olsrd_option "$netmask"; then
362                 warning_invalid_value olsrd "$cfg" "netmask"
363                 return 0
364         fi
365
366         [ "$HNA4_COUNT" -le 0 ] && echo -n "${N}Hna4${N}{"
367         echo -n "${N}${T}${T}$netaddr $netmask"
368         HNA4_COUNT=$((HNA4_COUNT + 1))
369
370         return 0
371 }
372
373 olsrd_write_hna6() {
374         local cfg="$1"
375         validate_varname "$cfg" || return 0
376         local ignore
377
378         config_get_bool ignore "$cfg" ignore 0
379         [ "$ignore" -ne 0 ] && return 0
380
381         config_get netaddr "$cfg" netaddr
382         if ! validate_olsrd_option "$netaddr"; then
383                 warning_invalid_value olsrd "$cfg" "netaddr"
384                 return 0
385         fi
386
387         config_get prefix "$cfg" prefix
388         if ! validate_olsrd_option "$prefix"; then
389                 warning_invalid_value olsrd "$cfg" "prefix"
390                 return 0
391         fi
392
393         [ "$HNA6_COUNT" -le 0 ] && echo -n "${N}Hna6${N}{"
394         echo -n "${N}${T}${T}$netaddr $prefix"
395         HNA6_COUNT=$((HNA6_COUNT + 1))
396
397         return 0
398 }
399
400 olsrd_write_loadplugin() {
401         local cfg="$1"
402         validate_varname "$cfg" || return 0
403         local ignore
404         local name
405         local suffix
406         local lat
407         local lon
408         local latlon_infile
409
410         config_get_bool ignore "$cfg" ignore 0
411         [ "$ignore" -ne 0 ] && return 0
412
413         config_get library "$cfg" library
414         if ! validate_olsrd_option "$library"; then
415                 warning_invalid_value olsrd "$cfg" "library"
416                 return 0
417         fi
418         if ! [ -x "/lib/$library" -o -x "/usr/lib/$library" -o -x "/usr/local/lib/$library" ]; then
419                 echo "Warning: Plugin library '$library' not found, skipped" 1>&2
420                 return 0
421         fi
422
423         case "$library" in
424                 olsrd_nameservice.*)
425                         config_get name "$cfg" name
426                         [ -z "$name" ] && config_set "$cfg" name $SYSTEM_HOSTNAME
427
428                         config_get suffix "$cfg" suffix
429                         [ -z "$suffix" ] && config_set "$cfg" suffix '.olsr'
430
431                         config_get lat "$cfg" lat
432                         config_get lon "$cfg" lon
433                         config_get latlon_infile "$cfg" latlon_infile
434                         if [ \( -z "$lat" -o -z "$lat" \) -a -z "$latlon_infile" ]; then
435                                 if [ -f '/var/run/latlon.txt' ]; then
436                                         config_set "$cfg" lat ''
437                                         config_set "$cfg" lon ''
438                                         config_set "$cfg" latlon_infile '/var/run/latlon.txt'
439                                 else
440                                         config_set "$cfg" lat "$SYSTEM_LAT"
441                                         config_set "$cfg" lon "$SYSTEM_LON"
442                                 fi
443                         fi
444
445                         config_get latlon_file "$cfg" latlon_file
446                         [ -z "$latlon_file" ] && config_set "$cfg" latlon_file '/var/run/latlon.js'
447                 ;;
448         esac
449
450         echo -n "${N}LoadPlugin \"$library\"${N}{"
451         config_write_options "$OLSRD_LOADPLUGIN_SCHEMA" "$cfg" olsrd_write_plparam "${T}"
452         echo "${N}}"
453
454         return 0
455 }
456
457 olsrd_write_interface() {
458         local cfg="$1"
459         validate_varname "$cfg" || return 0
460         local ignore
461         local interfaces
462         local interface
463         local ifnames
464
465         config_get_bool ignore "$cfg" ignore 0
466         [ "$ignore" -ne 0 ] && return 0
467
468         ifnames=
469         config_get interfaces "$cfg" interface
470         for interface in $interfaces; do
471                 if validate_varname "$interface"; then
472                         if get_ifname "$interface"; then
473                                 ifnames="$ifnames \"$IFNAME\""
474                         else
475                                 echo "Warning: Interface '$interface' not found, skipped" 1>&2
476                         fi
477                 else
478                         warning_invalid_value olsrd "$cfg" "interface"
479                 fi
480         done
481
482         [ -z "$ifnames" ] && return 0
483
484         echo -n "${N}Interface$ifnames${N}{"
485         config_write_options "$OLSRD_INTERFACE_SCHEMA" "$cfg" olsrd_write_option "${T}"
486         echo "${N}}"
487         INTERFACES_COUNT=$((INTERFACES_COUNT + 1))
488
489         return 0
490 }
491
492 olsrd_update_schema() {
493         local command="$1"
494         validate_varname "$command" || return 0
495         local varname="$2"
496         validate_varname "$varname" || return 0
497         local value="$3"
498         local cfg="$CONFIG_SECTION"
499         local cfgt
500         local cur_varname
501
502         config_get cfgt "$cfg" TYPE
503         case "$cfgt" in
504                 olsrd) config_update_schema OLSRD_OLSRD_SCHEMA "$command" "$varname" "$value";;
505                 IpcConnect) config_update_schema OLSRD_IPCCONNECT_SCHEMA "$command" "$varname" "$value";;
506                 LoadPlugin) config_update_schema OLSRD_LOADPLUGIN_SCHEMA "$command" "$varname" "$value";;
507                 Interface) config_update_schema OLSRD_INTERFACE_SCHEMA "$command" "$varname" "$value";;
508         esac
509
510         return 0
511 }
512
513 olsrd_write_config() {
514         OLSRD_IPVERSION_6AND4=0
515         OLSRD_COUNT=0
516         config_foreach olsrd_write_olsrd olsrd
517         IPCCONNECT_COUNT=0
518         config_foreach olsrd_write_ipcconnect IpcConnect
519         HNA4_COUNT=0
520         config_foreach olsrd_write_hna4 Hna4
521         [ "$HNA4_COUNT" -gt 0 ] && echo "${N}}"
522         HNA6_COUNT=0
523         config_foreach olsrd_write_hna6 Hna6
524         [ "$HNA6_COUNT" -gt 0 ] && echo "${N}}"
525         config_foreach olsrd_write_loadplugin LoadPlugin
526         INTERFACES_COUNT=0
527         config_foreach olsrd_write_interface Interface
528         echo
529
530         return 0
531 }
532
533 start() {
534         SYSTEM_HOSTNAME=
535         SYSTEM_LAT=
536         SYSTEM_LON=
537         config_load system
538         config_foreach system_config system
539
540         option_cb() {
541                 olsrd_update_schema "option" "$@"
542         }
543
544         list_cb() {
545                 olsrd_update_schema "list" "$@"
546         }
547
548         include /lib/network
549         scan_interfaces
550         config_load olsrd
551         reset_cb
552
553         OLSRD_CONFIG_FILE=
554         config_foreach olsrd_find_config_file olsrd
555
556         if [ -z "$OLSRD_CONFIG_FILE" ]; then
557                 mkdir -p -- /var/etc/
558                 olsrd_write_config > /var/etc/olsrd.conf
559                 if [ "$INTERFACES_COUNT" -gt 0 -a "$OLSRD_COUNT" -gt 0 ]; then
560                         OLSRD_CONFIG_FILE=/var/etc/olsrd.conf
561                 fi
562         fi
563
564         [ -z "$OLSRD_CONFIG_FILE" ] && return 1
565
566         local bindv6only='0'
567         if [ "$OLSRD_IPVERSION_6AND4" -ne 0 ]; then
568                 bindv6only="$(sysctl -n net.ipv6.bindv6only)"
569                 sysctl -w net.ipv6.bindv6only=1
570                 sed -e 's/^\t\t[0-9.]*[ ][0-9.]*$//' < "$OLSRD_CONFIG_FILE" > /var/etc/olsrd.conf.ipv6
571                 olsrd -f /var/etc/olsrd.conf.ipv6 -nofork < /dev/null > /dev/null &
572
573                 sed -e 's/^IpVersion[ ][ ]*6$/IpVersion 4/' -e 's/^\t\t[A-Fa-f0-9.:]*[:][A-Fa-f0-9.:]*[ ][0-9]*$//' < "$OLSRD_CONFIG_FILE" > /var/etc/olsrd.conf.ipv4
574                 olsrd -f /var/etc/olsrd.conf.ipv4 -nofork < /dev/null > /dev/null &
575                 sleep 3
576                 sysctl -w net.ipv6.bindv6only="$bindv6only"
577         else
578                 olsrd -f "$OLSRD_CONFIG_FILE" -nofork < /dev/null > /dev/null &
579         fi
580 }
581
582 stop() {
583         killall olsrd
584 }