root/usr/src/cmd/cmd-inet/usr.lib/in.ripngd/timer.c
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

/*      Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T     */
/*        All Rights Reserved   */

/*
 * Portions of this source code were derived from Berkeley 4.3 BSD
 * under license from the Regents of the University of California.
 */

/*
 * Routing Table Management Daemon
 */
#include "defs.h"

int supplyinterval;                     /* current supply interval */

/*
 * Timer routine.  Performs routing information supply
 * duties and manages timers on routing table entries.
 * Management of the RTS_CHANGED bit assumes that we multicast
 * each time called.
 */
void
timer(void)
{
        struct rthash *rh;
        struct rt_entry *rt;
        boolean_t timetomulticast = _B_FALSE;
        int i;
        static int iftime;              /* interface timer */
        static int mtime;               /* periodic mcast supply timer */
        static int alarmtime = 0;       /* time elapsed since last call */
        int mintime;                    /* tracks when next timer will expire */

        /*
         * On the initial call to timer(), the various times that are kept track
         * of need to be initialized.  After initializing everything, "remember"
         * (via a static) how long until the next timer expires.
         */
        if (alarmtime == 0) {
                supplyinterval = GET_RANDOM(MIN_SUPPLY_TIME, MAX_SUPPLY_TIME);
                iftime = 0;
                mtime = supplyinterval;
                alarmtime = supplyinterval;
                (void) alarm(alarmtime);
                return;
        }

        /*
         * Initialize mintime to a suitable "large" value and then compare it to
         * other times in the future to determine which event will occur next.
         */
        mintime = INT_MAX;
        (void) sighold(SIGHUP);
        (void) sighold(SIGUSR1);
        (void) sighold(SIGUSR2);

        iftime += alarmtime;
        if (iftime >= CHECK_INTERVAL) {
                initifs();
                iftime = 0;
        }
        mintime = min(mintime, CHECK_INTERVAL - iftime);

        mtime += alarmtime;
        if (mtime >= supplyinterval) {
                if (supplier)
                        timetomulticast = _B_TRUE;
                mtime = 0;
                supplyinterval = GET_RANDOM(MIN_SUPPLY_TIME, MAX_SUPPLY_TIME);
        }
        mintime = min(mintime, supplyinterval - mtime);

        for (i = IPV6_ABITS; i >= 0; i--) {
                if (net_hashes[i] == NULL)
                        continue;

                for (rh = net_hashes[i];
                    rh < &net_hashes[i][ROUTEHASHSIZ]; rh++) {
                        for (rt = rh->rt_forw; rt != (struct rt_entry *)rh;
                            rt = rt->rt_forw) {
                                /*
                                 * We don't advance time on a routing entry for
                                 * an interface because we catch
                                 * interfaces going up and down in initifs.
                                 */
                                rt->rt_state &= ~RTS_CHANGED;
                                if ((rt->rt_state & RTS_INTERFACE) != 0)
                                        continue;
                                rt->rt_timer += alarmtime;
                                if (rt->rt_timer >= GARBAGE_TIME) {
                                        rt = rt->rt_back;
                                        rtdelete(rt->rt_forw);
                                        continue;
                                }
                                if (rt->rt_timer >= EXPIRE_TIME) {
                                        rtdown(rt);
                                        mintime = min(mintime,
                                            GARBAGE_TIME - rt->rt_timer);
                                } else {
                                        mintime = min(mintime,
                                            EXPIRE_TIME - rt->rt_timer);
                                }
                        }
                }
        }

        if (timetomulticast) {
                supplyall(&allrouters, 0, (struct interface *)NULL, _B_TRUE);
                (void) gettimeofday(&now, (struct timezone *)NULL);
                lastmcast = now;
                lastfullupdate = now;
                needupdate = _B_FALSE;  /* cancel any pending dynamic update */
                nextmcast.tv_sec = 0;
        }
        (void) sigrelse(SIGUSR2);
        (void) sigrelse(SIGUSR1);
        (void) sigrelse(SIGHUP);

        /*
         * "Remember" (via a static) how long until the next timer expires.
         */
        alarmtime = mintime;
        (void) alarm(alarmtime);
}

/*
 * On SIGTERM, let everyone know we're going away.
 */
void
term(void)
{
        struct rthash *rh;
        struct rt_entry *rt;
        int i;

        if (!supplier)
                exit(EXIT_SUCCESS);
        for (i = IPV6_ABITS; i >= 0; i--) {
                if (net_hashes[i] == NULL)
                        continue;

                for (rh = net_hashes[i]; rh < &net_hashes[i][ROUTEHASHSIZ];
                    rh++) {
                        for (rt = rh->rt_forw; rt != (struct rt_entry *)rh;
                            rt = rt->rt_forw) {
                                rt->rt_metric = HOPCNT_INFINITY;
                        }
                }
        }
        supplyall(&allrouters, 0, (struct interface *)NULL, _B_TRUE);
        (void) unlink(PATH_PID);
        exit(EXIT_SUCCESS);
}