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 29NET_INADDR_ANY="0.0.0.0" 30NET_IN6ADDR_ANY_INIT="::0" 31 32# Print warnings to console 33warn_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# 41shcat() { 42 while [ $# -ge 1 ]; do 43 while read i; do 44 echo "$i" 45 done < $1 46 shift 47 done 48} 49 50net_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# 75unset 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# 85get_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# 101get_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# 121if_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# 131physical_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# 142in_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# 161get_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# 178create_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# 192create_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# 220get_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# 260get_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# 291get_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# 304not_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# 321doDHCPhostname() 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# 358inet_oneline_epilogue_no_up="netmask + broadcast +" 359inet_oneline_epilogue="netmask + broadcast + up" 360 361inet_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# 441inet6_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# 466move_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# 568ipadm_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# 602if_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# 652net_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# 715update_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# 767service_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# 782service_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# 808is_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# 822is_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# 851is_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# 864nwam_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# 880nwam_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} 892