xref: /netbsd-src/external/mpl/dhcp/dist/client/scripts/linux (revision 41e8421f37d76436f9e3d8e13eb30b47c8aaf258)
16fb29d29Schristos#!/bin/bash
26fb29d29Schristos# dhclient-script for Linux. Dan Halbert, March, 1997.
36fb29d29Schristos# Updated for Linux 2.[12] by Brian J. Murrell, January 1999.
46fb29d29Schristos# No guarantees about this. I'm a novice at the details of Linux
56fb29d29Schristos# networking.
66fb29d29Schristos
76fb29d29Schristos# Notes:
86fb29d29Schristos
96fb29d29Schristos# 0. This script is based on the netbsd script supplied with dhcp-970306.
106fb29d29Schristos
116fb29d29Schristos# 1. ifconfig down apparently deletes all relevant routes and flushes
126fb29d29Schristos# the arp cache, so this doesn't need to be done explicitly.
136fb29d29Schristos
146fb29d29Schristos# 2. The alias address handling here has not been tested AT ALL.
156fb29d29Schristos# I'm just going by the doc of modern Linux ip aliasing, which uses
166fb29d29Schristos# notations like eth0:0, eth0:1, for each alias.
176fb29d29Schristos
186fb29d29Schristos# 3. I have to calculate the network address, and calculate the broadcast
196fb29d29Schristos# address if it is not supplied. This might be much more easily done
206fb29d29Schristos# by the dhclient C code, and passed on.
216fb29d29Schristos
226fb29d29Schristos# 4. TIMEOUT not tested. ping has a flag I don't know, and I'm suspicious
236fb29d29Schristos# of the $1 in its args.
246fb29d29Schristos
256fb29d29Schristos# 5. Script refresh in 2017. The aliasing code was too convoluted and needs
266fb29d29Schristos# to go away. Migrated DHCPv4 script to ip command from iproute2 suite.
276fb29d29Schristos# This is based on Debian script with some tweaks. ifconfig is no longer
286fb29d29Schristos# used. Everything is done using ip tool from ip-route2.
296fb29d29Schristos
306fb29d29Schristos# 'ip' just looks too weird. Also, we now have unit-tests! Those unit-tests
316fb29d29Schristos# overwirte this line to use a fake ip-echo tool. It's also convenient
326fb29d29Schristos# if your system holds ip tool in a non-standard location.
336fb29d29Schristosip=/sbin/ip
346fb29d29Schristos
356fb29d29Schristos# update /etc/resolv.conf based on received values
366fb29d29Schristos# This updated version mostly follows Debian script by Andrew Pollock et al.
376fb29d29Schristosmake_resolv_conf() {
386fb29d29Schristos    local new_resolv_conf
396fb29d29Schristos
406fb29d29Schristos    # DHCPv4
416fb29d29Schristos    if [ -n "$new_domain_search" ] || [ -n "$new_domain_name" ] ||
426fb29d29Schristos       [ -n "$new_domain_name_servers" ]; then
436fb29d29Schristos        new_resolv_conf=/etc/resolv.conf.dhclient-new
446fb29d29Schristos        rm -f $new_resolv_conf
456fb29d29Schristos
466fb29d29Schristos        if [ -n "$new_domain_name" ]; then
476fb29d29Schristos            echo domain ${new_domain_name%% *} >>$new_resolv_conf
486fb29d29Schristos        fi
496fb29d29Schristos
506fb29d29Schristos        if [ -n "$new_domain_search" ]; then
516fb29d29Schristos            if [ -n "$new_domain_name" ]; then
526fb29d29Schristos                domain_in_search_list=""
536fb29d29Schristos                for domain in $new_domain_search; do
546fb29d29Schristos                    if [ "$domain" = "${new_domain_name}" ] ||
556fb29d29Schristos                       [ "$domain" = "${new_domain_name}." ]; then
566fb29d29Schristos                        domain_in_search_list="Yes"
576fb29d29Schristos                    fi
586fb29d29Schristos                done
596fb29d29Schristos                if [ -z "$domain_in_search_list" ]; then
606fb29d29Schristos                    new_domain_search="$new_domain_name $new_domain_search"
616fb29d29Schristos                fi
626fb29d29Schristos            fi
636fb29d29Schristos            echo "search ${new_domain_search}" >> $new_resolv_conf
646fb29d29Schristos        elif [ -n "$new_domain_name" ]; then
656fb29d29Schristos            echo "search ${new_domain_name}" >> $new_resolv_conf
666fb29d29Schristos        fi
676fb29d29Schristos
686fb29d29Schristos        if [ -n "$new_domain_name_servers" ]; then
696fb29d29Schristos            for nameserver in $new_domain_name_servers; do
706fb29d29Schristos                echo nameserver $nameserver >>$new_resolv_conf
716fb29d29Schristos            done
726fb29d29Schristos        else # keep 'old' nameservers
736fb29d29Schristos            sed -n /^\w*[Nn][Aa][Mm][Ee][Ss][Ee][Rr][Vv][Ee][Rr]/p /etc/resolv.conf >>$new_resolv_conf
746fb29d29Schristos        fi
756fb29d29Schristos
766fb29d29Schristos	if [ -f /etc/resolv.conf ]; then
776fb29d29Schristos	    chown --reference=/etc/resolv.conf $new_resolv_conf
786fb29d29Schristos	    chmod --reference=/etc/resolv.conf $new_resolv_conf
796fb29d29Schristos	fi
806fb29d29Schristos        mv -f $new_resolv_conf /etc/resolv.conf
816fb29d29Schristos    # DHCPv6
826fb29d29Schristos    elif [ -n "$new_dhcp6_domain_search" ] || [ -n "$new_dhcp6_name_servers" ]; then
836fb29d29Schristos        new_resolv_conf=/etc/resolv.conf.dhclient-new
846fb29d29Schristos        rm -f $new_resolv_conf
856fb29d29Schristos
866fb29d29Schristos        if [ -n "$new_dhcp6_domain_search" ]; then
876fb29d29Schristos            echo "search ${new_dhcp6_domain_search}" >> $new_resolv_conf
886fb29d29Schristos        fi
896fb29d29Schristos
906fb29d29Schristos        if [ -n "$new_dhcp6_name_servers" ]; then
916fb29d29Schristos            for nameserver in $new_dhcp6_name_servers; do
926fb29d29Schristos                # append %interface to link-local-address nameservers
936fb29d29Schristos                if [ "${nameserver##fe80::}" != "$nameserver" ] ||
946fb29d29Schristos                   [ "${nameserver##FE80::}" != "$nameserver" ]; then
956fb29d29Schristos                    nameserver="${nameserver}%${interface}"
966fb29d29Schristos                fi
976fb29d29Schristos                echo nameserver $nameserver >>$new_resolv_conf
986fb29d29Schristos            done
996fb29d29Schristos        else # keep 'old' nameservers
1006fb29d29Schristos            sed -n /^\w*[Nn][Aa][Mm][Ee][Ss][Ee][Rr][Vv][Ee][Rr]/p /etc/resolv.conf >>$new_resolv_conf
1016fb29d29Schristos        fi
1026fb29d29Schristos
1036fb29d29Schristos	if [ -f /etc/resolv.conf ]; then
1046fb29d29Schristos            chown --reference=/etc/resolv.conf $new_resolv_conf
1056fb29d29Schristos            chmod --reference=/etc/resolv.conf $new_resolv_conf
1066fb29d29Schristos	fi
1076fb29d29Schristos        mv -f $new_resolv_conf /etc/resolv.conf
1086fb29d29Schristos    fi
1096fb29d29Schristos}
1106fb29d29Schristos
1116fb29d29Schristos# set host name
1126fb29d29Schristosset_hostname() {
1136fb29d29Schristos    local current_hostname
1146fb29d29Schristos
1156fb29d29Schristos    if [ -n "$new_host_name" ]; then
1166fb29d29Schristos        current_hostname=$(hostname)
1176fb29d29Schristos
1186fb29d29Schristos        # current host name is empty, '(none)' or 'localhost' or differs from new one from DHCP
1196fb29d29Schristos        if [ -z "$current_hostname" ] ||
1206fb29d29Schristos           [ "$current_hostname" = '(none)' ] ||
1216fb29d29Schristos           [ "$current_hostname" = 'localhost' ] ||
1226fb29d29Schristos           [ "$current_hostname" = "$old_host_name" ]; then
1236fb29d29Schristos           if [ "$new_host_name" != "$old_host_name" ]; then
1246fb29d29Schristos               hostname "$new_host_name"
1256fb29d29Schristos           fi
1266fb29d29Schristos        fi
1276fb29d29Schristos    fi
1286fb29d29Schristos}
1296fb29d29Schristos
1306fb29d29Schristos# run given script
1316fb29d29Schristosrun_hook() {
1326fb29d29Schristos    local script
1336fb29d29Schristos    local exit_status
1346fb29d29Schristos    script="$1"
1356fb29d29Schristos
1366fb29d29Schristos    if [ -f $script ]; then
1376fb29d29Schristos        . $script
1386fb29d29Schristos    fi
1396fb29d29Schristos
1406fb29d29Schristos    if [ -n "$exit_status" ] && [ "$exit_status" -ne 0 ]; then
1416fb29d29Schristos        logger -p daemon.err "$script returned non-zero exit status $exit_status"
1426fb29d29Schristos    fi
1436fb29d29Schristos
1446fb29d29Schristos    return $exit_status
1456fb29d29Schristos}
1466fb29d29Schristos
1476fb29d29Schristos# run scripts in given directory
1486fb29d29Schristosrun_hookdir() {
1496fb29d29Schristos    local dir
1506fb29d29Schristos    local exit_status
1516fb29d29Schristos    dir="$1"
1526fb29d29Schristos
1536fb29d29Schristos    if [ -d "$dir" ]; then
1546fb29d29Schristos        for script in $(run-parts --list $dir); do
1556fb29d29Schristos            run_hook $script || true
1566fb29d29Schristos            exit_status=$?
1576fb29d29Schristos        done
1586fb29d29Schristos    fi
1596fb29d29Schristos
1606fb29d29Schristos    return $exit_status
1616fb29d29Schristos}
1626fb29d29Schristos
1636fb29d29Schristos# Must be used on exit.   Invokes the local dhcp client exit hooks, if any.
1646fb29d29Schristosexit_with_hooks() {
1656fb29d29Schristos    exit_status=$1
1666fb29d29Schristos
1676fb29d29Schristos    # Source the documented exit-hook script, if it exists
1686fb29d29Schristos    if ! run_hook /etc/dhclient-exit-hooks; then
1696fb29d29Schristos        exit_status=$?
1706fb29d29Schristos    fi
1716fb29d29Schristos
1726fb29d29Schristos    # Now run scripts in the Debian-specific directory.
1736fb29d29Schristos    if ! run_hookdir /etc/dhclient-exit-hooks.d; then
1746fb29d29Schristos        exit_status=$?
1756fb29d29Schristos    fi
1766fb29d29Schristos
1776fb29d29Schristos    exit $exit_status
1786fb29d29Schristos}
1796fb29d29Schristos
1806fb29d29Schristos# This function was largely borrowed from dhclient-script that
1816fb29d29Schristos# ships with Centos, authored by Jiri Popelka and David Cantrell
1826fb29d29Schristos# of Redhat. Thanks guys.
1836fb29d29Schristosadd_ipv6_addr_with_DAD() {
1846fb29d29Schristos    ${ip} -6 addr replace ${new_ip6_address}/${new_ip6_prefixlen} \
1856fb29d29Schristos    dev ${interface} scope global valid_lft ${new_max_life} \
1866fb29d29Schristos        preferred_lft ${new_preferred_life}
1876fb29d29Schristos
1886fb29d29Schristos    if [ ${dad_wait_time} -le 0 ]
1896fb29d29Schristos    then
1906fb29d29Schristos        # if we're not waiting for DAD, assume we're good
1916fb29d29Schristos        return 0
1926fb29d29Schristos    fi
1936fb29d29Schristos
1946fb29d29Schristos    # Repeatedly test whether newly added address passed
1956fb29d29Schristos    # duplicate address detection (DAD)
1966fb29d29Schristos    for i in $(seq 1 ${dad_wait_time}); do
1976fb29d29Schristos        sleep 1 # give the DAD some time
1986fb29d29Schristos
1996fb29d29Schristos        addr=$(${ip} -6 addr show dev ${interface} \
2006fb29d29Schristos            | grep ${new_ip6_address}/${new_ip6_prefixlen})
2016fb29d29Schristos
2026fb29d29Schristos        # tentative flag == DAD is still not complete
2036fb29d29Schristos        tentative=$(echo "${addr}" | grep tentative)
2046fb29d29Schristos        # dadfailed flag == address is already in use somewhere else
2056fb29d29Schristos        dadfailed=$(echo "${addr}" | grep dadfailed)
2066fb29d29Schristos
2076fb29d29Schristos        if [ -n "${dadfailed}" ] ; then
2086fb29d29Schristos            # address was added with valid_lft/preferred_lft 'forever',
2096fb29d29Schristos            # remove it
2106fb29d29Schristos            ${ip} -6 addr del ${new_ip6_address}/${new_ip6_prefixlen} \
2116fb29d29Schristos                dev ${interface}
2126fb29d29Schristos
2136fb29d29Schristos            exit_with_hooks 3
2146fb29d29Schristos        fi
2156fb29d29Schristos
2166fb29d29Schristos        if [ -z "${tentative}" ] ; then
2176fb29d29Schristos            if [ -n "${addr}" ]; then
2186fb29d29Schristos                # DAD is over
2196fb29d29Schristos                    return 0
2206fb29d29Schristos            else
2216fb29d29Schristos                # address was auto-removed (or not added at all)
2226fb29d29Schristos                exit_with_hooks 3
2236fb29d29Schristos            fi
2246fb29d29Schristos        fi
2256fb29d29Schristos    done
2266fb29d29Schristos
2276fb29d29Schristos    return 0
2286fb29d29Schristos}
2296fb29d29Schristos
2306fb29d29Schristos# Invoke the local dhcp client enter hooks, if they exist.
2316fb29d29Schristosrun_hook /etc/dhclient-enter-hooks
2326fb29d29Schristosrun_hookdir /etc/dhclient-enter-hooks.d
2336fb29d29Schristos
2346fb29d29Schristos# Execute the operation
2356fb29d29Schristoscase "$reason" in
2366fb29d29Schristos
2376fb29d29Schristos    ### DHCPv4 Handlers
2386fb29d29Schristos
2396fb29d29Schristos    MEDIUM|ARPCHECK|ARPSEND)
2406fb29d29Schristos        # Do nothing
2416fb29d29Schristos        ;;
2426fb29d29Schristos    PREINIT)
2436fb29d29Schristos        # The DHCP client is requesting that an interface be
2446fb29d29Schristos        # configured as required in order to send packets prior to
2456fb29d29Schristos        # receiving an actual address. - dhclient-script(8)
2466fb29d29Schristos
2476fb29d29Schristos        # ensure interface is up
2486fb29d29Schristos        ${ip} link set dev ${interface} up
2496fb29d29Schristos
2506fb29d29Schristos        if [ -n "$alias_ip_address" ]; then
2516fb29d29Schristos            # flush alias IP from interface
2526fb29d29Schristos            ${ip} -4 addr flush dev ${interface} label ${interface}:0
2536fb29d29Schristos        fi
2546fb29d29Schristos
2556fb29d29Schristos        ;;
2566fb29d29Schristos
2576fb29d29Schristos    BOUND|RENEW|REBIND|REBOOT)
2586fb29d29Schristos        set_hostname
2596fb29d29Schristos
2606fb29d29Schristos        if [ -n "$old_ip_address" ] && [ -n "$alias_ip_address" ] &&
2616fb29d29Schristos           [ "$alias_ip_address" != "$old_ip_address" ]; then
2626fb29d29Schristos            # alias IP may have changed => flush it
2636fb29d29Schristos            ${ip} -4 addr flush dev ${interface} label ${interface}:0
2646fb29d29Schristos        fi
2656fb29d29Schristos
2666fb29d29Schristos        if [ -n "$old_ip_address" ] &&
2676fb29d29Schristos           [ "$old_ip_address" != "$new_ip_address" ]; then
2686fb29d29Schristos            # leased IP has changed => flush it
2696fb29d29Schristos            ${ip} -4 addr flush dev ${interface} label ${interface}
2706fb29d29Schristos        fi
2716fb29d29Schristos
2726fb29d29Schristos        if [ -z "$old_ip_address" ] ||
2736fb29d29Schristos           [ "$old_ip_address" != "$new_ip_address" ] ||
2746fb29d29Schristos           [ "$reason" = "BOUND" ] || [ "$reason" = "REBOOT" ]; then
2756fb29d29Schristos            # new IP has been leased or leased IP changed => set it
2766fb29d29Schristos            ${ip} -4 addr add ${new_ip_address}${new_subnet_mask:+/$new_subnet_mask} \
2776fb29d29Schristos                ${new_broadcast_address:+broadcast $new_broadcast_address} \
2786fb29d29Schristos                dev ${interface} label ${interface}
2796fb29d29Schristos
2806fb29d29Schristos            if [ -n "$new_interface_mtu" ]; then
2816fb29d29Schristos                # set MTU
2826fb29d29Schristos                ${ip} link set dev ${interface} mtu ${new_interface_mtu}
2836fb29d29Schristos            fi
2846fb29d29Schristos
2856fb29d29Schristos	    # if we have $new_rfc3442_classless_static_routes then we have to
2866fb29d29Schristos	    # ignore $new_routers entirely
2876fb29d29Schristos	    if [ ! "$new_rfc3442_classless_static_routes" ]; then
2886fb29d29Schristos		    # set if_metric if IF_METRIC is set or there's more than one router
2896fb29d29Schristos		    if_metric="$IF_METRIC"
2906fb29d29Schristos		    if [ "${new_routers%% *}" != "${new_routers}" ]; then
2916fb29d29Schristos			if_metric=${if_metric:-1}
2926fb29d29Schristos		    fi
2936fb29d29Schristos
2946fb29d29Schristos		    for router in $new_routers; do
2956fb29d29Schristos			if [ "$new_subnet_mask" = "255.255.255.255" ]; then
2966fb29d29Schristos			    # point-to-point connection => set explicit route
2976fb29d29Schristos			    ${ip} -4 route add ${router} dev $interface >/dev/null 2>&1
2986fb29d29Schristos			fi
2996fb29d29Schristos
3006fb29d29Schristos			# set default route
3016fb29d29Schristos			${ip} -4 route add default via ${router} dev ${interface} \
3026fb29d29Schristos			    ${if_metric:+metric $if_metric} >/dev/null 2>&1
3036fb29d29Schristos
3046fb29d29Schristos			if [ -n "$if_metric" ]; then
3056fb29d29Schristos			    if_metric=$((if_metric+1))
3066fb29d29Schristos			fi
3076fb29d29Schristos		    done
3086fb29d29Schristos	    fi
3096fb29d29Schristos        fi
3106fb29d29Schristos
3116fb29d29Schristos        if [ -n "$alias_ip_address" ] &&
3126fb29d29Schristos           [ "$new_ip_address" != "$alias_ip_address" ]; then
3136fb29d29Schristos            # separate alias IP given, which may have changed
3146fb29d29Schristos            # => flush it, set it & add host route to it
3156fb29d29Schristos            ${ip} -4 addr flush dev ${interface} label ${interface}:0
3166fb29d29Schristos            ${ip} -4 addr add ${alias_ip_address}${alias_subnet_mask:+/$alias_subnet_mask} \
3176fb29d29Schristos                dev ${interface} label ${interface}:0
3186fb29d29Schristos            ${ip} -4 route add ${alias_ip_address} dev ${interface} >/dev/null 2>&1
3196fb29d29Schristos        fi
3206fb29d29Schristos
3216fb29d29Schristos        # update /etc/resolv.conf
3226fb29d29Schristos        make_resolv_conf
3236fb29d29Schristos
3246fb29d29Schristos        ;;
3256fb29d29Schristos
3266fb29d29Schristos    EXPIRE|FAIL|RELEASE|STOP)
3276fb29d29Schristos        if [ -n "$alias_ip_address" ]; then
3286fb29d29Schristos            # flush alias IP
3296fb29d29Schristos            ${ip} -4 addr flush dev ${interface} label ${interface}:0
3306fb29d29Schristos        fi
3316fb29d29Schristos
3326fb29d29Schristos        if [ -n "$old_ip_address" ]; then
3336fb29d29Schristos            # flush leased IP
3346fb29d29Schristos            ${ip} -4 addr flush dev ${interface} label ${interface}
3356fb29d29Schristos        fi
3366fb29d29Schristos
3376fb29d29Schristos        if [ -n "$alias_ip_address" ]; then
3386fb29d29Schristos            # alias IP given => set it & add host route to it
3396fb29d29Schristos            ${ip} -4 addr add ${alias_ip_address}${alias_subnet_mask:+/$alias_subnet_mask} \
3406fb29d29Schristos                dev ${interface} label ${interface}:0
3416fb29d29Schristos            ${ip} -4 route add ${alias_ip_address} dev ${interface} >/dev/null 2>&1
3426fb29d29Schristos        fi
3436fb29d29Schristos
3446fb29d29Schristos        ;;
3456fb29d29Schristos
3466fb29d29Schristos    TIMEOUT)
3476fb29d29Schristos        if [ -n "$alias_ip_address" ]; then
3486fb29d29Schristos            # flush alias IP
3496fb29d29Schristos            ${ip} -4 addr flush dev ${interface} label ${interface}:0
3506fb29d29Schristos        fi
3516fb29d29Schristos
3526fb29d29Schristos        # set IP from recorded lease
3536fb29d29Schristos        ${ip} -4 addr add ${new_ip_address}${new_subnet_mask:+/$new_subnet_mask} \
3546fb29d29Schristos            ${new_broadcast_address:+broadcast $new_broadcast_address} \
3556fb29d29Schristos            dev ${interface} label ${interface}
3566fb29d29Schristos
3576fb29d29Schristos        if [ -n "$new_interface_mtu" ]; then
3586fb29d29Schristos            # set MTU
3596fb29d29Schristos            ${ip} link set dev ${interface} mtu ${new_interface_mtu}
3606fb29d29Schristos        fi
3616fb29d29Schristos
3626fb29d29Schristos        # if there is no router recorded in the lease or the 1st router answers pings
3636fb29d29Schristos        if [ -z "$new_routers" ] || ping -q -c 1 "${new_routers%% *}"; then
3646fb29d29Schristos	    # if we have $new_rfc3442_classless_static_routes then we have to
3656fb29d29Schristos	    # ignore $new_routers entirely
3666fb29d29Schristos	    if [ ! "$new_rfc3442_classless_static_routes" ]; then
3676fb29d29Schristos		    if [ -n "$alias_ip_address" ] &&
3686fb29d29Schristos		       [ "$new_ip_address" != "$alias_ip_address" ]; then
3696fb29d29Schristos			# separate alias IP given => set up the alias IP & add host route to it
3706fb29d29Schristos			${ip} -4 addr add \
3716fb29d29Schristos                              ${alias_ip_address}${alias_subnet_mask:+/$alias_subnet_mask} \
3726fb29d29Schristos			      dev ${interface} label ${interface}:0
3736fb29d29Schristos			${ip} -4 route add ${alias_ip_address} dev ${interface} >/dev/null 2>&1
3746fb29d29Schristos		    fi
3756fb29d29Schristos
3766fb29d29Schristos		    # set if_metric if IF_METRIC is set or there's more than one router
3776fb29d29Schristos		    if_metric="$IF_METRIC"
3786fb29d29Schristos		    if [ "${new_routers%% *}" != "${new_routers}" ]; then
3796fb29d29Schristos			if_metric=${if_metric:-1}
3806fb29d29Schristos		    fi
3816fb29d29Schristos
3826fb29d29Schristos		    # set default route
3836fb29d29Schristos		    for router in $new_routers; do
3846fb29d29Schristos			${ip} -4 route add default via ${router} dev ${interface} \
3856fb29d29Schristos			    ${if_metric:+metric $if_metric} >/dev/null 2>&1
3866fb29d29Schristos
3876fb29d29Schristos			if [ -n "$if_metric" ]; then
3886fb29d29Schristos			    if_metric=$((if_metric+1))
3896fb29d29Schristos			fi
3906fb29d29Schristos		    done
3916fb29d29Schristos	    fi
3926fb29d29Schristos
3936fb29d29Schristos            # update /etc/resolv.conf
3946fb29d29Schristos            make_resolv_conf
3956fb29d29Schristos        else
3966fb29d29Schristos            # flush all IPs from interface
3976fb29d29Schristos            ip -4 addr flush dev ${interface}
3986fb29d29Schristos            exit_with_hooks 2
3996fb29d29Schristos        fi
4006fb29d29Schristos
4016fb29d29Schristos        ;;
4026fb29d29Schristos
403*41e8421fSchristos    V6ONLY)
404*41e8421fSchristos        if [ -n "$old_ip_address" ]; then
405*41e8421fSchristos            # flush leased IP
406*41e8421fSchristos            ${ip} -4 addr flush dev ${interface} label ${interface}
407*41e8421fSchristos        fi
408*41e8421fSchristos
409*41e8421fSchristos        ;;
410*41e8421fSchristos
4116fb29d29Schristos    ### DHCPv6 Handlers
4126fb29d29Schristos    # TODO handle prefix change: ?based on ${old_ip6_prefix} and ${new_ip6_prefix}?
4136fb29d29Schristos
4146fb29d29Schristos    PREINIT6)
4156fb29d29Schristos        # ensure interface is up
4166fb29d29Schristos        ${ip} link set ${interface} up
4176fb29d29Schristos
4186fb29d29Schristos        # We need to give the kernel some time to active interface
4196fb29d29Schristos        interface_up_wait_time=5
4206fb29d29Schristos        for i in $(seq 0 ${interface_up_wait_time})
4216fb29d29Schristos        do
422*41e8421fSchristos            ${ip} link show dev ${interface} | grep -q LOWER_UP 2>&1
4236fb29d29Schristos            if [ $? -eq 0 ]; then
4246fb29d29Schristos                break;
4256fb29d29Schristos            fi
4266fb29d29Schristos            sleep 1
4276fb29d29Schristos        done
4286fb29d29Schristos
4296fb29d29Schristos        # flush any stale global permanent IPs from interface
4306fb29d29Schristos        ${ip} -6 addr flush dev ${interface} scope global permanent
4316fb29d29Schristos
4326fb29d29Schristos        # Wait for duplicate address detection for this interface if the
4336fb29d29Schristos        # --dad-wait-time parameter has been specified and is greater than
4346fb29d29Schristos        # zero.
4356fb29d29Schristos        if [ ${dad_wait_time} -gt 0 ]; then
4366fb29d29Schristos            # Check if any IPv6 address on this interface is marked as
4376fb29d29Schristos            # tentative.
4386fb29d29Schristos            ${ip} addr show ${interface} | grep inet6 | grep tentative \
4396fb29d29Schristos                &> /dev/null
4406fb29d29Schristos            if [ $? -eq 0 ]; then
4416fb29d29Schristos                # Wait for duplicate address detection to complete or for
4426fb29d29Schristos                # the timeout specified as --dad-wait-time.
4436fb29d29Schristos                for i in $(seq 0 $dad_wait_time)
4446fb29d29Schristos                do
4456fb29d29Schristos                    # We're going to poll for the tentative flag every second.
4466fb29d29Schristos                    sleep 1
4476fb29d29Schristos                    ${ip} addr show ${interface} | grep inet6 | grep tentative \
4486fb29d29Schristos                        &> /dev/null
4496fb29d29Schristos                    if [ $? -ne 0 ]; then
4506fb29d29Schristos                        break;
4516fb29d29Schristos                    fi
4526fb29d29Schristos                done
4536fb29d29Schristos            fi
4546fb29d29Schristos        fi
4556fb29d29Schristos
4566fb29d29Schristos        ;;
4576fb29d29Schristos
4586fb29d29Schristos    BOUND6|RENEW6|REBIND6)
4596fb29d29Schristos        if [ "${new_ip6_address}" ] && [ "${new_ip6_prefixlen}" ]; then
4606fb29d29Schristos            # set leased IP
4616fb29d29Schristos            add_ipv6_addr_with_DAD
4626fb29d29Schristos        fi
4636fb29d29Schristos
4646fb29d29Schristos        # update /etc/resolv.conf
4656fb29d29Schristos        if [ "${reason}" = BOUND6 ] ||
4666fb29d29Schristos           [ "${new_dhcp6_name_servers}" != "${old_dhcp6_name_servers}" ] ||
4676fb29d29Schristos           [ "${new_dhcp6_domain_search}" != "${old_dhcp6_domain_search}" ]; then
4686fb29d29Schristos            make_resolv_conf
4696fb29d29Schristos        fi
4706fb29d29Schristos
4716fb29d29Schristos        ;;
4726fb29d29Schristos
4736fb29d29Schristos    DEPREF6)
4746fb29d29Schristos        if [ -z "${cur_ip6_prefixlen}" ]; then
4756fb29d29Schristos            exit_with_hooks 2
4766fb29d29Schristos        fi
4776fb29d29Schristos
4786fb29d29Schristos        # set preferred lifetime of leased IP to 0
4796fb29d29Schristos        ${ip} -6 addr change ${cur_ip6_address}/${cur_ip6_prefixlen} \
4806fb29d29Schristos            dev ${interface} scope global preferred_lft 0
4816fb29d29Schristos
4826fb29d29Schristos        ;;
4836fb29d29Schristos
4846fb29d29Schristos    EXPIRE6|RELEASE6|STOP6)
4856fb29d29Schristos        if [ -z "${old_ip6_address}" ] || [ -z "${old_ip6_prefixlen}" ]; then
4866fb29d29Schristos            exit_with_hooks 2
4876fb29d29Schristos        fi
4886fb29d29Schristos
4896fb29d29Schristos        # delete leased IP
4906fb29d29Schristos        ${ip} -6 addr del ${old_ip6_address}/${old_ip6_prefixlen} \
4916fb29d29Schristos            dev ${interface}
4926fb29d29Schristos
4936fb29d29Schristos        ;;
4946fb29d29Schristosesac
4956fb29d29Schristos
4966fb29d29Schristosexit_with_hooks 0
497