1/* $KAME: timer.c,v 1.9 2002/06/10 19:59:47 itojun Exp $ */ 2 3/*- 4 * SPDX-License-Identifier: BSD-3-Clause 5 * 6 * Copyright (C) 1998 WIDE Project. 7 * Copyright (C) 2011 Hiroki Sato <hrs@FreeBSD.org> 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the project nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35#include <sys/queue.h> 36#include <sys/socket.h> 37 38#include <net/if.h> 39#include <net/if_dl.h> 40#include <netinet/in.h> 41 42#include <unistd.h> 43#include <syslog.h> 44#include <stdlib.h> 45#include <string.h> 46#include <search.h> 47#include <time.h> 48#include <netdb.h> 49 50#include "rtadvd.h" 51#include "timer_subr.h" 52#include "timer.h" 53 54struct rtadvd_timer_head_t ra_timer = 55 TAILQ_HEAD_INITIALIZER(ra_timer); 56static struct timespec tm_limit; 57static struct timespec tm_max; 58 59void 60rtadvd_timer_init(void) 61{ 62 /* Generate maximum time in timespec. */ 63 tm_limit.tv_sec = (-1) & ~((time_t)1 << ((sizeof(tm_max.tv_sec) * 8) - 1)); 64 tm_limit.tv_nsec = (-1) & ~((long)1 << ((sizeof(tm_max.tv_nsec) * 8) - 1)); 65 tm_max = tm_limit; 66 TAILQ_INIT(&ra_timer); 67} 68 69void 70rtadvd_update_timeout_handler(void) 71{ 72 struct ifinfo *ifi; 73 74 TAILQ_FOREACH(ifi, &ifilist, ifi_next) { 75 switch (ifi->ifi_state) { 76 case IFI_STATE_CONFIGURED: 77 case IFI_STATE_TRANSITIVE: 78 if (ifi->ifi_ra_timer != NULL) 79 continue; 80 81 syslog(LOG_DEBUG, "<%s> add timer for %s (idx=%d)", 82 __func__, ifi->ifi_ifname, ifi->ifi_ifindex); 83 ifi->ifi_ra_timer = rtadvd_add_timer(ra_timeout, 84 ra_timer_update, ifi, ifi); 85 ra_timer_update((void *)ifi, 86 &ifi->ifi_ra_timer->rat_tm); 87 rtadvd_set_timer(&ifi->ifi_ra_timer->rat_tm, 88 ifi->ifi_ra_timer); 89 break; 90 case IFI_STATE_UNCONFIGURED: 91 if (ifi->ifi_ra_timer == NULL) 92 continue; 93 94 syslog(LOG_DEBUG, 95 "<%s> remove timer for %s (idx=%d)", __func__, 96 ifi->ifi_ifname, ifi->ifi_ifindex); 97 rtadvd_remove_timer(ifi->ifi_ra_timer); 98 ifi->ifi_ra_timer = NULL; 99 break; 100 } 101 } 102} 103 104struct rtadvd_timer * 105rtadvd_add_timer(struct rtadvd_timer *(*timeout)(void *), 106 void (*update)(void *, struct timespec *), 107 void *timeodata, void *updatedata) 108{ 109 struct rtadvd_timer *rat; 110 111 if (timeout == NULL) { 112 syslog(LOG_ERR, 113 "<%s> timeout function unspecified", __func__); 114 exit(1); 115 } 116 117 rat = malloc(sizeof(*rat)); 118 if (rat == NULL) { 119 syslog(LOG_ERR, 120 "<%s> can't allocate memory", __func__); 121 exit(1); 122 } 123 memset(rat, 0, sizeof(*rat)); 124 125 rat->rat_expire = timeout; 126 rat->rat_update = update; 127 rat->rat_expire_data = timeodata; 128 rat->rat_update_data = updatedata; 129 rat->rat_tm = tm_max; 130 131 /* link into chain */ 132 TAILQ_INSERT_TAIL(&ra_timer, rat, rat_next); 133 134 return (rat); 135} 136 137void 138rtadvd_remove_timer(struct rtadvd_timer *rat) 139{ 140 141 if (rat == NULL) 142 return; 143 144 TAILQ_REMOVE(&ra_timer, rat, rat_next); 145 free(rat); 146} 147 148/* 149 * Check expiration for each timer. If a timer expires, 150 * call the expire function for the timer and update the timer. 151 * Return the next interval for select() call. 152 */ 153struct timespec * 154rtadvd_check_timer(void) 155{ 156 static struct timespec returnval; 157 struct timespec now; 158 struct rtadvd_timer *rat; 159 160 clock_gettime(CLOCK_MONOTONIC_FAST, &now); 161 tm_max = tm_limit; 162 TAILQ_FOREACH(rat, &ra_timer, rat_next) { 163 if (TS_CMP(&rat->rat_tm, &now, <=)) { 164 if (((*rat->rat_expire)(rat->rat_expire_data) == NULL)) 165 continue; /* the timer was removed */ 166 if (rat->rat_update) 167 (*rat->rat_update)(rat->rat_update_data, &rat->rat_tm); 168 TS_ADD(&rat->rat_tm, &now, &rat->rat_tm); 169 } 170 if (TS_CMP(&rat->rat_tm, &tm_max, <)) 171 tm_max = rat->rat_tm; 172 } 173 if (TS_CMP(&tm_max, &tm_limit, ==)) { 174 /* no need to timeout */ 175 return (NULL); 176 } else if (TS_CMP(&tm_max, &now, <)) { 177 /* this may occur when the interval is too small */ 178 returnval.tv_sec = returnval.tv_nsec = 0; 179 } else 180 TS_SUB(&tm_max, &now, &returnval); 181 return (&returnval); 182} 183 184void 185rtadvd_set_timer(struct timespec *tm, struct rtadvd_timer *rat) 186{ 187 struct timespec now; 188 189 /* reset the timer */ 190 clock_gettime(CLOCK_MONOTONIC_FAST, &now); 191 TS_ADD(&now, tm, &rat->rat_tm); 192 193 /* update the next expiration time */ 194 if (TS_CMP(&rat->rat_tm, &tm_max, <)) 195 tm_max = rat->rat_tm; 196} 197