1 #!/bin/sh 2 # 3 # CDDL HEADER START 4 # 5 # The contents of this file are subject to the terms of the 6 # Common Development and Distribution License (the "License"). 7 # You may not use this file except in compliance with the License. 8 # 9 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 # or http://www.opensolaris.org/os/licensing. 11 # See the License for the specific language governing permissions 12 # and limitations under the License. 13 # 14 # When distributing Covered Code, include this CDDL HEADER in each 15 # file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 # If applicable, add the following below this CDDL HEADER, with the 17 # fields enclosed by brackets "[]" replaced with your own identifying 18 # information: Portions Copyright [yyyy] [name of copyright owner] 19 # 20 # CDDL HEADER END 21 # 22 # 23 # Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. 24 # 25 # Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T. 26 # All rights reserved. 27 # 28 29 NET_INADDR_ANY="0.0.0.0" 30 NET_IN6ADDR_ANY_INIT="::0" 31 32 # Print warnings to console 33 warn_failed_ifs() { 34 echo "Failed to $1 interface(s):$2" >/dev/msglog 35 } 36 37 # 38 # shcat file 39 # Simulates cat in sh so it doesn't need to be on the root filesystem. 40 # 41 shcat() { 42 while [ $# -ge 1 ]; do 43 while read i; do 44 echo "$i" 45 done < $1 46 shift 47 done 48 } 49 50 net_record_err() 51 { 52 message=$1 53 err=$2 54 55 echo "$message" | smf_console 56 if [ $err -ne 0 ]; then 57 echo "Error code = $err" | smf_console 58 fi 59 } 60 61 # 62 # inet_list list of IPv4 interfaces. 63 # inet6_list list of IPv6 interfaces. 64 # ipmp_list list of IPMP IPv4 interfaces. 65 # ipmp6_list list of IPMP IPv6 interfaces. 66 # inet_plumbed list of plumbed IPv4 interfaces. 67 # inet6_plumbed list of plumbed IPv6 interfaces. 68 # ipmp_created list of created IPMP IPv4 interfaces. 69 # ipmp6_created list of created IPMP IPv6 interfaces. 70 # inet_failed list of IPv4 interfaces that failed to plumb. 71 # inet6_failed list of IPv6 interfaces that failed to plumb. 72 # ipmp_failed list of IPMP IPv4 interfaces that failed to be created. 73 # ipmp6_failed list of IPMP IPv6 interfaces that failed to be created. 74 # 75 unset inet_list inet_plumbed inet_failed \ 76 inet6_list inet6_plumbed inet6_failed \ 77 ipmp_list ipmp_created ipmp_failed \ 78 ipmp6_list ipmp6_created ipmp6_failed 79 80 # 81 # get_physical interface 82 # 83 # Return physical interface corresponding to the given interface. 84 # 85 get_physical() 86 { 87 ORIGIFS="$IFS" 88 IFS="${IFS}:" 89 set -- $1 90 IFS="$ORIGIFS" 91 92 echo $1 93 } 94 95 # 96 # get_logical interface 97 # 98 # Return logical interface number. Zero will be returned 99 # if there is no explicit logical number. 100 # 101 get_logical() 102 { 103 ORIGIFS="$IFS" 104 IFS="${IFS}:" 105 set -- $1 106 IFS="$ORIGIFS" 107 108 if [ -z "$2" ]; then 109 echo 0 110 else 111 echo $2 112 fi 113 } 114 115 # 116 # if_comp if1 if2 117 # 118 # Compare interfaces. Do the physical interface names and logical interface 119 # numbers match? 120 # 121 if_comp() 122 { 123 physical_comp $1 $2 && [ `get_logical $1` -eq `get_logical $2` ] 124 } 125 126 # 127 # physical_comp if1 if2 128 # 129 # Do the two interfaces share a physical interface? 130 # 131 physical_comp() 132 { 133 [ "`get_physical $1`" = "`get_physical $2`" ] 134 } 135 136 # 137 # in_list op item list 138 # 139 # Is "item" in the given list? Use "op" to do the test, applying it to 140 # "item" and each member of the list in turn until it returns success. 141 # 142 in_list() 143 { 144 op=$1 145 item=$2 146 shift 2 147 148 while [ $# -gt 0 ]; do 149 $op $item $1 && return 0 150 shift 151 done 152 153 return 1 154 } 155 156 # 157 # get_groupifname groupname 158 # 159 # Return the IPMP meta-interface name for the group, if it exists. 160 # 161 get_groupifname() 162 { 163 /sbin/ipmpstat -gP -o groupname,group | while IFS=: read name ifname; do 164 if [ "$name" = "$1" ]; then 165 echo "$ifname" 166 return 167 fi 168 done 169 } 170 171 # 172 # create_ipmp ifname groupname type 173 # 174 # Helper function for create_groupifname() that returns zero if it's able 175 # to create an IPMP interface of the specified type and place it in the 176 # specified group, or non-zero otherwise. 177 # 178 create_ipmp() 179 { 180 /sbin/ifconfig $1 >/dev/null 2>&1 && return 1 181 /sbin/ifconfig $1 inet6 >/dev/null 2>&1 && return 1 182 /sbin/ifconfig $1 $3 ipmp group $2 2>/dev/null 183 } 184 185 # 186 # create_groupifname groupname type 187 # 188 # Create an IPMP meta-interface name for the group. We only use this 189 # function if all of the interfaces in the group failed at boot and there 190 # were no /etc/hostname[6].<if> files for the IPMP meta-interface. 191 # 192 create_groupifname() 193 { 194 # 195 # This is a horrible way to count from 0 to 999, but in sh and 196 # without necessarily having /usr mounted, what else can we do? 197 # 198 for a in "" 1 2 3 4 5 6 7 8 9; do 199 for b in 0 1 2 3 4 5 6 7 8 9; do 200 for c in 0 1 2 3 4 5 6 7 8 9; do 201 # strip leading zeroes 202 [ "$a" = "" ] && [ "$b" = 0 ] && b="" 203 if create_ipmp ipmp$a$b$c $1 $2; then 204 echo ipmp$a$b$c 205 return 206 fi 207 done 208 done 209 done 210 } 211 212 # 213 # get_hostname_ipmpinfo interface type 214 # 215 # Return all requested IPMP keywords from hostname file for a given interface. 216 # 217 # Example: 218 # get_hostname_ipmpinfo hme0 inet keyword [ keyword ... ] 219 # 220 get_hostname_ipmpinfo() 221 { 222 case "$2" in 223 inet) file=/etc/hostname.$1 224 ;; 225 inet6) file=/etc/hostname6.$1 226 ;; 227 *) 228 return 229 ;; 230 esac 231 232 [ -r "$file" ] || return 233 234 type=$2 235 shift 2 236 237 # 238 # Read through the hostname file looking for the specified 239 # keywords. Since there may be several keywords that cancel 240 # each other out, the caller must post-process as appropriate. 241 # 242 while read line; do 243 [ -z "$line" ] && continue 244 /sbin/ifparse -s "$type" $line 245 done < "$file" | while read one two; do 246 for keyword in "$@"; do 247 [ "$one" = "$keyword" ] && echo "$one $two" 248 done 249 done 250 } 251 252 # 253 # get_group_for_type interface type list 254 # 255 # Look through the set of hostname files associated with the same physical 256 # interface as "interface", and determine which group they would configure. 257 # Only hostname files associated with the physical interface or logical 258 # interface zero are allowed to set the group. 259 # 260 get_group_for_type() 261 { 262 physical=`get_physical $1` 263 type=$2 264 group="" 265 266 # 267 # The last setting of the group is the one that counts, which is 268 # the reason for the second while loop. 269 # 270 shift 2 271 for ifname in "$@"; do 272 if if_comp "$physical" $ifname; then 273 get_hostname_ipmpinfo $ifname $type group 274 fi 275 done | while :; do 276 read keyword grname || { 277 echo "$group" 278 break 279 } 280 group="$grname" 281 done 282 } 283 284 # 285 # get_group interface 286 # 287 # If there is both an inet and inet6 version of an interface, the group 288 # could be set in either set of hostname files. Since inet6 is configured 289 # after inet, if there's a setting in both files, inet6 wins. 290 # 291 get_group() 292 { 293 group=`get_group_for_type $1 inet6 $inet6_list` 294 [ -z "$group" ] && group=`get_group_for_type $1 inet $inet_list` 295 echo $group 296 } 297 298 # 299 # Given the interface name and the address family (inet or inet6), determine 300 # whether this is a VRRP VNIC. 301 # 302 # This is used to determine whether to bring the interface up 303 # 304 not_vrrp_interface() { 305 macaddrtype=`/sbin/dladm show-vnic $1 -o MACADDRTYPE -p 2>/dev/null` 306 307 case "$macaddrtype" in 308 'vrrp'*''$2'') vrrp=1 309 ;; 310 *) vrrp=0 311 ;; 312 esac 313 return $vrrp 314 } 315 316 # doDHCPhostname interface 317 # Pass to this function the name of an interface. It will return 318 # true if one should enable the use of DHCP client-side host name 319 # requests on the interface, and false otherwise. 320 # 321 doDHCPhostname() 322 { 323 if [ -f /etc/dhcp.$1 ] && [ -f /etc/hostname.$1 ]; then 324 set -- `shcat /etc/hostname.$1` 325 [ $# -eq 2 -a "$1" = "inet" ] 326 return $? 327 fi 328 return 1 329 } 330 331 # 332 # inet_process_hostname processor [ args ] 333 # 334 # Process an inet hostname file. The contents of the file 335 # are taken from standard input. Each line is passed 336 # on the command line to the "processor" command. 337 # Command line arguments can be passed to the processor. 338 # 339 # Examples: 340 # inet_process_hostname /sbin/ifconfig hme0 < /etc/hostname.hme0 341 # 342 # inet_process_hostname /sbin/ifparse -f < /etc/hostname.hme0 343 # 344 # If there is only line in an hostname file we assume it contains 345 # the old style address which results in the interface being brought up 346 # and the netmask and broadcast address being set ($inet_oneline_epilogue). 347 # 348 # Note that if the interface is a VRRP interface, do not bring the address 349 # up ($inet_oneline_epilogue_no_up). 350 # 351 # If there are multiple lines we assume the file contains a list of 352 # commands to the processor with neither the implied bringing up of the 353 # interface nor the setting of the default netmask and broadcast address. 354 # 355 # Return non-zero if any command fails so that the caller may alert 356 # users to errors in the configuration. 357 # 358 inet_oneline_epilogue_no_up="netmask + broadcast +" 359 inet_oneline_epilogue="netmask + broadcast + up" 360 361 inet_process_hostname() 362 { 363 if doDHCPhostname $2; then 364 : 365 else 366 # 367 # Redirecting input from a file results in a sub-shell being 368 # used, hence this outer loop surrounding the "multiple_lines" 369 # and "ifcmds" variables. 370 # 371 while :; do 372 multiple_lines=false 373 ifcmds="" 374 retval=0 375 376 while read one rest; do 377 if [ -n "$ifcmds" ]; then 378 # 379 # This handles the first N-1 380 # lines of a N-line hostname file. 381 # 382 $* $ifcmds || retval=$? 383 multiple_lines=true 384 fi 385 386 # 387 # Strip out the "ipmp" keyword if it's the 388 # first token, since it's used to control 389 # interface creation, not configuration. 390 # 391 [ "$one" = ipmp ] && one= 392 ifcmds="$one $rest" 393 done 394 395 # 396 # If the hostname file is empty or consists of only 397 # blank lines, break out of the outer loop without 398 # configuring the newly plumbed interface. 399 # 400 [ -z "$ifcmds" ] && return $retval 401 if [ $multiple_lines = false ]; then 402 # 403 # The traditional one-line hostname file. 404 # Note that we only bring it up if the 405 # interface is not a VRRP VNIC. 406 # 407 if not_vrrp_interface $2 $3; then 408 estr="$inet_oneline_epilogue" 409 else 410 estr="$inet_oneline_epilogue_no_up" 411 fi 412 ifcmds="$ifcmds $estr" 413 fi 414 415 # 416 # This handles either the single-line case or 417 # the last line of the N-line case. 418 # 419 $* $ifcmds || return $? 420 return $retval 421 done 422 fi 423 } 424 425 # 426 # inet6_process_hostname processor [ args ] 427 # 428 # Process an inet6 hostname file. The contents of the file 429 # are taken from standard input. Each line is passed 430 # on the command line to the "processor" command. 431 # Command line arguments can be passed to the processor. 432 # 433 # Examples: 434 # inet6_process_hostname /sbin/ifconfig hme0 inet6 < /etc/hostname6.hme0 435 # 436 # inet6_process_hostname /sbin/ifparse -f inet6 < /etc/hostname6.hme0 437 # 438 # Return non-zero if any of the commands fail so that the caller may alert 439 # users to errors in the configuration. 440 # 441 inet6_process_hostname() 442 { 443 retval=0 444 while read one rest; do 445 # 446 # See comment in inet_process_hostname for details. 447 # 448 [ "$one" = ipmp ] && one= 449 ifcmds="$one $rest" 450 451 if [ -n "$ifcmds" ]; then 452 $* $ifcmds || retval=$? 453 fi 454 done 455 return $retval 456 } 457 458 # 459 # Process interfaces that failed to plumb. Find the IPMP meta-interface 460 # that should host the addresses. For IPv6, only static addresses defined 461 # in hostname6 files are moved, autoconfigured addresses are not moved. 462 # 463 # Example: 464 # move_addresses inet6 465 # 466 move_addresses() 467 { 468 type="$1" 469 eval "failed=\"\$${type}_failed\"" 470 eval "list=\"\$${type}_list\"" 471 process_func="${type}_process_hostname" 472 processed="" 473 474 if [ "$type" = inet ]; then 475 typedesc="IPv4" 476 zaddr="0.0.0.0" 477 hostpfx="/etc/hostname" 478 else 479 typedesc="IPv6" 480 zaddr="::" 481 hostpfx="/etc/hostname6" 482 fi 483 484 echo "Moving addresses from missing ${typedesc} interface(s):\c" \ 485 >/dev/msglog 486 487 for ifname in $failed; do 488 in_list if_comp $ifname $processed && continue 489 490 group=`get_group $ifname` 491 if [ -z "$group" ]; then 492 in_list physical_comp $ifname $processed || { 493 echo " $ifname (not moved -- not" \ 494 "in an IPMP group)\c" >/dev/msglog 495 processed="$processed $ifname" 496 } 497 continue 498 fi 499 500 # 501 # Lookup the IPMP meta-interface name. If one doesn't exist, 502 # create it. 503 # 504 grifname=`get_groupifname $group` 505 [ -z "$grifname" ] && grifname=`create_groupifname $group $type` 506 507 # 508 # The hostname files are processed twice. In the first 509 # pass, we are looking for all commands that apply to the 510 # non-additional interface address. These may be 511 # scattered over several files. We won't know whether the 512 # address represents a failover address or not until we've 513 # read all the files associated with the interface. 514 # 515 # In the first pass through the hostname files, all 516 # additional logical interface commands are removed. The 517 # remaining commands are concatenated together and passed 518 # to ifparse to determine whether the non-additional 519 # logical interface address is a failover address. If it 520 # as a failover address, the address may not be the first 521 # item on the line, so we can't just substitute "addif" 522 # for "set". We prepend an "addif $zaddr" command, and 523 # let the embedded "set" command set the address later. 524 # 525 /sbin/ifparse -f $type ` 526 for item in $list; do 527 if_comp $ifname $item && $process_func \ 528 /sbin/ifparse $type < $hostpfx.$item 529 done | while read three four; do 530 [ "$three" != addif ] && echo "$three $four \c" 531 done` | while read one two; do 532 [ -z "$one" ] && continue 533 [ "$one $two" = "$inet_oneline_epilogue" ] && \ 534 continue 535 line="addif $zaddr $one $two" 536 /sbin/ifconfig $grifname $type $line >/dev/null 537 done 538 539 # 540 # In the second pass, look for the the "addif" commands 541 # that configure additional failover addresses. Addif 542 # commands are not valid in logical interface hostname 543 # files. 544 # 545 if [ "$ifname" = "`get_physical $ifname`" ]; then 546 $process_func /sbin/ifparse -f $type < $hostpfx.$ifname \ 547 | while read one two; do 548 [ "$one" = addif ] && \ 549 /sbin/ifconfig $grifname $type \ 550 addif $two >/dev/null 551 done 552 fi 553 554 in_list physical_comp $ifname $processed || { 555 processed="$processed $ifname" 556 echo " $ifname (moved to $grifname)\c" > /dev/msglog 557 } 558 done 559 echo "." >/dev/msglog 560 } 561 562 # 563 # ipadm_from_gz_if ifname 564 # 565 # Return true if we are in a non-global zone and Layer-3 protection of 566 # IP addresses is being enforced on the interface by the global zone 567 # 568 ipadm_from_gz_if() 569 { 570 pif=`/sbin/ipadm show-if -o persistent -p $1 2>/dev/null | egrep '4|6'` 571 if smf_is_globalzone || ![[ $pif == *4* || $pif == *6* ]]; then 572 return 1 573 else 574 # 575 # In the non-global zone, plumb the interface to show current 576 # flags and check if Layer-3 protection has been enforced by 577 # the global zone. Note that this function may return 578 # with a plumbed interface. Ideally, we would not have to 579 # plumb the interface to check l3protect, but since we 580 # the `allowed-ips' datalink property cannot currently be 581 # examined in any other way from the non-global zone, we 582 # resort to plumbing the interface 583 # 584 /sbin/ifconfig $1 plumb > /dev/null 2>&1 585 l3protect=`/sbin/ipadm show-if -o current -p $1|grep -c 'Z'` 586 if [ $l3protect = 0 ]; then 587 return 1 588 else 589 return 0 590 fi 591 fi 592 } 593 594 # 595 # if_configure type class interface_list 596 # 597 # Configure all of the interfaces of type `type' (e.g., "inet6") in 598 # `interface_list' according to their /etc/hostname[6].* files. `class' 599 # describes the class of interface (e.g., "IPMP"), as a diagnostic aid. 600 # For inet6 interfaces, the interface is also brought up. 601 # 602 if_configure() 603 { 604 fail= 605 type=$1 606 class=$2 607 process_func=${type}_process_hostname 608 shift 2 609 610 if [ "$type" = inet ]; then 611 desc="IPv4" 612 hostpfx="/etc/hostname" 613 else 614 desc="IPv6" 615 hostpfx="/etc/hostname6" 616 fi 617 [ -n "$class" ] && desc="$class $desc" 618 619 echo "configuring $desc interfaces:\c" 620 while [ $# -gt 0 ]; do 621 $process_func /sbin/ifconfig $1 $type < $hostpfx.$1 >/dev/null 622 if [ $? != 0 ]; then 623 ipadm_from_gz_if $1 624 if [ $? != 0 ]; then 625 fail="$fail $1" 626 fi 627 elif [ "$type" = inet6 ]; then 628 # 629 # only bring the interface up if it is not a 630 # VRRP VNIC 631 # 632 if not_vrrp_interface $1 $type; then 633 /sbin/ifconfig $1 inet6 up || fail="$fail $1" 634 fi 635 fi 636 echo " $1\c" 637 shift 638 done 639 echo "." 640 641 [ -n "$fail" ] && warn_failed_ifs "configure $desc" "$fail" 642 } 643 644 # 645 # net_reconfigure is called from the network/physical service (by the 646 # net-physical and net-nwam method scripts) to perform tasks that only 647 # need to be done during a reconfigure boot. This needs to be 648 # isolated in a function since network/physical has two instances 649 # (default and nwam) that have distinct method scripts that each need 650 # to do these things. 651 # 652 net_reconfigure () 653 { 654 # 655 # Is this a reconfigure boot? If not, then there's nothing 656 # for us to do. 657 # 658 reconfig=`svcprop -c -p system/reconfigure \ 659 system/svc/restarter:default 2>/dev/null` 660 if [ $? -ne 0 -o "$reconfig" = false ]; then 661 return 0 662 fi 663 664 # 665 # Ensure that the datalink-management service is running since 666 # manifest-import has not yet run for a first boot after 667 # upgrade. We wouldn't need to do that if manifest-import ran 668 # earlier in boot, since there is an explicit dependency 669 # between datalink-management and network/physical. 670 # 671 svcadm enable -ts network/datalink-management:default 672 673 # 674 # There is a bug in SMF which causes the svcadm command above 675 # to exit prematurely (with an error code of 3) before having 676 # waited for the service to come online after having enabled 677 # it. Until that bug is fixed, we need to have the following 678 # loop to explicitly wait for the service to come online. 679 # 680 i=0 681 while [ $i -lt 30 ]; do 682 i=`expr $i + 1` 683 sleep 1 684 state=`svcprop -p restarter/state \ 685 network/datalink-management:default 2>/dev/null` 686 if [ $? -ne 0 ]; then 687 continue 688 elif [ "$state" = "online" ]; then 689 break 690 fi 691 done 692 if [ "$state" != "online" ]; then 693 echo "The network/datalink-management service \c" 694 echo "did not come online." 695 return 1 696 fi 697 698 # 699 # Initialize the set of physical links, and validate and 700 # remove all the physical links which were removed during the 701 # system shutdown. 702 # 703 /sbin/dladm init-phys 704 return 0 705 } 706 707 # 708 # Check for use of the default "Port VLAN Identifier" (PVID) -- VLAN 1. 709 # If there is one for a given interface, then warn the user and force the 710 # PVID to zero (if it's not already set). We do this by generating a list 711 # of interfaces with VLAN 1 in use first, and then parsing out the 712 # corresponding base datalink entries to check for ones without a 713 # "default_tag" property. 714 # 715 update_pvid() 716 { 717 datalink=/etc/dladm/datalink.conf 718 719 ( 720 # Find datalinks using VLAN 1 explicitly 721 # configured by dladm 722 /usr/bin/nawk ' 723 /^#/ || NF < 2 { next } 724 { linkdata[$1]=$2; } 725 /;vid=int,1;/ { 726 sub(/.*;linkover=int,/, "", $2); 727 sub(/;.*/, "", $2); 728 link=linkdata[$2]; 729 sub(/name=string,/, "", link); 730 sub(/;.*/, "", link); 731 print link; 732 }' $datalink 733 ) | ( /usr/bin/sort -u; echo END; cat $datalink ) | /usr/bin/nawk ' 734 /^END$/ { state=1; } 735 state == 0 { usingpvid[++nusingpvid]=$1; next; } 736 /^#/ || NF < 2 { next; } 737 { 738 # If it is already present and has a tag set, 739 # then believe it. 740 if (!match($2, /;default_tag=/)) 741 next; 742 sub(/name=string,/, "", $2); 743 sub(/;.*/, "", $2); 744 for (i = 1; i <= nusingpvid; i++) { 745 if (usingpvid[i] == $2) 746 usingpvid[i]=""; 747 } 748 } 749 END { 750 for (i = 1; i <= nusingpvid; i++) { 751 if (usingpvid[i] != "") { 752 printf("Warning: default VLAN tag set to 0" \ 753 " on %s\n", usingpvid[i]); 754 cmd=sprintf("dladm set-linkprop -p " \ 755 "default_tag=0 %s\n", usingpvid[i]); 756 system(cmd); 757 } 758 } 759 }' 760 } 761 762 # 763 # service_exists fmri 764 # 765 # returns success (0) if the service exists, 1 otherwise. 766 # 767 service_exists() 768 { 769 /usr/sbin/svccfg -s $1 listpg > /dev/null 2>&1 770 if [ $? -eq 0 ]; then 771 return 0; 772 fi 773 return 1; 774 } 775 776 # 777 # service_is_enabled fmri 778 # 779 # returns success (0) if the service is enabled (permanently or 780 # temporarily), 1 otherwise. 781 # 782 service_is_enabled() 783 { 784 # 785 # The -c option must be specified to use the composed view 786 # because the general/enabled property takes immediate effect. 787 # See Example 2 in svcprop(1). 788 # 789 # Look at the general_ovr/enabled (if it is present) first to 790 # determine the temporarily enabled state. 791 # 792 tstate=`/usr/bin/svcprop -c -p general_ovr/enabled $1 2>/dev/null` 793 if [ $? -eq 0 ]; then 794 [ "$tstate" = "true" ] && return 0 795 return 1 796 fi 797 798 state=`/usr/bin/svcprop -c -p general/enabled $1 2>/dev/null` 799 [ "$state" = "true" ] && return 0 800 return 1 801 } 802 803 # 804 # is_valid_v4addr addr 805 # 806 # Returns 0 if a valid IPv4 address is given, 1 otherwise. 807 # 808 is_valid_v4addr() 809 { 810 echo $1 | /usr/xpg4/bin/awk 'NF != 1 { exit 1 } \ 811 $1 !~ /^((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}\ 812 (25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])$/ \ 813 { exit 1 }' 814 return $? 815 } 816 817 # 818 # is_valid_v6addr addr 819 # 820 # Returns 0 if a valid IPv6 address is given, 1 otherwise. 821 # 822 is_valid_v6addr() 823 { 824 echo $1 | /usr/xpg4/bin/awk 'NF != 1 { exit 1 } \ 825 # 1:2:3:4:5:6:7:8 826 $1 !~ /^([a-fA-F0-9]{1,4}:){7}[a-fA-F0-9]{1,4}$/ && 827 # 1:2:3::6:7:8 828 $1 !~ /^([a-fA-F0-9]{1,4}:){0,6}:([a-fA-F0-9]{1,4}:){0,6}\ 829 [a-fA-F0-9]{1,4}$/ && 830 # 1:2:3:: 831 $1 !~ /^([a-fA-F0-9]{1,4}:){0,7}:$/ && 832 # ::7:8 833 $1 !~ /^:(:[a-fA-F0-9]{1,4}){0,6}:[a-fA-F0-9]{1,4}$/ && 834 # ::f:1.2.3.4 835 $1 !~ /^:(:[a-fA-F0-9]{1,4}){0,5}:\ 836 ((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}\ 837 (25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])$/ && 838 # a:b:c:d:e:f:1.2.3.4 839 $1 !~ /^([a-fA-F0-9]{1,4}:){6}\ 840 ((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}\ 841 (25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])$/ \ 842 { exit 1 }' 843 return $? 844 } 845 846 # 847 # is_valid_addr addr 848 # 849 # Returns 0 if a valid IPv4 or IPv6 address is given, 1 otherwise. 850 # 851 is_valid_addr() 852 { 853 is_valid_v4addr $1 || is_valid_v6addr $1 854 } 855 856 # 857 # nwam_get_loc_prop location property 858 # 859 # echoes the value of the property for the given location 860 # return: 861 # 0 => property is set 862 # 1 => property is not set 863 # 864 nwam_get_loc_prop() 865 { 866 value=`/usr/sbin/nwamcfg "select loc $1; get -V $2" 2>/dev/null` 867 rtn=$? 868 echo $value 869 return $rtn 870 } 871 872 # 873 # nwam_get_loc_list_prop location property 874 # 875 # echoes a space-separated list of the property values for the given location 876 # return: 877 # 0 => property is set 878 # 1 => property is not set 879 # 880 nwam_get_loc_list_prop() 881 { 882 clist=`/usr/sbin/nwamcfg "select loc $1; get -V $2" 2>/dev/null` 883 rtn=$? 884 # 885 # nwamcfg gives us a comma-separated list; 886 # need to convert commas to spaces. 887 # 888 slist=`echo $clist | sed -e s/","/" "/g` 889 echo $slist 890 return $rtn 891 }