1 1.17 msaitoh /* $NetBSD: ring.c,v 1.17 2024/05/13 00:32:39 msaitoh Exp $ */ 2 1.7 thorpej 3 1.1 cgd /* 4 1.3 cgd * Copyright (c) 1988, 1993 5 1.3 cgd * The Regents of the University of California. All rights reserved. 6 1.1 cgd * 7 1.1 cgd * Redistribution and use in source and binary forms, with or without 8 1.1 cgd * modification, are permitted provided that the following conditions 9 1.1 cgd * are met: 10 1.1 cgd * 1. Redistributions of source code must retain the above copyright 11 1.1 cgd * notice, this list of conditions and the following disclaimer. 12 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 cgd * notice, this list of conditions and the following disclaimer in the 14 1.1 cgd * documentation and/or other materials provided with the distribution. 15 1.13 agc * 3. Neither the name of the University nor the names of its contributors 16 1.1 cgd * may be used to endorse or promote products derived from this software 17 1.1 cgd * without specific prior written permission. 18 1.1 cgd * 19 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 1.1 cgd * SUCH DAMAGE. 30 1.1 cgd */ 31 1.1 cgd 32 1.8 christos #include <sys/cdefs.h> 33 1.1 cgd #ifndef lint 34 1.7 thorpej #if 0 35 1.7 thorpej static char sccsid[] = "@(#)ring.c 8.2 (Berkeley) 5/30/95"; 36 1.7 thorpej #else 37 1.17 msaitoh __RCSID("$NetBSD: ring.c,v 1.17 2024/05/13 00:32:39 msaitoh Exp $"); 38 1.7 thorpej #endif 39 1.1 cgd #endif /* not lint */ 40 1.1 cgd 41 1.1 cgd /* 42 1.1 cgd * This defines a structure for a ring buffer. 43 1.1 cgd * 44 1.1 cgd * The circular buffer has two parts: 45 1.1 cgd *((( 46 1.1 cgd * full: [consume, supply) 47 1.1 cgd * empty: [supply, consume) 48 1.1 cgd *]]] 49 1.1 cgd * 50 1.1 cgd */ 51 1.1 cgd 52 1.1 cgd #include <stdio.h> 53 1.6 jtk #include <string.h> 54 1.6 jtk #include <strings.h> 55 1.1 cgd #include <errno.h> 56 1.1 cgd #include <sys/types.h> 57 1.1 cgd #include <sys/ioctl.h> 58 1.1 cgd #include <sys/socket.h> 59 1.1 cgd 60 1.1 cgd #include "ring.h" 61 1.1 cgd #include "general.h" 62 1.1 cgd 63 1.1 cgd /* Internal macros */ 64 1.1 cgd 65 1.1 cgd #if !defined(MIN) 66 1.1 cgd #define MIN(a,b) (((a)<(b))? (a):(b)) 67 1.1 cgd #endif /* !defined(MIN) */ 68 1.1 cgd 69 1.1 cgd #define ring_subtract(d,a,b) (((a)-(b) >= 0)? \ 70 1.1 cgd (a)-(b): (((a)-(b))+(d)->size)) 71 1.1 cgd 72 1.1 cgd #define ring_increment(d,a,c) (((a)+(c) < (d)->top)? \ 73 1.1 cgd (a)+(c) : (((a)+(c))-(d)->size)) 74 1.1 cgd 75 1.1 cgd #define ring_decrement(d,a,c) (((a)-(c) >= (d)->bottom)? \ 76 1.1 cgd (a)-(c) : (((a)-(c))-(d)->size)) 77 1.1 cgd 78 1.1 cgd 79 1.1 cgd /* 80 1.1 cgd * The following is a clock, used to determine full, empty, etc. 81 1.1 cgd * 82 1.1 cgd * There is some trickiness here. Since the ring buffers are initialized 83 1.1 cgd * to ZERO on allocation, we need to make sure, when interpreting the 84 1.1 cgd * clock, that when the times are EQUAL, then the buffer is FULL. 85 1.1 cgd */ 86 1.1 cgd static u_long ring_clock = 0; 87 1.1 cgd 88 1.1 cgd 89 1.1 cgd #define ring_empty(d) (((d)->consume == (d)->supply) && \ 90 1.1 cgd ((d)->consumetime >= (d)->supplytime)) 91 1.1 cgd #define ring_full(d) (((d)->supply == (d)->consume) && \ 92 1.1 cgd ((d)->supplytime > (d)->consumetime)) 93 1.1 cgd 94 1.1 cgd 95 1.1 cgd 96 1.1 cgd 97 1.1 cgd 98 1.1 cgd /* Buffer state transition routines */ 99 1.1 cgd 100 1.11 christos int 101 1.11 christos ring_init(Ring *ring, unsigned char *buffer, int count) 102 1.1 cgd { 103 1.15 christos memset(ring, 0, sizeof *ring); 104 1.1 cgd 105 1.1 cgd ring->size = count; 106 1.1 cgd 107 1.1 cgd ring->supply = ring->consume = ring->bottom = buffer; 108 1.1 cgd 109 1.1 cgd ring->top = ring->bottom+ring->size; 110 1.1 cgd 111 1.9 thorpej #ifdef ENCRYPTION 112 1.9 thorpej ring->clearto = 0; 113 1.9 thorpej #endif /* ENCRYPTION */ 114 1.1 cgd 115 1.1 cgd return 1; 116 1.1 cgd } 117 1.1 cgd 118 1.1 cgd /* Mark routines */ 119 1.1 cgd 120 1.1 cgd /* 121 1.1 cgd * Mark the most recently supplied byte. 122 1.1 cgd */ 123 1.1 cgd 124 1.11 christos void 125 1.11 christos ring_mark(Ring *ring) 126 1.1 cgd { 127 1.1 cgd ring->mark = ring_decrement(ring, ring->supply, 1); 128 1.1 cgd } 129 1.1 cgd 130 1.1 cgd /* 131 1.1 cgd * Is the ring pointing to the mark? 132 1.1 cgd */ 133 1.1 cgd 134 1.11 christos int 135 1.11 christos ring_at_mark(Ring *ring) 136 1.1 cgd { 137 1.1 cgd if (ring->mark == ring->consume) { 138 1.1 cgd return 1; 139 1.1 cgd } else { 140 1.1 cgd return 0; 141 1.1 cgd } 142 1.1 cgd } 143 1.1 cgd 144 1.1 cgd /* 145 1.1 cgd * Clear any mark set on the ring. 146 1.1 cgd */ 147 1.1 cgd 148 1.11 christos void 149 1.11 christos ring_clear_mark(Ring *ring) 150 1.1 cgd { 151 1.1 cgd ring->mark = 0; 152 1.1 cgd } 153 1.1 cgd 154 1.1 cgd /* 155 1.1 cgd * Add characters from current segment to ring buffer. 156 1.1 cgd */ 157 1.11 christos void 158 1.11 christos ring_supplied(Ring *ring, int count) 159 1.1 cgd { 160 1.1 cgd ring->supply = ring_increment(ring, ring->supply, count); 161 1.1 cgd ring->supplytime = ++ring_clock; 162 1.1 cgd } 163 1.1 cgd 164 1.1 cgd /* 165 1.1 cgd * We have just consumed "c" bytes. 166 1.1 cgd */ 167 1.11 christos void 168 1.11 christos ring_consumed(Ring *ring, int count) 169 1.1 cgd { 170 1.1 cgd if (count == 0) /* don't update anything */ 171 1.1 cgd return; 172 1.1 cgd 173 1.1 cgd if (ring->mark && 174 1.1 cgd (ring_subtract(ring, ring->mark, ring->consume) < count)) { 175 1.1 cgd ring->mark = 0; 176 1.1 cgd } 177 1.9 thorpej #ifdef ENCRYPTION 178 1.9 thorpej if (ring->consume < ring->clearto && 179 1.9 thorpej ring->clearto <= ring->consume + count) 180 1.9 thorpej ring->clearto = 0; 181 1.9 thorpej else if (ring->consume + count > ring->top && 182 1.16 mrg ring->bottom <= ring->clearto) 183 1.9 thorpej ring->clearto = 0; 184 1.9 thorpej #endif /* ENCRYPTION */ 185 1.1 cgd ring->consume = ring_increment(ring, ring->consume, count); 186 1.1 cgd ring->consumetime = ++ring_clock; 187 1.1 cgd /* 188 1.1 cgd * Try to encourage "ring_empty_consecutive()" to be large. 189 1.1 cgd */ 190 1.1 cgd if (ring_empty(ring)) { 191 1.1 cgd ring->consume = ring->supply = ring->bottom; 192 1.1 cgd } 193 1.1 cgd } 194 1.1 cgd 195 1.1 cgd 196 1.1 cgd 197 1.1 cgd /* Buffer state query routines */ 198 1.1 cgd 199 1.1 cgd 200 1.1 cgd /* Number of bytes that may be supplied */ 201 1.11 christos int 202 1.11 christos ring_empty_count(Ring *ring) 203 1.1 cgd { 204 1.1 cgd if (ring_empty(ring)) { /* if empty */ 205 1.1 cgd return ring->size; 206 1.1 cgd } else { 207 1.1 cgd return ring_subtract(ring, ring->consume, ring->supply); 208 1.1 cgd } 209 1.1 cgd } 210 1.1 cgd 211 1.1 cgd /* number of CONSECUTIVE bytes that may be supplied */ 212 1.11 christos int 213 1.11 christos ring_empty_consecutive(Ring *ring) 214 1.1 cgd { 215 1.1 cgd if ((ring->consume < ring->supply) || ring_empty(ring)) { 216 1.1 cgd /* 217 1.1 cgd * if consume is "below" supply, or empty, then 218 1.1 cgd * return distance to the top 219 1.1 cgd */ 220 1.1 cgd return ring_subtract(ring, ring->top, ring->supply); 221 1.1 cgd } else { 222 1.1 cgd /* 223 1.1 cgd * else, return what we may. 224 1.1 cgd */ 225 1.1 cgd return ring_subtract(ring, ring->consume, ring->supply); 226 1.1 cgd } 227 1.1 cgd } 228 1.1 cgd 229 1.1 cgd /* Return the number of bytes that are available for consuming 230 1.1 cgd * (but don't give more than enough to get to cross over set mark) 231 1.1 cgd */ 232 1.1 cgd 233 1.11 christos int 234 1.11 christos ring_full_count(Ring *ring) 235 1.1 cgd { 236 1.1 cgd if ((ring->mark == 0) || (ring->mark == ring->consume)) { 237 1.1 cgd if (ring_full(ring)) { 238 1.1 cgd return ring->size; /* nothing consumed, but full */ 239 1.1 cgd } else { 240 1.1 cgd return ring_subtract(ring, ring->supply, ring->consume); 241 1.1 cgd } 242 1.1 cgd } else { 243 1.1 cgd return ring_subtract(ring, ring->mark, ring->consume); 244 1.1 cgd } 245 1.1 cgd } 246 1.1 cgd 247 1.1 cgd /* 248 1.1 cgd * Return the number of CONSECUTIVE bytes available for consuming. 249 1.1 cgd * However, don't return more than enough to cross over set mark. 250 1.1 cgd */ 251 1.11 christos int 252 1.11 christos ring_full_consecutive(Ring *ring) 253 1.1 cgd { 254 1.1 cgd if ((ring->mark == 0) || (ring->mark == ring->consume)) { 255 1.1 cgd if ((ring->supply < ring->consume) || ring_full(ring)) { 256 1.1 cgd return ring_subtract(ring, ring->top, ring->consume); 257 1.1 cgd } else { 258 1.1 cgd return ring_subtract(ring, ring->supply, ring->consume); 259 1.1 cgd } 260 1.1 cgd } else { 261 1.1 cgd if (ring->mark < ring->consume) { 262 1.1 cgd return ring_subtract(ring, ring->top, ring->consume); 263 1.1 cgd } else { /* Else, distance to mark */ 264 1.1 cgd return ring_subtract(ring, ring->mark, ring->consume); 265 1.1 cgd } 266 1.1 cgd } 267 1.1 cgd } 268 1.1 cgd 269 1.1 cgd /* 270 1.17 msaitoh * Move data into the "supply" portion of the ring buffer. 271 1.1 cgd */ 272 1.11 christos void 273 1.11 christos ring_supply_data(Ring *ring, unsigned char *buffer, int count) 274 1.1 cgd { 275 1.1 cgd int i; 276 1.1 cgd 277 1.1 cgd while (count) { 278 1.1 cgd i = MIN(count, ring_empty_consecutive(ring)); 279 1.5 jtk memmove(ring->supply, buffer, i); 280 1.1 cgd ring_supplied(ring, i); 281 1.1 cgd count -= i; 282 1.1 cgd buffer += i; 283 1.1 cgd } 284 1.1 cgd } 285 1.1 cgd 286 1.9 thorpej #ifdef ENCRYPTION 287 1.9 thorpej void 288 1.11 christos ring_encrypt(Ring *ring, void (*encryptor)(unsigned char *, int)) 289 1.9 thorpej { 290 1.9 thorpej unsigned char *s, *c; 291 1.9 thorpej 292 1.9 thorpej if (ring_empty(ring) || ring->clearto == ring->supply) 293 1.9 thorpej return; 294 1.9 thorpej 295 1.9 thorpej if (!(c = ring->clearto)) 296 1.9 thorpej c = ring->consume; 297 1.9 thorpej 298 1.9 thorpej s = ring->supply; 299 1.9 thorpej 300 1.9 thorpej if (s <= c) { 301 1.9 thorpej (*encryptor)(c, ring->top - c); 302 1.9 thorpej (*encryptor)(ring->bottom, s - ring->bottom); 303 1.9 thorpej } else 304 1.9 thorpej (*encryptor)(c, s - c); 305 1.9 thorpej 306 1.9 thorpej ring->clearto = ring->supply; 307 1.9 thorpej } 308 1.9 thorpej 309 1.9 thorpej void 310 1.11 christos ring_clearto(Ring *ring) 311 1.9 thorpej { 312 1.9 thorpej 313 1.9 thorpej if (!ring_empty(ring)) 314 1.9 thorpej ring->clearto = ring->supply; 315 1.9 thorpej else 316 1.9 thorpej ring->clearto = 0; 317 1.9 thorpej } 318 1.9 thorpej #endif /* ENCRYPTION */ 319