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 54 struct rtadvd_timer_head_t ra_timer = 55 TAILQ_HEAD_INITIALIZER(ra_timer); 56 static struct timespec tm_limit; 57 static struct timespec tm_max; 58 59 void 60 rtadvd_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 69 void 70 rtadvd_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 104 struct rtadvd_timer * 105 rtadvd_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 137 void 138 rtadvd_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 */ 153 struct timespec * 154 rtadvd_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 184 void 185 rtadvd_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