171333Sitojun/* $FreeBSD$ */ 2118664Sume/* $KAME: timer.c,v 1.9 2002/06/10 19:59:47 itojun Exp $ */ 362656Skris 455505Sshin/* 555505Sshin * Copyright (C) 1998 WIDE Project. 6224144Shrs * Copyright (C) 2011 Hiroki Sato <hrs@FreeBSD.org> 755505Sshin * All rights reserved. 8222732Shrs * 955505Sshin * Redistribution and use in source and binary forms, with or without 1055505Sshin * modification, are permitted provided that the following conditions 1155505Sshin * are met: 1255505Sshin * 1. Redistributions of source code must retain the above copyright 1355505Sshin * notice, this list of conditions and the following disclaimer. 1455505Sshin * 2. Redistributions in binary form must reproduce the above copyright 1555505Sshin * notice, this list of conditions and the following disclaimer in the 1655505Sshin * documentation and/or other materials provided with the distribution. 1755505Sshin * 3. Neither the name of the project nor the names of its contributors 1855505Sshin * may be used to endorse or promote products derived from this software 1955505Sshin * without specific prior written permission. 20222732Shrs * 2155505Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 2255505Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2355505Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2455505Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2555505Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2655505Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2755505Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2855505Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2955505Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3055505Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3155505Sshin * SUCH DAMAGE. 3255505Sshin */ 3355505Sshin 34222732Shrs#include <sys/queue.h> 35224144Shrs#include <sys/socket.h> 3655505Sshin 37224144Shrs#include <net/if.h> 38224144Shrs#include <net/if_dl.h> 39224144Shrs#include <netinet/in.h> 40224144Shrs 4155505Sshin#include <unistd.h> 4255505Sshin#include <syslog.h> 4355505Sshin#include <stdlib.h> 4455505Sshin#include <string.h> 45136764Ssuz#include <search.h> 46253970Shrs#include <time.h> 47224144Shrs#include <netdb.h> 48224144Shrs 49224144Shrs#include "rtadvd.h" 50224144Shrs#include "timer_subr.h" 5155505Sshin#include "timer.h" 5255505Sshin 53222732Shrsstruct rtadvd_timer_head_t ra_timer = 54222732Shrs TAILQ_HEAD_INITIALIZER(ra_timer); 55253970Shrsstatic struct timespec tm_limit; 56253970Shrsstatic struct timespec tm_max; 5755505Sshin 5855505Sshinvoid 59222732Shrsrtadvd_timer_init(void) 6055505Sshin{ 61253970Shrs /* Generate maximum time in timespec. */ 62253995Shrs tm_limit.tv_sec = (-1) & ~((time_t)1 << ((sizeof(tm_max.tv_sec) * 8) - 1)); 63253995Shrs tm_limit.tv_nsec = (-1) & ~((long)1 << ((sizeof(tm_max.tv_nsec) * 8) - 1)); 64222732Shrs tm_max = tm_limit; 65222732Shrs TAILQ_INIT(&ra_timer); 6655505Sshin} 6755505Sshin 68224144Shrsvoid 69224144Shrsrtadvd_update_timeout_handler(void) 70224144Shrs{ 71224144Shrs struct ifinfo *ifi; 72224144Shrs 73224144Shrs TAILQ_FOREACH(ifi, &ifilist, ifi_next) { 74224144Shrs switch (ifi->ifi_state) { 75224144Shrs case IFI_STATE_CONFIGURED: 76224144Shrs case IFI_STATE_TRANSITIVE: 77224144Shrs if (ifi->ifi_ra_timer != NULL) 78224144Shrs continue; 79224144Shrs 80224144Shrs syslog(LOG_DEBUG, "<%s> add timer for %s (idx=%d)", 81224144Shrs __func__, ifi->ifi_ifname, ifi->ifi_ifindex); 82224144Shrs ifi->ifi_ra_timer = rtadvd_add_timer(ra_timeout, 83224144Shrs ra_timer_update, ifi, ifi); 84224144Shrs ra_timer_update((void *)ifi, 85224144Shrs &ifi->ifi_ra_timer->rat_tm); 86224144Shrs rtadvd_set_timer(&ifi->ifi_ra_timer->rat_tm, 87224144Shrs ifi->ifi_ra_timer); 88224144Shrs break; 89224144Shrs case IFI_STATE_UNCONFIGURED: 90224144Shrs if (ifi->ifi_ra_timer == NULL) 91224144Shrs continue; 92224144Shrs 93224144Shrs syslog(LOG_DEBUG, 94224144Shrs "<%s> remove timer for %s (idx=%d)", __func__, 95224144Shrs ifi->ifi_ifname, ifi->ifi_ifindex); 96224144Shrs rtadvd_remove_timer(ifi->ifi_ra_timer); 97224144Shrs ifi->ifi_ra_timer = NULL; 98224144Shrs break; 99224144Shrs } 100224144Shrs } 101224144Shrs 102224144Shrs return; 103224144Shrs} 104224144Shrs 10555505Sshinstruct rtadvd_timer * 106173412Skevlortadvd_add_timer(struct rtadvd_timer *(*timeout)(void *), 107253970Shrs void (*update)(void *, struct timespec *), 10898172Sume void *timeodata, void *updatedata) 10955505Sshin{ 110222732Shrs struct rtadvd_timer *rat; 11155505Sshin 112222732Shrs if (timeout == NULL) { 11355505Sshin syslog(LOG_ERR, 114222732Shrs "<%s> timeout function unspecified", __func__); 11555505Sshin exit(1); 11655505Sshin } 11755505Sshin 118222732Shrs rat = malloc(sizeof(*rat)); 119222732Shrs if (rat == NULL) { 12055505Sshin syslog(LOG_ERR, 121222732Shrs "<%s> can't allocate memory", __func__); 12255505Sshin exit(1); 12355505Sshin } 124222732Shrs memset(rat, 0, sizeof(*rat)); 12555505Sshin 126222732Shrs rat->rat_expire = timeout; 127222732Shrs rat->rat_update = update; 128222732Shrs rat->rat_expire_data = timeodata; 129222732Shrs rat->rat_update_data = updatedata; 130222732Shrs rat->rat_tm = tm_max; 131222732Shrs 13255505Sshin /* link into chain */ 133222732Shrs TAILQ_INSERT_TAIL(&ra_timer, rat, rat_next); 13455505Sshin 135222732Shrs return (rat); 13655505Sshin} 13755505Sshin 13855505Sshinvoid 139222732Shrsrtadvd_remove_timer(struct rtadvd_timer *rat) 14062656Skris{ 141222732Shrs 142222732Shrs if (rat == NULL) 143222732Shrs return; 144222732Shrs 145222732Shrs TAILQ_REMOVE(&ra_timer, rat, rat_next); 146222732Shrs free(rat); 14762656Skris} 14862656Skris 14955505Sshin/* 15098172Sume * Check expiration for each timer. If a timer expires, 15155505Sshin * call the expire function for the timer and update the timer. 15255505Sshin * Return the next interval for select() call. 15355505Sshin */ 154253970Shrsstruct timespec * 155222732Shrsrtadvd_check_timer(void) 15655505Sshin{ 157253970Shrs static struct timespec returnval; 158253970Shrs struct timespec now; 159222732Shrs struct rtadvd_timer *rat; 16055505Sshin 161253970Shrs clock_gettime(CLOCK_MONOTONIC_FAST, &now); 162222732Shrs tm_max = tm_limit; 163222732Shrs TAILQ_FOREACH(rat, &ra_timer, rat_next) { 164253970Shrs if (TS_CMP(&rat->rat_tm, &now, <=)) { 165222732Shrs if (((*rat->rat_expire)(rat->rat_expire_data) == NULL)) 16698172Sume continue; /* the timer was removed */ 167222732Shrs if (rat->rat_update) 168222732Shrs (*rat->rat_update)(rat->rat_update_data, &rat->rat_tm); 169253970Shrs TS_ADD(&rat->rat_tm, &now, &rat->rat_tm); 17055505Sshin } 171253970Shrs if (TS_CMP(&rat->rat_tm, &tm_max, <)) 172222732Shrs tm_max = rat->rat_tm; 17355505Sshin } 174253970Shrs if (TS_CMP(&tm_max, &tm_limit, ==)) { 17562656Skris /* no need to timeout */ 176222732Shrs return (NULL); 177253970Shrs } else if (TS_CMP(&tm_max, &now, <)) { 17855505Sshin /* this may occur when the interval is too small */ 179253970Shrs returnval.tv_sec = returnval.tv_nsec = 0; 180118664Sume } else 181253970Shrs TS_SUB(&tm_max, &now, &returnval); 182222732Shrs return (&returnval); 18355505Sshin} 18455505Sshin 185224144Shrsvoid 186253970Shrsrtadvd_set_timer(struct timespec *tm, struct rtadvd_timer *rat) 18755505Sshin{ 188253970Shrs struct timespec now; 18955505Sshin 190224144Shrs /* reset the timer */ 191253970Shrs clock_gettime(CLOCK_MONOTONIC_FAST, &now); 192253970Shrs TS_ADD(&now, tm, &rat->rat_tm); 19355505Sshin 194224144Shrs /* update the next expiration time */ 195253970Shrs if (TS_CMP(&rat->rat_tm, &tm_max, <)) 196224144Shrs tm_max = rat->rat_tm; 19755505Sshin 198224144Shrs return; 19955505Sshin} 200