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