157416Smarkm/* 257416Smarkm * Copyright (c) 1988, 1993 357416Smarkm * The Regents of the University of California. All rights reserved. 457416Smarkm * 557416Smarkm * Redistribution and use in source and binary forms, with or without 657416Smarkm * modification, are permitted provided that the following conditions 757416Smarkm * are met: 857416Smarkm * 1. Redistributions of source code must retain the above copyright 957416Smarkm * notice, this list of conditions and the following disclaimer. 1057416Smarkm * 2. Redistributions in binary form must reproduce the above copyright 1157416Smarkm * notice, this list of conditions and the following disclaimer in the 1257416Smarkm * documentation and/or other materials provided with the distribution. 1357416Smarkm * 3. All advertising materials mentioning features or use of this software 1457416Smarkm * must display the following acknowledgement: 1557416Smarkm * This product includes software developed by the University of 1657416Smarkm * California, Berkeley and its contributors. 1757416Smarkm * 4. Neither the name of the University nor the names of its contributors 1857416Smarkm * may be used to endorse or promote products derived from this software 1957416Smarkm * without specific prior written permission. 2057416Smarkm * 2157416Smarkm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2257416Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2357416Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2457416Smarkm * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2557416Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2657416Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2757416Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2857416Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2957416Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3057416Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3157416Smarkm * SUCH DAMAGE. 3257416Smarkm */ 3357416Smarkm 3457416Smarkm#include "telnet_locl.h" 3557416Smarkm 36233294SstasRCSID("$Id$"); 3757416Smarkm 3857416Smarkm/* 3957416Smarkm * This defines a structure for a ring buffer. 4057416Smarkm * 4157416Smarkm * The circular buffer has two parts: 4257416Smarkm *((( 4357416Smarkm * full: [consume, supply) 4457416Smarkm * empty: [supply, consume) 4557416Smarkm *]]] 4657416Smarkm * 4757416Smarkm */ 4857416Smarkm 4957416Smarkm/* Internal macros */ 5057416Smarkm 5157416Smarkm#define ring_subtract(d,a,b) (((a)-(b) >= 0)? \ 5257416Smarkm (a)-(b): (((a)-(b))+(d)->size)) 5357416Smarkm 5457416Smarkm#define ring_increment(d,a,c) (((a)+(c) < (d)->top)? \ 5557416Smarkm (a)+(c) : (((a)+(c))-(d)->size)) 5657416Smarkm 5757416Smarkm#define ring_decrement(d,a,c) (((a)-(c) >= (d)->bottom)? \ 5857416Smarkm (a)-(c) : (((a)-(c))-(d)->size)) 5957416Smarkm 6057416Smarkm 6157416Smarkm/* 6257416Smarkm * The following is a clock, used to determine full, empty, etc. 6357416Smarkm * 6457416Smarkm * There is some trickiness here. Since the ring buffers are initialized 6557416Smarkm * to ZERO on allocation, we need to make sure, when interpreting the 6657416Smarkm * clock, that when the times are EQUAL, then the buffer is FULL. 6757416Smarkm */ 6857416Smarkmstatic u_long ring_clock = 0; 6957416Smarkm 7057416Smarkm 7157416Smarkm#define ring_empty(d) (((d)->consume == (d)->supply) && \ 7257416Smarkm ((d)->consumetime >= (d)->supplytime)) 7357416Smarkm#define ring_full(d) (((d)->supply == (d)->consume) && \ 7457416Smarkm ((d)->supplytime > (d)->consumetime)) 7557416Smarkm 7657416Smarkm 7757416Smarkm 7857416Smarkm 7957416Smarkm 8057416Smarkm/* Buffer state transition routines */ 8157416Smarkm 8257416Smarkmint 8357416Smarkmring_init(Ring *ring, unsigned char *buffer, int count) 8457416Smarkm{ 8557416Smarkm memset(ring, 0, sizeof *ring); 8657416Smarkm 8757416Smarkm ring->size = count; 8857416Smarkm 8957416Smarkm ring->supply = ring->consume = ring->bottom = buffer; 9057416Smarkm 9157416Smarkm ring->top = ring->bottom+ring->size; 9257416Smarkm 9357416Smarkm#if defined(ENCRYPTION) 9457416Smarkm ring->clearto = 0; 9557416Smarkm#endif 9657416Smarkm 9757416Smarkm return 1; 9857416Smarkm} 9957416Smarkm 10057416Smarkm/* Mark routines */ 10157416Smarkm 10257416Smarkm/* 10357416Smarkm * Mark the most recently supplied byte. 10457416Smarkm */ 10557416Smarkm 10657416Smarkmvoid 10757416Smarkmring_mark(Ring *ring) 10857416Smarkm{ 10957416Smarkm ring->mark = ring_decrement(ring, ring->supply, 1); 11057416Smarkm} 11157416Smarkm 11257416Smarkm/* 11357416Smarkm * Is the ring pointing to the mark? 11457416Smarkm */ 11557416Smarkm 11657416Smarkmint 11757416Smarkmring_at_mark(Ring *ring) 11857416Smarkm{ 11957416Smarkm if (ring->mark == ring->consume) { 12057416Smarkm return 1; 12157416Smarkm } else { 12257416Smarkm return 0; 12357416Smarkm } 12457416Smarkm} 12557416Smarkm 12657416Smarkm/* 12757416Smarkm * Clear any mark set on the ring. 12857416Smarkm */ 12957416Smarkm 13057416Smarkmvoid 13157416Smarkmring_clear_mark(Ring *ring) 13257416Smarkm{ 13357416Smarkm ring->mark = 0; 13457416Smarkm} 13557416Smarkm 13657416Smarkm/* 13757416Smarkm * Add characters from current segment to ring buffer. 13857416Smarkm */ 13957416Smarkmvoid 14057416Smarkmring_supplied(Ring *ring, int count) 14157416Smarkm{ 14257416Smarkm ring->supply = ring_increment(ring, ring->supply, count); 14357416Smarkm ring->supplytime = ++ring_clock; 14457416Smarkm} 14557416Smarkm 14657416Smarkm/* 14757416Smarkm * We have just consumed "c" bytes. 14857416Smarkm */ 14957416Smarkmvoid 15057416Smarkmring_consumed(Ring *ring, int count) 15157416Smarkm{ 15257416Smarkm if (count == 0) /* don't update anything */ 15357416Smarkm return; 15457416Smarkm 15557416Smarkm if (ring->mark && 15657416Smarkm (ring_subtract(ring, ring->mark, ring->consume) < count)) { 15757416Smarkm ring->mark = 0; 15857416Smarkm } 15957416Smarkm#if defined(ENCRYPTION) 16057416Smarkm if (ring->consume < ring->clearto && 16157416Smarkm ring->clearto <= ring->consume + count) 16257416Smarkm ring->clearto = 0; 16357416Smarkm else if (ring->consume + count > ring->top && 16457416Smarkm ring->bottom <= ring->clearto && 16557416Smarkm ring->bottom + ((ring->consume + count) - ring->top)) 16657416Smarkm ring->clearto = 0; 16757416Smarkm#endif 16857416Smarkm ring->consume = ring_increment(ring, ring->consume, count); 16957416Smarkm ring->consumetime = ++ring_clock; 17057416Smarkm /* 17157416Smarkm * Try to encourage "ring_empty_consecutive()" to be large. 17257416Smarkm */ 17357416Smarkm if (ring_empty(ring)) { 17457416Smarkm ring->consume = ring->supply = ring->bottom; 17557416Smarkm } 17657416Smarkm} 17757416Smarkm 17857416Smarkm 17957416Smarkm 18057416Smarkm/* Buffer state query routines */ 18157416Smarkm 18257416Smarkm 18357416Smarkm/* Number of bytes that may be supplied */ 18457416Smarkmint 18557416Smarkmring_empty_count(Ring *ring) 18657416Smarkm{ 18757416Smarkm if (ring_empty(ring)) { /* if empty */ 18857416Smarkm return ring->size; 18957416Smarkm } else { 19057416Smarkm return ring_subtract(ring, ring->consume, ring->supply); 19157416Smarkm } 19257416Smarkm} 19357416Smarkm 19457416Smarkm/* number of CONSECUTIVE bytes that may be supplied */ 19557416Smarkmint 19657416Smarkmring_empty_consecutive(Ring *ring) 19757416Smarkm{ 19857416Smarkm if ((ring->consume < ring->supply) || ring_empty(ring)) { 19957416Smarkm /* 20057416Smarkm * if consume is "below" supply, or empty, then 20157416Smarkm * return distance to the top 20257416Smarkm */ 20357416Smarkm return ring_subtract(ring, ring->top, ring->supply); 20457416Smarkm } else { 20557416Smarkm /* 20657416Smarkm * else, return what we may. 20757416Smarkm */ 20857416Smarkm return ring_subtract(ring, ring->consume, ring->supply); 20957416Smarkm } 21057416Smarkm} 21157416Smarkm 21257416Smarkm/* Return the number of bytes that are available for consuming 21357416Smarkm * (but don't give more than enough to get to cross over set mark) 21457416Smarkm */ 21557416Smarkm 21657416Smarkmint 21757416Smarkmring_full_count(Ring *ring) 21857416Smarkm{ 21957416Smarkm if ((ring->mark == 0) || (ring->mark == ring->consume)) { 22057416Smarkm if (ring_full(ring)) { 22157416Smarkm return ring->size; /* nothing consumed, but full */ 22257416Smarkm } else { 22357416Smarkm return ring_subtract(ring, ring->supply, ring->consume); 22457416Smarkm } 22557416Smarkm } else { 22657416Smarkm return ring_subtract(ring, ring->mark, ring->consume); 22757416Smarkm } 22857416Smarkm} 22957416Smarkm 23057416Smarkm/* 23157416Smarkm * Return the number of CONSECUTIVE bytes available for consuming. 23257416Smarkm * However, don't return more than enough to cross over set mark. 23357416Smarkm */ 23457416Smarkmint 23557416Smarkmring_full_consecutive(Ring *ring) 23657416Smarkm{ 23757416Smarkm if ((ring->mark == 0) || (ring->mark == ring->consume)) { 23857416Smarkm if ((ring->supply < ring->consume) || ring_full(ring)) { 23957416Smarkm return ring_subtract(ring, ring->top, ring->consume); 24057416Smarkm } else { 24157416Smarkm return ring_subtract(ring, ring->supply, ring->consume); 24257416Smarkm } 24357416Smarkm } else { 24457416Smarkm if (ring->mark < ring->consume) { 24557416Smarkm return ring_subtract(ring, ring->top, ring->consume); 24657416Smarkm } else { /* Else, distance to mark */ 24757416Smarkm return ring_subtract(ring, ring->mark, ring->consume); 24857416Smarkm } 24957416Smarkm } 25057416Smarkm} 25157416Smarkm 25257416Smarkm/* 25357416Smarkm * Move data into the "supply" portion of of the ring buffer. 25457416Smarkm */ 25557416Smarkmvoid 25657416Smarkmring_supply_data(Ring *ring, unsigned char *buffer, int count) 25757416Smarkm{ 25857416Smarkm int i; 25957416Smarkm 26057416Smarkm while (count) { 26157416Smarkm i = min(count, ring_empty_consecutive(ring)); 26257416Smarkm memmove(ring->supply, buffer, i); 26357416Smarkm ring_supplied(ring, i); 26457416Smarkm count -= i; 26557416Smarkm buffer += i; 26657416Smarkm } 26757416Smarkm} 26857416Smarkm 26957416Smarkm#ifdef notdef 27057416Smarkm 27157416Smarkm/* 27257416Smarkm * Move data from the "consume" portion of the ring buffer 27357416Smarkm */ 27457416Smarkmvoid 27557416Smarkmring_consume_data(Ring *ring, unsigned char *buffer, int count) 27657416Smarkm{ 27757416Smarkm int i; 27857416Smarkm 27957416Smarkm while (count) { 28057416Smarkm i = min(count, ring_full_consecutive(ring)); 28157416Smarkm memmove(buffer, ring->consume, i); 28257416Smarkm ring_consumed(ring, i); 28357416Smarkm count -= i; 28457416Smarkm buffer += i; 28557416Smarkm } 28657416Smarkm} 28757416Smarkm#endif 28857416Smarkm 28957416Smarkm#if defined(ENCRYPTION) 29057416Smarkmvoid 29157416Smarkmring_encrypt(Ring *ring, void (*encryptor)(unsigned char *, int)) 29257416Smarkm{ 29357416Smarkm unsigned char *s, *c; 29457416Smarkm 29557416Smarkm if (ring_empty(ring) || ring->clearto == ring->supply) 29657416Smarkm return; 29757416Smarkm 29857416Smarkm if (!(c = ring->clearto)) 29957416Smarkm c = ring->consume; 30057416Smarkm 30157416Smarkm s = ring->supply; 30257416Smarkm 30357416Smarkm if (s <= c) { 30457416Smarkm (*encryptor)(c, ring->top - c); 30557416Smarkm (*encryptor)(ring->bottom, s - ring->bottom); 30657416Smarkm } else 30757416Smarkm (*encryptor)(c, s - c); 30857416Smarkm 30957416Smarkm ring->clearto = ring->supply; 31057416Smarkm} 31157416Smarkm 31257416Smarkmvoid 31357416Smarkmring_clearto(Ring *ring) 31457416Smarkm{ 31557416Smarkm if (!ring_empty(ring)) 31657416Smarkm ring->clearto = ring->supply; 31757416Smarkm else 31857416Smarkm ring->clearto = 0; 31957416Smarkm} 32057416Smarkm#endif 32157416Smarkm 322