1/*-
2 * Copyright (c) 1982, 1986, 1989, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 4. Neither the name of the University nor the names of its contributors
14 *    may be used to endorse or promote products derived from this software
15 *    without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 *	@(#)kern_time.c	8.1 (Berkeley) 6/10/93
30 */
31#include <sys/kernel.h>
32#include <sys/time.h>
33
34/*
35 * ratecheck(): simple time-based rate-limit checking.
36 */
37int
38ratecheck(struct timeval *lasttime, const struct timeval *mininterval)
39{
40	struct timeval tv, delta;
41	int rv = 0;
42
43	getmicrouptime(&tv);		/* NB: 10ms precision */
44	delta = tv;
45	timevalsub(&delta, lasttime);
46
47	/*
48	 * check for 0,0 is so that the message will be seen at least once,
49	 * even if interval is huge.
50	 */
51	if (timevalcmp(&delta, mininterval, >=) ||
52		(lasttime->tv_sec == 0 && lasttime->tv_usec == 0)) {
53		*lasttime = tv;
54		rv = 1;
55	}
56
57	return (rv);
58}
59
60/*
61 * ppsratecheck(): packets (or events) per second limitation.
62 *
63 * Return 0 if the limit is to be enforced (e.g. the caller
64 * should drop a packet because of the rate limitation).
65 *
66 * maxpps of 0 always causes zero to be returned.  maxpps of -1
67 * always causes 1 to be returned; this effectively defeats rate
68 * limiting.
69 *
70 * Note that we maintain the struct timeval for compatibility
71 * with other bsd systems.  We reuse the storage and just monitor
72 * clock ticks for minimal overhead.
73 */
74int
75ppsratecheck(struct timeval *lasttime, int *curpps, int maxpps)
76{
77	int now;
78
79	/*
80	 * Reset the last time and counter if this is the first call
81	 * or more than a second has passed since the last update of
82	 * lasttime.
83	 */
84	now = ticks;
85	if (lasttime->tv_sec == 0 || (u_int)(now - lasttime->tv_sec) >= hz) {
86		lasttime->tv_sec = now;
87		*curpps = 1;
88		return (maxpps != 0);
89	} else {
90		(*curpps)++;		/* NB: ignore potential overflow */
91		return (maxpps < 0 || *curpps <= maxpps);
92	}
93}
94
95static void
96timevalfix(struct timeval *t1)
97{
98
99	if (t1->tv_usec < 0) {
100		t1->tv_sec--;
101		t1->tv_usec += 1000000;
102	}
103	if (t1->tv_usec >= 1000000) {
104		t1->tv_sec++;
105		t1->tv_usec -= 1000000;
106	}
107}
108
109/*
110 * Add and subtract routines for timevals.
111 * N.B.: subtract routine doesn't deal with
112 * results which are before the beginning,
113 * it just gets very confused in this case.
114 * Caveat emptor.
115 */
116void
117timevaladd(struct timeval *t1, const struct timeval *t2)
118{
119
120	t1->tv_sec += t2->tv_sec;
121	t1->tv_usec += t2->tv_usec;
122	timevalfix(t1);
123}
124
125void
126timevalsub(struct timeval *t1, const struct timeval *t2)
127{
128
129	t1->tv_sec -= t2->tv_sec;
130	t1->tv_usec -= t2->tv_usec;
131	timevalfix(t1);
132}
133