xref: /mOS-networking-stack/core/src/tcp_rb.c (revision 05e3289c)
176404edcSAsim Jamshed #include <stdio.h>
276404edcSAsim Jamshed #include <stdlib.h>
376404edcSAsim Jamshed #include <stdint.h>
476404edcSAsim Jamshed #include <stdbool.h>
576404edcSAsim Jamshed #include <string.h>
676404edcSAsim Jamshed #include <assert.h>
776404edcSAsim Jamshed #include <errno.h>
876404edcSAsim Jamshed #include <unistd.h>
976404edcSAsim Jamshed #include <sys/uio.h>
1076404edcSAsim Jamshed #include <ctype.h>
1176404edcSAsim Jamshed #include "debug.h"
1276404edcSAsim Jamshed #include "tcp_rb.h"
1376404edcSAsim Jamshed 
1476404edcSAsim Jamshed #define FREE(x) do { free(x); x = NULL; } while (0)
1576404edcSAsim Jamshed #ifndef MIN
1676404edcSAsim Jamshed #define MIN(a, b) ((a) < (b) ? (a) : (b))
1776404edcSAsim Jamshed #endif
1876404edcSAsim Jamshed #ifndef MAX
1976404edcSAsim Jamshed #define MAX(a, b) ((a) < (b) ? (b) : (a))
2076404edcSAsim Jamshed #endif
2176404edcSAsim Jamshed 
2276404edcSAsim Jamshed #define PRINTF(f, args...) printf("%s:%d: " f, __FILE__, __LINE__, ##args)
2376404edcSAsim Jamshed 
2476404edcSAsim Jamshed /* -------------------------------------------------------------------------- */
2576404edcSAsim Jamshed /* Private */
2676404edcSAsim Jamshed /* -------------------------------------------------------------------------- */
2776404edcSAsim Jamshed 
2876404edcSAsim Jamshed static inline boff_t
loff2boff(tcprb_t * rb,loff_t loff)2976404edcSAsim Jamshed loff2boff(tcprb_t *rb, loff_t loff)
3076404edcSAsim Jamshed {
3176404edcSAsim Jamshed 	int woff = loff - rb->head; /* window offset */
3276404edcSAsim Jamshed 	if (woff < 0 || woff > rb->len)
3376404edcSAsim Jamshed 		return -1;
3476404edcSAsim Jamshed 
3576404edcSAsim Jamshed 	return (boff_t)((loff + rb->corr) % rb->len);
3676404edcSAsim Jamshed }
3776404edcSAsim Jamshed /*--------------------------------------------------------------------------*/
3876404edcSAsim Jamshed static inline tcpfrag_t *
frags_new(void)3976404edcSAsim Jamshed frags_new(void)
4076404edcSAsim Jamshed {
4176404edcSAsim Jamshed 	return (tcpfrag_t *)calloc(sizeof(tcpfrag_t), 1);
4276404edcSAsim Jamshed }
4376404edcSAsim Jamshed /*--------------------------------------------------------------------------*/
4476404edcSAsim Jamshed static inline void
frags_del(tcpfrag_t * f)4576404edcSAsim Jamshed frags_del(tcpfrag_t *f)
4676404edcSAsim Jamshed {
4776404edcSAsim Jamshed 	free(f);
4876404edcSAsim Jamshed }
4976404edcSAsim Jamshed /*--------------------------------------------------------------------------*/
5076404edcSAsim Jamshed static inline void
frags_insert(tcprb_t * rb,tcpfrag_t * f)5176404edcSAsim Jamshed frags_insert(tcprb_t *rb, tcpfrag_t *f)
5276404edcSAsim Jamshed {
5376404edcSAsim Jamshed 	struct _tcpfrag_t *walk;
5476404edcSAsim Jamshed 
5576404edcSAsim Jamshed 	TAILQ_FOREACH(walk, &rb->frags, link)
5676404edcSAsim Jamshed 		if (walk->head > f->head) {
5776404edcSAsim Jamshed 			TAILQ_INSERT_BEFORE(walk, f, link);
5876404edcSAsim Jamshed 			break;
5976404edcSAsim Jamshed 		}
6076404edcSAsim Jamshed 
6176404edcSAsim Jamshed 	if (!walk)
6276404edcSAsim Jamshed 		TAILQ_INSERT_TAIL(&rb->frags, f, link);
6376404edcSAsim Jamshed }
6476404edcSAsim Jamshed /*--------------------------------------------------------------------------*/
6576404edcSAsim Jamshed static inline tcpbufseg_t *
bufseg_new(mem_pool_t mp)6676404edcSAsim Jamshed bufseg_new(mem_pool_t mp)
6776404edcSAsim Jamshed {
6876404edcSAsim Jamshed 	//return (tcpbufseg_t *)malloc(sizeof(tcpbufseg_t));
6976404edcSAsim Jamshed 	return (tcpbufseg_t *)MPAllocateChunk(mp);
7076404edcSAsim Jamshed }
7176404edcSAsim Jamshed /*--------------------------------------------------------------------------*/
7276404edcSAsim Jamshed static inline void
bufseg_del(mem_pool_t mp,tcpbufseg_t * b)7376404edcSAsim Jamshed bufseg_del(mem_pool_t mp, tcpbufseg_t *b)
7476404edcSAsim Jamshed {
7576404edcSAsim Jamshed 	//free(b);
7676404edcSAsim Jamshed 	MPFreeChunk(mp, b);
7776404edcSAsim Jamshed }
7876404edcSAsim Jamshed /*--------------------------------------------------------------------------*/
7976404edcSAsim Jamshed /* For on-demand buffser segment allocation, the buffer segment queue must
8076404edcSAsim Jamshed  * be always traversed in directin of from head to tail */
8176404edcSAsim Jamshed static inline tcpbufseg_t *
buf_first(tcprb_t * rb)8276404edcSAsim Jamshed buf_first(tcprb_t *rb)
8376404edcSAsim Jamshed {
8476404edcSAsim Jamshed 	tcpbufseg_t *tmp;
8576404edcSAsim Jamshed 
8676404edcSAsim Jamshed 	if ((tmp = TAILQ_FIRST(&rb->bufsegs)))
8776404edcSAsim Jamshed 		return tmp;
8876404edcSAsim Jamshed 
8976404edcSAsim Jamshed 	if ((rb->lbufsegs == 0) || ((tmp = bufseg_new(rb->mp)) == NULL))
9076404edcSAsim Jamshed 		return NULL;
9176404edcSAsim Jamshed 
9276404edcSAsim Jamshed 	tmp->id = 0;
9376404edcSAsim Jamshed 	TAILQ_INSERT_TAIL(&rb->bufsegs, tmp, link);
9476404edcSAsim Jamshed 
9576404edcSAsim Jamshed 	return tmp;
9676404edcSAsim Jamshed }
9776404edcSAsim Jamshed /*--------------------------------------------------------------------------*/
9876404edcSAsim Jamshed static inline tcpbufseg_t *
buf_next(tcprb_t * rb,tcpbufseg_t * buf)9976404edcSAsim Jamshed buf_next(tcprb_t *rb, tcpbufseg_t *buf)
10076404edcSAsim Jamshed {
10176404edcSAsim Jamshed 	tcpbufseg_t *tmp;
10276404edcSAsim Jamshed 
10376404edcSAsim Jamshed 	if ((tmp = TAILQ_NEXT(buf, link)))
10476404edcSAsim Jamshed 		return tmp;
10576404edcSAsim Jamshed 
10676404edcSAsim Jamshed 	if ((rb->lbufsegs <= buf->id + 1) || ((tmp = bufseg_new(rb->mp)) == NULL))
10776404edcSAsim Jamshed 		return NULL;
10876404edcSAsim Jamshed 
10976404edcSAsim Jamshed  	tmp->id = buf->id + 1;
11076404edcSAsim Jamshed 	TAILQ_INSERT_TAIL(&rb->bufsegs, tmp, link);
11176404edcSAsim Jamshed 
11276404edcSAsim Jamshed 	return tmp;
11376404edcSAsim Jamshed }
11476404edcSAsim Jamshed /*--------------------------------------------------------------------------*/
11576404edcSAsim Jamshed static inline tcpbufseg_t *
buf_getbuf(tcprb_t * rb,boff_t off)11676404edcSAsim Jamshed buf_getbuf(tcprb_t *rb, boff_t off)
11776404edcSAsim Jamshed {
11876404edcSAsim Jamshed 	tcpbufseg_t *buf;
11976404edcSAsim Jamshed 	int id = off / UNITBUFSIZE;
12076404edcSAsim Jamshed 	assert(id >= 0);
12176404edcSAsim Jamshed 
12276404edcSAsim Jamshed #if 0
12376404edcSAsim Jamshed 	int max = rb->len / UNITBUFSIZE;
12476404edcSAsim Jamshed 
12576404edcSAsim Jamshed 	if (max / 2 > id) {
12676404edcSAsim Jamshed 		buf = TAILQ_FIRST(&rb->bufsegs);
12776404edcSAsim Jamshed 		while (id--)
12876404edcSAsim Jamshed 			buf = TAILQ_NEXT(buf, link);
12976404edcSAsim Jamshed 	} else {
13076404edcSAsim Jamshed 		buf = TAILQ_LAST(&rb->bufsegs, blist);
13176404edcSAsim Jamshed 		while (max - ++id)
13276404edcSAsim Jamshed 			buf = TAILQ_PREV(buf, blist, link);
13376404edcSAsim Jamshed 	}
13476404edcSAsim Jamshed #else
13576404edcSAsim Jamshed 	buf = buf_first(rb);
13676404edcSAsim Jamshed 	while (id--)
13776404edcSAsim Jamshed 		buf = buf_next(rb, buf);
13876404edcSAsim Jamshed #endif
13976404edcSAsim Jamshed 
14076404edcSAsim Jamshed 	assert(buf);
14176404edcSAsim Jamshed 
14276404edcSAsim Jamshed 	return buf;
14376404edcSAsim Jamshed }
14476404edcSAsim Jamshed /*--------------------------------------------------------------------------*/
14576404edcSAsim Jamshed #define TAILQ_LOOP_NEXT(head, headname, elm, field) \
14676404edcSAsim Jamshed 	((*(((struct headname *)((head)->tqh_last))->tqh_last)) == (elm) ? \
14776404edcSAsim Jamshed 	 ((head)->tqh_first) : ((elm)->field.tqe_next))
14876404edcSAsim Jamshed 
14976404edcSAsim Jamshed static inline int
buf_try_resize(tcprb_t * rb,int len,loff_t data,int datalen)15076404edcSAsim Jamshed buf_try_resize(tcprb_t *rb, int len, loff_t data, int datalen)
15176404edcSAsim Jamshed {
15276404edcSAsim Jamshed 	/* FIXME: resizing is temporally disabled because of on-demand buffer
15376404edcSAsim Jamshed 	 * allocation patch */
15476404edcSAsim Jamshed 	//return 0;
15576404edcSAsim Jamshed 
15676404edcSAsim Jamshed 	assert(rb);
15776404edcSAsim Jamshed 	assert(rb->len);
15876404edcSAsim Jamshed 	assert(len % UNITBUFSIZE == 0 || len < 2);
15976404edcSAsim Jamshed 
16076404edcSAsim Jamshed 	int segdiff = (len - rb->len) / UNITBUFSIZE;
16176404edcSAsim Jamshed 	if (segdiff == 0)
16276404edcSAsim Jamshed 		return 0;
16376404edcSAsim Jamshed 
16476404edcSAsim Jamshed 	boff_t head = loff2boff(rb, data);
16576404edcSAsim Jamshed 	boff_t tail = (data + datalen - 1) % rb->len;
16676404edcSAsim Jamshed 
16776404edcSAsim Jamshed 	tcpbufseg_t *headseg = buf_getbuf(rb, head);
16876404edcSAsim Jamshed 	tcpbufseg_t *tailseg = buf_getbuf(rb, tail);
16976404edcSAsim Jamshed 
17076404edcSAsim Jamshed 	if (segdiff > 0) {
17176404edcSAsim Jamshed 		/* Expand the buffer */
17276404edcSAsim Jamshed 		rb->len = len;
17376404edcSAsim Jamshed 		boff_t new_head = loff2boff(rb, data);
17476404edcSAsim Jamshed 		rb->corr = (rb->corr + (segdiff * UNITBUFSIZE) - (new_head - head))
17576404edcSAsim Jamshed 				   % rb->len;
17676404edcSAsim Jamshed 		if (rb->corr < 0)
17776404edcSAsim Jamshed 			rb->corr += rb->len;
17876404edcSAsim Jamshed 
17976404edcSAsim Jamshed 		if (head > tail && headseg == tailseg) {
18076404edcSAsim Jamshed 			tcpbufseg_t *seg = bufseg_new(rb->mp);
18176404edcSAsim Jamshed 			assert(seg);
18276404edcSAsim Jamshed 			memcpy(&seg->buf[head % UNITBUFSIZE],
18376404edcSAsim Jamshed 				   &headseg->buf[head % UNITBUFSIZE],
18476404edcSAsim Jamshed 				   UNITBUFSIZE - (head % UNITBUFSIZE));
18576404edcSAsim Jamshed 			TAILQ_INSERT_AFTER(&rb->bufsegs, tailseg, seg, link);
18676404edcSAsim Jamshed 			headseg = seg;
18776404edcSAsim Jamshed 			segdiff--;
18876404edcSAsim Jamshed 		}
18976404edcSAsim Jamshed 		while (segdiff--) {
19076404edcSAsim Jamshed 			tcpbufseg_t *seg = bufseg_new(rb->mp);
19176404edcSAsim Jamshed 			assert(seg);
19276404edcSAsim Jamshed 			TAILQ_INSERT_AFTER(&rb->bufsegs, tailseg, seg, link);
19376404edcSAsim Jamshed 		}
19476404edcSAsim Jamshed 	} else /* if (segdiff < 0) */ {
19576404edcSAsim Jamshed 		/* Shrink the buffer */
19676404edcSAsim Jamshed 		tcpbufseg_t *seg;
19776404edcSAsim Jamshed 
19876404edcSAsim Jamshed 		segdiff *= -1;
19976404edcSAsim Jamshed 		int shrinkable = (rb->len - datalen) / UNITBUFSIZE;
20076404edcSAsim Jamshed 		int tobeshrank = segdiff;
20176404edcSAsim Jamshed 
20276404edcSAsim Jamshed 		rb->len -= (tobeshrank * UNITBUFSIZE);
20376404edcSAsim Jamshed 		if (rb->len) {
20476404edcSAsim Jamshed 			boff_t new_head = loff2boff(rb, data);
20576404edcSAsim Jamshed 			rb->corr = (rb->corr - (tobeshrank * UNITBUFSIZE) -
20676404edcSAsim Jamshed 						(new_head - head)) % rb->len;
20776404edcSAsim Jamshed 			if (rb->corr < 0)
20876404edcSAsim Jamshed 				rb->corr += rb->len;
20976404edcSAsim Jamshed 		}
21076404edcSAsim Jamshed 
21176404edcSAsim Jamshed 		if (shrinkable < segdiff) {
21276404edcSAsim Jamshed 			/* Mark some fragments as empty */
21376404edcSAsim Jamshed 			loff_t eh = data + rb->len +
21476404edcSAsim Jamshed 				(UNITBUFSIZE - (loff2boff(rb, data) % UNITBUFSIZE));
21576404edcSAsim Jamshed 			//loff_t et = eh + (segdiff - shrinkable) * UNITBUFSIZE;
21676404edcSAsim Jamshed 			loff_t et = data + datalen;
21776404edcSAsim Jamshed 
21876404edcSAsim Jamshed 			struct _tcpfrag_t *f = TAILQ_FIRST(&rb->frags), *new;
21976404edcSAsim Jamshed 
22076404edcSAsim Jamshed 			TAILQ_FOREACH(f, &rb->frags, link) {
22176404edcSAsim Jamshed 				if (f->tail <= eh)
22276404edcSAsim Jamshed 					continue;
22376404edcSAsim Jamshed 
22476404edcSAsim Jamshed 				if (f->tail > et) {
22576404edcSAsim Jamshed 					new = frags_new();
22676404edcSAsim Jamshed 					new->head = et;
22776404edcSAsim Jamshed 					new->tail = f->tail;
22876404edcSAsim Jamshed 					TAILQ_INSERT_AFTER(&rb->frags, f, new, link);
22976404edcSAsim Jamshed 
23076404edcSAsim Jamshed 					f->tail = et;
23176404edcSAsim Jamshed 				}
23276404edcSAsim Jamshed 
23376404edcSAsim Jamshed 				if (f->head >= eh && f->tail <= et) {
23476404edcSAsim Jamshed 					f->empty = true;
23576404edcSAsim Jamshed 					continue;
23676404edcSAsim Jamshed 				}
23776404edcSAsim Jamshed 
23876404edcSAsim Jamshed 				if (f->head < eh) {
23976404edcSAsim Jamshed 					new = frags_new();
24076404edcSAsim Jamshed 					new->head = eh;
24176404edcSAsim Jamshed 					new->tail = f->tail;
24276404edcSAsim Jamshed 					TAILQ_INSERT_AFTER(&rb->frags, f, new, link);
24376404edcSAsim Jamshed 
24476404edcSAsim Jamshed 					f->tail = eh;
24576404edcSAsim Jamshed 					continue;
24676404edcSAsim Jamshed 				}
24776404edcSAsim Jamshed 			}
24876404edcSAsim Jamshed 
24976404edcSAsim Jamshed 			/* shrink the buffer */
25076404edcSAsim Jamshed 			int skip = rb->len / UNITBUFSIZE;
25176404edcSAsim Jamshed 			for (seg = headseg; seg; ) {
25276404edcSAsim Jamshed 				if (skip-- <= 0) {
25376404edcSAsim Jamshed 					TAILQ_REMOVE(&rb->bufsegs, seg, link);
25476404edcSAsim Jamshed 					bufseg_del(rb->mp, seg);
25576404edcSAsim Jamshed 				}
25676404edcSAsim Jamshed 				seg = TAILQ_LOOP_NEXT(&rb->bufsegs, blist, tailseg, link);
25776404edcSAsim Jamshed 				if (seg == headseg)
25876404edcSAsim Jamshed 					break;
25976404edcSAsim Jamshed 			}
26076404edcSAsim Jamshed 		} else {
26176404edcSAsim Jamshed 			while (tobeshrank &&
26276404edcSAsim Jamshed 					(seg = TAILQ_LOOP_NEXT(&rb->bufsegs, blist, tailseg, link))
26376404edcSAsim Jamshed 					!= headseg) {
26476404edcSAsim Jamshed 				TAILQ_REMOVE(&rb->bufsegs, seg, link);
26576404edcSAsim Jamshed 				bufseg_del(rb->mp, seg);
26676404edcSAsim Jamshed 				tobeshrank--;
26776404edcSAsim Jamshed 			}
26876404edcSAsim Jamshed 			if (tobeshrank) {
26976404edcSAsim Jamshed 				assert(tobeshrank == 1);
27076404edcSAsim Jamshed 				assert((tail % UNITBUFSIZE) < (head % UNITBUFSIZE));
27176404edcSAsim Jamshed 				memcpy(&tailseg->buf[head % UNITBUFSIZE],
27276404edcSAsim Jamshed 						&headseg->buf[head % UNITBUFSIZE],
27376404edcSAsim Jamshed 						UNITBUFSIZE - (head % UNITBUFSIZE));
27476404edcSAsim Jamshed 				TAILQ_REMOVE(&rb->bufsegs, headseg, link);
27576404edcSAsim Jamshed 				bufseg_del(rb->mp, headseg);
27676404edcSAsim Jamshed 				headseg = tailseg;
27776404edcSAsim Jamshed 				tobeshrank = 0;
27876404edcSAsim Jamshed 			}
27976404edcSAsim Jamshed 		}
28076404edcSAsim Jamshed 	}
28176404edcSAsim Jamshed 
28276404edcSAsim Jamshed 	return 0;
28376404edcSAsim Jamshed }
28476404edcSAsim Jamshed /*--------------------------------------------------------------------------*/
28576404edcSAsim Jamshed /* buf_read() and buf_write() are highly symmetic, so use macro for function
28676404edcSAsim Jamshed  * definition to ease code maintenance. */
28776404edcSAsim Jamshed 
28876404edcSAsim Jamshed /* TODO: We do not have tailing anymore. simplify these functions */
28976404edcSAsim Jamshed 
29076404edcSAsim Jamshed #define MEMCPY_FOR_read(a, b, len) memcpy(a, b, len)
29176404edcSAsim Jamshed #define MEMCPY_FOR_write(a, b, len) memcpy(b, a, len)
29276404edcSAsim Jamshed 
29376404edcSAsim Jamshed #define FUNCDEF_BUF_RW(rw) \
29476404edcSAsim Jamshed static inline void \
29576404edcSAsim Jamshed buf_##rw(tcprb_t *rb, uint8_t *buf, int len, loff_t off) \
29676404edcSAsim Jamshed { \
29776404edcSAsim Jamshed 	tcpbufseg_t *bufseg = NULL; \
29876404edcSAsim Jamshed  \
29976404edcSAsim Jamshed 	assert(rb); \
30076404edcSAsim Jamshed  \
30176404edcSAsim Jamshed 	boff_t from = loff2boff(rb, off); \
30276404edcSAsim Jamshed 	boff_t to = loff2boff(rb, off + len); \
30376404edcSAsim Jamshed 	tcpbufseg_t *bufseg_from = buf_getbuf(rb, from); \
30476404edcSAsim Jamshed 	tcpbufseg_t *bufseg_to = buf_getbuf(rb, to); \
30576404edcSAsim Jamshed  \
30676404edcSAsim Jamshed 	if (from > to) { \
30776404edcSAsim Jamshed 		off = UNITBUFSIZE - (from % UNITBUFSIZE); \
30876404edcSAsim Jamshed 		MEMCPY_FOR_##rw(&buf[0], &bufseg_from->buf[from % UNITBUFSIZE], off); \
30976404edcSAsim Jamshed 		for (bufseg = buf_next(rb, bufseg_from); \
31076404edcSAsim Jamshed 			 bufseg && (bufseg != bufseg_to); \
31176404edcSAsim Jamshed 			 bufseg = buf_next(rb, bufseg)) { \
31276404edcSAsim Jamshed 			MEMCPY_FOR_##rw(&buf[off], &bufseg->buf[0], UNITBUFSIZE); \
31376404edcSAsim Jamshed 			off += UNITBUFSIZE; \
31476404edcSAsim Jamshed 		} \
31576404edcSAsim Jamshed 		for (bufseg = buf_first(rb); \
31676404edcSAsim Jamshed 			 bufseg && (bufseg != bufseg_to); \
31776404edcSAsim Jamshed 			 bufseg = buf_next(rb, bufseg)) { \
31876404edcSAsim Jamshed 			MEMCPY_FOR_##rw(&buf[off], &bufseg->buf[0], UNITBUFSIZE); \
31976404edcSAsim Jamshed 			off += UNITBUFSIZE; \
32076404edcSAsim Jamshed 		} \
32176404edcSAsim Jamshed 		MEMCPY_FOR_##rw(&buf[off], &bufseg_to->buf[0], to % UNITBUFSIZE); \
32276404edcSAsim Jamshed 	} else if (bufseg_from == bufseg_to) { \
32376404edcSAsim Jamshed 		MEMCPY_FOR_##rw(&buf[0], &bufseg_from->buf[from % UNITBUFSIZE], len); \
32476404edcSAsim Jamshed 	} else { \
32576404edcSAsim Jamshed 		off = UNITBUFSIZE - (from % UNITBUFSIZE); \
32676404edcSAsim Jamshed 		MEMCPY_FOR_##rw(&buf[0], &bufseg_from->buf[from % UNITBUFSIZE], off); \
32776404edcSAsim Jamshed 		for (bufseg = buf_next(rb, bufseg_from); \
32876404edcSAsim Jamshed 			 bufseg && (bufseg != bufseg_to); \
32976404edcSAsim Jamshed 			 bufseg = buf_next(rb, bufseg)) { \
33076404edcSAsim Jamshed 			MEMCPY_FOR_##rw(&buf[off], &bufseg->buf[0], UNITBUFSIZE); \
33176404edcSAsim Jamshed 			off += UNITBUFSIZE; \
33276404edcSAsim Jamshed 		} \
33376404edcSAsim Jamshed 		MEMCPY_FOR_##rw(&buf[off], &bufseg_to->buf[0], to % UNITBUFSIZE); \
33476404edcSAsim Jamshed 	} \
33576404edcSAsim Jamshed }
33676404edcSAsim Jamshed 
33776404edcSAsim Jamshed FUNCDEF_BUF_RW(read)
FUNCDEF_BUF_RW(write)33876404edcSAsim Jamshed FUNCDEF_BUF_RW(write)
33976404edcSAsim Jamshed /* -------------------------------------------------------------------------- */
34076404edcSAsim Jamshed /* Public */
34176404edcSAsim Jamshed /* -------------------------------------------------------------------------- */
34276404edcSAsim Jamshed 
34376404edcSAsim Jamshed inline loff_t
34476404edcSAsim Jamshed seq2loff(tcprb_t *rb, uint32_t seq, uint32_t isn)
34576404edcSAsim Jamshed {
34676404edcSAsim Jamshed 	loff_t off = seq - isn;
34776404edcSAsim Jamshed 
34876404edcSAsim Jamshed 	while (off < rb->head)
34976404edcSAsim Jamshed 		off += 0x100000000;
35076404edcSAsim Jamshed 
35176404edcSAsim Jamshed 	return off;
35276404edcSAsim Jamshed }
35376404edcSAsim Jamshed /*--------------------------------------------------------------------------*/
35476404edcSAsim Jamshed inline tcprb_t *
tcprb_new(mem_pool_t mp,int len,unsigned buf_mgmt)35576404edcSAsim Jamshed tcprb_new(mem_pool_t mp, int len, unsigned buf_mgmt)
35676404edcSAsim Jamshed {
35776404edcSAsim Jamshed 	tcprb_t *rb;
35876404edcSAsim Jamshed 
35976404edcSAsim Jamshed 	if (len % UNITBUFSIZE || len < 2)
36076404edcSAsim Jamshed 		return NULL;
36176404edcSAsim Jamshed 
36276404edcSAsim Jamshed 	if (!(rb = calloc(sizeof(tcprb_t), 1)))
36376404edcSAsim Jamshed 		return NULL;
36476404edcSAsim Jamshed 
36576404edcSAsim Jamshed 	TAILQ_INIT(&rb->bufsegs);
36676404edcSAsim Jamshed 	rb->lbufsegs = ((len - 1) / UNITBUFSIZE) + 1;
36776404edcSAsim Jamshed 
36876404edcSAsim Jamshed #if 0
36976404edcSAsim Jamshed 	int i;
37076404edcSAsim Jamshed 	for (i = 0; i < rb->lbufsegs; i++) {
37176404edcSAsim Jamshed 		tcpbufseg_t *bufseg = bufseg_new(mp);
37276404edcSAsim Jamshed 		if (!bufseg) {
37376404edcSAsim Jamshed 			TAILQ_FOREACH(bufseg, &rb->bufsegs, link)
37476404edcSAsim Jamshed 				bufseg_del(mp, bufseg);
37576404edcSAsim Jamshed 			FREE(rb);
37676404edcSAsim Jamshed 			return NULL;
37776404edcSAsim Jamshed 		}
37876404edcSAsim Jamshed 		TAILQ_INSERT_TAIL(&rb->bufsegs, bufseg, link);
37976404edcSAsim Jamshed 	}
38076404edcSAsim Jamshed #endif
38176404edcSAsim Jamshed 
38276404edcSAsim Jamshed 	rb->buf_mgmt = buf_mgmt;
38376404edcSAsim Jamshed 	rb->mp = mp;
38476404edcSAsim Jamshed 	rb->len = rb->metalen = len;
38576404edcSAsim Jamshed 	TAILQ_INIT(&rb->frags);
38676404edcSAsim Jamshed 
38776404edcSAsim Jamshed 	return rb;
38876404edcSAsim Jamshed }
38976404edcSAsim Jamshed /*--------------------------------------------------------------------------*/
39076404edcSAsim Jamshed inline int
tcprb_del(tcprb_t * rb)39176404edcSAsim Jamshed tcprb_del(tcprb_t *rb)
39276404edcSAsim Jamshed {
39376404edcSAsim Jamshed 	struct _tcpbufseg_t *bwalk, *bnext;
39476404edcSAsim Jamshed 	struct _tcpfrag_t *fwalk, *fnext;
39576404edcSAsim Jamshed 
39676404edcSAsim Jamshed 	for (bwalk = TAILQ_FIRST(&rb->bufsegs); bwalk; bwalk = bnext) {
39776404edcSAsim Jamshed 		bnext = TAILQ_NEXT(bwalk, link);
39876404edcSAsim Jamshed 		bufseg_del(rb->mp, bwalk);
39976404edcSAsim Jamshed 	}
40076404edcSAsim Jamshed 
40176404edcSAsim Jamshed 	for (fwalk = TAILQ_FIRST(&rb->frags); fwalk; fwalk = fnext) {
40276404edcSAsim Jamshed 		fnext = TAILQ_NEXT(fwalk, link);
40376404edcSAsim Jamshed 		frags_del(fwalk);
40476404edcSAsim Jamshed 	}
40576404edcSAsim Jamshed 
40676404edcSAsim Jamshed 	FREE(rb);
40776404edcSAsim Jamshed 
40876404edcSAsim Jamshed 	return 0;
40976404edcSAsim Jamshed }
41076404edcSAsim Jamshed /*--------------------------------------------------------------------------*/
41176404edcSAsim Jamshed inline int
tcprb_setpile(tcprb_t * rb,loff_t new)41276404edcSAsim Jamshed tcprb_setpile(tcprb_t *rb, loff_t new)
41376404edcSAsim Jamshed {
41476404edcSAsim Jamshed 	if (!rb || new > (rb->head + rb->len) || new < rb->head)
41576404edcSAsim Jamshed 		return -1;
41676404edcSAsim Jamshed 
41776404edcSAsim Jamshed 	tcpfrag_t *cf = TAILQ_FIRST(&rb->frags); /* contiguous buffer seg. */
41876404edcSAsim Jamshed 
41976404edcSAsim Jamshed 	if (!cf || (cf->head != rb->head)) {
42076404edcSAsim Jamshed 		/* No contiguous buffer seg. */
42176404edcSAsim Jamshed 		assert(rb->pile == rb->head);
42276404edcSAsim Jamshed 		return -1;
42376404edcSAsim Jamshed 	}
42476404edcSAsim Jamshed 
42576404edcSAsim Jamshed 	if (new > cf->tail)
42676404edcSAsim Jamshed 		return -1;
42776404edcSAsim Jamshed 
42876404edcSAsim Jamshed 	rb->pile = new;
42976404edcSAsim Jamshed 
43076404edcSAsim Jamshed 	return 0;
43176404edcSAsim Jamshed }
43276404edcSAsim Jamshed /*--------------------------------------------------------------------------*/
43376404edcSAsim Jamshed inline int
tcprb_cflen(tcprb_t * rb)43476404edcSAsim Jamshed tcprb_cflen(tcprb_t *rb)
43576404edcSAsim Jamshed {
43676404edcSAsim Jamshed 	tcpfrag_t *cf = TAILQ_FIRST(&rb->frags); /* contiguous buffer seg. */
43776404edcSAsim Jamshed 
43876404edcSAsim Jamshed 	if (!cf || (cf->head != rb->head))
43976404edcSAsim Jamshed 		/* No contiguous buffer seg. to taverse */
44076404edcSAsim Jamshed 		return 0;
44176404edcSAsim Jamshed 
44276404edcSAsim Jamshed 	int cflen = cf->tail - rb->pile; /* length of cf */
44376404edcSAsim Jamshed 
44476404edcSAsim Jamshed 	assert(cflen >= 0);
44576404edcSAsim Jamshed 
44676404edcSAsim Jamshed 	return cflen;
44776404edcSAsim Jamshed }
44876404edcSAsim Jamshed /*--------------------------------------------------------------------------*/
44976404edcSAsim Jamshed inline int
tcprb_ffhead(tcprb_t * rb,int len)45076404edcSAsim Jamshed tcprb_ffhead(tcprb_t *rb, int len)
45176404edcSAsim Jamshed {
45276404edcSAsim Jamshed 	if (!rb || len < 0)
45376404edcSAsim Jamshed 		return 0;
45476404edcSAsim Jamshed 	else if (len == 0)
45576404edcSAsim Jamshed 		return 0;
45676404edcSAsim Jamshed 
45776404edcSAsim Jamshed 	tcpfrag_t *cf = TAILQ_FIRST(&rb->frags); /* contiguous buffer seg. */
45876404edcSAsim Jamshed 
45976404edcSAsim Jamshed 	if (!cf || (cf->head != rb->head))
46076404edcSAsim Jamshed 		/* No contiguous buffer seg. to taverse */
46176404edcSAsim Jamshed 		return 0;
46276404edcSAsim Jamshed 
46376404edcSAsim Jamshed 	int cflen = cf->tail - cf->head; /* length of cf */
46476404edcSAsim Jamshed 	assert(cflen > 0);
46576404edcSAsim Jamshed 
46676404edcSAsim Jamshed 	int ff = MIN(len, cflen);
46776404edcSAsim Jamshed 	ff = MIN(ff, rb->pile - rb->head); /* head cannot go further than pile */
46876404edcSAsim Jamshed 
46976404edcSAsim Jamshed 	if (cflen == ff) {
47076404edcSAsim Jamshed 		/* Fast forward entire contiguous segment */
47176404edcSAsim Jamshed 		TAILQ_REMOVE(&rb->frags, cf, link);
47276404edcSAsim Jamshed 		frags_del(cf);
47376404edcSAsim Jamshed 	} else {
47476404edcSAsim Jamshed 		cf->head += ff;
47576404edcSAsim Jamshed 	}
47676404edcSAsim Jamshed 
47776404edcSAsim Jamshed 	rb->head += ff;
47876404edcSAsim Jamshed 
47976404edcSAsim Jamshed 	return ff;
48076404edcSAsim Jamshed }
48176404edcSAsim Jamshed /*--------------------------------------------------------------------------*/
482*05e3289cSYoungGyoun /* return the number of bytes that would be fast forwarded */
483*05e3289cSYoungGyoun inline int
tcprb_fflen(tcprb_t * rb,uint8_t * buf,int len,loff_t off)484*05e3289cSYoungGyoun tcprb_fflen(tcprb_t *rb, uint8_t *buf, int len, loff_t off)
485*05e3289cSYoungGyoun {
486*05e3289cSYoungGyoun 	if (!rb || !buf || len < 0 ||
487*05e3289cSYoungGyoun 		off < rb->head || off >= rb->pile + rb->metalen)
488*05e3289cSYoungGyoun 		return -1;
489*05e3289cSYoungGyoun 	/* nothing to write or already written */
490*05e3289cSYoungGyoun 	else if (len == 0 || off + len < rb->pile)
491*05e3289cSYoungGyoun 		return 0;
492*05e3289cSYoungGyoun 
493*05e3289cSYoungGyoun 	int ff = (off + len) - (rb->head + MIN(rb->len, rb->metalen));
494*05e3289cSYoungGyoun 	if (ff <= 0)
495*05e3289cSYoungGyoun 		return 0;
496*05e3289cSYoungGyoun 
497*05e3289cSYoungGyoun 	tcpfrag_t *cf = TAILQ_FIRST(&rb->frags); /* contiguous buffer seg. */
498*05e3289cSYoungGyoun 
499*05e3289cSYoungGyoun 	if (!cf || (cf->head != rb->head))
500*05e3289cSYoungGyoun 		/* No contiguous buffer seg. to traverse */
501*05e3289cSYoungGyoun 		return 0;
502*05e3289cSYoungGyoun 
503*05e3289cSYoungGyoun 	int cflen = cf->tail - cf->head; /* length of cf */
504*05e3289cSYoungGyoun 	assert(cflen > 0);
505*05e3289cSYoungGyoun 
506*05e3289cSYoungGyoun 	int fflen = MIN(len, cflen);
507*05e3289cSYoungGyoun 	fflen = MIN(ff, rb->pile - rb->head); /* head cannot go further than pile */
508*05e3289cSYoungGyoun 
509*05e3289cSYoungGyoun 	return fflen;
510*05e3289cSYoungGyoun }
511*05e3289cSYoungGyoun /*--------------------------------------------------------------------------*/
51276404edcSAsim Jamshed static inline int
tcprb_get_datalen(tcprb_t * rb)51376404edcSAsim Jamshed tcprb_get_datalen(tcprb_t *rb)
51476404edcSAsim Jamshed {
51576404edcSAsim Jamshed 	tcpfrag_t *lastfrag = TAILQ_LAST(&rb->frags, flist);
51676404edcSAsim Jamshed 	return lastfrag ? (int)(lastfrag->tail - rb->head) : 0;
51776404edcSAsim Jamshed }
51876404edcSAsim Jamshed /*--------------------------------------------------------------------------*/
51976404edcSAsim Jamshed inline int
tcprb_resize_meta(tcprb_t * rb,int len)52076404edcSAsim Jamshed tcprb_resize_meta(tcprb_t *rb, int len)
52176404edcSAsim Jamshed {
52276404edcSAsim Jamshed #ifdef DISABLE_DYN_RESIZE
52376404edcSAsim Jamshed 	assert(len == 0);
52476404edcSAsim Jamshed 
52576404edcSAsim Jamshed 	struct _tcpfrag_t *fwalk, *fnext;
52676404edcSAsim Jamshed 
52776404edcSAsim Jamshed 	rb->metalen = 0;
52876404edcSAsim Jamshed 
52976404edcSAsim Jamshed 	for (fwalk = TAILQ_FIRST(&rb->frags); fwalk; fwalk = fnext) {
53076404edcSAsim Jamshed 		fnext = TAILQ_NEXT(fwalk, link);
53176404edcSAsim Jamshed 		TAILQ_REMOVE(&rb->frags, fwalk, link);
53276404edcSAsim Jamshed 		frags_del(fwalk);
53376404edcSAsim Jamshed 	}
53476404edcSAsim Jamshed 
53576404edcSAsim Jamshed 	return 0;
53676404edcSAsim Jamshed #else
53776404edcSAsim Jamshed 	int diff, ff, datalen;
53876404edcSAsim Jamshed 
53976404edcSAsim Jamshed 	if ((diff = len - rb->metalen) > 0) {
54076404edcSAsim Jamshed 		rb->metalen = len;
54176404edcSAsim Jamshed 	} else if (diff < 0) {
54276404edcSAsim Jamshed 		ff = diff - (rb->len - tcprb_get_datalen(rb));
54376404edcSAsim Jamshed 		tcprb_ffhead(rb, ff);
54476404edcSAsim Jamshed 		datalen = tcprb_get_datalen(rb);
54576404edcSAsim Jamshed 		rb->metalen = MAX(datalen, len);
54676404edcSAsim Jamshed 	}
54776404edcSAsim Jamshed 
54876404edcSAsim Jamshed 	return rb->metalen;
54976404edcSAsim Jamshed #endif
55076404edcSAsim Jamshed }
55176404edcSAsim Jamshed /*--------------------------------------------------------------------------*/
55276404edcSAsim Jamshed inline int
tcprb_setpolicy(tcprb_t * rb,uint8_t policy)553a834ea89SAsim Jamshed tcprb_setpolicy(tcprb_t *rb, uint8_t policy)
554a834ea89SAsim Jamshed {
555a834ea89SAsim Jamshed 	if (policy >= MOS_OVERLAP_CNT)
556a834ea89SAsim Jamshed 		return -1;
557a834ea89SAsim Jamshed 
558a834ea89SAsim Jamshed 	rb->overlap = policy;
559a834ea89SAsim Jamshed 	return 0;
560a834ea89SAsim Jamshed }
561a834ea89SAsim Jamshed /*--------------------------------------------------------------------------*/
562a834ea89SAsim Jamshed inline int
tcprb_resize(tcprb_t * rb,int len)56376404edcSAsim Jamshed tcprb_resize(tcprb_t *rb, int len)
56476404edcSAsim Jamshed {
56576404edcSAsim Jamshed #ifdef DISABLE_DYN_RESIZE
56676404edcSAsim Jamshed 	assert(len == 0);
56776404edcSAsim Jamshed 
56876404edcSAsim Jamshed 	struct _tcpbufseg_t *bwalk, *bnext;
56976404edcSAsim Jamshed 	struct _tcpfrag_t *fwalk, *fnext;
57076404edcSAsim Jamshed 
57176404edcSAsim Jamshed 	rb->metalen = 0;
57276404edcSAsim Jamshed 	rb->len = 0;
57376404edcSAsim Jamshed 
57476404edcSAsim Jamshed 	for (bwalk = TAILQ_FIRST(&rb->bufsegs); bwalk; bwalk = bnext) {
57576404edcSAsim Jamshed 		bnext = TAILQ_NEXT(bwalk, link);
57676404edcSAsim Jamshed 		TAILQ_REMOVE(&rb->bufsegs, bwalk, link);
57776404edcSAsim Jamshed 		bufseg_del(rb->mp, bwalk);
57876404edcSAsim Jamshed 	}
57976404edcSAsim Jamshed 
58076404edcSAsim Jamshed 	for (fwalk = TAILQ_FIRST(&rb->frags); fwalk; fwalk = fnext) {
58176404edcSAsim Jamshed 		fnext = TAILQ_NEXT(fwalk, link);
58276404edcSAsim Jamshed 		TAILQ_REMOVE(&rb->frags, fwalk, link);
58376404edcSAsim Jamshed 		frags_del(fwalk);
58476404edcSAsim Jamshed 	}
58576404edcSAsim Jamshed 
58676404edcSAsim Jamshed 	return 0;
58776404edcSAsim Jamshed #else
58876404edcSAsim Jamshed 	int diff, ff;
58976404edcSAsim Jamshed 
59076404edcSAsim Jamshed 	if (len % UNITBUFSIZE)
59176404edcSAsim Jamshed 		return -1;
59276404edcSAsim Jamshed 	else if (len == rb->len)
59376404edcSAsim Jamshed 		return 0;
59476404edcSAsim Jamshed 
59576404edcSAsim Jamshed 	if ((diff = rb->len - len) > 0 && /* shrinking */
59676404edcSAsim Jamshed 		(ff = diff - (rb->len - tcprb_get_datalen(rb))))
59776404edcSAsim Jamshed 		tcprb_ffhead(rb, ff);
59876404edcSAsim Jamshed 
59976404edcSAsim Jamshed 	return buf_try_resize(rb, len, rb->head,
60076404edcSAsim Jamshed 						  tcprb_get_datalen(rb));
60176404edcSAsim Jamshed #endif
60276404edcSAsim Jamshed }
60376404edcSAsim Jamshed /*--------------------------------------------------------------------------*/
60476404edcSAsim Jamshed inline int
tcprb_ppeek(tcprb_t * rb,uint8_t * buf,int len,loff_t off)60576404edcSAsim Jamshed tcprb_ppeek(tcprb_t *rb, uint8_t *buf, int len, loff_t off)
60676404edcSAsim Jamshed {
60776404edcSAsim Jamshed 	struct _tcpfrag_t *f;
60876404edcSAsim Jamshed 
60976404edcSAsim Jamshed 	if (!rb || rb->buf_mgmt != BUFMGMT_FULL || !buf || len < 0)
61076404edcSAsim Jamshed 		return -1;
61176404edcSAsim Jamshed 	else if (len == 0)
61276404edcSAsim Jamshed 		return 0;
61376404edcSAsim Jamshed 
61476404edcSAsim Jamshed 	TAILQ_FOREACH(f, &rb->frags, link)
61576404edcSAsim Jamshed 		if (off >= f->head && off < f->tail) {
61676404edcSAsim Jamshed 			if (f->empty)
61776404edcSAsim Jamshed 				f = NULL;
61876404edcSAsim Jamshed 			break;
61976404edcSAsim Jamshed 		}
62076404edcSAsim Jamshed 
62176404edcSAsim Jamshed 	if (!f) /* No proper fragment found */
62276404edcSAsim Jamshed 		return -1;
62376404edcSAsim Jamshed 
62476404edcSAsim Jamshed 	int plen = MIN(len, f->tail - off);
62576404edcSAsim Jamshed 
62676404edcSAsim Jamshed 	buf_read(rb, buf, plen, off);
62776404edcSAsim Jamshed 
62876404edcSAsim Jamshed 	return plen;
62976404edcSAsim Jamshed }
63076404edcSAsim Jamshed /*--------------------------------------------------------------------------*/
63176404edcSAsim Jamshed inline int
tcprb_pwrite(tcprb_t * rb,uint8_t * buf,int len,loff_t off)63276404edcSAsim Jamshed tcprb_pwrite(tcprb_t *rb, uint8_t *buf, int len, loff_t off)
63376404edcSAsim Jamshed {
63476404edcSAsim Jamshed 	int ff, olen;
63576404edcSAsim Jamshed 	loff_t efhead = -1;      /* head of empty fragment */
63676404edcSAsim Jamshed 	int eflen = 0;           /* length of empty fragment */
63776404edcSAsim Jamshed 
638*05e3289cSYoungGyoun 	/*
639*05e3289cSYoungGyoun 	 * we don't raise MOS_ON_ERROR anymore here,
640*05e3289cSYoungGyoun 	 * (out of receive buffer case is handled at ProcessTCPPayload())
641*05e3289cSYoungGyoun 	 */
64276404edcSAsim Jamshed 	if (!rb || !buf || len < 0 ||
64376404edcSAsim Jamshed 		off < rb->head || off >= rb->pile + rb->metalen)
64476404edcSAsim Jamshed 		return -1;
64576404edcSAsim Jamshed 	else if (len == 0)
64676404edcSAsim Jamshed 		return 0;
64776404edcSAsim Jamshed 	else if (off + len < rb->pile) /* already written */
64876404edcSAsim Jamshed 		return len;
64976404edcSAsim Jamshed 
650*05e3289cSYoungGyoun 	/* check whether we should move its head offset (fast forward) */
65176404edcSAsim Jamshed 	olen = len;
65276404edcSAsim Jamshed 	if ((ff = (off + len) - (rb->head + MIN(rb->len, rb->metalen))) > 0)
65376404edcSAsim Jamshed 		len -= ff - tcprb_ffhead(rb, ff);
65476404edcSAsim Jamshed 	if (rb->metalen > rb->len)
65576404edcSAsim Jamshed 		eflen = MIN(olen - len, rb->metalen - rb->len);
65676404edcSAsim Jamshed 	if (eflen)
65776404edcSAsim Jamshed 		efhead = off + len;
65876404edcSAsim Jamshed 
65976404edcSAsim Jamshed 	/* write data */
66076404edcSAsim Jamshed 	struct _tcpfrag_t *f = TAILQ_FIRST(&rb->frags), *fnext;
66176404edcSAsim Jamshed 	int uoff = 0; /* offset of `buf` */
66276404edcSAsim Jamshed 
66376404edcSAsim Jamshed 	/* head: position of first byte of the fragment
66476404edcSAsim Jamshed 	 * tail: head + length of the fragment */
66576404edcSAsim Jamshed 	while (uoff < len) {
66676404edcSAsim Jamshed 		bool skip = false;
66776404edcSAsim Jamshed 		int wrlen = 0; /* length to be written */
66876404edcSAsim Jamshed 
66976404edcSAsim Jamshed 		while (f) {
67076404edcSAsim Jamshed 			struct _tcpfrag_t *ef, *nef;
67176404edcSAsim Jamshed 			fnext = TAILQ_NEXT(f, link);
67276404edcSAsim Jamshed 
67376404edcSAsim Jamshed 			if (f->empty) {
67476404edcSAsim Jamshed 				/* skip empty fragment */
67576404edcSAsim Jamshed 				f = fnext;
67676404edcSAsim Jamshed 				continue;
67776404edcSAsim Jamshed 			}
67876404edcSAsim Jamshed 
67976404edcSAsim Jamshed 			if (f->head <= off + uoff) {
68076404edcSAsim Jamshed 				if (f->tail > off + uoff) {
68176404edcSAsim Jamshed 					skip = true;
68276404edcSAsim Jamshed 					wrlen = f->tail - (off + uoff);
68376404edcSAsim Jamshed 					break;
68476404edcSAsim Jamshed 				} else if (f->tail == off + uoff) {
68576404edcSAsim Jamshed 					skip = false;
68676404edcSAsim Jamshed 
68776404edcSAsim Jamshed 					/* shrink empty fragment */
68876404edcSAsim Jamshed 					for (ef = fnext;
68976404edcSAsim Jamshed 						 ef && ef->empty && ef->head < f->tail + len - uoff;
69076404edcSAsim Jamshed 						 ef = nef) {
69176404edcSAsim Jamshed 						nef = TAILQ_NEXT(ef, link);
69276404edcSAsim Jamshed 
69376404edcSAsim Jamshed 						if (ef->tail <= f->tail + len - uoff) {
69476404edcSAsim Jamshed 							TAILQ_REMOVE(&rb->frags, ef, link);
69576404edcSAsim Jamshed 						} else {
69676404edcSAsim Jamshed 							ef->head = f->tail + len - uoff;
69776404edcSAsim Jamshed 							/* break is not necessary, but for early escape */
69876404edcSAsim Jamshed 							break;
69976404edcSAsim Jamshed 						}
70076404edcSAsim Jamshed 					}
70176404edcSAsim Jamshed 					fnext = TAILQ_NEXT(f, link);
70276404edcSAsim Jamshed 
70376404edcSAsim Jamshed 					wrlen = fnext ? MIN(fnext->head - (off + uoff), len - uoff)
70476404edcSAsim Jamshed 								  : len - uoff;
70576404edcSAsim Jamshed 					f->tail += wrlen;
70676404edcSAsim Jamshed 					if (fnext && (f->tail == fnext->head)) {
70776404edcSAsim Jamshed 						/* merge 'f' and 'fnext' */
70876404edcSAsim Jamshed 						f->tail = fnext->tail;
70976404edcSAsim Jamshed 						TAILQ_REMOVE(&rb->frags, fnext, link);
71076404edcSAsim Jamshed 						frags_del(fnext);
71176404edcSAsim Jamshed 					}
71276404edcSAsim Jamshed 					break;
71376404edcSAsim Jamshed 				}
71476404edcSAsim Jamshed 			} else if (f->head <= off + len) {
71576404edcSAsim Jamshed 				skip = false;
71676404edcSAsim Jamshed 				wrlen = MIN(f->head - (off + uoff), len - uoff);
71776404edcSAsim Jamshed 				f->head -= wrlen;
71876404edcSAsim Jamshed 
71976404edcSAsim Jamshed 				/* shrink empty fragment */
72076404edcSAsim Jamshed 				for (ef = TAILQ_PREV(f, flist, link);
72176404edcSAsim Jamshed 					 ef && ef->empty && ef->tail < f->head;
72276404edcSAsim Jamshed 					 ef = nef) {
72376404edcSAsim Jamshed 					nef = TAILQ_PREV(ef, flist, link);
72476404edcSAsim Jamshed 
72576404edcSAsim Jamshed 					if (ef->head <= f->head) {
72676404edcSAsim Jamshed 						TAILQ_REMOVE(&rb->frags, ef, link);
72776404edcSAsim Jamshed 					} else {
72876404edcSAsim Jamshed 						ef->tail = f->head;
72976404edcSAsim Jamshed 						/* break is not necessary, but for early escape */
73076404edcSAsim Jamshed 						break;
73176404edcSAsim Jamshed 					}
73276404edcSAsim Jamshed 				}
73376404edcSAsim Jamshed 
73476404edcSAsim Jamshed 				break;
73576404edcSAsim Jamshed 			} else /* if (f->head > off + len) */ {
73676404edcSAsim Jamshed 				/* early escape */
73776404edcSAsim Jamshed 				f = NULL;
73876404edcSAsim Jamshed 				break;
73976404edcSAsim Jamshed 			}
74076404edcSAsim Jamshed 
74176404edcSAsim Jamshed 			f = fnext;
74276404edcSAsim Jamshed 		}
74376404edcSAsim Jamshed 
74476404edcSAsim Jamshed 		if (!f) {
74576404edcSAsim Jamshed 			struct _tcpfrag_t *new;
74676404edcSAsim Jamshed 
74776404edcSAsim Jamshed 			/* create new fragment and insert it into the list */
74876404edcSAsim Jamshed 			new = frags_new();
74976404edcSAsim Jamshed 
75076404edcSAsim Jamshed 			new->head = off;
75176404edcSAsim Jamshed 			new->tail = off + len;
75276404edcSAsim Jamshed 			wrlen = len;
75376404edcSAsim Jamshed 
75476404edcSAsim Jamshed 			frags_insert(rb, new);
75576404edcSAsim Jamshed 		}
75676404edcSAsim Jamshed 
75776404edcSAsim Jamshed 		/* copy data */
758a834ea89SAsim Jamshed 		if ((rb->overlap == MOS_OVERLAP_POLICY_LAST || !skip)
759a834ea89SAsim Jamshed 			&& rb->buf_mgmt)
76076404edcSAsim Jamshed 			buf_write(rb, &buf[uoff], wrlen, off + uoff);
76176404edcSAsim Jamshed 		uoff += wrlen;
76276404edcSAsim Jamshed 	}
76376404edcSAsim Jamshed 
76476404edcSAsim Jamshed 	/* Insert empty fragment if necessary */
76576404edcSAsim Jamshed 	if (eflen) {
76676404edcSAsim Jamshed 		assert(rb->metalen > rb->len);
76776404edcSAsim Jamshed 
76876404edcSAsim Jamshed 		struct _tcpfrag_t *new;
76976404edcSAsim Jamshed 
77076404edcSAsim Jamshed 		/* create new fragment and insert it into the list */
77176404edcSAsim Jamshed 		new = frags_new();
77276404edcSAsim Jamshed 
77376404edcSAsim Jamshed 		new->empty = true;
77476404edcSAsim Jamshed 		new->head = efhead;
77576404edcSAsim Jamshed 		new->tail = efhead + eflen;
77676404edcSAsim Jamshed 
77776404edcSAsim Jamshed 		frags_insert(rb, new);
77876404edcSAsim Jamshed 	}
77976404edcSAsim Jamshed 
78076404edcSAsim Jamshed 	return len;
78176404edcSAsim Jamshed }
78276404edcSAsim Jamshed /*--------------------------------------------------------------------------*/
78376404edcSAsim Jamshed #define PRT_CL_RST		"\x1b[0m"
78476404edcSAsim Jamshed #define PRT_FG_BLK		"\x1b[30m"
78576404edcSAsim Jamshed #define PRT_FG_RED		"\x1b[31m"
78676404edcSAsim Jamshed #define PRT_FG_GRN		"\x1b[32m"
78776404edcSAsim Jamshed #define PRT_FG_YEL		"\x1b[33m"
78876404edcSAsim Jamshed #define PRT_FG_BLU		"\x1b[34m"
78976404edcSAsim Jamshed #define PRT_FG_PUR		"\x1b[35m"
79076404edcSAsim Jamshed #define PRT_FG_CYN		"\x1b[36m"
79176404edcSAsim Jamshed #define PRT_FG_GRY		"\x1b[37m"
79276404edcSAsim Jamshed #define PRT_BG_BLK		"\x1b[40m"
79376404edcSAsim Jamshed #define PRT_BG_RED		"\x1b[41m"
79476404edcSAsim Jamshed #define PRT_BG_GRN		"\x1b[42m"
79576404edcSAsim Jamshed #define PRT_BG_YEL		"\x1b[43m"
79676404edcSAsim Jamshed #define PRT_BG_BLU		"\x1b[44m"
79776404edcSAsim Jamshed #define PRT_BG_PUR		"\x1b[45m"
79876404edcSAsim Jamshed #define PRT_BG_CYN		"\x1b[46m"
79976404edcSAsim Jamshed #define PRT_BG_GRY		"\x1b[47m"
80076404edcSAsim Jamshed /*--------------------------------------------------------------------------*/
80176404edcSAsim Jamshed inline void
tcprb_printfrags(struct _tcprb_t * rb)80276404edcSAsim Jamshed tcprb_printfrags(struct _tcprb_t *rb)
80376404edcSAsim Jamshed {
80476404edcSAsim Jamshed 	struct _tcpfrag_t *walk;
80576404edcSAsim Jamshed 
80676404edcSAsim Jamshed 	printf("frags: ");
80776404edcSAsim Jamshed 	TAILQ_FOREACH(walk, &rb->frags, link) {
80876404edcSAsim Jamshed 		printf("[%lu - %lu]:'", walk->head, walk->tail - 1);
80976404edcSAsim Jamshed #if 1
81076404edcSAsim Jamshed 		if (walk->empty)
81176404edcSAsim Jamshed 			printf("EMPTY");
81276404edcSAsim Jamshed 		else {
81376404edcSAsim Jamshed 			loff_t i;
81476404edcSAsim Jamshed 			for (i = walk->head; i < walk->tail; i++) {
81576404edcSAsim Jamshed 				tcpbufseg_t *bufseg;
81676404edcSAsim Jamshed 				boff_t j = loff2boff(rb, i);
81776404edcSAsim Jamshed 				bufseg = buf_getbuf(rb, j);
81876404edcSAsim Jamshed 				char c = bufseg->buf[j % UNITBUFSIZE];
81976404edcSAsim Jamshed 				if (isgraph(c))
82076404edcSAsim Jamshed 					printf("%c", c);
82176404edcSAsim Jamshed 				else {
82276404edcSAsim Jamshed 					printf(PRT_FG_BLU);
82376404edcSAsim Jamshed 					if (c == ' ')
82476404edcSAsim Jamshed 						printf(" ");
82576404edcSAsim Jamshed 					else if (c == '\0')
82676404edcSAsim Jamshed 						printf("0");
82776404edcSAsim Jamshed 					else if (c == '\r')
82876404edcSAsim Jamshed 						printf("R");
82976404edcSAsim Jamshed 					else if (c == '\n')
83076404edcSAsim Jamshed 						printf("N");
83176404edcSAsim Jamshed 					else if (c == '\t')
83276404edcSAsim Jamshed 						printf("T");
83376404edcSAsim Jamshed 					else
83476404edcSAsim Jamshed 						printf("?");
83576404edcSAsim Jamshed 					printf(PRT_CL_RST);
83676404edcSAsim Jamshed 				}
83776404edcSAsim Jamshed 			}
83876404edcSAsim Jamshed 		}
83976404edcSAsim Jamshed #endif
84076404edcSAsim Jamshed 		printf("' ");
84176404edcSAsim Jamshed 	}
84276404edcSAsim Jamshed 	printf("\n");
84376404edcSAsim Jamshed }
84476404edcSAsim Jamshed inline void
tcprb_printbufsegs(tcprb_t * rb)84576404edcSAsim Jamshed tcprb_printbufsegs(tcprb_t *rb)
84676404edcSAsim Jamshed {
84776404edcSAsim Jamshed 	struct _tcpbufseg_t *walk;
84876404edcSAsim Jamshed 
84976404edcSAsim Jamshed 	printf("bufsegs: ");
85076404edcSAsim Jamshed 	TAILQ_FOREACH(walk, &rb->bufsegs, link) {
85176404edcSAsim Jamshed 		printf("[%d]:'", walk->id);
85276404edcSAsim Jamshed #if 1
85376404edcSAsim Jamshed 		int j;
85476404edcSAsim Jamshed 		for (j = 0; j < UNITBUFSIZE; j++) {
85576404edcSAsim Jamshed 			char c = walk->buf[j];
85676404edcSAsim Jamshed 			if (isgraph(c))
85776404edcSAsim Jamshed 				printf("%c", c);
85876404edcSAsim Jamshed 			else {
85976404edcSAsim Jamshed 				printf(PRT_FG_BLU);
86076404edcSAsim Jamshed 				if (c == ' ')
86176404edcSAsim Jamshed 					printf(" ");
86276404edcSAsim Jamshed 				else if (c == '\0')
86376404edcSAsim Jamshed 					printf("0");
86476404edcSAsim Jamshed 				else if (c == '\r')
86576404edcSAsim Jamshed 					printf("R");
86676404edcSAsim Jamshed 				else if (c == '\n')
86776404edcSAsim Jamshed 					printf("N");
86876404edcSAsim Jamshed 				else if (c == '\t')
86976404edcSAsim Jamshed 					printf("T");
87076404edcSAsim Jamshed 				else
87176404edcSAsim Jamshed 					printf("?");
87276404edcSAsim Jamshed 				printf(PRT_CL_RST);
87376404edcSAsim Jamshed 			}
87476404edcSAsim Jamshed 		}
87576404edcSAsim Jamshed #endif
87676404edcSAsim Jamshed 		printf("' ");
87776404edcSAsim Jamshed 	}
87876404edcSAsim Jamshed 	printf("\n");
87976404edcSAsim Jamshed }
88076404edcSAsim Jamshed /*--------------------------------------------------------------------------*/
88176404edcSAsim Jamshed inline void
tcprb_printrb(struct _tcprb_t * rb)88276404edcSAsim Jamshed tcprb_printrb(struct _tcprb_t *rb)
88376404edcSAsim Jamshed {
88476404edcSAsim Jamshed 	printf("  rb: len: %d, meta: %d, "
88576404edcSAsim Jamshed 			"(head: %ld <= pile: %ld <= tail: %ld)\n  ",
88676404edcSAsim Jamshed 			rb->len, rb->metalen, rb->head, rb->pile, rb->head + rb->metalen);
88776404edcSAsim Jamshed 	tcprb_printfrags(rb);
88876404edcSAsim Jamshed 	tcprb_printbufsegs(rb);
88976404edcSAsim Jamshed 	printf("-------------------------------------------------\n");
89076404edcSAsim Jamshed }
89176404edcSAsim Jamshed /*--------------------------------------------------------------------------*/
892a834ea89SAsim Jamshed inline void
tcp_rb_overlapchk(mtcp_manager_t mtcp,struct pkt_ctx * pctx,struct tcp_stream * recvside_stream)893a834ea89SAsim Jamshed tcp_rb_overlapchk(mtcp_manager_t mtcp, struct pkt_ctx *pctx,
894a834ea89SAsim Jamshed 		    struct tcp_stream *recvside_stream)
895a834ea89SAsim Jamshed {
896a834ea89SAsim Jamshed #define DOESOVERLAP(a1, a2, b1, b2)				\
897a834ea89SAsim Jamshed 	((a1 != b2) && (a2 != b1) && ((a1 > b2) != (a2 > b1)))
898a834ea89SAsim Jamshed 
899a834ea89SAsim Jamshed 	/* Check whether this packet is retransmitted or not. */
900a834ea89SAsim Jamshed 	tcprb_t *rb;
901a834ea89SAsim Jamshed 	struct socket_map *walk;
902a834ea89SAsim Jamshed 	if (pctx->p.payloadlen > 0 && recvside_stream->rcvvar != NULL
903a834ea89SAsim Jamshed 	    && (rb = recvside_stream->rcvvar->rcvbuf) != NULL) {
904a834ea89SAsim Jamshed 		struct _tcpfrag_t *f;
905a834ea89SAsim Jamshed 		loff_t off = seq2loff(rb, pctx->p.seq, recvside_stream->rcvvar->irs + 1);
906a834ea89SAsim Jamshed 		TAILQ_FOREACH(f, &rb->frags, link)
907a834ea89SAsim Jamshed 			if (DOESOVERLAP(f->head, f->tail, off, off + pctx->p.payloadlen)) {
908a834ea89SAsim Jamshed 				/*
909a834ea89SAsim Jamshed 				 * call it immediately (before pkt payload is attached
910a834ea89SAsim Jamshed 				 * to the tcp ring buffer)
911a834ea89SAsim Jamshed 				 */
912*05e3289cSYoungGyoun 				if (recvside_stream->side == MOS_SIDE_CLI) {
913*05e3289cSYoungGyoun 					SOCKQ_FOREACH_REVERSE(walk, &recvside_stream->msocks) {
914*05e3289cSYoungGyoun 						HandleCallback(mtcp, MOS_HK_RCV, walk,
915*05e3289cSYoungGyoun 							       recvside_stream->side,
916*05e3289cSYoungGyoun 							       pctx, MOS_ON_REXMIT);
917*05e3289cSYoungGyoun 					} SOCKQ_FOREACH_END;
918*05e3289cSYoungGyoun 				} else { /* recvside_stream->side == MOS_SIDE_SVR */
919a834ea89SAsim Jamshed 					SOCKQ_FOREACH_START(walk, &recvside_stream->msocks) {
920a834ea89SAsim Jamshed 						HandleCallback(mtcp, MOS_HK_RCV, walk,
921a834ea89SAsim Jamshed 							       recvside_stream->side,
922a834ea89SAsim Jamshed 							       pctx, MOS_ON_REXMIT);
923a834ea89SAsim Jamshed 					} SOCKQ_FOREACH_END;
924*05e3289cSYoungGyoun 				}
925a834ea89SAsim Jamshed 				/* recvside_stream->cb_events |= MOS_ON_REXMIT; */
926a834ea89SAsim Jamshed 				TRACE_DBG("RETX!\n");
927a834ea89SAsim Jamshed 				break;
928a834ea89SAsim Jamshed 			}
929a834ea89SAsim Jamshed 	}
930a834ea89SAsim Jamshed }
931a834ea89SAsim Jamshed /*--------------------------------------------------------------------------*/
932