$Id: ns-233-dccp-1.patch 210 2008-05-13 03:43:55Z omehani $
Adaptation of the DCCP patch for ns-2.31 [0] to ns-2.33.
Olivier Mehani <olivier.mehani@nicta.com.au>.

[0] http://lifc.univ-fcomte.fr/~dedu/ns2/dccp-ns2.31.patch
====
diff -urNU5 ns-2.33/common/packet.h ns-2.33-dccp/common/packet.h
--- ns-2.33/common/packet.h	2008-04-01 13:00:25.000000000 +1100
+++ ns-2.33-dccp/common/packet.h	2008-05-05 17:24:47.000000000 +1000
@@ -177,12 +177,23 @@
 static const packet_t PT_HDLC = 59;
 
         // Bell Labs Traffic Trace Type (PackMime OL)
 static const packet_t PT_BLTRACE = 60;
 
+ 	// DCCP packets
+static const packet_t PT_DCCP = 61;
+static const packet_t PT_DCCP_REQ = 62;
+static const packet_t PT_DCCP_RESP = 63;
+static const packet_t PT_DCCP_ACK = 64;
+static const packet_t PT_DCCP_DATA = 65;
+static const packet_t PT_DCCP_DATAACK = 66;
+static const packet_t PT_DCCP_CLOSE  = 67;
+static const packet_t PT_DCCP_CLOSEREQ = 68;
+static const packet_t PT_DCCP_RESET = 69;
+ 	
         // insert new packet types here
-static packet_t       PT_NTYPE = 61; // This MUST be the LAST one
+static packet_t       PT_NTYPE = 70; // This MUST be the LAST one
 
 enum packetClass
 {
 	UNCLASSIFIED,
 	ROUTING,
@@ -375,10 +386,21 @@
 		name_[PT_XCP]="xcp";
 
 		// Bell Labs (PackMime OL)
 		name_[PT_BLTRACE]="BellLabsTrace";
 		
+		// DCCP
+		name_[PT_DCCP]="DCCP";
+		name_[PT_DCCP_REQ]="DCCP_Request";
+		name_[PT_DCCP_RESP]="DCCP_Response";
+		name_[PT_DCCP_ACK]="DCCP_Ack";
+		name_[PT_DCCP_DATA]="DCCP_Data";
+		name_[PT_DCCP_DATAACK]="DCCP_DataAck";
+		name_[PT_DCCP_CLOSE]="DCCP_Close";
+		name_[PT_DCCP_CLOSEREQ]="DCCP_CloseReq";
+		name_[PT_DCCP_RESET]="DCCP_Reset";
+
 		name_[PT_NTYPE]= "undefined";
 	}
 	static int addPacket(char *name);
 	static packet_t getType(const char *name)
 	{
@@ -695,15 +717,38 @@
 	if (n > 0) 
 		p->allocdata(n);
 	return (p);
 }
 
+#include "dccp/dccp_packets.h"
 
 inline void Packet::free(Packet* p)
 {
+	hdr_dccp *dccph;
 	if (p->fflag_) {
 		if (p->ref_count_ == 0) {
+
+			//free DCCP options on dropped packets
+			switch (HDR_CMN(p)->ptype_){
+			case PT_DCCP:
+			case PT_DCCP_REQ:
+			case PT_DCCP_RESP:
+			case PT_DCCP_ACK:
+			case PT_DCCP_DATA:
+			case PT_DCCP_DATAACK:
+			case PT_DCCP_CLOSE:
+			case PT_DCCP_CLOSEREQ:
+			case PT_DCCP_RESET:
+				dccph = hdr_dccp::access(p);
+				if (dccph->options_ != NULL){
+					delete (dccph->options_);
+				}
+				break;
+			default:
+				;
+			}
+
 			/*
 			 * A packet's uid may be < 0 (out of a event queue), or
 			 * == 0 (newed but never gets into the event queue.
 			 */
 			assert(p->uid_ <= 0);
@@ -722,13 +767,34 @@
 	}
 }
 
 inline Packet* Packet::copy() const
 {
-	
+	hdr_dccp *dccph, *dccph_p;
 	Packet* p = alloc();
 	memcpy(p->bits(), bits_, hdrlen_);
+
+	//copy DCCP options_, since it is a pointer
+	switch (HDR_CMN(this)->ptype_){
+	case PT_DCCP:
+	case PT_DCCP_REQ:
+	case PT_DCCP_RESP:
+	case PT_DCCP_ACK:
+	case PT_DCCP_DATA:
+	case PT_DCCP_DATAACK:
+	case PT_DCCP_CLOSE:
+	case PT_DCCP_CLOSEREQ:
+	case PT_DCCP_RESET:
+		dccph = hdr_dccp::access(this);
+		dccph_p = hdr_dccp::access(p);
+		if (dccph->options_ != NULL)
+			dccph_p->options_ = new DCCPOptions(*dccph->options_);
+		break;
+	default:
+		;
+	}
+
 	if (data_) 
 		p->data_ = data_->copy();
 	p->txinfo_.init(&txinfo_);
  
 	return (p);
diff -urNU5 ns-2.33/dccp/bsd_queue.h ns-2.33-dccp/dccp/bsd_queue.h
--- ns-2.33/dccp/bsd_queue.h	1970-01-01 10:00:00.000000000 +1000
+++ ns-2.33-dccp/dccp/bsd_queue.h	2008-05-05 17:17:43.000000000 +1000
@@ -0,0 +1,539 @@
+/*
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)queue.h	8.5 (Berkeley) 8/20/94
+ * $FreeBSD: /repoman/r/ncvs/src/sys/sys/queue.h,v 1.54 2002/08/05 05:18:43 alfred Exp $
+ */
+#ifndef _NS_BSD_QUEUE_H_
+#define	_NS_BSD_QUEUE_H_
+
+/* #include <sys/cdefs.h> */
+#define	__offsetof(type, field)	((size_t)(&((type *)0)->field))
+
+/*
+ * This file defines four types of data structures: singly-linked lists,
+ * singly-linked tail queues, lists and tail queues.
+ *
+ * A singly-linked list is headed by a single forward pointer. The elements
+ * are singly linked for minimum space and pointer manipulation overhead at
+ * the expense of O(n) removal for arbitrary elements. New elements can be
+ * added to the list after an existing element or at the head of the list.
+ * Elements being removed from the head of the list should use the explicit
+ * macro for this purpose for optimum efficiency. A singly-linked list may
+ * only be traversed in the forward direction.  Singly-linked lists are ideal
+ * for applications with large datasets and few or no removals or for
+ * implementing a LIFO queue.
+ *
+ * A singly-linked tail queue is headed by a pair of pointers, one to the
+ * head of the list and the other to the tail of the list. The elements are
+ * singly linked for minimum space and pointer manipulation overhead at the
+ * expense of O(n) removal for arbitrary elements. New elements can be added
+ * to the list after an existing element, at the head of the list, or at the
+ * end of the list. Elements being removed from the head of the tail queue
+ * should use the explicit macro for this purpose for optimum efficiency.
+ * A singly-linked tail queue may only be traversed in the forward direction.
+ * Singly-linked tail queues are ideal for applications with large datasets
+ * and few or no removals or for implementing a FIFO queue.
+ *
+ * A list is headed by a single forward pointer (or an array of forward
+ * pointers for a hash table header). The elements are doubly linked
+ * so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before
+ * or after an existing element or at the head of the list. A list
+ * may only be traversed in the forward direction.
+ *
+ * A tail queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or
+ * after an existing element, at the head of the list, or at the end of
+ * the list. A tail queue may be traversed in either direction.
+ *
+ * For details on the use of these macros, see the queue(3) manual page.
+ *
+ *
+ *			SLIST	LIST	STAILQ	TAILQ
+ * _HEAD		+	+	+	+
+ * _HEAD_INITIALIZER	+	+	+	+
+ * _ENTRY		+	+	+	+
+ * _INIT		+	+	+	+
+ * _EMPTY		+	+	+	+
+ * _FIRST		+	+	+	+
+ * _NEXT		+	+	+	+
+ * _PREV		-	-	-	+
+ * _LAST		-	-	+	+
+ * _FOREACH		+	+	+	+
+ * _FOREACH_REVERSE	-	-	-	+
+ * _INSERT_HEAD		+	+	+	+
+ * _INSERT_BEFORE	-	+	-	+
+ * _INSERT_AFTER	+	+	+	+
+ * _INSERT_TAIL		-	-	+	+
+ * _CONCAT		-	-	+	+
+ * _REMOVE_HEAD		+	-	+	-
+ * _REMOVE		+	+	+	+
+ *
+ */
+
+/* Undefine the ones allocated in lib/bsd-list.h */
+#undef LIST_HEAD
+#undef LIST_ENTRY
+#undef LIST_INIT
+#undef LIST_INSERT_AFTER
+#undef LIST_INSERT_BEFORE
+#undef LIST_INSERT_HEAD
+#undef LIST_REMOVE
+
+#define QUEUE_MACRO_DEBUG 0
+#if QUEUE_MACRO_DEBUG
+/* Store the last 2 places the queue element or head was altered */
+struct qm_trace {
+	char * lastfile;
+	int lastline;
+	char * prevfile;
+	int prevline;
+};
+
+#define TRACEBUF	struct qm_trace trace;
+#define TRASHIT(x)	do {(x) = (void *)-1;} while (0)
+
+#define QMD_TRACE_HEAD(head) do {					\
+	(head)->trace.prevline = (head)->trace.lastline;		\
+	(head)->trace.prevfile = (head)->trace.lastfile;		\
+	(head)->trace.lastline = __LINE__;				\
+	(head)->trace.lastfile = __FILE__;				\
+} while (0)
+
+#define QMD_TRACE_ELEM(elem) do {					\
+	(elem)->trace.prevline = (elem)->trace.lastline;		\
+	(elem)->trace.prevfile = (elem)->trace.lastfile;		\
+	(elem)->trace.lastline = __LINE__;				\
+	(elem)->trace.lastfile = __FILE__;				\
+} while (0)
+
+#else
+#define QMD_TRACE_ELEM(elem)
+#define QMD_TRACE_HEAD(head)
+#define TRACEBUF
+#define TRASHIT(x)
+#endif	/* QUEUE_MACRO_DEBUG */
+
+/*
+ * Singly-linked List declarations.
+ */
+#define	SLIST_HEAD(name, type)						\
+struct name {								\
+	struct type *slh_first;	/* first element */			\
+}
+
+#define	SLIST_HEAD_INITIALIZER(head)					\
+	{ NULL }
+ 
+#define	SLIST_ENTRY(type)						\
+struct {								\
+	struct type *sle_next;	/* next element */			\
+}
+ 
+/*
+ * Singly-linked List functions.
+ */
+#define	SLIST_EMPTY(head)	((head)->slh_first == NULL)
+
+#define	SLIST_FIRST(head)	((head)->slh_first)
+
+#define	SLIST_FOREACH(var, head, field)					\
+	for ((var) = SLIST_FIRST((head));				\
+	    (var);							\
+	    (var) = SLIST_NEXT((var), field))
+
+#define SLIST_FOREACH_PREVPTR(var, varp, head, field)			\
+	for ((varp) = &SLIST_FIRST((head));				\
+	    ((var) = *(varp)) != NULL;					\
+	    (varp) = &SLIST_NEXT((var), field))
+
+#define	SLIST_INIT(head) do {						\
+	SLIST_FIRST((head)) = NULL;					\
+} while (0)
+
+#define	SLIST_INSERT_AFTER(slistelm, elm, field) do {			\
+	SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field);	\
+	SLIST_NEXT((slistelm), field) = (elm);				\
+} while (0)
+
+#define	SLIST_INSERT_HEAD(head, elm, field) do {			\
+	SLIST_NEXT((elm), field) = SLIST_FIRST((head));			\
+	SLIST_FIRST((head)) = (elm);					\
+} while (0)
+
+#define	SLIST_NEXT(elm, field)	((elm)->field.sle_next)
+
+#define	SLIST_REMOVE(head, elm, type, field) do {			\
+	if (SLIST_FIRST((head)) == (elm)) {				\
+		SLIST_REMOVE_HEAD((head), field);			\
+	}								\
+	else {								\
+		struct type *curelm = SLIST_FIRST((head));		\
+		while (SLIST_NEXT(curelm, field) != (elm))		\
+			curelm = SLIST_NEXT(curelm, field);		\
+		SLIST_NEXT(curelm, field) =				\
+		    SLIST_NEXT(SLIST_NEXT(curelm, field), field);	\
+	}								\
+} while (0)
+
+#define	SLIST_REMOVE_HEAD(head, field) do {				\
+	SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field);	\
+} while (0)
+
+/*
+ * Singly-linked Tail queue declarations.
+ */
+#define	STAILQ_HEAD(name, type)						\
+struct name {								\
+	struct type *stqh_first;/* first element */			\
+	struct type **stqh_last;/* addr of last next element */		\
+}
+
+#define	STAILQ_HEAD_INITIALIZER(head)					\
+	{ NULL, &(head).stqh_first }
+
+#define	STAILQ_ENTRY(type)						\
+struct {								\
+	struct type *stqe_next;	/* next element */			\
+}
+
+/*
+ * Singly-linked Tail queue functions.
+ */
+#define	STAILQ_CONCAT(head1, head2) do {				\
+	if (!STAILQ_EMPTY((head2))) {					\
+		*(head1)->stqh_last = (head2)->stqh_first;		\
+		(head1)->stqh_last = (head2)->stqh_last;		\
+		STAILQ_INIT((head2));					\
+	}								\
+} while (0)
+
+#define	STAILQ_EMPTY(head)	((head)->stqh_first == NULL)
+
+#define	STAILQ_FIRST(head)	((head)->stqh_first)
+
+#define	STAILQ_FOREACH(var, head, field)				\
+	for((var) = STAILQ_FIRST((head));				\
+	   (var);							\
+	   (var) = STAILQ_NEXT((var), field))
+
+#define	STAILQ_INIT(head) do {						\
+	STAILQ_FIRST((head)) = NULL;					\
+	(head)->stqh_last = &STAILQ_FIRST((head));			\
+} while (0)
+
+#define	STAILQ_INSERT_AFTER(head, tqelm, elm, field) do {		\
+	if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\
+		(head)->stqh_last = &STAILQ_NEXT((elm), field);		\
+	STAILQ_NEXT((tqelm), field) = (elm);				\
+} while (0)
+
+#define	STAILQ_INSERT_HEAD(head, elm, field) do {			\
+	if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL)	\
+		(head)->stqh_last = &STAILQ_NEXT((elm), field);		\
+	STAILQ_FIRST((head)) = (elm);					\
+} while (0)
+
+#define	STAILQ_INSERT_TAIL(head, elm, field) do {			\
+	STAILQ_NEXT((elm), field) = NULL;				\
+	*(head)->stqh_last = (elm);					\
+	(head)->stqh_last = &STAILQ_NEXT((elm), field);			\
+} while (0)
+
+#define	STAILQ_LAST(head, type, field)					\
+	(STAILQ_EMPTY((head)) ?						\
+		NULL :							\
+	        ((struct type *)					\
+		((char *)((head)->stqh_last) - __offsetof(struct type, field))))
+
+#define	STAILQ_NEXT(elm, field)	((elm)->field.stqe_next)
+
+#define	STAILQ_REMOVE(head, elm, type, field) do {			\
+	if (STAILQ_FIRST((head)) == (elm)) {				\
+		STAILQ_REMOVE_HEAD((head), field);			\
+	}								\
+	else {								\
+		struct type *curelm = STAILQ_FIRST((head));		\
+		while (STAILQ_NEXT(curelm, field) != (elm))		\
+			curelm = STAILQ_NEXT(curelm, field);		\
+		if ((STAILQ_NEXT(curelm, field) =			\
+		     STAILQ_NEXT(STAILQ_NEXT(curelm, field), field)) == NULL)\
+			(head)->stqh_last = &STAILQ_NEXT((curelm), field);\
+	}								\
+} while (0)
+
+#define	STAILQ_REMOVE_HEAD(head, field) do {				\
+	if ((STAILQ_FIRST((head)) =					\
+	     STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL)		\
+		(head)->stqh_last = &STAILQ_FIRST((head));		\
+} while (0)
+
+#define	STAILQ_REMOVE_HEAD_UNTIL(head, elm, field) do {			\
+	if ((STAILQ_FIRST((head)) = STAILQ_NEXT((elm), field)) == NULL)	\
+		(head)->stqh_last = &STAILQ_FIRST((head));		\
+} while (0)
+
+/*
+ * List declarations.
+ */
+#define	LIST_HEAD(name, type)						\
+struct name {								\
+	struct type *lh_first;	/* first element */			\
+}
+
+#define	LIST_HEAD_INITIALIZER(head)					\
+	{ NULL }
+
+#define	LIST_ENTRY(type)						\
+struct {								\
+	struct type *le_next;	/* next element */			\
+	struct type **le_prev;	/* address of previous next element */	\
+}
+
+/*
+ * List functions.
+ */
+
+#define	LIST_EMPTY(head)	((head)->lh_first == NULL)
+
+#define	LIST_FIRST(head)	((head)->lh_first)
+
+#define	LIST_FOREACH(var, head, field)					\
+	for ((var) = LIST_FIRST((head));				\
+	    (var);							\
+	    (var) = LIST_NEXT((var), field))
+
+#define	LIST_INIT(head) do {						\
+	LIST_FIRST((head)) = NULL;					\
+} while (0)
+
+#define	LIST_INSERT_AFTER(listelm, elm, field) do {			\
+	if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\
+		LIST_NEXT((listelm), field)->field.le_prev =		\
+		    &LIST_NEXT((elm), field);				\
+	LIST_NEXT((listelm), field) = (elm);				\
+	(elm)->field.le_prev = &LIST_NEXT((listelm), field);		\
+} while (0)
+
+#define	LIST_INSERT_BEFORE(listelm, elm, field) do {			\
+	(elm)->field.le_prev = (listelm)->field.le_prev;		\
+	LIST_NEXT((elm), field) = (listelm);				\
+	*(listelm)->field.le_prev = (elm);				\
+	(listelm)->field.le_prev = &LIST_NEXT((elm), field);		\
+} while (0)
+
+#define	LIST_INSERT_HEAD(head, elm, field) do {				\
+	if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL)	\
+		LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\
+	LIST_FIRST((head)) = (elm);					\
+	(elm)->field.le_prev = &LIST_FIRST((head));			\
+} while (0)
+
+#define	LIST_NEXT(elm, field)	((elm)->field.le_next)
+
+#define	LIST_REMOVE(elm, field) do {					\
+	if (LIST_NEXT((elm), field) != NULL)				\
+		LIST_NEXT((elm), field)->field.le_prev = 		\
+		    (elm)->field.le_prev;				\
+	*(elm)->field.le_prev = LIST_NEXT((elm), field);		\
+} while (0)
+
+/*
+ * Tail queue declarations.
+ */
+#define	TAILQ_HEAD(name, type)						\
+struct name {								\
+	struct type *tqh_first;	/* first element */			\
+	struct type **tqh_last;	/* addr of last next element */		\
+	TRACEBUF							\
+}
+
+#define	TAILQ_HEAD_INITIALIZER(head)					\
+	{ NULL, &(head).tqh_first }
+
+#define	TAILQ_ENTRY(type)						\
+struct {								\
+	struct type *tqe_next;	/* next element */			\
+	struct type **tqe_prev;	/* address of previous next element */	\
+	TRACEBUF							\
+}
+
+/*
+ * Tail queue functions.
+ */
+#define	TAILQ_CONCAT(head1, head2, field) do {				\
+	if (!TAILQ_EMPTY(head2)) {					\
+		*(head1)->tqh_last = (head2)->tqh_first;		\
+		(head2)->tqh_first->field.tqe_prev = (head1)->tqh_last;	\
+		(head1)->tqh_last = (head2)->tqh_last;			\
+		TAILQ_INIT((head2));					\
+		QMD_TRACE_HEAD(head);					\
+		QMD_TRACE_HEAD(head2);					\
+	}								\
+} while (0)
+
+#define	TAILQ_EMPTY(head)	((head)->tqh_first == NULL)
+
+#define	TAILQ_FIRST(head)	((head)->tqh_first)
+
+#define	TAILQ_FOREACH(var, head, field)					\
+	for ((var) = TAILQ_FIRST((head));				\
+	    (var);							\
+	    (var) = TAILQ_NEXT((var), field))
+
+#define	TAILQ_FOREACH_REVERSE(var, head, headname, field)		\
+	for ((var) = TAILQ_LAST((head), headname);			\
+	    (var);							\
+	    (var) = TAILQ_PREV((var), headname, field))
+
+#define	TAILQ_INIT(head) do {						\
+	TAILQ_FIRST((head)) = NULL;					\
+	(head)->tqh_last = &TAILQ_FIRST((head));			\
+	QMD_TRACE_HEAD(head);						\
+} while (0)
+
+#define	TAILQ_INSERT_AFTER(head, listelm, elm, field) do {		\
+	if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\
+		TAILQ_NEXT((elm), field)->field.tqe_prev = 		\
+		    &TAILQ_NEXT((elm), field);				\
+	else {								\
+		(head)->tqh_last = &TAILQ_NEXT((elm), field);		\
+		QMD_TRACE_HEAD(head);					\
+	}								\
+	TAILQ_NEXT((listelm), field) = (elm);				\
+	(elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field);		\
+	QMD_TRACE_ELEM(&(elm)->field);					\
+	QMD_TRACE_ELEM(&listelm->field);				\
+} while (0)
+
+#define	TAILQ_INSERT_BEFORE(listelm, elm, field) do {			\
+	(elm)->field.tqe_prev = (listelm)->field.tqe_prev;		\
+	TAILQ_NEXT((elm), field) = (listelm);				\
+	*(listelm)->field.tqe_prev = (elm);				\
+	(listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field);		\
+	QMD_TRACE_ELEM(&(elm)->field);					\
+	QMD_TRACE_ELEM(&listelm->field);				\
+} while (0)
+
+#define	TAILQ_INSERT_HEAD(head, elm, field) do {			\
+	if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL)	\
+		TAILQ_FIRST((head))->field.tqe_prev =			\
+		    &TAILQ_NEXT((elm), field);				\
+	else								\
+		(head)->tqh_last = &TAILQ_NEXT((elm), field);		\
+	TAILQ_FIRST((head)) = (elm);					\
+	(elm)->field.tqe_prev = &TAILQ_FIRST((head));			\
+	QMD_TRACE_HEAD(head);						\
+	QMD_TRACE_ELEM(&(elm)->field);					\
+} while (0)
+
+#define	TAILQ_INSERT_TAIL(head, elm, field) do {			\
+	TAILQ_NEXT((elm), field) = NULL;				\
+	(elm)->field.tqe_prev = (head)->tqh_last;			\
+	*(head)->tqh_last = (elm);					\
+	(head)->tqh_last = &TAILQ_NEXT((elm), field);			\
+	QMD_TRACE_HEAD(head);						\
+	QMD_TRACE_ELEM(&(elm)->field);					\
+} while (0)
+
+#define	TAILQ_LAST(head, headname)					\
+	(*(((struct headname *)((head)->tqh_last))->tqh_last))
+
+#define	TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
+
+#define	TAILQ_PREV(elm, headname, field)				\
+	(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
+
+#define	TAILQ_REMOVE(head, elm, field) do {				\
+	if ((TAILQ_NEXT((elm), field)) != NULL)				\
+		TAILQ_NEXT((elm), field)->field.tqe_prev = 		\
+		    (elm)->field.tqe_prev;				\
+	else {								\
+		(head)->tqh_last = (elm)->field.tqe_prev;		\
+		QMD_TRACE_HEAD(head);					\
+	}								\
+	*(elm)->field.tqe_prev = TAILQ_NEXT((elm), field);		\
+	TRASHIT((elm)->field.tqe_next);					\
+	TRASHIT((elm)->field.tqe_prev);					\
+	QMD_TRACE_ELEM(&(elm)->field);					\
+} while (0)
+
+
+#ifdef _KERNEL
+
+/*
+ * XXX insque() and remque() are an old way of handling certain queues.
+ * They bogusly assumes that all queue heads look alike.
+ */
+
+struct quehead {
+	struct quehead *qh_link;
+	struct quehead *qh_rlink;
+};
+
+#ifdef	__GNUC__
+
+static __inline void
+insque(void *a, void *b)
+{
+	struct quehead *element = (struct quehead *)a,
+		 *head = (struct quehead *)b;
+
+	element->qh_link = head->qh_link;
+	element->qh_rlink = head;
+	head->qh_link = element;
+	element->qh_link->qh_rlink = element;
+}
+
+static __inline void
+remque(void *a)
+{
+	struct quehead *element = (struct quehead *)a;
+
+	element->qh_link->qh_rlink = element->qh_rlink;
+	element->qh_rlink->qh_link = element->qh_link;
+	element->qh_rlink = 0;
+}
+
+#else /* !__GNUC__ */
+
+void	insque(void *a, void *b);
+void	remque(void *a);
+
+#endif /* __GNUC__ */
+
+#endif /* _KERNEL */
+
+#endif /* !_NS_BSD_QUEUE_H_ */
diff -urNU5 ns-2.33/dccp/dccp_ackv.cc ns-2.33-dccp/dccp/dccp_ackv.cc
--- ns-2.33/dccp/dccp_ackv.cc	1970-01-01 10:00:00.000000000 +1000
+++ ns-2.33-dccp/dccp/dccp_ackv.cc	2008-05-05 17:17:43.000000000 +1000
@@ -0,0 +1,920 @@
+/* -*-	Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
+
+/* Copyright (c) 2004  Nils-Erik Mattsson 
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: ns-233-dccp-1.patch 210 2008-05-13 03:43:55Z omehani $ */
+
+#include <stdio.h>
+#include "dccp_ackv.h"
+
+/* Static string representation of packet states */
+char* DCCPAckVector::packet_state_str_[DCCP_NUM_PACKET_STATES] =
+{"Received", "ECN-marked", "Reserved", "Not Received" };
+
+//private methods
+
+/* Add items to the head of the vector
+ * arg: state  - packet state to set on items
+ *      runlen - run length to set on items
+ *      count  - number of similar items to add
+ * ret: true if successful
+ *      false if more space is needed and doubleMaxSize() fails.
+ */
+bool DCCPAckVector::addItems(dccp_packet_state state, u_int8_t runlen, int count){
+	u_int8_t temp = state;	
+	int new_head, walker;
+	u_int8_t item = (temp << DCCP_RUN_LENGTH_BITS | (runlen & DCCP_RUN_LENGTH_MASK));
+	if (size_+count > max_size_){
+		//increase size and try again
+		return (doubleMaxSize() && addItems(state,runlen,count));
+	}
+
+	if(size_ != 0)
+		seq_head_ +=(runlen+1)*count;
+	
+	new_head = (head_ - count + max_size_) % max_size_;
+	walker = new_head;
+	
+	while(walker != head_){
+		vector_[walker] = item;
+		walker = (walker + 1) % max_size_;
+	}
+	
+	size_ += count;
+	head_ = new_head;
+
+	return true;
+}
+
+/* Find where in the vector a info about a seqnum exists
+ * arg: seqnum    - sequence number to find
+ *      where     - resulting position in the vector
+ *      seq_start - starting sequence number corresponding to where
+ *      seq_end   - ending sequence number corresponding to where
+ * ret: true if found
+ *      false otherwise (where, seq_start, seq_end invalid)
+ */
+bool DCCPAckVector::findSeqNum(u_int32_t seqnum, u_int16_t *where, u_int32_t *seq_start, u_int32_t *seq_end){
+	if (size_ == 0 || seqnum > seq_head_ || seqnum < seq_tail_ )
+		return false;
+	
+	*where = head_;
+	*seq_start = seq_head_;
+	*seq_end = 0;
+	int stop = (tail_ + 1) % max_size_;
+	
+	do{
+		*seq_end = *seq_start - (vector_[*where] & DCCP_RUN_LENGTH_MASK);
+		
+		if (*seq_end <= seqnum && *seq_start >= seqnum){
+			return true;
+		}
+		
+		*where = (*where + 1) % max_size_;
+		*seq_start = *seq_end - 1;
+	} while(*where != stop);
+	
+	//should never get here!!
+	return false;
+}
+
+/* Increase the maximum size of the vector by a factor two
+ * until DCCP_MAX_ACKV_SIZE is reached.
+ * ret:  true if successful, false if already at DCCP_MAX_ACKV_SIZE
+ */
+bool DCCPAckVector::doubleMaxSize(){
+	if (max_size_ == DCCP_MAX_ACKV_SIZE)
+		return false;
+    
+	int new_max_size = max_size_ * 2;
+
+	if (new_max_size > DCCP_MAX_ACKV_SIZE)
+		new_max_size = DCCP_MAX_ACKV_SIZE;
+
+	u_char *new_vector = new u_char[new_max_size];
+	int walker = head_;
+
+	for (int i = 0; i < size_; i++){
+		new_vector[i] = vector_[walker];
+		walker = (walker + 1) % max_size_;
+	}
+	max_size_ = new_max_size;
+
+	if (size_ > 0) {
+		head_ = 0;
+		tail_ = size_-1;
+	}
+	
+	delete [] vector_;
+	vector_ = new_vector;
+	return true;
+}
+
+/* Add an acknowledgment to ack history
+ * arg: seqnum - sequence number of the sent ack packet
+ */
+void DCCPAckVector::addToAckHistory(u_int32_t seqnum){
+	struct dccp_ackv_hist_entry *elm = STAILQ_FIRST(&ack_hist_);
+	if(elm != NULL && elm->seq_sent_ >= seqnum){
+		fprintf(stderr, "DCCPAckVector::addToAckHistory - Sequence number to send is old! (seqnum %d < seq_sent_ %d)\n",seqnum, elm->seq_sent_);
+		fflush(stdout);
+		abort();
+	} else if (elm != NULL && elm->ack_num_ > seq_head_) {
+		fprintf(stderr, "DCCPAckVector::addToAckHistory - Last Ack number %d is larger than seq_head_ %d\n", elm->ack_num_, seq_head_);
+		fflush(stdout);
+		abort();
+	} else {
+		/*if (elm != NULL && elm->ack_num_ == seq_head_) {
+			fprintf(stderr, "DCCPAckVector::addToAckHistory - Last Ack number %d is equal to seq_head_ %d\n", elm->ack_num_, seq_head_);
+			fflush(stdout);
+			abort();
+			}*/
+		struct dccp_ackv_hist_entry *new_entry = new struct dccp_ackv_hist_entry;
+		new_entry->seq_sent_ = seqnum;
+		new_entry->ack_num_ = seq_head_;
+		new_entry->ene_ = ene_;
+		STAILQ_INSERT_HEAD(&ack_hist_, new_entry, linfo_);
+	}
+}
+
+/* Remove all items in the ack history */
+void DCCPAckVector::clearAckHistory(){
+	struct dccp_ackv_hist_entry *elm, *elm2;
+
+	/* Empty packet history */
+	elm = STAILQ_FIRST(&ack_hist_);
+	while (elm != NULL) {
+		elm2 = STAILQ_NEXT(elm, linfo_);
+		delete elm;
+		elm = elm2;
+	}
+	
+	STAILQ_INIT(&ack_hist_);
+}
+
+//public methods
+
+/* Return a string reprenting a packet state
+ * arg: state - packet state
+ * ret: a string representation of state
+ */
+const char* DCCPAckVector::packetStateAsStr(dccp_packet_state state){
+        if (state < DCCP_NUM_PACKET_STATES && state >= 0)
+		return packet_state_str_[state];
+	else
+		return "Unknown";
+}
+
+/* Constructor
+ * arg: initialSize - initial size for the ack vector
+ * ret: a new DCCPAckVector
+ */
+DCCPAckVector::DCCPAckVector(u_int16_t initialSize){
+	vector_ = new u_char[initialSize];
+	size_ = 0;
+	max_size_ = initialSize;
+	ene_ = 0;
+	head_ = 0;
+	tail_ = 0;
+	seq_head_ = 0;
+	seq_tail_ = 0;
+	p_walk_ = 0;
+	seq_p_walk_ = 0;
+	delta_p_walk_ = 0;
+	p_walking_ = false;
+	p_reverse_ = false;
+	i_walk_ = 0;
+	seq_i_walk_ = 0;
+	i_walking_ = false;
+
+	ackv_cons_[DCCP_PACKET_RECV][DCCP_PACKET_RECV]         = DCCP_PACKET_RECV;
+	ackv_cons_[DCCP_PACKET_RECV][DCCP_PACKET_ECN]          = DCCP_PACKET_RECV;
+	ackv_cons_[DCCP_PACKET_RECV][DCCP_PACKET_RESERVED]     = DCCP_PACKET_RESERVED;
+	ackv_cons_[DCCP_PACKET_RECV][DCCP_PACKET_NOT_RECV]     = DCCP_PACKET_RECV;
+	ackv_cons_[DCCP_PACKET_ECN][DCCP_PACKET_RECV]          = DCCP_PACKET_ECN;
+	ackv_cons_[DCCP_PACKET_ECN][DCCP_PACKET_ECN]           = DCCP_PACKET_ECN;
+	ackv_cons_[DCCP_PACKET_ECN][DCCP_PACKET_RESERVED]      = DCCP_PACKET_RESERVED;
+	ackv_cons_[DCCP_PACKET_ECN][DCCP_PACKET_NOT_RECV]      = DCCP_PACKET_ECN;
+	ackv_cons_[DCCP_PACKET_RESERVED][DCCP_PACKET_RECV]     = DCCP_PACKET_RESERVED;
+	ackv_cons_[DCCP_PACKET_RESERVED][DCCP_PACKET_ECN]      = DCCP_PACKET_RESERVED;
+	ackv_cons_[DCCP_PACKET_RESERVED][DCCP_PACKET_RESERVED] = DCCP_PACKET_RESERVED;
+	ackv_cons_[DCCP_PACKET_RESERVED][DCCP_PACKET_NOT_RECV] = DCCP_PACKET_RESERVED;
+	ackv_cons_[DCCP_PACKET_NOT_RECV][DCCP_PACKET_RECV]     = DCCP_PACKET_RECV;
+	ackv_cons_[DCCP_PACKET_NOT_RECV][DCCP_PACKET_ECN]      = DCCP_PACKET_ECN;
+	ackv_cons_[DCCP_PACKET_NOT_RECV][DCCP_PACKET_RESERVED] = DCCP_PACKET_RESERVED;
+	ackv_cons_[DCCP_PACKET_NOT_RECV][DCCP_PACKET_NOT_RECV] = DCCP_PACKET_NOT_RECV;
+	
+	STAILQ_INIT(&ack_hist_);
+}
+
+/* Destructor */
+DCCPAckVector::~DCCPAckVector(){
+	clearAckHistory();
+	delete [] vector_;
+}
+
+/* Add a packet to the ack vector (using ackv_cons_ when needed)
+ * Will fill with NOT_RECV packets when packets are missing
+ * arg: seqnum - sequence number of packet
+ *      state  - packet state
+ * ret: true if successful
+ *      false if more space is needed and doubleMaxSize() fails
+ *            or if packet is older than the oldest in the vector
+ */
+bool DCCPAckVector::addPacket(u_int32_t seqnum, dccp_packet_state state){
+	int dist = seqnum - seq_head_;
+	u_int8_t runlen = 0;
+	
+	if (size_ == 0){
+		seq_head_ = seqnum;
+		seq_tail_ = seqnum;
+		head_ = 0;
+		tail_ = max_size_-1;
+	} else if (dist > 1){  //some packets are missing
+		int num_fulls = (dist-2) / (DCCP_RUN_LENGTH_MASK+1);
+		int last_runlen = (dist-2) % (DCCP_RUN_LENGTH_MASK+1);
+	
+		if (size_ + num_fulls + 1 + 1 > max_size_)
+			return doubleMaxSize() && addPacket(seqnum, state);
+
+		if (num_fulls > 0)
+			addItems(DCCP_PACKET_NOT_RECV, DCCP_RUN_LENGTH_MASK, num_fulls);
+
+		addItems(DCCP_PACKET_NOT_RECV,last_runlen);
+
+	} else if (dist == 1) { //expected packet
+		u_int8_t last_runlen = vector_[head_] & DCCP_RUN_LENGTH_MASK;
+		u_int8_t last_state = vector_[head_] >> DCCP_RUN_LENGTH_BITS;
+		if (last_runlen < DCCP_RUN_LENGTH_MASK && last_state == (u_int8_t) state){
+			vector_[head_] += 1;
+			seq_head_ = seqnum;
+			return true;
+		}
+
+	} else {
+		dccp_packet_state curr_state;
+		if (getState(seqnum, &curr_state))
+			if (alterState(seqnum,ackv_cons_[curr_state][state])){
+				return true;
+			}
+		
+		return false;
+	}
+
+	if (!addItems(state, runlen)){
+		return false;
+	}
+
+	return true;
+}
+
+/* Add a packet to the ack vector (using ackv_cons_ when needed)
+ * Will fill with NOT_RECV packets when packets are missing
+ * arg: seqnum   - sequence number of packet
+ *      ecn      - packets ecn code point
+ *      addNonce - if true, add packet nonce to ecn echo sum
+ * ret: true if successful
+ *      false if more space is needed and doubleMaxSize() fails
+ *            or if packet is older than the oldest in the vector
+ */
+bool DCCPAckVector::addPacket(u_int32_t seqnum, dccp_ecn_codepoint ecn, bool addNonce){
+	dccp_packet_state state = DCCP_PACKET_RECV;
+	if (ecn == ECN_CE)
+		state = DCCP_PACKET_ECN;
+
+	bool result = addPacket(seqnum, state);
+	if (result && addNonce && (ecn == ECN_ECT0 || ecn == ECN_ECT1))
+		ene_ = ene_ ^ ecn;
+	
+	return result;
+}
+
+/* Remove packets older and including given seqnum from ack vector
+ * arg: seqnum - sequence number of the largest packet to remove
+ */
+void DCCPAckVector::removePackets(u_int32_t seqnum){
+	if (size_ == 0 || seqnum < seq_tail_)
+		return;
+	else if (seqnum > seq_head_) { 
+		size_ = 0;
+		seq_tail_ = seq_head_;
+		tail_ = head_;
+		ene_ = 0;
+		return;
+	}
+
+	u_int16_t where;
+	u_int32_t seq_start;
+	u_int32_t seq_end;
+
+	u_int32_t dist = 0;
+
+	if (findSeqNum(seqnum, &where, &seq_start, &seq_end)){
+		dist = seq_start-seq_end;
+		if (dist > 0 && seq_start != seqnum){
+			vector_[where] = vector_[where] - (seqnum-seq_end+1);
+			size_ = ((where - head_ + max_size_) % max_size_)+1;
+			tail_ = where;
+			seq_tail_ = seqnum + 1;
+		} else if (where == head_){
+			size_ = 0;
+			seq_tail_ = seq_head_;
+			tail_ = head_;
+			ene_ = 0;
+		} else {
+			where = ((where -1 + max_size_) % max_size_);
+			size_ = ((where - head_ + max_size_) % max_size_)+1;
+			tail_ = where;
+			seq_tail_ = seqnum +1;
+		}
+
+
+	}
+	
+}
+
+/* Merge two ack vectors.
+ * Will read packet states from ackv and add them to this vector
+ * using ackv_cons_.
+ * If (ackv->seq_first_ > this->seq_first_)
+ *    pad with DCCP_PACKET_NOT_RECV until they match
+ * Discards all packets older than this->seq_last_.
+ * If this->getSize() == 0
+ *    use setAckVector()
+ * arg: ackv - ack vector to merge with
+ * ret: true if successful
+ *      false if ackv == NULL or the upper limit on size is exceeded
+ * Note: Adds packet in seqnum order until either successful
+ *       or out of space.
+ *       will NOT change ecn nonce echo as needed by the state change
+ */
+bool DCCPAckVector::mergeWith(DCCPAckVector *ackv){
+	bool result = false;
+	
+	if (ackv == NULL)
+		return false;
+	else if (ackv->getSize() == 0)
+		return true;
+
+	if (size_ == 0){
+		u_int16_t size;
+		size = ackv->getSize();
+		u_char vect[size];
+		if (ackv->getAckVector(vect, &size) > 0)
+			if (setAckVector(vect,size,ackv->getFirstSeqNum(),ackv->getENE()))
+				result = true;
+	} else {
+		u_int32_t seqnum;
+		dccp_packet_state state;
+		ackv->startReversePacketWalk();
+		while(ackv->prevPacket(&seqnum, &state)){
+			if (!addPacket(seqnum,state) && seqnum >= seq_tail_){
+				fprintf(stdout,"DCCPAckVector::mergeWith() failed\n");
+				result = false;
+				break;
+			}
+		}
+	}
+
+	
+	return result;
+}
+
+/* Alter state of one packet.
+ * Will split items as needed. Note will not alter 
+ * arg: seqnum   - sequence number of packet to add
+ *      newstate - packets new state
+ *      oldstate - the packets old state
+ * ret: true if successful
+ *      false if packet is not in vector or size
+ *            if the upper limit on size is exceeded
+ * Note: will not alter the vector on failure.
+ *       will NOT change ecn nonce echo as needed by the state change
+ */
+bool DCCPAckVector::alterState(u_int32_t seqnum, dccp_packet_state newstate, dccp_packet_state *oldstate){
+	u_int16_t where;
+	u_int32_t seq_start;
+	u_int32_t seq_end;
+	u_char items[3];
+	int num_to_add = 0;
+	dccp_packet_state old_state;
+	u_int8_t old_runlen;
+	bool result = false;
+	
+	if (findSeqNum(seqnum, &where, &seq_start, &seq_end)){
+		old_state = (dccp_packet_state) (vector_[where] >> DCCP_RUN_LENGTH_BITS);
+
+		if (oldstate != NULL)
+			*oldstate = old_state;
+		
+		if (old_state != newstate){			
+			old_runlen = vector_[where] & DCCP_RUN_LENGTH_MASK;
+			if (old_runlen == 0){
+				vector_[where] = ((u_int8_t) newstate) << DCCP_RUN_LENGTH_BITS;
+				result = true;
+			} else if (seqnum == seq_start || seqnum == seq_end){
+				if (size_ + 1 > max_size_){
+				        //increase size and try again
+					result = (doubleMaxSize() && alterState(seqnum, newstate));
+				} else {
+					if(seqnum == seq_start){
+						items[0] = ((u_int8_t) newstate) << DCCP_RUN_LENGTH_BITS;
+						items[1] = (((u_int8_t) old_state) << DCCP_RUN_LENGTH_BITS)
+							+ (old_runlen-1);
+					} else {
+						items[0] = (((u_int8_t) old_state) << DCCP_RUN_LENGTH_BITS)
+							+ (old_runlen-1);
+						items[1] = ((u_int8_t) newstate) << DCCP_RUN_LENGTH_BITS;
+					}
+					num_to_add = 2;
+				}
+			} else {
+				if (size_ + 2 > max_size_){
+				        //increase size and try again
+					result = (doubleMaxSize() && alterState(seqnum, newstate));
+				} else {
+					items[0] = (((u_int8_t) old_state) << DCCP_RUN_LENGTH_BITS)
+							+ (old_runlen-1-(seqnum-seq_end));
+					items[1] = ((u_int8_t) newstate) << DCCP_RUN_LENGTH_BITS;
+					items[2] = (((u_int8_t) old_state) << DCCP_RUN_LENGTH_BITS)
+							+ (old_runlen-1-(seq_start-seqnum));
+					num_to_add = 3;
+				}
+			}
+		} else
+			result = true;
+	}
+	
+	if (num_to_add > 1){
+		if(where == tail_){
+			tail_ = (tail_ + (num_to_add - 1)) % max_size_;			
+		} else if (where == head_){
+			head_ = (head_ - (num_to_add - 1) + max_size_) % max_size_;
+			where = head_;
+		} else {
+			int from = head_;
+			int to = (head_ - (num_to_add - 1) + max_size_) % max_size_;
+			head_ = to;
+			while (from != where){
+				vector_[to] = vector_[from];
+				from = (from + 1) % max_size_;
+				to = (to + 1) % max_size_;
+			}
+			where = (where - (num_to_add - 1) + max_size_) % max_size_;
+		}
+		for(int i = 0; i < num_to_add; i++){
+			vector_[where] = items[i];
+			where = (where + 1 ) % max_size_;
+		}
+		size_ += num_to_add - 1;
+		result = true;
+	}
+	
+	return result;
+	
+}
+
+/* Returns the state of a packet
+ * arg: seqnum - packets sequence number
+ *      state  - the packets state (if found)
+ * ret: true if packet is found
+ *      false if not
+ */
+bool DCCPAckVector::getState(u_int32_t seqnum, dccp_packet_state *state){
+	if (size_ == 0 || seqnum > seq_head_ || seqnum < seq_tail_)
+		return false;
+	bool result = false;
+	u_int16_t where;
+	u_int32_t seq_start;
+	u_int32_t seq_end;
+
+	if(findSeqNum(seqnum, &where, &seq_start, &seq_end)){
+		*state = (dccp_packet_state) (vector_[where] >> DCCP_RUN_LENGTH_BITS);
+		result = true;
+	}
+
+	return result;
+}
+
+/* Start a walk through the ack vector packet by packet,
+ * descending on sequence number.
+ */
+void DCCPAckVector::startPacketWalk(){
+	p_walk_ = head_;
+	seq_p_walk_ = seq_head_;
+	delta_p_walk_ = 0;
+	p_walking_ = (size_ != 0);
+	p_reverse_ = false;
+}
+
+/* Next packet in walk
+ * arg: seqnum - sequence number of next packet
+ *      state  - packet state
+ * ret: true if packet is found
+ *      false if packet is not found or walk not initiated.
+ */
+bool DCCPAckVector::nextPacket(u_int32_t *seqnum, dccp_packet_state *state){
+	if (!p_walking_ || p_reverse_)
+		return false;
+
+	u_int8_t runlen = vector_[p_walk_] & DCCP_RUN_LENGTH_MASK;
+
+	if (delta_p_walk_ > runlen){
+		p_walk_ = (p_walk_+1) % max_size_;
+		delta_p_walk_ = 0;
+	}
+		
+	*seqnum = seq_p_walk_;
+	*state = (dccp_packet_state) (vector_[p_walk_] >> DCCP_RUN_LENGTH_BITS);
+
+	delta_p_walk_++;
+
+	p_walking_ = (seq_p_walk_ != seq_tail_);
+
+	seq_p_walk_--;
+
+	return true;
+}
+
+/* Start a walk through the ack vector packet by packet,
+ * ascending on sequence number.
+ */
+void DCCPAckVector::startReversePacketWalk(){
+	p_walk_ = tail_;
+	seq_p_walk_ = seq_tail_;
+	delta_p_walk_ = 0;
+	p_walking_ = (size_ != 0);
+	p_reverse_ = true;
+}
+
+/* Previous packet in walk
+ * arg: seqnum - sequence number of previous packet
+ *      state  - packet state
+ * ret: true if packet is found
+ *      false if packet is not found or walk not initiated.
+ */
+bool DCCPAckVector::prevPacket(u_int32_t *seqnum, dccp_packet_state *state){
+	if (!p_walking_ || !p_reverse_)
+		return false;
+
+	u_int8_t runlen = vector_[p_walk_] & DCCP_RUN_LENGTH_MASK;
+
+	if (delta_p_walk_ > runlen){
+		p_walk_ = (p_walk_+max_size_-1) % max_size_;
+		delta_p_walk_ = 0;
+	}
+		
+	*seqnum = seq_p_walk_;
+	*state = (dccp_packet_state) (vector_[p_walk_] >> DCCP_RUN_LENGTH_BITS);
+
+	delta_p_walk_++;
+
+	p_walking_ = (seq_p_walk_ != seq_head_);
+
+	seq_p_walk_++;
+
+	return true;
+}
+
+/* Start a walk through the ack vector, item for item
+ * Most recent interval first.
+ */
+void DCCPAckVector::startIntervalWalk(){
+	i_walk_ = head_;
+	seq_i_walk_ = seq_head_;
+	i_walking_ = size_ != 0;
+}
+
+/* Next interval in walk
+ * arg: interval  - found interval
+ *      seq_start - the sequence number that started the interval
+ *      seq_end   - the sequence number that ended the interval
+ *      state     - the state of the packet in the interval
+ * ret: true if an interval is found
+ *      false if not or walk not initiated.
+ */
+bool DCCPAckVector::nextInterval(u_char *interval, u_int32_t *seq_start, u_int32_t *seq_end, dccp_packet_state *state){
+	if (!i_walking_)
+		return false;
+
+	*interval = vector_[i_walk_];
+	*seq_start = seq_i_walk_;
+	*seq_end = seq_i_walk_ - (vector_[i_walk_] & DCCP_RUN_LENGTH_MASK);
+	*state = (dccp_packet_state) (vector_[i_walk_] >> DCCP_RUN_LENGTH_BITS);
+	
+	i_walking_ = (i_walk_ != tail_);
+	i_walk_ = (i_walk_ +1) % max_size_;
+	seq_i_walk_ = *seq_end - 1;
+	
+	return true;
+}
+
+/* Return the ECN Nonce Echo
+ * ret: ECN Nonce Echo
+ */
+u_int8_t DCCPAckVector::getENE(){
+	return ene_;
+}
+
+/* Set the ECN Nonce Echo
+ * arg: ene - new ene
+ */
+void DCCPAckVector::setENE(u_int8_t ene){
+	ene_ = ene;
+}
+
+/* Chech if ack vector is empty
+ * ret: true if empty, otherwise false
+ */
+bool DCCPAckVector::isEmpty(){
+	return (size_ == 0);
+}
+
+/* Return the first sequence number represented in the ack vector
+ * ret: first sequence number in the vector
+ *      0 if empty
+ */
+u_int32_t DCCPAckVector::getFirstSeqNum(){
+	return seq_head_;
+}
+
+/* Return the current size of the ack vector
+ * ret: current size
+ */
+u_int32_t DCCPAckVector::getLastSeqNum(){
+	return seq_tail_;
+}
+
+/* Return the current size of the ack vector
+ * ret: current size
+ */
+int DCCPAckVector::getSize(){
+	return size_;
+}
+
+/* Return the ack vector
+ * arg: vect - array to store ack vector in
+ *      size - size of vect
+ * ret: The size of returned ack vector (also in size) if successful
+ *      DCCP_ACKV_EMPTY if its empty
+ *      DCCP_ACKV_ERR_SIZE if size is too small
+ *	(will set size to the size needed)
+ */	
+int DCCPAckVector::getAckVector(u_char* vect, u_int16_t *size){
+	if (size_ == 0)
+		return DCCP_ACKV_EMPTY;
+	else if (size_ > *size){
+		*size = size_;
+		return DCCP_ACKV_ERR_SIZE;
+	}
+
+	int walker = head_;
+
+	for (int i = 0; i < size_; i++){
+		vect[i] = vector_[walker];
+		walker = (walker + 1) % max_size_;
+	}
+	*size = size_;
+	
+	return size_;
+}
+
+/* Import an ack vector (clearing the old one)
+ * arg: vect      - ack vector to set
+ *      size      - size of vect
+ *      seq_start - sequnce number of the first packet in ack vector
+ *      ene       - the current ecn nonce echo
+ * ret: true if successful
+ *      false if out of space
+ */
+bool DCCPAckVector::setAckVector(const u_char* vect, u_int16_t size, u_int32_t seq_start, u_int8_t ene){
+	if (size > max_size_) {
+		size_ = 0;
+		return (doubleMaxSize() && setAckVector(vect, size, seq_start, ene));
+	}
+
+	u_int32_t seq_end = seq_start;
+	
+	for (int i = 0; i < size; i++){
+		vector_[i] = vect[i];
+		if (i == size-1)
+			seq_end -= vect[i] & DCCP_RUN_LENGTH_MASK;
+		else
+			seq_end -= (vect[i] & DCCP_RUN_LENGTH_MASK) + 1;
+	}
+
+	size_ = size;
+	head_ = 0;
+	tail_ = size_-1;
+	seq_head_ = seq_start;
+	seq_tail_ = seq_end;
+	ene_ = ene;
+
+	clearAckHistory();
+	return true;
+}
+
+
+/* Return and mark the ackvector as sent in history
+ * arg: seqnum - sequence number of packet on which ackvector is added
+ *      acknum - acknowledgement number on that packet (== seq_first_)
+ *      vect   - ack vector to send
+ *      size   - size of ackvector
+ * ret: same as getAckVector()
+ * Note: Fails hard if seq_first_ != acknum! 
+ */
+int DCCPAckVector::sendAckVector(u_int32_t seqnum, u_int32_t acknum, u_char* vect, u_int16_t *size){
+	if (acknum != seq_head_){
+		fprintf(stdout, "DCCPAckVector::sendAckVector acknum %d != seq_head %d\n",acknum,seq_head_);
+		fflush(stdout);
+		abort();
+	}
+
+	int result = getAckVector(vect, size);
+
+	if (result > 0) {
+		addToAckHistory(seqnum);
+	}
+
+	return result;
+}
+
+/* Add ack vector options and mark as sent in history
+ * arg: seqnum  - sequence number of packet on which ackvector is added
+ *      acknum  - acknowledgement number on that packet (== seq_first_)
+ *      options - DCCPOptions object to add ackvector to
+ * ret: DCCP_OPT_NO_ERR on success
+ *      similar to getAckVector and addOptions()
+ */
+int DCCPAckVector::sendAckVector(u_int32_t seqnum, u_int32_t acknum, DCCPOptions *options){
+	if (acknum != seq_head_){
+		fprintf(stdout, "DCCPAckVector::sendAckVector acknum %d != seq_head %d\n",acknum,seq_head_);
+		fflush(stdout);
+		abort();
+	} else if (size_ == 0){
+		fprintf(stdout, "DCCPAckVector::sendAckVector size_ == 0\n");
+		fflush(stdout);
+		abort();
+	}
+	u_char vect[size_];
+	u_int16_t size;
+	size = size_;
+        int result = getAckVector(vect,&size);
+	if (result > 0){
+		//for now, assume that the ackvector can be contained in one option
+		if (ene_ == 0)
+			result = options->addOption(DCCP_OPT_ACK_VECTOR_N0, vect, size);
+		else
+			result = options->addOption(DCCP_OPT_ACK_VECTOR_N1, vect, size);
+		if (result == DCCP_OPT_NO_ERR){
+			addToAckHistory(seqnum);
+		} else {
+			fprintf(stderr, "DCCPAckVector::sendAckVector - Failed to add ack vector to option: err %d, size %d\n",result, size);
+			fflush(stdout);
+			abort();
+		}
+
+	} else {
+		fprintf(stderr, "DCCPAckVector::sendAckVector - Get vector returned %d\n",result);
+		fflush(stdout);
+		abort();
+	}
+       
+	return result;
+}
+
+/* Check if state may be cleared due to an received ack.
+ * If ackv is present, check in that to see if an ack has been acked
+ * otherwise check only on acknum
+ * arg: acknum - acknowledgement number recv
+ *      ackv - ackvector received (if any)
+ */
+void DCCPAckVector::ackRecv(u_int32_t acknum, DCCPAckVector *ackv){
+	struct dccp_ackv_hist_entry *elm = NULL, *next_elm = NULL;
+	dccp_packet_state state;
+	u_int8_t ene_sub = 0;
+	
+	elm = STAILQ_FIRST(&ack_hist_);
+	while (elm != NULL){
+		if (ackv == NULL) {
+			if (acknum == elm->seq_sent_)
+				break;
+		} else if (ackv->getState(elm->seq_sent_, &state) && (state == DCCP_PACKET_RECV || state == DCCP_PACKET_ECN)){
+			break;
+		}
+		elm = STAILQ_NEXT(elm, linfo_);
+	}
+
+	if (elm != NULL){
+		ene_sub = elm->ene_;
+		ene_ = ene_ ^ (elm->ene_);
+		removePackets(elm->ack_num_);
+		do{
+		       next_elm = STAILQ_NEXT(elm, linfo_);
+		       STAILQ_REMOVE(&ack_hist_,elm,dccp_ackv_hist_entry,linfo_);
+		       delete elm;
+		       elm = next_elm;
+		} while (elm != NULL);
+
+		//subtract ene from later acks
+		elm = STAILQ_FIRST(&ack_hist_);
+		while (elm != NULL) {
+			elm->ene_ = (elm->ene_) ^ ene_sub;
+			elm = STAILQ_NEXT(elm, linfo_);
+		}
+	}
+	
+}
+
+/* Print ack vector state including intervals and ack history
+ * Note: Uses interval walk
+ */
+void DCCPAckVector::print(){
+	if (isEmpty()) {
+		fprintf(stdout, "DCCPAckVector :: Ack vector is empty (max_size_ %d)\n",max_size_);
+	} else {
+		fprintf(stdout, "DCCPAckVector :: size_ %d, max_size_ %d, head_ %d, tail_ %d, seq_head_ %d, seq_tail_ %d, ene_ %d\n", size_, max_size_,head_,tail_,seq_head_,seq_tail_, ene_);
+		startIntervalWalk();
+		u_char interval;
+		u_int32_t seq_start;
+		u_int32_t seq_end;
+		dccp_packet_state state;
+
+		while(nextInterval(&interval, &seq_start, &seq_end, &state)){
+			fprintf(stdout, "interval 0x%X (%d): state %s, runlen %d, (seq %d - %d)\n",interval, interval, packetStateAsStr(state), seq_start-seq_end,seq_start,seq_end);
+		}
+	}
+	printHistory();
+}
+
+/* Print all packets
+ * arg: asc - if true, print in ascending order, otherwise descending
+ * Note: uses packet walk
+ */
+void DCCPAckVector::printPackets(bool asc){
+	if (isEmpty()) {
+		fprintf(stdout, "DCCPAckVector :: Ack vector is empty (max_size_ %d)\n",max_size_);
+	} else {
+		fprintf(stdout, "DCCPAckVector :: size_ %d, max_size_ %d, head_ %d, tail_ %d, seq_head_ %d, seq_tail_ %d, ene_ %d\n", size_, max_size_,head_,tail_,seq_head_,seq_tail_, ene_);
+		u_int32_t seq_num;
+		dccp_packet_state state;
+
+		if (asc){
+			startReversePacketWalk();
+			while(prevPacket(&seq_num,&state)){
+				fprintf(stdout, "Packet : seq %d state %s\n",seq_num, packetStateAsStr(state));
+			}
+		} else {
+			startPacketWalk();
+			while(nextPacket(&seq_num,&state)){
+				fprintf(stdout, "Packet : seq %d state %s\n",seq_num, packetStateAsStr(state));
+			}
+		}
+	}
+}
+
+/* Print ack history */
+void DCCPAckVector::printHistory(){
+	struct dccp_ackv_hist_entry *elm = STAILQ_FIRST(&ack_hist_);
+	if (elm == NULL)
+		fprintf(stdout, "DCCPAckVector :: Ack history is empty\n");
+	else {
+		fprintf(stdout, "DCCPAckVector :: Ack history:\n");
+		while (elm != NULL){
+			fprintf(stdout, "Seq %d sent with ack %d and ene %d\n", elm->seq_sent_, elm->ack_num_,elm->ene_);
+			elm = STAILQ_NEXT(elm, linfo_);
+		}
+	}
+}
+
+
+
+
+
+
+
+
diff -urNU5 ns-2.33/dccp/dccp_ackv.h ns-2.33-dccp/dccp/dccp_ackv.h
--- ns-2.33/dccp/dccp_ackv.h	1970-01-01 10:00:00.000000000 +1000
+++ ns-2.33-dccp/dccp/dccp_ackv.h	2008-05-05 17:17:43.000000000 +1000
@@ -0,0 +1,352 @@
+/* -*-	Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
+
+/* Copyright (c) 2004  Nils-Erik Mattsson 
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: ns-233-dccp-1.patch 210 2008-05-13 03:43:55Z omehani $ */
+
+#ifndef ns_dccp_ackv_h
+#define ns_dccp_ackv_h
+
+#include "config.h"
+
+#include "bsd_queue.h"
+#include "dccp_types.h"
+#include "dccp_opt.h"
+
+#define DCCP_RUN_LENGTH_BITS 6
+#define DCCP_RUN_LENGTH_MASK 0x3F
+
+#define DCCP_PACKET_STATE_BITS 2
+#define DCCP_PACKET_STATE_MASK 0xC0
+
+#define DCCP_MAX_ACKV_SIZE 0xFFFF
+
+#define DCCP_ACKV_OK 0
+#define DCCP_ACKV_EMPTY -1
+#define DCCP_ACKV_ERR_SIZE -2
+
+//ack history
+STAILQ_HEAD(dccp_ackv_hist,dccp_ackv_hist_entry); 
+ 
+struct dccp_ackv_hist_entry {
+	STAILQ_ENTRY(dccp_ackv_hist_entry) linfo_;    
+	u_int32_t seq_sent_;            
+	u_int32_t ack_num_;
+	u_int8_t ene_;
+};
+
+/* Class DCCPAckVector represents an ack vector.
+   Implemented as the October 2003 draft suggests */
+class DCCPAckVector {
+private:
+	//packet state names
+	static char* packet_state_str_[DCCP_NUM_PACKET_STATES];
+
+        u_char* vector_;       //the real ack vector as a byte array
+	u_int16_t size_;       //current size of vector
+	u_int16_t max_size_;   //maximum size of vector (can increase)
+	u_int16_t head_,tail_; //head and tail in the array
+	u_int32_t seq_head_, seq_tail_;  //seq num of head and tail
+	u_int8_t ene_;         //ecn nonce echo
+
+	//packet walking variables
+	u_int16_t p_walk_;     //current item in the vector
+	u_int32_t seq_p_walk_; //current seq num
+	int delta_p_walk_;     //current location within an element
+	bool p_walking_;       //true if a packet walk is initiated
+	bool p_reverse_;       //true if an reverse packet walk is initiated
+
+	//interval walking variables
+	u_int16_t i_walk_;     //current item in the vector
+	u_int32_t seq_i_walk_; //current seq num
+	bool i_walking_;       //true if an interval walk is initiated
+
+	//history of acknowledgents (ack vectors) sent
+	struct dccp_ackv_hist ack_hist_;
+
+	/* Add items to the head of the vector
+	 * arg: state  - packet state to set on items
+	 *      runlen - run length to set on items
+	 *      count  - number of similar items to add
+	 * ret: true if successful
+	 *      false if more space is needed and doubleMaxSize() fails.
+	 */
+	bool addItems(dccp_packet_state state, u_int8_t runlen, int count = 1);
+
+	/* Find where in the vector a info about a seqnum exists
+	 * arg: seqnum    - sequence number to find
+	 *      where     - resulting position in the vector
+	 *      seq_start - starting sequence number corresponding to where
+	 *      seq_end   - ending sequence number corresponding to where
+	 * ret: true if found
+	 *      false otherwise (where, seq_start, seq_end invalid)
+	 */
+	bool findSeqNum(u_int32_t seqnum, u_int16_t *where, u_int32_t *seq_start, u_int32_t *seq_end);
+
+	/* Increase the maximum size of the vector by a factor two
+	 * until DCCP_MAX_ACKV_SIZE is reached.
+	 * ret:  true if successful, false if already at DCCP_MAX_ACKV_SIZE
+	 */
+	bool doubleMaxSize();
+
+	/* Add an acknowledgment to ack history
+	 * arg: seqnum - sequence number of the sent ack packet
+	 */
+	void addToAckHistory(u_int32_t seqnum);
+
+	/* Remove all items in the ack history */
+	void clearAckHistory();
+
+public:
+	//ack vector conistency matrix
+	dccp_packet_state ackv_cons_[DCCP_NUM_PACKET_STATES][DCCP_NUM_PACKET_STATES];
+
+	/* Return a string reprenting a packet state
+	 * arg: state - packet state
+	 * ret: a string representation of state
+	 */
+	static const char* packetStateAsStr(dccp_packet_state state);
+
+	/* Constructor
+	 * arg: initialSize - initial size for the ack vector
+	 * ret: a new DCCPAckVector
+	 */
+	DCCPAckVector(u_int16_t initialSize);
+
+	/* Destructor */
+	~DCCPAckVector();
+
+	/* Add a packet to the ack vector (using ackv_cons_ when needed)
+	 * Will fill with NOT_RECV packets when packets are missing
+	 * arg: seqnum - sequence number of packet
+	 *      state  - packet state
+	 * ret: true if successful
+	 *      false if more space is needed and doubleMaxSize() fails
+	 *            or if packet is older than the oldest in the vector
+	 */
+	bool addPacket(u_int32_t seqnum, dccp_packet_state state);
+
+	/* Add a packet to the ack vector (using ackv_cons_ when needed)
+	 * Will fill with NOT_RECV packets when packets are missing
+	 * arg: seqnum   - sequence number of packet
+	 *      ecn      - packets ecn code point
+	 *      addNonce - if true, add packet nonce to ecn echo sum
+	 * ret: true if successful
+	 *      false if more space is needed and doubleMaxSize() fails
+	 *            or if packet is older than the oldest in the vector
+	 */
+	bool addPacket(u_int32_t seqnum, dccp_ecn_codepoint ecn, bool addNonce);
+
+	/* Remove packets older and including given seqnum from ack vector
+	 * arg: seqnum - sequence number of the largest packet to remove
+	 */
+	void removePackets(u_int32_t seqnum);
+
+	/* Merge two ack vectors.
+	 * Will read packet states from ackv and add them to this vector
+	 * using ackv_cons_.
+	 * If (ackv->seq_first_ > this->seq_first_)
+	 *    pad with DCCP_PACKET_NOT_RECV until they match
+	 * Discards all packets older than this->seq_last_.
+	 * If this->getSize() == 0
+	 *    use setAckVector()
+	 * arg: ackv - ack vector to merge with
+	 * ret: true if successful
+	 *      false if ackv == NULL or the upper limit on size is exceeded
+	 * Note: Adds packet in seqnum order until either successful
+	 *       or out of space.
+	 *       will NOT change ecn nonce echo as needed by the state change
+	 */
+	bool mergeWith(DCCPAckVector *ackv);
+	
+	/* Alter state of one packet.
+	 * Will split items as needed. Note will not alter 
+	 * arg: seqnum   - sequence number of packet to add
+	 *      newstate - packets new state
+	 *      oldstate - the packets old state
+	 * ret: true if successful
+	 *      false if packet is not in vector or size
+	 *            if the upper limit on size is exceeded
+	 * Note: will not alter the vector on failure.
+	 *       will NOT change ecn nonce echo as needed by the state change
+	 */
+	bool alterState(u_int32_t seqnum, dccp_packet_state newstate, dccp_packet_state *oldstate = NULL);
+	
+	/* Returns the state of a packet
+	 * arg: seqnum - packets sequence number
+	 *      state  - the packets state (if found)
+	 * ret: true if packet is found
+	 *      false if not
+	 */
+	bool getState(u_int32_t seqnum, dccp_packet_state *state);
+
+
+	/* Packet walk functions.
+	 * Note you can't start a descending packet walk and then
+	 * use prevPacket(), and similiar, you can't use nextPacket
+	 * if you started an ascending packet walk.
+	 */
+
+	/* Start a walk through the ack vector packet by packet,
+	 * descending on sequence number.
+	 */
+	void startPacketWalk();
+
+	/* Next packet in walk
+	 * arg: seqnum - sequence number of next packet
+	 *      state  - packet state
+	 * ret: true if packet is found
+	 *      false if packet is not found or walk not initiated.
+	 */
+	bool nextPacket(u_int32_t *seqnum, dccp_packet_state *state);
+
+	/* Start a walk through the ack vector packet by packet,
+	 * ascending on sequence number.
+	 */
+	void startReversePacketWalk();
+
+	/* Previous packet in walk
+	 * arg: seqnum - sequence number of previous packet
+	 *      state  - packet state
+	 * ret: true if packet is found
+	 *      false if packet is not found or walk not initiated.
+	 */
+	bool prevPacket(u_int32_t *seqnum, dccp_packet_state *state);
+
+	/* Start a walk through the ack vector, item for item
+	 * Most recent interval first.
+	 */
+	void startIntervalWalk();
+
+	/* Next interval in walk
+	 * arg: interval  - found interval
+	 *      seq_start - the sequence number that started the interval
+	 *      seq_end   - the sequence number that ended the interval
+	 *      state     - the state of the packet in the interval
+	 * ret: true if an interval is found
+	 *      false if not or walk not initiated.
+	 */
+	bool nextInterval(u_char *interval, u_int32_t *seq_start, u_int32_t *seq_end, dccp_packet_state *state);
+
+	/* Return the ECN Nonce Echo
+	 * ret: ECN Nonce Echo
+	 */
+	u_int8_t getENE();
+
+	/* Set the ECN Nonce Echo
+	 * arg: ene - new ene
+	 */
+	void setENE(u_int8_t ene);
+
+	/* Chech if ack vector is empty
+	 * ret: true if empty, otherwise false
+	 */
+	bool isEmpty();
+
+	/* Return the first sequence number represented in the ack vector
+	 * ret: first sequence number in the vector
+	 *      0 if empty
+	 */
+	u_int32_t getFirstSeqNum();
+
+	/* Return the last sequence number represented in the ack vector
+	 * ret: last sequence number in the vector
+	 *      0 if empty
+	 */
+	u_int32_t getLastSeqNum();
+	
+	/* Return the current size of the ack vector
+	 * ret: current size
+	 */
+	int getSize();
+		
+	/* Return the ack vector
+	 * arg: vect - array to store ack vector in
+	 *      size - size of vect
+	 * ret: The size of returned ack vector (also in size) if successful
+	 *      DCCP_ACKV_EMPTY if its empty
+	 *      DCCP_ACKV_ERR_SIZE if size is too small
+	 *	(will set size to the size needed)
+	 */		
+	int getAckVector(u_char* vect, u_int16_t *size);
+
+	/* Import an ack vector (clearing the old one)
+	 * arg: vect      - ack vector to set
+	 *      size      - size of vect
+	 *      seq_start - sequnce number of the first packet in ack vector
+	 *      ene       - the current ecn nonce echo
+	 * ret: true if successful
+	 *      false if out of space
+	 */
+	bool setAckVector(const u_char* vect, u_int16_t size, u_int32_t seq_start, u_int8_t ene);
+	
+	/* Return and mark the ackvector as sent in history
+	 * arg: seqnum - sequence number of packet on which ackvector is added
+	 *      acknum - acknowledgement number on that packet (== seq_first_)
+	 *      vect   - ack vector to send
+	 *      size   - size of ackvector
+	 * ret: same as getAckVector()
+	 * Note: Fails hard if seq_first_ != acknum! 
+	 */
+	int sendAckVector(u_int32_t seqnum, u_int32_t acknum, u_char* vect, u_int16_t *size);
+
+	/* Add ack vector options and mark as sent in history
+	 * arg: seqnum  - sequence number of packet on which ackvector is added
+	 *      acknum  - acknowledgement number on that packet (== seq_first_)
+	 *      options - DCCPOptions object to add ackvector to
+	 * ret: DCCP_OPT_NO_ERR on success
+	 *      similar to getAckVector and addOptions()
+	 */
+	int sendAckVector(u_int32_t seqnum, u_int32_t acknum, DCCPOptions *options);
+	
+	/* Check if state may be cleared due to an received ack.
+	 * If ackv is present, check in that to see if an ack has been acked
+	 * otherwise check only on acknum
+	 * arg: acknum - acknowledgement number recv
+	 *      ackv - ackvector received (if any)
+	 */
+	void ackRecv(u_int32_t acknum, DCCPAckVector *ackv = NULL);
+
+	/* Print ack vector state including intervals and ack history
+	 * Note: Uses interval walk
+	 */
+	void print();
+
+	/* Print all packets
+	 * arg: asc - if true, print in ascending order, otherwise descending
+	 * Note: uses packet walk
+	 */
+	void printPackets(bool asc = false);
+
+	/* Print ack history */
+	void printHistory();
+}; 
+
+#endif
+
+
+
diff -urNU5 ns-2.33/dccp/dccp.cc ns-2.33-dccp/dccp/dccp.cc
--- ns-2.33/dccp/dccp.cc	1970-01-01 10:00:00.000000000 +1000
+++ ns-2.33-dccp/dccp/dccp.cc	2008-05-05 17:17:43.000000000 +1000
@@ -0,0 +1,1979 @@
+/* -*-	Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
+
+/* Copyright (c) 2004  Nils-Erik Mattsson 
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ *
+ * $Id: ns-233-dccp-1.patch 210 2008-05-13 03:43:55Z omehani $ */
+
+#include "ip.h"
+#include "dccp.h"
+#include "flags.h"
+#include "random.h"
+
+//string representation of types
+char* DCCPAgent::state_str_[DCCP_NUM_STATES] =
+{"CLOSED", "LISTEN", "RESPOND", "REQUEST", "OPEN", "CLOSEREQ", "CLOSING"};
+
+int DCCPAgent::hdr_size_[DCCP_NUM_PTYPES] =
+{ DCCP_REQ_HDR_SIZE, DCCP_RESP_HDR_SIZE, DCCP_DATA_HDR_SIZE,
+  DCCP_ACK_HDR_SIZE, DCCP_DACK_HDR_SIZE, DCCP_CREQ_HDR_SIZE,
+  DCCP_CLOSE_HDR_SIZE, DCCP_RESET_HDR_SIZE };
+
+char* DCCPAgent::ptype_str_[DCCP_NUM_PTYPES] =
+{ "REQUEST", "RESPONSE", "DATA", "ACK", "DATAACK", "CLOSEREQ", "CLOSE", "RESET" };
+
+char* DCCPAgent::reset_reason_str_[DCCP_NUM_RESET_REASONS]=
+{ "Unspecified" , "Closed", "Invalid Packet", "Option Error", "Feature Error",
+  "Connection Refused", "Bad Service Name", "Too Busy", "Bad Init Cookie",
+  "Unknown", "Unanswered Challenge", "Fruitless Negotiation",
+  "Agression Penalty", "No Connection", "Aborted", "Extended Seqnos",
+  "Mandatory Failure"
+};
+
+char* DCCPAgent::feature_location_str_[DCCP_NUM_FEAT_LOCS] =
+{ "LOCAL", "REMOTE" };
+
+//OTcl linkage for DCCP agent
+static class DCCPClass : public TclClass {
+public:
+	DCCPClass() : TclClass("Agent/DCCP") {};
+	TclObject* create(int argc, const char*const* argv){
+		return (new DCCPAgent());
+	}
+} class_dccp;
+
+//methods for timer classes
+
+/* Constructor
+ * arg: agent - the owning agent (to notify about timeout)
+ * ret: A new DCCPRetransmitTimer
+ */
+DCCPRetransmitTimer::DCCPRetransmitTimer(DCCPAgent* agent) : TimerHandler(){
+	agent_ = agent;
+}
+
+/* Initialize the timer.
+ * arg: delay       - initial delay
+ *      maxToTDelay - total maximum delay
+ */
+void DCCPRetransmitTimer::init(double delay, double maxTotDelay){
+	force_cancel();
+	backoff_failed_ = false;
+	delay_ = delay;
+	tot_delay_ = 0;
+	max_tot_delay_ = maxTotDelay;
+}
+
+/* Called when the timer has expired
+ * arg: e - The event that happened (i.e. the timer expired)
+ */
+void DCCPRetransmitTimer::expire(Event *e){
+	agent_->timeout(DCCP_TIMER_RTX);
+}
+
+/* Back off the timer (by a factor of 2)
+ * The last back off will reach the max_tot_delay.
+ */
+void DCCPRetransmitTimer::backOff(){
+	if (tot_delay_ == 0){  //first scheduled
+	} else 	if (tot_delay_ + delay_ * 2 <= max_tot_delay_){
+		//we have not reached max_tot_delay
+		delay_ *= 2;    //exp back-off
+	} else {  //if we double, we would go beyond max_tot_delay
+		delay_ = max_tot_delay_-tot_delay_;
+		backoff_failed_ = true;
+	}
+	tot_delay_ += delay_;
+	
+	if(delay_ > 0.0)
+		resched(delay_);	
+}
+
+/* Check if the back-off failed (that is if max_tot_delay is reached)
+ * ret: true if back-off failed, otherwise false. 
+ */
+bool DCCPRetransmitTimer::backOffFailed(){
+	return backoff_failed_;
+}
+
+/* Constructor
+ * arg: agent - the owning agent (to notify about timeout)
+ * ret: A new DCCPSendTimer
+ */
+DCCPSendTimer::DCCPSendTimer(DCCPAgent* agent) : TimerHandler(){
+	agent_ = agent;
+}
+
+/* Called when the timer has expired
+ * arg: e - The event that happened (i.e. the timer expired)
+ */
+void DCCPSendTimer::expire(Event *e){
+	agent_->timeout(DCCP_TIMER_SND);
+}
+
+//private methods
+
+/* Creates a new packet and fills in some header fields
+ * ret: a new packet
+ */
+Packet* DCCPAgent::newPacket(){
+	Packet* pkt = allocpkt();
+	hdr_dccp* dccph = hdr_dccp::access(pkt);
+	hdr_dccpack* dccpah = hdr_dccpack::access(pkt);
+	hdr_flags* flagsh = hdr_flags::access(pkt);
+
+	//fill in seq number and (possibly) ack number
+	dccph->seq_num_ = seq_num_;
+	dccpah->ack_num_ = seq_num_recv_;
+
+	dccph->options_ = NULL;
+	dccph->ccval_ = 0;
+	dccph->cscov_ = cscov_;
+	
+	if (use_ecn_local_){  //mark packet as ecn capable
+		if (nonces_->uniform(-0.5,0.5) > 0){
+			//set ect(1)
+			flagsh->ect() = 0;
+			flagsh->ce() = 1;
+		} else {
+			//set ect(0)
+			flagsh->ect() = 1;
+			flagsh->ce() = 0;
+		}
+	} else {
+		flagsh->ect() = 0;
+		flagsh->ce() = 0;
+	}
+
+	return pkt;
+}
+
+/* Check if an incoming packet is valid
+ * arg: pkt - incoming packet
+ * ret: true if the packet is valid, otherwise false
+ */
+bool DCCPAgent::checkPacket(Packet* pkt){
+	bool new_pkt;
+	bool result = true;
+	hdr_cmn* cmnh = hdr_cmn::access(pkt);
+	hdr_dccp* dccph = hdr_dccp::access(pkt);
+	hdr_dccpack* dccpah = hdr_dccpack::access(pkt);
+
+	if (cmnh->error()){  //e.g. "checksum failed"
+		debug("%f, DCCP(%s)::checkPacket() - Packet is corrupt (%d)\n",
+			      now(), name(), dccph->seq_num_);
+		return false;
+	}
+	
+	bool ack_recv = (dccph->type_ != DCCP_DATA) && (dccph->type_ != DCCP_REQUEST);
+	if (ack_recv && packet_sent_ && dccpah->ack_num_ >= seq_num_){
+		//invalid ack_num_
+		debug("%f, DCCP(%s)::checkPacket() - Ack num not valid (%d)\n",
+			      now(), name(), dccpah->ack_num_);
+		return false;
+	} else if (ack_recv && !packet_sent_){
+		//if no packet has been sent, allow only resets with acknum 0
+		if (!(dccph->type_ == DCCP_RESET && dccpah->ack_num_ == 0)){
+			debug("%f, DCCP(%s)::checkPacket() - Ack num not valid (No packet sent!) (%d)\n",
+			      now(), name(), dccpah->ack_num_);
+			return false;
+		}
+	}
+		
+	new_pkt = (dccph->seq_num_ > seq_num_recv_);
+
+	if (dccph->type_ == DCCP_RESET) //reset is always valid 
+		result = true;
+	else
+		switch (state_){
+		case DCCP_STATE_CLOSED:
+			result = false;
+			break;
+		case DCCP_STATE_LISTEN:
+			result = (dccph->type_ == DCCP_REQUEST);
+		break;
+		case DCCP_STATE_RESPOND:
+			result = (new_pkt && dccph->type_ == DCCP_REQUEST ||
+				  dccph->type_ == DCCP_CLOSE ||
+				  new_pkt && dccph->type_ == DCCP_ACK ||
+				  new_pkt && dccph->type_ == DCCP_DATAACK);
+			break;
+		case DCCP_STATE_OPEN:
+			result = (dccph->type_ == DCCP_CLOSE ||
+				  dccph->type_ == DCCP_CLOSEREQ && !server_ ||
+				  dccph->type_ == DCCP_ACK ||
+				  dccph->type_ == DCCP_DATA ||
+				  dccph->type_ == DCCP_DATAACK);
+			break;
+		case DCCP_STATE_REQUEST:
+			result = (dccph->type_ == DCCP_RESPONSE
+				  && dccpah->ack_num_ == seq_num_-1 ||
+				  dccph->type_ == DCCP_CLOSE);
+			break;
+		case DCCP_STATE_CLOSEREQ:
+			result = (dccph->type_ == DCCP_CLOSE ||
+				  dccph->type_ == DCCP_ACK ||
+				  dccph->type_ == DCCP_DATA ||
+				  dccph->type_ == DCCP_DATAACK);
+		break;
+		case DCCP_STATE_CLOSING:
+			result = (dccph->type_ == DCCP_CLOSEREQ ||
+				  dccph->type_ == DCCP_ACK ||
+				  dccph->type_ == DCCP_DATA ||
+				  dccph->type_ == DCCP_DATAACK);
+		break;
+
+		default:
+			fprintf(stderr, "%f, DCCP(%s):checkPacket() - Illegal state (%d)!\n",
+			now(), name(),state_);
+			fflush(stdout);
+			abort();
+		}
+	
+	if (result){
+		//set highest seqnum and acknum recv so far
+		if (seq_num_recv_ < dccph->seq_num_)
+			seq_num_recv_ = dccph->seq_num_;
+		if (ack_recv && ack_num_recv_ < dccpah->ack_num_)
+			ack_num_recv_ = dccpah->ack_num_;
+	}
+	return result;
+}
+
+
+/* Add feature negotiation options on packets for features
+ * currently under negotiation. Will use getFeature() to obtain values.
+ */
+void DCCPAgent::addFeatureOptions(){
+	int result;
+	u_int8_t type;
+	u_char* data = new u_char[DCCP_OPT_MAX_LENGTH];
+	int i;
+	
+	for(i = 0; i < feat_list_used_; i++){
+		if (!packet_recv_ || feat_list_first_[i] || feat_list_seq_num_[i] <= ack_num_recv_){
+			//this is the first time, or last change for this
+			//feature should have been confirmed by now 
+
+			if (feat_list_loc_[i] == DCCP_FEAT_LOC_LOCAL)
+				type = DCCP_OPT_CHANGEL;
+			else
+				type = DCCP_OPT_CHANGER;
+
+			result	= getFeature(feat_list_num_[i], feat_list_loc_[i], data, DCCP_OPT_MAX_LENGTH);
+			if (result > 0){
+				feat_list_seq_num_[i] = seq_num_;
+				debug("%f, DCCP(%s)::addFeatureOptions() - Adding option type %d for feat %d, location %s, seq %d\n",
+				      now(), name(), type, feat_list_num_[i], featureLocationAsStr(feat_list_loc_[i]),feat_list_seq_num_[i]);
+				opt_->addFeatureOption(type,feat_list_num_[i], data, result);
+				feat_list_first_[i] = false;
+			} else
+				debug("%f, DCCP(%s)::addFeatureOptions() - getFeature() failed for feature %d, location %s. Error: %d \n",
+					now(), name(), feat_list_num_[i], featureLocationAsStr(feat_list_loc_[i]),result);
+			
+		} else
+			debug("%f, DCCP(%s)::addFeatureOptions() - Old change still pending for feat %d, location %s (seq_sent: %d ack_recv: %d)\n",
+				      now(), name(), feat_list_num_[i], featureLocationAsStr(feat_list_loc_[i]),feat_list_seq_num_[i],ack_num_recv_);
+	}
+		
+	for(i = 0; i < feat_conf_used_; i++){
+		if (feat_conf_loc_[i] == DCCP_FEAT_LOC_LOCAL)
+			type = DCCP_OPT_CONFIRML;
+		else
+			type = DCCP_OPT_CONFIRMR;
+		
+		result	= getFeature(feat_conf_num_[i], feat_conf_loc_[i], data, DCCP_OPT_MAX_LENGTH);
+		if (result > 0){
+			debug("%f, DCCP(%s)::addFeatureOptions() - Adding option type %d for feat %d, location %s\n", now(), name(), type, feat_conf_num_[i], featureLocationAsStr(feat_conf_loc_[i]));
+			opt_->addFeatureOption(type,feat_conf_num_[i], data, result);
+		} else
+		    debug("%f, DCCP(%s)::addFeatureOptions() - getFeature() failed for feature %d, location %s. Error: %d \n", now(), name(), feat_conf_num_[i], featureLocationAsStr(feat_conf_loc_[i]),result); 
+	}
+	feat_conf_used_ = 0;
+	delete [] data;
+}
+
+/* Finish feature negotiation for a feature abd remove it from
+ * the list of ongoing feature negotiations.
+ * arg: num      - feature number
+ *      location - feature location
+ * ret: true if the feature is removed
+ *      false if it doesn't exist in the list
+ */
+bool DCCPAgent::finishFeatureNegotiation(u_int8_t num, dccp_feature_location location){
+	int walker = 0;
+	while (walker < feat_list_used_){ //walk through the list
+		if (feat_list_num_[walker] == num && feat_list_loc_[walker] == location){
+			//we found the feature
+			//move the rest of the list one step up
+			if (walker + 1 < feat_list_used_){
+				for(int i = walker; i < feat_list_used_-1; i++){
+					feat_list_num_[i] = feat_list_num_[i+1];
+					feat_list_loc_[i] = feat_list_loc_[i+1];
+				}
+			}
+			feat_list_used_--;
+			return true;
+				
+		}
+		walker++;
+	}
+	return false;
+}
+
+/* Add a feature to the list of features to confirm
+ * Will only add one entry for each (feat,loc) pair
+ * arg: num      - feature number
+ *      location - feature location
+ */
+void DCCPAgent::confirmFeature(u_int8_t num, dccp_feature_location location){
+	int walker = 0;
+	while (walker < feat_conf_used_){ //walk through the list
+		if (feat_conf_num_[walker] == num && feat_conf_loc_[walker] == location){
+			//we have found the feature
+			break;
+		}
+		walker++;
+	}
+
+	if (walker == feat_conf_used_ && feat_conf_used_ < feat_size_){
+		//add to the end of list
+		feat_conf_num_[walker] = num;
+		feat_conf_loc_[walker] = location;
+		feat_conf_used_++;
+	}
+}
+
+/* Find a feature in the list of ongoing negotiations
+ * arg: num      - feature number
+ *      location - feature location
+ * ret: position in the feature list if successfull
+ *      otherwise -1
+ */
+int DCCPAgent::findFeatureInList(u_int8_t num, dccp_feature_location location){
+	int walker = 0;
+	while (walker < feat_list_used_){ //walk through the list
+		if (feat_list_num_[walker] == num && feat_list_loc_[walker] == location){
+			//we have found the feature
+			return walker;
+		}
+		walker++;
+	}
+	return -1;
+}
+
+//protected methods
+
+/* OTcl binding of variables */
+void DCCPAgent::delay_bind_init_all(){
+	delay_bind_init_one("packetSize_");
+	delay_bind_init_one("initial_rtx_to_");
+	delay_bind_init_one("max_rtx_to_");
+	delay_bind_init_one("resp_to_");
+	delay_bind_init_one("sb_size_");
+	delay_bind_init_one("opt_size_");
+	delay_bind_init_one("feat_size_");
+	delay_bind_init_one("ackv_size_");
+	delay_bind_init_one("ccid_");
+	delay_bind_init_one("use_ecn_local_");
+	delay_bind_init_one("use_ecn_remote_");
+	delay_bind_init_one("ack_ratio_local_");
+	delay_bind_init_one("ack_ratio_remote_");
+	delay_bind_init_one("use_ackv_local_");
+	delay_bind_init_one("use_ackv_remote_");
+	delay_bind_init_one("q_scheme_");
+	delay_bind_init_one("q_local_");
+	delay_bind_init_one("q_remote_");
+	delay_bind_init_one("snd_delay_");
+	delay_bind_init_one("nam_tracevar_");
+	delay_bind_init_one("trace_all_oneline_");
+	delay_bind_init_one("allow_mult_neg_");
+	delay_bind_init_one("ndp_limit_");
+	delay_bind_init_one("ccval_limit_");
+	delay_bind_init_one("num_data_pkt_");
+	delay_bind_init_one("num_ack_pkt_");
+	delay_bind_init_one("num_dataack_pkt_");
+	delay_bind_init_one("cscov_");
+	
+	Agent::delay_bind_init_all();
+
+        reset();
+}
+
+int DCCPAgent::delay_bind_dispatch(const char *varName, const char *localName, TclObject *tracer){
+        if (delay_bind(varName, localName, "packetSize_", &size_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "initial_rtx_to_", &initial_rtx_to_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "max_rtx_to_", &max_rtx_to_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "resp_to_", &resp_to_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "sb_size_", &sb_size_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "opt_size_", &opt_size_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "feat_size_", &feat_size_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "ackv_size_", &ackv_size_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "ccid_", &ccid_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "use_ecn_local_", &use_ecn_local_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "use_ecn_remote_", &use_ecn_remote_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "ack_ratio_local_", &ack_ratio_local_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "ack_ratio_remote_", &ack_ratio_remote_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "use_ackv_local_", &use_ackv_local_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "use_ackv_remote_", &use_ackv_remote_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "q_scheme_", &q_scheme_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "q_local_", &q_local_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "q_remote_", &q_remote_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "snd_delay_", &snd_delay_, tracer)) return TCL_OK;
+	if (delay_bind_bool(varName, localName, "trace_all_oneline_", &trace_all_oneline_ , tracer)) return TCL_OK;
+        if (delay_bind_bool(varName, localName, "nam_tracevar_", &nam_tracevar_ , tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "allow_mult_neg_", &allow_mult_neg_ , tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "ndp_limit_", &ndp_limit_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "ccval_limit_", &ccval_limit_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "num_data_pkt_", &num_data_pkt_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "num_ack_pkt_", &num_ack_pkt_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "num_dataack_pkt_", &num_dataack_pkt_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "cscov_", &cscov_, tracer)) return TCL_OK;
+	return Agent::delay_bind_dispatch(varName, localName, tracer);
+}
+
+/* Return a string representation of a type */
+const char* DCCPAgent::stateAsStr(dccp_state state){
+        if (state < DCCP_NUM_STATES && state >= 0)
+		return state_str_[state];
+	else
+		return "UNKNOWN";
+}
+
+const char* DCCPAgent::packetTypeAsStr(dccp_packet_type type){
+	if (type < DCCP_NUM_PTYPES && type >= 0)
+		return ptype_str_[type];
+	else
+		return "UNKNOWN";
+}
+
+const char* DCCPAgent::resetReasonAsStr(dccp_reset_reason reason){
+	if (reason < DCCP_NUM_RESET_REASONS && reason >= 0)
+		return reset_reason_str_[reason];
+	else
+		return "Unknown";
+}
+
+const char* DCCPAgent::featureLocationAsStr(dccp_feature_location location){
+	if (location < DCCP_NUM_FEAT_LOCS && location >= 0)
+		return feature_location_str_[location];
+	else
+		return "UNKNOWN";
+}
+
+/* Return the header size (without options) of a packet type
+ * arg: type - packet type
+ * ret: header size
+ */
+int DCCPAgent::headerSize(dccp_packet_type type){
+	if (type < DCCP_NUM_PTYPES && type >= 0)
+		return hdr_size_[type];
+	else
+		return 0;
+}
+
+/* Extract the ecn codepoint
+ * arg: pkt - packet
+ * ret: ecn codepoint of packet
+ */
+dccp_ecn_codepoint DCCPAgent::getECNCodePoint(Packet* pkt){
+	hdr_flags* flagsh = hdr_flags::access(pkt);
+	if (flagsh->ect() == 1 && flagsh->ce() == 1)
+		return ECN_CE;
+	else if (flagsh->ect() == 0 && flagsh->ce() == 1)
+		return ECN_ECT1;
+	else if (flagsh->ect() == 1 && flagsh->ce() == 0)
+		return ECN_ECT0;
+	else
+		return ECN_NOT_ECT;
+}
+
+/* Get the packet nonce
+ * arg: pkt - packet
+ * ret: 0 if ECT(0) is set
+ *      1 if ECT(1) is set
+ *      otherwise -1
+ */
+int DCCPAgent::getNonce(Packet* pkt){
+	dccp_ecn_codepoint ecn = DCCPAgent::getECNCodePoint(pkt);
+	if (ecn == ECN_ECT0 || ecn == ECN_ECT1)
+		return ecn;
+	else
+		return -1;
+}
+
+/* Changes state (and cancel/init/sched timers)
+ * arg: new_state - new state
+ */
+inline void DCCPAgent::changeState(dccp_state new_state){
+	debug("%f, DCCP(%s)::changeState() - State changed from %s (%d) to %s (%d)\n",
+	      now(), name(), stateAsStr(state_), state_, stateAsStr(new_state), new_state);
+	state_ = new_state;
+	switch (new_state){
+	case DCCP_STATE_RESPOND:
+		timer_rtx_->force_cancel();
+		timer_rtx_->sched(resp_to_);
+		break;
+	case DCCP_STATE_OPEN:
+		timer_rtx_->force_cancel();
+		break;
+	case DCCP_STATE_REQUEST:
+	case DCCP_STATE_CLOSEREQ:
+	case DCCP_STATE_CLOSING:
+		cancelTimers();
+		timer_rtx_->init(initial_rtx_to_,max_rtx_to_);
+		break;
+	default:
+		;
+	}
+}
+
+/* Reinitialize the agent */
+void DCCPAgent::reset(){
+	debug("%f, DCCP(%s)::reset() - Reset called (seq_num_ %d)\n", now(), name(), seq_num_);
+	
+	cancelTimers();
+	if (server_)
+		changeState(DCCP_STATE_LISTEN);
+	
+	if (state_ != DCCP_STATE_LISTEN && state_ != DCCP_STATE_CLOSED)
+		changeState(DCCP_STATE_CLOSED);
+	
+	delete opt_;
+	opt_ = new DCCPOptions(opt_size_);
+	delete sb_;
+	sb_ = new DCCPSendBuffer(sb_size_);
+	delete ackv_;
+	ackv_ = new DCCPAckVector(ackv_size_);
+        elapsed_time_recv_ = 0;
+	send_ackv_ = true;
+	manage_ackv_ = true;
+	seq_num_ = 0;
+	seq_num_recv_ = 0;
+	ack_num_recv_ = 0;
+	ackv_recv_ = NULL;
+	ack_num_ = 0;
+	ccval_ = 0;
+	send_ack_ = false;
+	conn_est_ = false;
+	output_ = false;
+	output_flag_ = false;
+	infinite_send_ = false;
+	close_on_empty_ = false;
+	server_ = false;
+	ndp_ = 0;
+	ack_ratio_local_ = DCCP_FEAT_DEF_ACK_RATIO;
+	ack_ratio_remote_ = DCCP_FEAT_DEF_ACK_RATIO;
+	q_local_ = DCCP_FEAT_DEF_Q;
+	q_remote_ = DCCP_FEAT_DEF_Q;
+	delete [] feat_list_num_;
+	delete [] feat_list_loc_;
+	delete [] feat_list_seq_num_;
+	delete [] feat_list_first_;
+	feat_list_num_ = new u_int8_t[feat_size_];
+	feat_list_loc_ = new dccp_feature_location[feat_size_];
+	feat_list_seq_num_ = new u_int32_t[feat_size_];
+	feat_list_first_ = new bool[feat_size_];
+	feat_list_used_ = 0;
+
+	delete [] feat_conf_num_;
+	delete [] feat_conf_loc_;
+	feat_conf_num_ = new u_int8_t[feat_size_];
+	feat_conf_loc_ = new dccp_feature_location[feat_size_];
+	feat_conf_used_ = 0;
+	
+	seq_last_feat_neg_ = 0;
+	feat_first_in_pkt_ = true;
+
+	packet_sent_ = false;
+	packet_recv_ = false;
+	ar_unacked_ = 0;
+
+	rtt_conn_est_ = 0.0;
+	
+	num_data_pkt_ = 0;
+	num_ack_pkt_ = 0;
+	num_dataack_pkt_ = 0;
+}
+
+/* Send a packet.
+ * arg: try_pure_ack - if true, try to send a pure ack if cc
+ *                     refuses to send a dataack
+ */
+void DCCPAgent::output(bool try_pure_ack){
+	int data_size;
+	Packet* pkt;
+	hdr_dccp *dccph;
+	hdr_dccpack *dccpah;
+	hdr_cmn *cmnh;
+	bool moreToSend;
+	bool tell_cc;
+	bool tell_app;
+	
+ again: 
+	data_size = 0;
+	moreToSend = false;
+	tell_cc = false;
+	tell_app = false;
+	pkt = newPacket();
+	dccph = hdr_dccp::access(pkt);
+	dccpah = hdr_dccpack::access(pkt);
+	cmnh = hdr_cmn::access(pkt);
+       
+	switch(state_){
+	case DCCP_STATE_REQUEST:
+		dccph->type_ = DCCP_REQUEST;
+		cmnh->ptype() = PT_DCCP_REQ;
+		packet_sent_ = true;
+		timer_rtx_->backOff();
+		rtt_conn_est_ = now();
+		goto send;
+		break;
+	case DCCP_STATE_RESPOND:
+		dccph->type_ = DCCP_RESPONSE;
+		cmnh->ptype() = PT_DCCP_RESP;
+		packet_sent_ = true;
+		rtt_conn_est_ = now();
+		goto send;
+		break;
+	case DCCP_STATE_OPEN: 
+		if(!conn_est_){ //the last ack in handshake
+			dccph->type_ = DCCP_ACK;
+			cmnh->ptype() = PT_DCCP_ACK;
+			send_ack_ = false;
+			conn_est_ = true;
+			goto send;
+		}
+			
+		if (infinite_send_ || !(sb_->empty())){
+			//we have data to send
+			dccph->type_ = DCCP_DATA;
+			cmnh->ptype() = PT_DCCP_DATA;
+			if (!infinite_send_){
+				cmnh->size() = sb_->top();
+			}
+			data_size = cmnh->size();
+		}
+
+		if (data_size > 0 && send_ack_){
+			dccph->type_ = DCCP_DATAACK;
+			cmnh->ptype() = PT_DCCP_DATAACK;
+		} else if (send_ack_) {
+			dccph->type_ = DCCP_ACK;
+			cmnh->ptype() = PT_DCCP_ACK;
+		} else if (data_size == 0)
+			goto free;
+		//ask cc of permission to send
+		if (!send_askPermToSend(data_size,pkt)) {
+			if (try_pure_ack && data_size > 0 && send_ack_){
+				//we had a DCCP-DataAck packet, try to send a pure ack
+				data_size = 0;
+				cmnh->size() = 0;
+				dccph->type_ = DCCP_ACK;
+				cmnh->ptype() = PT_DCCP_ACK;
+				if (!send_askPermToSend(data_size,pkt)) {
+					debug("%f, DCCP(%s)::output() - CC refused sending a pure ack packet\n",
+					      now(), name());
+					goto free;
+				}
+			} else 
+				goto free;
+		}
+		//remove from sendbuffer (if applicable)
+		if (data_size > 0 && !infinite_send_){
+			sb_->remove();
+			tell_app = sb_->empty();
+		}
+		
+		tell_cc = true;
+		
+		if (send_ack_){  //we are going to send an ack
+			dccpah->ack_num_ = ack_num_;
+			//add ackvector if applicable
+			if (use_ackv_local_ && send_ackv_) {
+				ackv_->sendAckVector(dccph->seq_num_, dccpah->ack_num_,opt_);
+			}
+		}
+		dccph->ccval_ = ccval_;
+		send_ack_ = false;
+		goto send;
+		break;
+	case DCCP_STATE_CLOSEREQ:
+		dccph->type_ = DCCP_CLOSEREQ;
+		cmnh->ptype() = PT_DCCP_CLOSEREQ;
+		timer_rtx_->backOff();
+		break;
+	case DCCP_STATE_CLOSING:
+		dccph->type_ = DCCP_CLOSE;
+		cmnh->ptype() = PT_DCCP_CLOSE;
+		timer_rtx_->backOff();
+		break;
+	default:
+		;
+	}
+       
+ send:
+	assert(opt_ != NULL);
+	addFeatureOptions();
+	
+	//calculate packet size and data offset
+	cmnh->size() = data_size + headerSize(dccph->type_)+opt_->getSize();
+	dccph->data_offset_ = (headerSize(dccph->type_)+opt_->getSize()) / 4;
+
+	//attach options
+	dccph->options_ = opt_;
+	opt_ = new DCCPOptions(opt_size_);
+	
+	//set ndp
+	if (data_size == 0)
+		ndp_ = (ndp_ + 1) % ndp_limit_;
+	dccph->ndp_ = ndp_;
+	
+	debug("%f, DCCP(%s)::output() - type %s (%d), seq: %d, ack: %d, size: %d, data_size %d, data_offset_ %d, ndp: %d, ecn: %d\n",
+	      now(), name(), packetTypeAsStr(dccph->type_), dccph->type_, dccph->seq_num_, dccpah->ack_num_, cmnh->size(), data_size, dccph->data_offset_,
+	      dccph->ndp_,getECNCodePoint(pkt));
+
+	moreToSend = (state_ == DCCP_STATE_OPEN && (infinite_send_ || !sb_->empty()));
+	seq_num_++;
+	if(tell_cc) //inform cc
+		send_packetSent(pkt, moreToSend, data_size);
+
+	switch(cmnh->ptype()){
+	case PT_DCCP_DATA:
+		num_data_pkt_++;
+		break;
+	case PT_DCCP_ACK:
+		num_ack_pkt_++;
+		break;
+	case PT_DCCP_DATAACK:
+		num_dataack_pkt_++;
+		break;
+	default:
+		;
+	}
+	
+	//send packet
+	send(pkt,0);
+
+	if (tell_app){ //inform application
+		assert(!moreToSend);
+		idle();
+
+		if (close_on_empty_)
+			close();
+		return;
+	}
+
+	ccval_ = 0;
+		
+	if (moreToSend)  //try to send more data if available
+		goto again;
+	return;
+ free:
+	Packet::free(pkt);
+}
+
+/* Send a reset packet.
+ * arg: reason  - reason for reset
+ *      data<X> - data to include on reset packet
+ */
+void DCCPAgent::sendReset(dccp_reset_reason reason, u_int8_t data1,
+	       u_int8_t data2, u_int8_t data3){
+	Packet *pkt = newPacket();
+	hdr_dccp *dccph = hdr_dccp::access(pkt);
+	hdr_dccpack *dccpah = hdr_dccpack::access(pkt);
+	hdr_dccpreset *dccpresh = hdr_dccpreset::access(pkt);
+	hdr_cmn *cmnh = hdr_cmn::access(pkt);
+
+	//fill in header info
+	dccph->type_ = DCCP_RESET;
+	cmnh->ptype() = PT_DCCP_RESET;
+	dccpresh->rst_reason_ = reason;
+	dccpresh->rst_data1_ = data1;
+	dccpresh->rst_data2_ = data2;
+	dccpresh->rst_data3_ = data3;
+	cmnh->size() = headerSize(dccph->type_);
+	dccph->data_offset_ = cmnh->size() / 4;
+	assert(cmnh->size() % 4 != 0);
+	dccph->options_ = new DCCPOptions(opt_size_);
+	if (state_ != DCCP_STATE_CLOSED && state_ != DCCP_STATE_LISTEN){
+		//we have valid sequence number
+		ndp_ = (ndp_ + 1) % ndp_limit_;
+		dccph->ndp_ = ndp_;
+		seq_num_++;
+	} else {
+		dccph->ndp_ = 1;
+		dccph->seq_num_ = 0;
+	}
+	dccpah->ack_num_ = seq_num_recv_;
+
+	debug("%f, DCCP(%s)::sendReset() - Sent a RESET packet (Reason %s (%d), data (%d,%d,%d), seq: %d, ack: %d, size: %d, data_offset_ %d, ndp: %d)\n",
+	      now(), name(), resetReasonAsStr(dccpresh->rst_reason_), dccpresh->rst_reason_, dccpresh->rst_data1_, dccpresh->rst_data2_, dccpresh->rst_data3_, dccph->seq_num_, dccpah->ack_num_, cmnh->size(), dccph->data_offset_,dccph->ndp_);
+	send(pkt,0);
+}
+
+/* Parse options in a packet.
+ * Will call parseOption() on every option found.
+ * Fails if parseOption() fails.
+ * arg: pkt - packet
+ * ret: true if parse is successful
+ *      false if the parse failed and the connection should be reset
+ */
+bool DCCPAgent::parseOptions(Packet *pkt){
+	int result = 0;
+	u_int8_t *type = new u_int8_t;
+	u_char *data = new u_char[DCCP_OPT_MAX_LENGTH];
+	hdr_dccp *dccph = hdr_dccp::access(pkt);
+	DCCPOptions* options = dccph->options_;
+
+	if(options == NULL){
+		delete type;
+		delete [] data;
+		return false;
+	}
+	
+	feat_first_in_pkt_ = true;
+
+	options->startOptionWalk();
+	result = options->nextOption(type, data, DCCP_OPT_MAX_LENGTH);
+
+	while (result >= 0){  //walk through and process opt until done or fail
+		if(!processOption(*type, data, result, pkt)){
+			delete type;
+			delete [] data;
+			return false;
+		}
+			
+		result = options->nextOption(type, data, DCCP_OPT_MAX_LENGTH);	
+	}
+	
+	delete type;
+	delete [] data;
+	return true;
+}
+
+/* Process an incoming option.
+ * arg: type - option type
+ *      data - option data
+ *      size - size of opption data
+ *      pkt  - the packet the option was received on
+ * ret: true if option processing was successful
+ *      false if it fails
+ */
+bool DCCPAgent::processOption(u_int8_t type, u_char* data, u_int8_t size, Packet *pkt){
+	debug("%f, DCCP(%s)::processOption() - Type %d, data %d, %d, %d ... size %d\n",
+	      now(), name(), type, (size > 0 ? data[0] : 0),(size > 1 ? data[1] : 0),
+	      (size > 2 ? data[2] : 0), size);
+	int result = 0;
+	dccp_feature_location loc;
+	hdr_dccp *dccph = hdr_dccp::access(pkt);
+	hdr_dccpack *dccpah = hdr_dccpack::access(pkt);
+
+	//allow only changeR(ack_ratio) when connection is established
+	if (state_ == DCCP_STATE_OPEN && (type == DCCP_OPT_CHANGER || type == DCCP_OPT_CONFIRML)){
+		if (size > 0 && getFeatureType((u_int8_t) data[0]) == DCCP_FEAT_TYPE_SP){
+			fprintf(stdout,"%f, DCCP(%s)::processOption() - Feature neg of feat %d is not allowed after connection establishment\n",
+				now(), name(), data[0]);
+			return true;
+		}
+	} else if (state_ == DCCP_STATE_OPEN && (type == DCCP_OPT_CHANGEL || type == DCCP_OPT_CONFIRMR) && size > 0 && getFeatureType((u_int8_t) data[0]) == DCCP_FEAT_TYPE_NN) {
+		fprintf(stdout,"%f, DCCP(%s)::processOption() - ChangeL or ConfirmR are not allowed for non-negotiable features (feat %u)\n",
+				now(), name(), data[0]);
+			return true;
+	}
+	
+	u_int16_t ui16 = 0;
+	u_int32_t ui32 = 0;
+
+	//check that feat neg options are processed in seq num order
+	if (type == DCCP_OPT_CHANGEL || type == DCCP_OPT_CHANGER
+	    || type == DCCP_OPT_CONFIRML || type == DCCP_OPT_CONFIRMR){
+		if (packet_recv_ && feat_first_in_pkt_ && dccph->seq_num_ <= seq_last_feat_neg_){
+			debug("%f, DCCP(%s)::processOption() - Type %d: feature neg option is out of order (last seq %u, seq now %u)\n", now(), name(), type, seq_last_feat_neg_,dccph->seq_num_);
+			return true;
+		} else {
+			seq_last_feat_neg_ = dccph->seq_num_;
+			feat_first_in_pkt_ = false;
+		}
+	}
+	
+	switch(type){
+	case DCCP_OPT_PADDING:
+		break;
+	case DCCP_OPT_QUIESCENCE:
+		break;
+	case DCCP_OPT_CHANGEL:
+		if (size > 1){
+			result = setFeature(data[0], DCCP_FEAT_LOC_REMOTE, &(data[1]), size-1);
+			if (result != DCCP_FEAT_OK)
+				goto reset;
+			confirmFeature(data[0], DCCP_FEAT_LOC_REMOTE);
+
+			if (allow_mult_neg_ > 0 && feat_conf_used_ > 0 && state_ == DCCP_STATE_OPEN){
+				//add an ack number to the packet with confirm options
+				send_ack_ = true;
+				ack_num_ = seq_num_recv_;
+			}
+
+		} else {
+			result = DCCP_FEAT_ERR_SIZE;
+			goto reset;
+		}
+		break;
+	case DCCP_OPT_CHANGER:
+		if (size > 1){
+			result = setFeature(data[0], DCCP_FEAT_LOC_LOCAL, &(data[1]), size-1);
+			if (result != DCCP_FEAT_OK)
+				goto reset;
+			confirmFeature(data[0], DCCP_FEAT_LOC_LOCAL);
+
+			if (allow_mult_neg_ > 0 && feat_conf_used_ > 0 && state_ == DCCP_STATE_OPEN){
+				//add an ack number to the packet with confirm options
+				send_ack_ = true;
+				ack_num_ = seq_num_recv_;
+			}
+
+		} else {
+			result = DCCP_FEAT_ERR_SIZE;
+			goto reset;
+		}
+		break;
+	case DCCP_OPT_CONFIRML:
+	case DCCP_OPT_CONFIRMR:
+		loc = DCCP_FEAT_LOC_REMOTE;
+		if (type == DCCP_OPT_CONFIRMR)
+			loc = DCCP_FEAT_LOC_LOCAL;
+		
+		if (size > 1){
+			if (featureIsChanging(data[0], loc)){
+				if (allow_mult_neg_ > 0){
+					if (dccph->type_ == DCCP_ACK ||
+					    dccph->type_ == DCCP_DATAACK ||
+					    dccph->type_ == DCCP_RESPONSE){
+						
+						if (dccpah->ack_num_ < feat_list_seq_num_[findFeatureInList(data[0], loc)]){
+							debug("%f, DCCP(%s)::processOption() - Confirm acknowledged an old Change. Ignoring confirm...\n", now(), name());
+							return true;
+						}
+					} else {
+						debug("%f, DCCP(%s)::processOption() - Missing ack num together with confirm option.\n", now(), name());
+					}
+				} 
+				if (setFeature(data[0], loc, &(data[1]), size-1,true) != DCCP_FEAT_ERR_TEST){
+					result = setFeature(data[0], loc, &(data[1]), size-1);
+					if (result != DCCP_FEAT_OK)
+						goto reset;
+					finishFeatureNegotiation(data[0], loc);
+				} else
+					debug("%f, DCCP(%s)::processOption() - Test of setFeature() failed for feature type %u. Ignoring confirm...\n", now(), name(), data[0]);
+				
+			} else {
+				//ignore
+			}
+		} else {
+			result = DCCP_FEAT_ERR_SIZE;
+			goto reset;
+		}
+		break;
+	case DCCP_OPT_ACK_VECTOR_N0:
+	case DCCP_OPT_ACK_VECTOR_N1:
+		debug("%f, DCCP(%s)::processOption() - Received ackvector (ene %d)\n",
+		      now(), name(), 1-(DCCP_OPT_ACK_VECTOR_N1-type));
+		if (dccph->type_ == DCCP_DATA) {
+			fprintf(stdout,"%f, DCCP(%s)::processOption() - Ackvector received on DCCP-Data packet!\n",now(), name());
+			break;
+		}
+			
+		if (ackv_recv_ != NULL){
+			fprintf(stderr,"%f, DCCP(%s)::processOption() - ackv_recv_ not null\n",now(), name());
+			fflush(stdout);
+			abort();
+		}
+		//store received ack vector
+		ackv_recv_ = new DCCPAckVector(ackv_size_);
+		if (!ackv_recv_->setAckVector(data,size,dccpah->ack_num_,1-(DCCP_OPT_ACK_VECTOR_N1-type))){
+			fprintf(stdout,"%f, DCCP(%s)::processOption() - Failed to set ack vector\n",now(), name());
+			delete ackv_recv_;
+			ackv_recv_ = NULL;
+		}
+		break;
+	case DCCP_OPT_ELAPSED_TIME:
+		if (size == 2){
+			((u_char*) &ui16)[0] = data[0];
+			((u_char*) &ui16)[1] = data[1];
+			elapsed_time_recv_ = ui16;
+		} else if (size == 4) {
+			((u_char*) &ui32)[0] = data[0];
+			((u_char*) &ui32)[1] = data[1];
+			((u_char*) &ui32)[2] = data[2];
+			((u_char*) &ui32)[3] = data[3];
+			elapsed_time_recv_ = ui32;
+		} else {
+			fprintf(stdout,"%f, DCCP(%s)::processOption() - Elapsed time with wrong size %d received\n",now(), name(), size);
+		}
+		break;
+	default:
+		if (type_ < DCCP_OPT_CC_START)
+			debug("%f, DCCP(%s)::processOption() - Unknown option (type %d)\n",
+		      now(), name(), type);
+	}
+
+	return true;
+ reset:
+	switch (result){
+	case DCCP_FEAT_NOT_PREFERED:
+		sendReset(DCCP_RST_FLESS_NEG,data[0],data[1],0);
+		break;
+	case DCCP_FEAT_UNKNOWN:
+		fprintf(stdout,"%f, DCCP(%s)::processOption() - Unknown feature (type %d)\n",
+		      now(), name(), data[0]);
+		break;
+	case DCCP_FEAT_ERR_SIZE:
+		sendReset(DCCP_RST_FEATURE_ERR,
+			  (size > 0 ? data[0] : 0),
+			  (size > 1 ? data[1] : 0),
+			  (size > 2 ? data[2] : 0));
+		break;				
+	}
+	return false;
+}
+
+/* Change a feature (i.e. initiate a feature negotiation).
+ * arg: num      - feature number
+ *      location - feature location
+ * ret: true if the feature is added to the list of ongoing feat neg
+ *      false if the list is full or the feature is already present
+ *            and multiple negotiations are not allowed.             
+ */
+bool DCCPAgent::changeFeature(u_int8_t num, dccp_feature_location location){
+	if (allow_mult_neg_ > 0){
+		int pos = findFeatureInList(num,location);
+
+		if (pos >= 0){
+			feat_list_seq_num_[pos] = seq_num_;
+			feat_list_first_[pos] = true;
+			return true;
+		}
+		//does not exist, check if full
+		if (feat_list_used_ == feat_size_)
+			return false;		
+	} else {
+		//check if the list is full, or if this feature is already in neg
+		if (feat_list_used_ == feat_size_ || featureIsChanging(num, location))
+			return false;
+	}
+
+	feat_list_num_[feat_list_used_] = num;
+	feat_list_loc_[feat_list_used_] = location;
+	feat_list_seq_num_[feat_list_used_] = 0;
+	feat_list_first_[feat_list_used_] = true;
+	debug("%f, DCCP(%s)::changeFeature() - Added feature %d, location %s\n",
+	      now(), name(), num, featureLocationAsStr(location));
+	feat_list_used_++;
+	return true;
+}
+
+/* Check if a feature is currently under negotiation.
+ * arg: num      - feature number
+ *      location - feature location
+ * ret: true if the feature is under negotiation
+ *      false otherwise
+ */
+bool DCCPAgent::featureIsChanging(u_int8_t num, dccp_feature_location location){
+	for (int i = 0; i< feat_list_used_; i++)
+		if(feat_list_num_[i] == num && feat_list_loc_[i] == location)
+			return true;
+	return false;
+}
+
+/* Build the list of features to neg on DCCP-Request packet */
+void DCCPAgent::buildInitialFeatureList(){
+	debug("%f, DCCP(%s)::buildInitialFeatureList() - values cc %d, ecnl %d, ecnr %d, ackrl %d, ackrr %d, ackvl %d, ackvr %d\n",
+			      now(), name(), ccid_, use_ecn_local_,use_ecn_remote_, ack_ratio_local_,ack_ratio_remote_,use_ackv_local_,use_ackv_remote_);
+	changeFeature(DCCP_FEAT_CC, DCCP_FEAT_LOC_LOCAL);
+	changeFeature(DCCP_FEAT_CC, DCCP_FEAT_LOC_REMOTE);
+	changeFeature(DCCP_FEAT_ECN, DCCP_FEAT_LOC_LOCAL);
+	changeFeature(DCCP_FEAT_ECN, DCCP_FEAT_LOC_REMOTE);
+	changeFeature(DCCP_FEAT_ACK_RATIO, DCCP_FEAT_LOC_LOCAL);
+	changeFeature(DCCP_FEAT_ACK_RATIO, DCCP_FEAT_LOC_REMOTE);
+	changeFeature(DCCP_FEAT_ACKV, DCCP_FEAT_LOC_LOCAL);
+	changeFeature(DCCP_FEAT_ACKV, DCCP_FEAT_LOC_REMOTE);
+	changeFeature(DCCP_FEAT_Q_SCHEME, DCCP_FEAT_LOC_LOCAL);
+	changeFeature(DCCP_FEAT_Q_SCHEME, DCCP_FEAT_LOC_REMOTE);
+	changeFeature(DCCP_FEAT_Q, DCCP_FEAT_LOC_LOCAL);
+	changeFeature(DCCP_FEAT_Q, DCCP_FEAT_LOC_REMOTE);
+}	
+
+/* Set a value for a specific feature.
+ * arg: num      - feature number
+ *      location - feature location
+ *      data     - feature data
+ *      size     - size of data
+ *      testSet  - if true, only check value for correctness, don't set
+ * ret: DCCP_FEAT_OK  if successful
+ *      DCCP_FEAT_UNKNOWN  if the feature number is unknown
+ *      DCCP_FEAT_NOT_PREFERED  if the value is not prefered
+ *      DCCP_FEAT_ERR_SIZE  if the size does not match the feature
+ *      DCCP_FEAT_ERR_TEST  if a non-neg feature failed the test.
+ *                          a negotiable feature that fails returns NOT_PREFERED
+ * Note: DCCP_FEAT_NOT_PREFERED is not applicable for non neg features.
+ *       NOT_PREFERED and ERR_SIZE will trigger a reset
+ */
+int DCCPAgent::setFeature(u_int8_t num, dccp_feature_location location,
+	       u_char* data, u_int8_t size, bool testSet){
+	u_int16_t ui16;
+	
+	switch(num){
+	case DCCP_FEAT_CC:
+		if (size == 1){
+			if (ccid_ == data[0])
+				return DCCP_FEAT_OK;
+			else
+				return DCCP_FEAT_NOT_PREFERED;
+		} else
+			return DCCP_FEAT_ERR_SIZE;
+		break;
+	case DCCP_FEAT_ECN:
+		if (size == 1){
+			if (location == DCCP_FEAT_LOC_LOCAL){
+				if (use_ecn_local_ && data[0] ||
+				    !(use_ecn_local_ || data[0]))
+					return DCCP_FEAT_OK;
+				else
+					return DCCP_FEAT_NOT_PREFERED;
+			
+			} else {
+				if (use_ecn_remote_ && data[0] ||
+				    !(use_ecn_remote_ || data[0]))
+					return DCCP_FEAT_OK;
+				else
+					return DCCP_FEAT_NOT_PREFERED;
+			}	
+		} else
+			return DCCP_FEAT_ERR_SIZE;
+		break;
+	case DCCP_FEAT_ACK_RATIO:
+		if (size == 2){
+			((u_char*) &ui16)[0] = data[0];
+			((u_char*) &ui16)[1] = data[1];
+			if (testSet){
+				if (location == DCCP_FEAT_LOC_LOCAL){
+					return ((ack_ratio_local_ != (u_int16_t) ui16) ? DCCP_FEAT_ERR_TEST : DCCP_FEAT_OK);
+				} else {
+					return ((ack_ratio_remote_ != (u_int16_t) ui16) ? DCCP_FEAT_ERR_TEST : DCCP_FEAT_OK);
+				}
+			} else {
+				if (location == DCCP_FEAT_LOC_LOCAL){
+					ack_ratio_local_ = (u_int16_t) ui16;
+					
+				} else
+					ack_ratio_remote_ = (u_int16_t) ui16;
+			}
+			return DCCP_FEAT_OK;
+		} else
+			return DCCP_FEAT_ERR_SIZE;
+		break;
+	case DCCP_FEAT_ACKV:
+		if (size == 1){
+			if (location == DCCP_FEAT_LOC_LOCAL){
+				if (use_ackv_local_ && data[0] ||
+				    !(use_ackv_local_ || data[0]))
+					return DCCP_FEAT_OK;
+				else
+					return DCCP_FEAT_NOT_PREFERED;
+			
+			} else {
+				if (use_ackv_remote_ == data[0]||
+				    !(use_ackv_remote_ || data[0]))
+					return DCCP_FEAT_OK;
+				else
+					return DCCP_FEAT_NOT_PREFERED;
+			}
+		} else
+			return DCCP_FEAT_ERR_SIZE;
+		break;
+	case DCCP_FEAT_Q_SCHEME:
+		if (size == 1){
+			if (q_scheme_ == data[0])
+				return DCCP_FEAT_OK;
+			else
+				return DCCP_FEAT_NOT_PREFERED;
+		} else
+			return DCCP_FEAT_ERR_SIZE;
+		break;
+	case DCCP_FEAT_Q:
+		if (size == 1){
+			if (location == DCCP_FEAT_LOC_LOCAL){
+				q_local_ = (data[0] > 0 ? 1 : 0);
+			} else {
+				q_remote_ = (data[0] > 0 ? 1 : 0);
+			}
+			return DCCP_FEAT_OK;
+		} else
+			return DCCP_FEAT_ERR_SIZE;
+		break;
+	default:
+		return DCCP_FEAT_UNKNOWN;
+	}
+}
+
+/* Obtain a value of a feature.
+ * Used in addFeatureOptions() to get the feature value.
+ * arg: num      - feature number
+ *      location - feature location
+ *      data     - feature data
+ *      size     - maximum size of data
+ * ret: DCCP_FEAT_OK            if successful
+ *      DCCP_FEAT_UNKNOWN       if the feature number is unknown
+ *      DCCP_FEAT_ERR_SIZE      if the size is too small
+ */
+int DCCPAgent::getFeature(u_int8_t num, dccp_feature_location location,
+	       u_char* data, u_int8_t maxSize){
+	u_int16_t ui16;
+	
+	switch(num){
+	case DCCP_FEAT_CC:
+		if (maxSize > 0){
+			data[0] = (u_int8_t) ccid_;
+			return 1;
+		} else
+			return DCCP_FEAT_ERR_SIZE;
+		break;
+	case DCCP_FEAT_ECN:
+		if (maxSize > 0){
+			if (location == DCCP_FEAT_LOC_LOCAL)
+				data[0] = (u_int8_t) use_ecn_local_;
+			else
+				data[0] = (u_int8_t) use_ecn_remote_;
+				
+			return 1;
+		} else
+			return DCCP_FEAT_ERR_SIZE;
+		break;
+	case DCCP_FEAT_ACK_RATIO:
+		if (maxSize > 1){
+			if (location == DCCP_FEAT_LOC_LOCAL)
+				ui16 = (u_int16_t) ack_ratio_local_;
+			else
+				ui16 = (u_int16_t) ack_ratio_remote_;
+			data[0] = ((u_char*) &ui16)[0];
+			data[1] = ((u_char*) &ui16)[1];
+			
+			return 2;
+		} else
+			return DCCP_FEAT_ERR_SIZE;
+		break;
+	case DCCP_FEAT_ACKV:
+		if (maxSize > 0){
+			if (location == DCCP_FEAT_LOC_LOCAL)
+				data[0] = (u_int8_t) use_ackv_local_;
+			else
+				data[0] = (u_int8_t) use_ackv_remote_;
+				
+			return 1;
+		} else
+			return DCCP_FEAT_ERR_SIZE;
+		break;
+	case DCCP_FEAT_Q_SCHEME:
+		if (maxSize > 0){
+			data[0] = (u_int8_t) q_scheme_;
+			return 1;
+		} else
+			return DCCP_FEAT_ERR_SIZE;
+		break;
+	case DCCP_FEAT_Q:
+		if (maxSize > 0){
+			if (location == DCCP_FEAT_LOC_LOCAL)
+				data[0] = (u_int8_t) q_local_;
+			else
+				data[0] = (u_int8_t) q_remote_;
+				
+			return 1;
+		} else
+			return DCCP_FEAT_ERR_SIZE;
+		break;
+	default:
+		return DCCP_FEAT_UNKNOWN;
+	}
+}
+
+/* Obtain the feature type
+ * arg: num      - feature number
+ * ret: the feature type, or DCCP_FEAT_TYPE_UKNOWN if unknown
+ */
+dccp_feature_type DCCPAgent::getFeatureType(u_int8_t num){
+	switch(num){
+	case DCCP_FEAT_CC:
+	case DCCP_FEAT_ECN:
+	case DCCP_FEAT_ACKV:
+	case DCCP_FEAT_Q_SCHEME:
+		return DCCP_FEAT_TYPE_SP;
+		break;
+	case DCCP_FEAT_ACK_RATIO:
+	case DCCP_FEAT_Q:
+		return DCCP_FEAT_TYPE_NN;
+	default:
+		return DCCP_FEAT_TYPE_UNKNOWN;
+	}
+}
+
+/* Cancel all timers */
+void DCCPAgent::cancelTimers(){
+	timer_snd_->force_cancel();
+	timer_rtx_->force_cancel();
+}
+
+
+/* Ask sender permission to send a packet
+ * arg: dataSize - size of data in packet (0 = pure ACK)
+ *      pkt      - the packet to send
+ * ret: true if permission is granted, otherwise false
+ * Note: Packet should not be used for other than manipulating
+ *       ecn marks!
+ */
+bool DCCPAgent::send_askPermToSend(int dataSize, Packet *pkt){
+	return (dataSize == 0 || timer_snd_->status() != TIMER_PENDING);
+}
+
+/* A(n) ACK/DATA/DATAACK packet has been sent (sender)
+ * arg: pkt        - packet sent
+ *      moreToSend - true if there exist more data to send
+ *      dataSize   - size of data sent
+ */
+void DCCPAgent::send_packetSent(Packet *pkt, bool moreToSend, int dataSize) {
+	if (snd_delay_ > 0)
+		timer_snd_->resched(snd_delay_);
+	else {
+		fprintf(stderr,"%f, DCCP(%s)::send_packetSend() - snd_delay_ is 0!\n", now(), name());
+		fflush(stdout);
+		abort();
+	}
+};
+
+/* A(n) ACK/DATA/DATAACK packet has been received (sender)
+ * arg: pkt        - packet received
+ *      dataSize   - size of data in packet
+ * If this function would like to send a packet, set output_ = true
+ * and output_flag_ if appropriate.
+ */
+void DCCPAgent::send_packetRecv(Packet *pkt, int dataSize) {	
+};
+
+/* A ACK/DATA/DATAACK packet has been received (receiver)
+ * arg: pkt        - packet received
+ *      dataSize   - size of data in packet
+ * If this function would like to send a packet, set output_ = true
+ * and output_flag_ if appropriate.
+ */
+void DCCPAgent::recv_packetRecv(Packet *pkt, int dataSize) {
+	hdr_dccp *dccph = hdr_dccp::access(pkt);
+
+	if (dccph->type_ != DCCP_DATA && dccph->type_ != DCCP_DATAACK
+	    && dccph->type_ != DCCP_ACK){
+		fprintf(stderr,"%f, DCCP(%s)::recv_packetRecv() - Got a packet of type %s!\n", now(), name(), packetTypeAsStr(dccph->type_));
+		fflush(stdout);
+		abort();
+	}
+
+	//ack ackording to ack ratio
+	if(dccph->type_ == DCCP_DATA || dccph->type_ == DCCP_DATAACK){
+		ar_unacked_++;
+		if (ar_unacked_ >= ack_ratio_local_){
+			send_ack_ = true;
+			ack_num_ = seq_num_recv_;
+			ar_unacked_= 0;
+			output_ = true;
+			output_flag_ = true;
+		}
+	}
+};
+
+/* Tracing functions */
+void DCCPAgent::traceAll() {
+}
+
+void DCCPAgent::traceVar(TracedVar* v) {
+}
+
+
+//public methods
+
+/* Constructor
+ * ret: A new DCCPAgent
+ */
+DCCPAgent::DCCPAgent() : Agent(PT_DCCP){
+	sb_size_ = DCCP_SB_SIZE;
+	opt_size_ = DCCP_OPT_SIZE; 
+	feat_size_ = DCCP_FEAT_SIZE;
+	ackv_size_ = DCCP_ACKV_SIZE;
+
+	ndp_limit_ = DCCP_NDP_LIMIT;
+	ccval_limit_ = DCCP_CCVAL_LIMIT;
+	
+	server_ = false;
+	seq_num_ = 0;
+	seq_num_recv_ = 0;
+	ack_num_recv_ = 0;
+	ackv_recv_ = NULL;
+	state_ = DCCP_STATE_CLOSED;
+	ack_num_ = 0;
+	ccval_ = 0;
+	cscov_ = DCCP_CSCOV_ALL;
+	send_ack_ = 0;
+	conn_est_ = false;
+	output_ = false;
+	output_flag_ = false;
+	infinite_send_ = false;
+	close_on_empty_ = false;
+	ndp_ = 0;
+	ccid_ = DCCP_CCID;
+	use_ecn_local_ = DCCP_FEAT_DEF_ECN;
+	use_ecn_remote_ = DCCP_FEAT_DEF_ECN;
+	ack_ratio_local_ = DCCP_FEAT_DEF_ACK_RATIO;
+	ack_ratio_remote_ = DCCP_FEAT_DEF_ACK_RATIO;
+	use_ackv_local_ = DCCP_FEAT_DEF_ACKV;
+	use_ackv_remote_ = DCCP_FEAT_DEF_ACKV;
+	q_scheme_ = DCCP_FEAT_DEF_Q_SCHEME;
+	q_local_ = DCCP_FEAT_DEF_Q;
+	q_remote_ = DCCP_FEAT_DEF_Q;
+	
+	feat_list_num_ = new u_int8_t[feat_size_];
+	feat_list_loc_ = new dccp_feature_location[feat_size_];
+	feat_list_seq_num_ = new u_int32_t[feat_size_];
+	feat_list_first_ = new bool[feat_size_];
+	feat_list_used_ = 0;
+
+	feat_conf_num_ = new u_int8_t[feat_size_];
+	feat_conf_loc_ = new dccp_feature_location[feat_size_];
+	feat_conf_used_ = 0;
+
+	seq_last_feat_neg_ = 0;
+	feat_first_in_pkt_ = true;
+
+	allow_mult_neg_ = 0;
+	
+	packet_sent_ = false;
+	packet_recv_ = false;
+	
+	sb_ = new DCCPSendBuffer(sb_size_);
+	opt_ = new DCCPOptions(opt_size_);
+	ackv_ = new DCCPAckVector(ackv_size_);
+	
+	send_ackv_ = true;
+	manage_ackv_ = true;
+
+	elapsed_time_recv_ = 0;
+	nonces_ = new RNG();
+	nonces_->set_seed((long int) 0);
+
+	timer_rtx_ = new DCCPRetransmitTimer(this);
+	timer_snd_ = new DCCPSendTimer(this);
+	
+	snd_delay_ = DCCP_SND_DELAY;
+
+	nam_tracevar_ = false;
+	trace_all_oneline_ = false;
+
+	ar_unacked_ = 0;
+
+	rtt_conn_est_ = 0.0;
+	
+	initial_rtx_to_ = DCCP_INITIAL_RTX_TO;
+	max_rtx_to_ = DCCP_MAX_RTX_TO;
+	resp_to_ = DCCP_RESP_TO;
+
+	num_data_pkt_ = 0;
+	num_ack_pkt_ = 0;
+	num_dataack_pkt_ = 0;
+}
+
+/* Destructor */
+DCCPAgent::~DCCPAgent(){
+	delete timer_rtx_;
+	delete timer_snd_;
+	delete sb_;
+	delete opt_;
+	delete nonces_;
+	delete [] feat_list_num_;
+	delete [] feat_list_loc_;
+	delete [] feat_list_seq_num_;
+	delete [] feat_list_first_;
+	delete [] feat_conf_num_;
+	delete [] feat_conf_loc_;
+}
+
+/* Process a "function call" from OTCl
+ * arg: argc - number of arguments
+ *      argv - arguments
+ * ret: TCL_OK if successful, TCL_ERROR otherwise
+ */
+int DCCPAgent::command(int argc, const char*const* argv){
+	if (argc == 3) {
+		if (strcmp(argv[1], "advance") == 0) {
+			advanceby(atoi(argv[2]));
+			return (TCL_OK);
+		}
+		if (strcmp(argv[1], "advanceby") == 0) {
+			advanceby(atoi(argv[2]));
+			return (TCL_OK);
+		}
+	}
+	return (Agent::command(argc, argv));
+}
+
+/* Receive a packet
+ * arg: pkt     - Packet received
+ *      handler - handler
+ */
+void DCCPAgent::recv(Packet* pkt, Handler* handler){
+	int data_size = 0;
+	bool ack_received = false;
+	bool data_or_ack_pkt = false;
+	bool processOptions = true;
+	bool tell_cc = false;
+	bool tell_app = false;
+	hdr_dccp *dccph = hdr_dccp::access(pkt);
+	hdr_dccpack *dccpah = hdr_dccpack::access(pkt);
+	hdr_dccpreset *dccpresh = hdr_dccpreset::access(pkt);
+	hdr_cmn *cmnh = hdr_cmn::access(pkt);
+	output_ = false;
+	output_flag_ = false;
+
+	//check if packet is valid
+	if (!checkPacket(pkt))
+		goto free;
+
+	//preprocess packet (if reset, reset the agent)
+	switch (dccph->type_){
+	case DCCP_REQUEST:
+	case DCCP_RESPONSE:
+		break;
+	case DCCP_DATA:
+	case DCCP_DATAACK:
+		data_or_ack_pkt = true;
+		data_size = cmnh->size() -  headerSize(dccph->type_)
+			- dccph->options_->getSize();
+		ack_received = (dccph->type_ == DCCP_DATAACK);
+		break;
+	case DCCP_ACK:
+		data_or_ack_pkt = true;
+		ack_received = true;
+		break;
+	case DCCP_CLOSEREQ:
+	case DCCP_CLOSE:
+		processOptions = false;
+		break;
+	case DCCP_RESET:
+		debug("%f, DCCP(%s)::recv() - Received a reset packet, reason %s (%d), data (%d,%d,%d))\n",
+		      now(), name(), resetReasonAsStr(dccpresh->rst_reason_), dccpresh->rst_reason_,
+		      dccpresh->rst_data1_,dccpresh->rst_data2_,dccpresh->rst_data3_);
+		ack_received = true;
+		reset();
+		goto free;
+		break;
+	default:
+		fprintf(stdout, "%f, DCCP(%s)::recv() - Received an unknown packet (type %d) in state %s (%d)!\n",
+			now(), name(), dccph->type_, stateAsStr(state_), state_);
+		goto free;
+	}
+	debug("%f, DCCP(%s)::recv() - type %s, seq %d, ack %d, packet size %d, data_size is %d, cscov_ %d\n",now(), name(), packetTypeAsStr(dccph->type_),dccph->seq_num_, dccpah->ack_num_,cmnh->size(),data_size, dccph->cscov_);
+	
+	//process options (not on close packets)
+	if (processOptions && !parseOptions(pkt)){
+		debug("%f, DCCP(%s)::recv() - Parse option failed!)\n", now(), name());
+		reset();
+		goto free;
+	}
+	
+	switch (state_){
+	case DCCP_STATE_CLOSED:
+		fprintf(stdout, "%f, DCCP(%s)::recv() - Received a %s (%d) packet in state %s!\n",
+			now(), name(), packetTypeAsStr(dccph->type_),
+			dccph->type_, stateAsStr(state_));
+		if (dccph->type_ != DCCP_RESET){
+			//ignore
+		}
+		goto free;
+		break;
+	case DCCP_STATE_LISTEN:
+		if(dccph->type_ == DCCP_REQUEST){
+			packet_recv_ = true;
+			changeState(DCCP_STATE_RESPOND);
+			//ack_num_ = seq_num_recv_;
+			output_ = true;
+			goto free_send;
+		} else if (dccph->type_ != DCCP_RESET){
+			//ignore
+		}
+		goto free;
+		break;
+	case DCCP_STATE_RESPOND:
+		if(dccph->type_ == DCCP_REQUEST){
+			//resend the RESPONSE
+			output_ = true;
+			goto free_send;
+		} else if (dccph->type_ == DCCP_CLOSE) {
+			sendReset(DCCP_RST_CLOSED,0,0,0);
+			reset();
+		} else if (ack_received && dccpah->ack_num_ == seq_num_-1) {
+			rtt_conn_est_ = now() - rtt_conn_est_;
+			debug("%f, DCCP(%s)::recv() - RTT estimated to %f s (server)!\n",now(), name(), rtt_conn_est_);
+			if (data_size > 0){
+				//the last ack in handshake contained data
+				tell_cc = true;
+				dccph->type_ = DCCP_DATA;
+				if (use_ackv_local_ && manage_ackv_)
+					ackv_->addPacket(dccph->seq_num_, getECNCodePoint(pkt), true);	
+			} else if (use_ackv_local_ && manage_ackv_)
+				ackv_->addPacket(dccph->seq_num_+1, DCCP_PACKET_NOT_RECV);
+			tell_app = (!infinite_send_) && sb_->empty();
+			conn_est_ = true;
+			changeState(DCCP_STATE_OPEN);
+			goto data;
+		} else if (ack_received)
+			debug("%f, DCCP(%s)::recv() - Invalid ack num %d to finalise the handshake\n",now(),name(), dccpah->ack_num_);
+		goto free;
+		break;
+	case DCCP_STATE_OPEN:
+		if (dccph->type_ == DCCP_CLOSE){
+			sendReset(DCCP_RST_CLOSED, 0 ,0 ,0);
+			reset();
+		} else if (dccph->type_ == DCCP_CLOSEREQ){
+			changeState(DCCP_STATE_CLOSING);
+			output_ = true;
+			goto free_send;
+		} else if (data_or_ack_pkt) {
+			if (use_ackv_local_ && manage_ackv_){
+				//add packet to local ackvector
+				if(!(ackv_->addPacket(dccph->seq_num_, getECNCodePoint(pkt), dccph->type_ != DCCP_ACK)))
+					fprintf(stdout, "%f, DCCP(%s)::recv() - Add packet to ack vector failed!\n",now(), name());
+
+				if (ack_received){
+					ackv_->ackRecv(dccpah->ack_num_, ackv_recv_);
+				}
+			}
+			tell_cc = true;
+			goto data;
+		}
+		goto free;
+		break;
+	case DCCP_STATE_REQUEST:
+		if (dccph->type_ == DCCP_RESPONSE){
+			packet_recv_ = true;
+			changeState(DCCP_STATE_OPEN);
+			send_ack_ = true;
+			ack_num_ = seq_num_recv_;
+			output_ = true;
+			rtt_conn_est_ = now() - rtt_conn_est_;
+			debug("%f, DCCP(%s)::recv() - RTT estimated to %f s (client)!\n",now(), name(), rtt_conn_est_);
+			if (use_ackv_local_ && manage_ackv_)
+				ackv_->addPacket(dccph->seq_num_+1,DCCP_PACKET_NOT_RECV);
+			goto free_send;
+		} else if (dccph->type_ == DCCP_CLOSE){
+			sendReset(DCCP_RST_CLOSED, 0 ,0 ,0);
+			reset();
+		} else if (dccph->type_ != DCCP_RESET){
+			//ignore
+		}
+		goto free;
+		break;
+	case DCCP_STATE_CLOSEREQ:
+	        if (dccph->type_ == DCCP_CLOSE) {
+			sendReset(DCCP_RST_CLOSED,0,0,0);
+			reset();
+		} else if (data_or_ack_pkt)
+			goto data;
+		goto free;
+		break;
+	case DCCP_STATE_CLOSING:
+		if (dccph->type_ == DCCP_CLOSEREQ){
+			changeState(DCCP_STATE_CLOSING);  //i.e. reset timer
+			output_ = true;
+			goto free_send;
+		} else if (data_or_ack_pkt)
+			goto data;
+		goto free;
+		break;
+	default:
+		fprintf(stderr, "%f, DCCP(%s):recv() - Illegal state (%d)!\n",
+			now(), name(),state_);
+		fflush(stdout);
+		abort();
+	}
+	
+ data:
+	if (data_or_ack_pkt) {
+		if (tell_cc){
+			recv_packetRecv(pkt,data_size);
+			send_packetRecv(pkt,data_size);
+		}
+		if(data_size > 0){
+			recvBytes(data_size);  //inform the application
+		}
+	}
+
+	if (tell_app)
+		idle();
+ free_send:
+	if (output_)
+		output(output_flag_);
+ free:
+	//remove received options
+	if (ackv_recv_ != NULL){
+		delete ackv_recv_;
+		ackv_recv_ = NULL;
+	}
+	elapsed_time_recv_ = 0;
+		
+	delete (dccph->options_);
+	dccph->options_ = NULL;
+	
+	Packet::free(pkt);
+}
+
+/* Send a packet,
+ * If this is the first packet to send, initiate a connection.
+ * arg: nbytes - number of bytes in packet (-1 -> infinite send)
+ *      flags  - Flags:
+ *                 "MSG_EOF" will close the connection when all data
+ *                  has been flag
+ */
+void DCCPAgent::sendmsg(int nbytes, const char *flags){
+	if (infinite_send_)
+		return;
+	
+	switch (state_){
+	case DCCP_STATE_CLOSED:
+	case DCCP_STATE_RESPOND:
+	case DCCP_STATE_REQUEST:
+	case DCCP_STATE_OPEN:
+		if (nbytes > 0) {
+			if (!(sb_->add(nbytes)))
+				debug("%f, DCCP(%s)::sendmsg() - Sendbuffer is full\n", now(), name());	
+		} else if (nbytes == 0) {
+			fprintf(stdout, "%f, DCCP(%s)::sendmsg() - Application tries to send 0 byte of data\n",
+			now(), name());
+			return;
+		} else {
+			debug("%f, DCCP(%s)::sendmsg() - Infinite send activated\n",
+			      now(), name());
+			infinite_send_ = true;
+		}
+
+		if (flags != NULL && strcmp(flags, "MSG_EOF") == 0) 
+			close_on_empty_ = TRUE;	
+		
+		if (state_ == DCCP_STATE_CLOSED) {
+			//initiate a connection
+			buildInitialFeatureList();
+			changeState(DCCP_STATE_REQUEST);
+			output();
+		} else if (state_ == DCCP_STATE_OPEN)
+			output();
+		break;
+	case DCCP_STATE_LISTEN:
+	case DCCP_STATE_CLOSEREQ:
+	case DCCP_STATE_CLOSING:
+		break;
+	default:
+		fprintf(stderr, "%f, DCCP(%s)::sendmsg() - Illegal state (%d)!\n",
+			now(), name(),state_);
+		fflush(stdout);
+		abort();
+	}
+}
+
+/* Close the connection */
+void DCCPAgent::close(){
+	debug("%f, DCCP(%s)::close() - The application wants to close the connection (state %s)\n", now(), name(),stateAsStr(state_));
+	switch(state_){
+	case DCCP_STATE_CLOSED:
+		fprintf(stdout, "%f, DCCP(%s)::close() - Already closed!\n",
+			now(), name());	
+		break;
+	case DCCP_STATE_RESPOND:
+		changeState(DCCP_STATE_CLOSEREQ);
+		output();
+		break;
+	case DCCP_STATE_REQUEST:
+		sendReset(DCCP_RST_CLOSED,0,0,0);
+		reset();
+		break;
+	case DCCP_STATE_OPEN:
+		if (server_)
+			changeState(DCCP_STATE_CLOSEREQ);
+		else
+			changeState(DCCP_STATE_CLOSING);
+		
+		output();
+		break;
+	case DCCP_STATE_LISTEN:
+		reset();
+		changeState(DCCP_STATE_CLOSED);
+		break;
+	case DCCP_STATE_CLOSEREQ:
+	case DCCP_STATE_CLOSING:
+		fprintf(stdout, "%f, DCCP(%s)::close() - Application tried to close when in state %s\n",
+			now(), name(), stateAsStr(state_));	
+		break;
+	default:
+		fprintf(stderr, "%f, DCCP(%s)::sendmsg() - Illegal state (%d)!\n",
+			now(), name(),state_);
+		fflush(stdout);
+		abort();
+	}
+
+}
+
+/* Listen for incoming connections
+ * Use close() to stop listen
+ */
+void DCCPAgent::listen(){
+	if (state_ == DCCP_STATE_CLOSED){
+		server_ = true;
+		changeState(DCCP_STATE_LISTEN);
+	} else
+		debug("%f, DCCP(%s)::listen() - Listen called while in state %s (%d)\n",
+		      now(), name(), stateAsStr(state_),state_);
+		
+}
+
+/* A timeout has occured
+ * arg: tno - id of timeout event
+ */
+void DCCPAgent::timeout(int tno){
+	debug("%f, DCCP(%s)::timeout() - Timeout %d occured!\n",
+		      now(), name(), tno);
+	switch (tno){
+	case DCCP_TIMER_RTX:
+		switch(state_){
+		case DCCP_STATE_RESPOND:
+			sendReset(DCCP_RST_CLOSED,0,0,0);
+			reset();
+			break;
+		case DCCP_STATE_REQUEST:
+			if (timer_rtx_->backOffFailed()){
+				sendReset(DCCP_RST_CLOSED,0,0,0);
+				reset(); 
+			} else
+				output();
+			break;
+		case DCCP_STATE_CLOSING:
+			if (timer_rtx_->backOffFailed()){
+				reset();
+			} else
+				output();
+			break;
+		case DCCP_STATE_CLOSEREQ:
+			if (timer_rtx_->backOffFailed()){
+				sendReset(DCCP_RST_CLOSED,0,0,0);
+				reset();
+			} else
+				output();
+			break;
+		default:
+			fprintf(stderr,"%f, DCCP(%s)::timeout() - Timer (%d) should not be running in state %s!\n",
+		      now(), name(), tno,stateAsStr(state_));
+			fflush(stdout);
+			abort();
+		}
+		break;
+	case DCCP_TIMER_SND:
+		switch(state_){
+		case DCCP_STATE_OPEN:
+			output();
+			break;
+		default:
+			fprintf(stderr,"%f, DCCP(%s)::timeout() - Timer (%d) should not be running in state %s!\n",
+				now(), name(), tno,stateAsStr(state_));
+			fflush(stdout);
+			abort();
+		}
+		break;
+	default:
+		fprintf(stdout,"%f, DCCP(%s)::timeout() - Unknown timeout occured (%d)!\n",
+		      now(), name(), tno);
+	}
+}
+
+/* Trace a variable.
+ * arg: v  - traced variable
+ */
+void DCCPAgent::trace(TracedVar* v) {
+	if (nam_tracevar_) {
+		Agent::trace(v);
+	} else if (trace_all_oneline_){
+		traceAll();
+	}else{ 
+		traceVar(v);
+	}
+}
+
+/* Send delta packets of packetSize_ size
+ * arg: delta - number of packets to send
+ */
+void DCCPAgent::advanceby(int delta){
+	if (delta <= 0)
+		return;
+	
+	if (!infinite_send_){
+		
+		switch (state_){
+		case DCCP_STATE_CLOSED:
+		case DCCP_STATE_RESPOND:
+		case DCCP_STATE_REQUEST:
+		case DCCP_STATE_OPEN:
+			
+			while (!sb_->full() && delta > 0){
+				sb_->add(size_);
+				delta--;
+			}
+			if (sb_->full()){
+				fprintf(stdout,"%f, DCCP(%s)::advanceby() - Sendbuffer is full (%d packets dropped)\n",
+					now(), name(), delta);
+			}
+			if (state_ == DCCP_STATE_CLOSED) {
+				//initiate a connection
+				buildInitialFeatureList();
+				changeState(DCCP_STATE_REQUEST);
+				output();
+			} else if (state_ == DCCP_STATE_OPEN)
+				output();
+		case DCCP_STATE_LISTEN:
+		case DCCP_STATE_CLOSEREQ:
+		case DCCP_STATE_CLOSING:
+			break;
+		default:
+			fprintf(stderr, "%f, DCCP(%s)::advanceby() - Illegal state (%d)!\n",
+				now(), name(),state_);
+			fflush(stdout);
+			abort();
+			
+		}
+	}
+}
+
+
diff -urNU5 ns-2.33/dccp/dccp.h ns-2.33-dccp/dccp/dccp.h
--- ns-2.33/dccp/dccp.h	1970-01-01 10:00:00.000000000 +1000
+++ ns-2.33-dccp/dccp/dccp.h	2008-05-05 17:17:43.000000000 +1000
@@ -0,0 +1,560 @@
+/* -*-	Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
+
+/* Copyright (c) 2004  Nils-Erik Mattsson 
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: ns-233-dccp-1.patch 210 2008-05-13 03:43:55Z omehani $ */
+
+#ifndef ns_dccp_h
+#define ns_dccp_h
+
+#include "agent.h"
+#include "dccp_types.h"
+#include "dccp_packets.h"
+#include "packet.h"
+#include "dccp_sb.h"
+#include "dccp_opt.h"
+#include "dccp_ackv.h"
+#include "rng.h"
+
+//ccid for DCCP agent (non-standard!)
+#define DCCP_CCID 254
+
+//limits for ndp and ccval
+#define DCCP_NDP_LIMIT 8
+#define DCCP_CCVAL_LIMIT 16
+
+//checksum coverage
+#define DCCP_CSCOV_ALL 0
+#define DCCP_CSCOV_HEADER_ONLY 1
+
+//timer identifiers
+#define DCCP_TIMER_RTX 0
+#define DCCP_TIMER_SND 1
+
+//retransmission parameters
+#define	DCCP_INITIAL_RTX_TO 3.0
+#define DCCP_MAX_RTX_TO 75.0
+#define DCCP_RESP_TO 75.0
+
+//send delay for send timer
+#define DCCP_SND_DELAY 0.0001
+
+#define DCCP_SB_SIZE 1000   //maximum number of packets in the send buffer 
+#define DCCP_OPT_SIZE 512   //maximum size of options per packet
+#define DCCP_FEAT_SIZE 24   //maximum size of ongoing feat neg
+#define DCCP_ACKV_SIZE 20   //initial maximum size of ackvector
+
+//features
+#define DCCP_FEAT_CC 1
+#define DCCP_FEAT_ECN 2
+#define DCCP_FEAT_ACK_RATIO 3
+#define DCCP_FEAT_ACKV 4
+
+//Quiescence features (experimental)
+#define DCCP_FEAT_Q_SCHEME 126  //quiescence scheme to use
+#define DCCP_FEAT_Q 127         //quiescence feature
+
+/* Quiescence scheme */
+#define DCCP_Q_SCHEME_NORMAL 0
+#define DCCP_Q_SCHEME_Q_FEAT  1
+#define DCCP_Q_SCHEME_Q_OPT 2
+
+//default values for features
+#define DCCP_FEAT_DEF_CCID 2
+#define DCCP_FEAT_DEF_ECN 1
+#define DCCP_FEAT_DEF_ACK_RATIO 2
+#define DCCP_FEAT_DEF_ACKV 0
+#define DCCP_FEAT_DEF_Q_SCHEME DCCP_Q_SCHEME_NORMAL
+#define DCCP_FEAT_DEF_Q 0
+
+//error values for features
+#define DCCP_FEAT_OK 0
+#define DCCP_FEAT_UNKNOWN -1
+#define DCCP_FEAT_NOT_PREFERED -2
+#define DCCP_FEAT_ERR_SIZE -3
+#define DCCP_FEAT_ERR_TEST -4
+
+#define DCCP_NUM_DUP_ACKS 3
+
+//forward decleration of class DCCPAgent
+class DCCPAgent;
+
+/* The DCCPRetransmitTimer is used for retransmission of packet
+ * or as a timeout while waiting for packets.
+ */
+class DCCPRetransmitTimer : public TimerHandler {
+protected:
+	DCCPAgent *agent_;     //the owning agent
+	double delay_;         //the scheduled delay
+	double tot_delay_;     //total delayed time so far
+	double max_tot_delay_; //maximum delayed time
+	bool backoff_failed_;  //true if max_tot_dealay_ is reached
+public:
+	/* Constructor
+	 * arg: agent - the owning agent (to notify about timeout)
+	 * ret: A new DCCPRetransmitTimer
+	 */
+	DCCPRetransmitTimer(DCCPAgent* agent);
+
+	/* Initialize the timer.
+	 * arg: delay       - initial delay
+	 *      maxToTDelay - total maximum delay
+	 */
+	void init(double delay, double maxTotDelay);
+
+	/* Called when the timer has expired
+	 * arg: e - The event that happened (i.e. the timer expired)
+	 */
+	virtual void expire(Event *e);
+
+	/* Back off the timer (by a factor of 2)
+	 * The last back off will reach the max_tot_delay.
+	 */
+	void backOff();
+
+	/* Check if the back-off failed (that is if max_tot_delay is reached)
+	 * ret: true if back-off failed, otherwise false. 
+	 */
+	bool backOffFailed();
+};
+
+/* The DCCPSendTimer models the time it takes to send a packet */
+class DCCPSendTimer : public TimerHandler {
+protected:
+	DCCPAgent *agent_;  //the owning agent
+public:
+	/* Constructor
+	 * arg: agent - the owning agent (to notify about timeout)
+	 * ret: A new DCCPSendTimer
+	 */
+	DCCPSendTimer(DCCPAgent* agent);
+
+	/* Called when the timer has expired
+	 * arg: e - The event that happened (i.e. the timer expired)
+	 */
+	virtual void expire(Event *e);
+};
+
+/* Class DCCPAgent implements a two-way agent using the DCCP protocol.
+ * Conforms to the October 2003 drafts.
+ * If changes are made to tcl variables, the agent should be reset
+ * to enable all changes.
+ * It provides a "cc" that simulates that it takes send_delay_ seconds
+ * to send a packet.
+ * Acks ackording to ack ratio.
+ * Can use ecn and/or ack vectors (no ecn verification) */
+class DCCPAgent : public Agent {
+private:
+	RNG* nonces_;   //random number generator
+
+	//string representation of types
+	static char* state_str_[DCCP_NUM_STATES];
+	static int hdr_size_[DCCP_NUM_PTYPES];
+	static char* ptype_str_[DCCP_NUM_PTYPES];
+	static char* reset_reason_str_[DCCP_NUM_RESET_REASONS];
+	static char* feature_location_str_[DCCP_NUM_FEAT_LOCS];
+	
+	bool server_;         //true if this agent i a server
+	dccp_state state_;    //current protocol state
+	bool packet_sent_;    //true after the first packet has been sent
+	bool packet_recv_;    //true after the first packet has been received
+
+	bool close_on_empty_; //if true, the connection is closed when the sendbuffer is empty
+	
+	//list of feature currently under negotiation
+	//consider these variables as one list
+        u_int8_t *feat_list_num_;              //feature number
+	dccp_feature_location *feat_list_loc_; //feature location
+	u_int32_t *feat_list_seq_num_;         //sequence number of the packet the feature was last negotiated on
+	bool *feat_list_first_;                //true if this feat has not been neg before
+	u_int8_t feat_list_used_;   //number of entries in the list
+
+	//list over features to confirm
+	u_int8_t *feat_conf_num_;              //feature number
+	dccp_feature_location *feat_conf_loc_; //feature location
+	u_int8_t feat_conf_used_;   //number of entries in the list
+
+	int allow_mult_neg_;       //allow multiple nn feature negotiations at one time
+	
+	//sequence number for the packet with last neg option processed
+	u_int32_t seq_last_feat_neg_; 
+	bool feat_first_in_pkt_;  //is this the first feat neg opt in pkt?
+	
+	DCCPRetransmitTimer* timer_rtx_;  //retransmit timer
+
+	DCCPSendTimer* timer_snd_;        //send timer
+	double snd_delay_;    //the delay of the send timer
+
+	/* Creates a new packet and fills in some header fields
+	 * ret: a new packet
+	 */
+	Packet* newPacket();
+
+	/* Check if an incoming packet is valid
+	 * arg: pkt - incoming packet
+	 * ret: true if the packet is valid, otherwise false
+	 */
+	bool checkPacket(Packet* pkt);
+
+	/* Add feature negotiation options on packets for features
+	 * currently under negotiation. Will use getFeature() to obtain values.
+	 */
+	void addFeatureOptions();
+
+	/* Finish feature negotiation for a feature abd remove it from
+	 * the list of ongoing feature negotiations.
+	 * arg: num      - feature number
+	 *      location - feature location
+	 * ret: true if the feature is removed
+	 *      false if it doesn't exist in the list
+	 */
+	bool finishFeatureNegotiation(u_int8_t num, dccp_feature_location location);
+
+	/* Add a feature to the list of features to confirm
+	 * Will only add one entry for each (feat,loc) pair
+	 * arg: num      - feature number
+	 *      location - feature location
+	 */
+	void confirmFeature(u_int8_t num, dccp_feature_location location);
+
+	/* Find a feature in the list of ongoing negotiations
+	 * arg: num      - feature number
+	 *      location - feature location
+	 * ret: position in the feature list if successfull
+	 *      otherwise -1
+	 */
+	int findFeatureInList(u_int8_t num, dccp_feature_location location);
+	
+protected:
+	int ndp_limit_;       //ndp limit
+	int ccval_limit_;     //ccval limit
+	
+	DCCPSendBuffer* sb_;  //send buffer. Contains packet sizes to send.
+	bool infinite_send_;  //send an unlimited amount of data
+	
+	u_int8_t ndp_;      //ndp of last packet sent
+	u_int32_t seq_num_; //next sequence number to send
+
+	u_int32_t seq_num_recv_;  //highest sequence number received so far
+	u_int32_t ack_num_recv_;  //highest ack received so far
+
+	DCCPAckVector *ackv_recv_;      //the received ack vector (if any)
+	u_int32_t elapsed_time_recv_;   //the received time elapsed (if any)
+	
+	u_int32_t ack_num_; //sequence number to ack
+	bool send_ack_;     //send an ack
+	u_int8_t ccval_;    //cc value to send
+	int cscov_;         //checksum coverage value to send
+	
+	bool conn_est_;     //true if the connection is established
+
+	bool output_;       //run output() after packet has been received
+	bool output_flag_;  //flag to hand to output. i.e. output(output_flag_)
+	
+	DCCPOptions *opt_;  //options to attach to the next outgoing packet
+
+	//feature variables (name_location_)
+	int ccid_;             //ccid is the same on both locations
+	int use_ecn_local_;   
+	int use_ecn_remote_;
+	int ack_ratio_local_;
+	int ack_ratio_remote_;
+	int use_ackv_local_;
+	int use_ackv_remote_;
+	int q_scheme_;         //quiescence scheme is the same on both locations
+	int q_local_;          //specifies if the remote sender is quiescent
+	int q_remote_;         //specifies if I am quiescent
+	
+	DCCPAckVector *ackv_;  //local ack_vector of all incoming packets
+	bool send_ackv_;       //if true, send ack vector on all acks 
+	bool manage_ackv_;     //if true, add incoming packets to ackv_ and clear state on ack-of-ack
+	
+	int nam_tracevar_;    
+	int trace_all_oneline_;
+
+	double initial_rtx_to_; //inital value for rtx timer delay
+	double max_rtx_to_;     //maximum total rtx delay (then back-off fails)
+	double resp_to_;        //response timer delay
+
+	int sb_size_;           //send buffer size
+	int opt_size_;          //maximum size of options on packets
+	int feat_size_;         //maximum number of ongoing feat neg
+	int ackv_size_;         //initial ackv_ size
+
+	int ar_unacked_;        //unacked data packets received
+
+	double rtt_conn_est_;   //rtt measured during connection establishment
+	
+	/* Return the current (simulated) time
+	 * ret: current time
+	 */
+	inline double now() { return (&Scheduler::instance() == NULL ? 0 : Scheduler::instance().clock()); }
+
+	/* OTcl binding of variables */
+	virtual void delay_bind_init_all();
+        virtual int delay_bind_dispatch(const char *varName, const char *localName, TclObject *tracer);
+
+	/* Return a string representation of a type */
+	const char* stateAsStr(dccp_state state);
+	const char* packetTypeAsStr(dccp_packet_type type);
+	const char* resetReasonAsStr(dccp_reset_reason reason);
+	const char* featureLocationAsStr(dccp_feature_location location);
+	/* Return the header size (without options) of a packet type
+	 * arg: type - packet type
+	 * ret: header size
+	 */
+	int headerSize(dccp_packet_type type);
+
+	/* Extract the ecn codepoint
+	 * arg: pkt - packet
+	 * ret: ecn codepoint of packet
+	 */
+	static dccp_ecn_codepoint getECNCodePoint(Packet* pkt);
+
+	/* Get the packet nonce
+	 * arg: pkt - packet
+	 * ret: 0 if ECT(0) is set
+	 *      1 if ECT(1) is set
+	 *      otherwise -1
+	 */
+	static int getNonce(Packet* pkt);
+
+	/* Changes state (and cancel/init/sched timers)
+	 * arg: new_state - new state
+	 */
+	void changeState(dccp_state new_state);
+
+	/* Reinitialize the agent */
+	virtual void reset();
+
+	/* Send a packet.
+	 * arg: try_pure_ack - if true, try to send a pure ack if cc
+	 *                     refuses to send a dataack
+	 */		       
+	void output(bool try_pure_ack = false);
+
+	/* Send a reset packet.
+	 * arg: reason  - reason for reset
+	 *      data<X> - data to include on reset packet
+	 */
+	void sendReset(dccp_reset_reason reason, u_int8_t data1,
+		       u_int8_t data2, u_int8_t data3);
+
+	/* Parse options in a packet.
+	 * Will call parseOption() on every option found.
+	 * Fails if parseOption() fails.
+	 * arg: pkt - packet
+	 * ret: true if parse is successful
+	 *      false if the parse failed and the connection should be reset
+	 */
+	virtual bool parseOptions(Packet *pkt);
+
+	/* Process an incoming option.
+	 * arg: type - option type
+	 *      data - option data
+	 *      size - size of opption data
+	 *      pkt  - the packet the option was received on
+	 * ret: true if option processing was successful
+	 *      false if it fails
+	 * This function will process:
+	 *      feature negotiation options
+ 	 *      ack vectors (extraction only)
+	 *      elapsed time (extraction only)      
+	 */	
+	virtual bool processOption(u_int8_t type, u_char* data, u_int8_t size, Packet *pkt);
+
+	/* Change a feature (i.e. initiate a feature negotiation).
+	 * arg: num      - feature number
+	 *      location - feature location
+	 * ret: true if the feature is added to the list of ongoing feat neg
+	 *      false if the list is full or the feature is already present
+	 */
+	bool changeFeature(u_int8_t num, dccp_feature_location location);
+
+	/* Check if a feature is currently under negotiation.
+	 * arg: num      - feature number
+	 *      location - feature location
+	 * ret: true if the feature is under negotiation
+	 *      false otherwise
+	 */
+	bool featureIsChanging(u_int8_t num, dccp_feature_location location);
+
+	/* Build the list of features to neg on DCCP-Request packet */
+	virtual void buildInitialFeatureList();
+
+	/* Set a value for a specific feature.
+	 * arg: num      - feature number
+	 *      location - feature location
+	 *      data     - feature data
+	 *      size     - size of data
+	 *      testSet  - if true, only check value for correctness, don't set
+	 * ret: DCCP_FEAT_OK  if successful
+	 *      DCCP_FEAT_UNKNOWN  if the feature number is unknown
+	 *      DCCP_FEAT_NOT_PREFERED  if the value is not prefered
+	 *      DCCP_FEAT_ERR_SIZE  if the size does not match the feature
+	 *      DCCP_FEAT_ERR_TEST  if a non-neg feature failed the test.
+	 *                          a negotiable feature that fails returns NOT_PREFERED
+	 * Note: DCCP_FEAT_NOT_PREFERED is not applicable for non neg features.
+	 *       NOT_PREFERED and ERR_SIZE will trigger a reset
+	 */
+	virtual int setFeature(u_int8_t num, dccp_feature_location location,
+			       u_char* data, u_int8_t size, bool testSet = false);
+
+	/* Obtain a value of a feature.
+	 * Used in addFeatureOptions() to get the feature value.
+	 * arg: num      - feature number
+	 *      location - feature location
+	 *      data     - feature data
+	 *      size     - maximum size of data
+	 * ret: DCCP_FEAT_OK            if successful
+	 *      DCCP_FEAT_UNKNOWN       if the feature number is unknown
+	 *      DCCP_FEAT_ERR_SIZE      if the size is too small
+	 */
+	virtual int getFeature(u_int8_t num, dccp_feature_location location,
+			       u_char* data, u_int8_t maxSize);
+
+	/* Obtain the feature type
+	 * arg: num      - feature number
+	 * ret: the feature type, or DCCP_FEAT_TYPE_UKNOWN if unknown
+	 */
+	virtual dccp_feature_type getFeatureType(u_int8_t num);
+
+	/* Cancel all timers */
+	virtual void cancelTimers();
+
+	//Interface to cc
+
+	/* Ask sender permission to send a packet
+	 * arg: dataSize - size of data in packet (0 = pure ACK)
+	 *      pkt      - the packet to send
+	 * ret: true if permission is granted, otherwise false
+	 * Note: Packet should not be used for other than manipulating
+	 *       ecn marks!
+	 */
+	virtual bool send_askPermToSend(int dataSize, Packet *pkt);
+
+	/* A(n) ACK/DATA/DATAACK packet has been sent (sender)
+	 * arg: pkt        - packet sent
+	 *      moreToSend - true if there exist more data to send
+	 *      dataSize   - size of data sent
+	 */
+	virtual void send_packetSent(Packet *pkt, bool moreToSend, int dataSize);
+	/* A(n) ACK/DATA/DATAACK packet has been received (sender)
+	 * arg: pkt        - packet received
+	 *      dataSize   - size of data in packet
+	 * If this function would like to send a packet, set output_ = true
+	 * and output_flag_ if appropriate.
+	 */
+	virtual void send_packetRecv(Packet *pkt, int dataSize);
+
+	/* A ACK/DATA/DATAACK packet has been received (receiver)
+	 * arg: pkt        - packet received
+	 *      dataSize   - size of data in packet
+	 * If this function would like to send a packet, set output_ = true
+	 * and output_flag_ if appropriate.
+	 */
+	virtual void recv_packetRecv(Packet *pkt, int dataSize);
+
+	/* Tracing functions */
+	virtual void traceAll();
+	virtual void traceVar(TracedVar* v);
+public:
+
+	//statistics on sent packets
+	
+	TracedInt num_data_pkt_;
+	TracedInt num_ack_pkt_;
+	TracedInt num_dataack_pkt_;
+	
+	/* Constructor
+	 * ret: A new DCCPAgent
+	 */
+	DCCPAgent();
+
+	/* Destructor */
+	virtual ~DCCPAgent();
+
+	
+	/* Process a "function call" from OTCl
+	 * arg: argc - number of arguments
+	 *      argv - arguments
+	 * ret: TCL_OK if successful, TCL_ERROR otherwise
+         *
+	 * Supported function call handled by this agent:
+	 * advanceby x   -  advances num packets
+	 * advance x     -  = advanceby x  
+	 */
+	int command(int argc, const char*const* argv);
+
+	/* Receive a packet
+	 * arg: pkt     - Packet received
+	 *      handler - handler
+	 */
+	virtual void recv(Packet* pkt, Handler* handler);
+
+	/* Send a packet,
+	 * If this is the first packet to send, initiate a connection.
+	 * arg: nbytes - number of bytes in packet (-1 -> infinite send)
+	 *      flags  - Flags:
+	 *                 "MSG_EOF" will close the connection when all data
+	 *                  has been flag
+	 */
+	virtual void sendmsg(int nbytes, const char *flags = 0);
+
+	/* Close the connection */
+	virtual void close();
+
+	/* Listen for incoming connections
+	 * Use close() to stop listen
+	 */ 
+	virtual void listen();
+
+	/* A timeout has occured
+	 * arg: tno - id of timeout event
+	 * Handles: Retransmit timer - DCCP_TIMER_RTX
+	 *          Send timer - DCCP_TIMER_SND
+	 */
+	virtual void timeout(int tno);
+
+	/* Trace a variable.
+	 * arg: v  - traced variable
+	 */
+	void trace(TracedVar* v);
+
+	/* Send delta packets of packetSize_ size
+	 * arg: delta - number of packets to send
+	 */
+	void advanceby(int delta);
+};
+
+#endif
+
+
+
+
+
+
diff -urNU5 ns-2.33/dccp/dccp_opt.cc ns-2.33-dccp/dccp/dccp_opt.cc
--- ns-2.33/dccp/dccp_opt.cc	1970-01-01 10:00:00.000000000 +1000
+++ ns-2.33-dccp/dccp/dccp_opt.cc	2008-05-05 17:17:43.000000000 +1000
@@ -0,0 +1,215 @@
+/* -*-	Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
+
+/* Copyright (c) 2004  Nils-Erik Mattsson 
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: ns-233-dccp-1.patch 210 2008-05-13 03:43:55Z omehani $ */
+
+#include <stdio.h>
+#include "dccp_opt.h"
+
+/* Constructor 
+ * arg: size - Maximum size for stored options
+ * returns: a new DCCPOptions object
+ */
+DCCPOptions::DCCPOptions(int size): size_(0), max_size_(size), current_(DCCP_OPT_ERR_WALK){
+	options_ = new u_char[max_size_];
+}
+
+/* Copy constructor */
+DCCPOptions::DCCPOptions(const DCCPOptions& orig){
+	options_ = new u_char[orig.max_size_];
+	memcpy (options_, orig.options_, orig.size_);
+	size_ = orig.size_;
+	max_size_ = orig.max_size_;
+	current_ = orig.current_;
+}
+
+
+/* Destructor */
+DCCPOptions::~DCCPOptions(){
+	delete [] options_;
+}
+
+/* Add an option
+ * arg: type     - Option type
+ *      data     - Option data
+ *      dataSize - Size of option data
+ * ret: DCCP_OPT_NO_ERR   if successful
+ *      DCCP_OPT_ERR_SIZE if the size of the option is wrong
+ *      DCCP_OPT_ERR_FULL if max_size_ is reached
+ */
+int DCCPOptions::addOption(u_int8_t type, const u_char* data, u_int8_t dataSize){
+	int length = ((dataSize == 0) ? 1 : dataSize+2);
+	if ((type < DCCP_OPT_SINGLE_BYTE_LIMIT && dataSize > 0) ||
+	    (type >= DCCP_OPT_SINGLE_BYTE_LIMIT && dataSize == 0) ||
+	    length > DCCP_OPT_MAX_LENGTH)
+		return DCCP_OPT_ERR_SIZE;
+	
+	if (size_ + length > max_size_) //out of space
+		return DCCP_OPT_ERR_FULL;
+
+	options_[size_++] = type;
+	if (dataSize > 0){
+		options_[size_++] = length;
+		for(int i = 0; i < dataSize; i++)
+			options_[size_++] = data[i];
+	}
+	
+	return DCCP_OPT_NO_ERR;
+}
+
+/* Add a feature option
+ * arg: type     - Option type
+ *      feat_num - Feature number
+ *      data     - Feature data
+ *      dataSize - Size of feature data
+ * ret: like addOption() but also
+ *      DCCP_OPT_ERR_TYPE if type is not ChangeR/L or ConfirmR/L
+ */
+int DCCPOptions::addFeatureOption(u_int8_t type, u_int8_t feat_num, const u_char *data,
+				   u_int8_t dataSize){
+	int length = dataSize + 3;
+	
+	if (dataSize == 0 || length > DCCP_OPT_MAX_LENGTH) //must include some data, but not too much
+		return DCCP_OPT_ERR_SIZE;
+	
+	if (type < DCCP_OPT_CHANGEL || type > DCCP_OPT_CONFIRMR)
+		return DCCP_OPT_ERR_TYPE;  //not an feature option
+	
+	if (size_ + length > max_size_) //out of space
+		return DCCP_OPT_ERR_FULL;
+
+	options_[size_++] = type;
+	options_[size_++] = length;
+	options_[size_++] = feat_num;
+
+	for(int i = 0; i < dataSize; i++)
+		options_[size_++] = data[i];
+
+	return DCCP_OPT_NO_ERR;
+}
+
+/* Extract an option
+ * arg: type     - Option type
+ *      data     - Array to copy option data to
+ *      maxSize  - Maximum size of data array
+ * ret: DCCP_OPT_NO_ERR if successful (for single byte option)
+ *      size of data obtained if successful for other options
+ *      DCCP_OPT_ERR_SIZE if the size of the data array is to small
+ *	DCCP_OPT_ERR_NOT_FOUND if the option is not found
+ */
+int DCCPOptions::getOption(u_int8_t type, u_char* data, u_int8_t maxSize){
+	int walker = 0, dataSize = 0;
+
+	while (walker < size_){
+		if (options_[walker] < DCCP_OPT_SINGLE_BYTE_LIMIT) {  //single byte option
+			if (options_[walker] == type)
+				return DCCP_OPT_NO_ERR;
+			walker++;
+		} else {  //multi byte option
+			dataSize = options_[walker+1]-2;
+			walker += 2;
+			if (options_[walker-2] == type) { 
+				if (maxSize >= dataSize){
+					for(int i = walker; i < walker+dataSize; i++)
+						data[i-walker] = options_[i];
+					return dataSize;
+				} else
+					return DCCP_OPT_ERR_SIZE;
+				//not reached
+			}
+			
+			walker += dataSize;
+		}
+		
+	}
+	return DCCP_OPT_ERR_NOT_FOUND;
+}
+
+/* Get the total size of options, including necessary padding.
+ * ret: size of options
+ */
+u_int16_t DCCPOptions::getSize(){
+	u_int16_t result = size_;
+	if ((size_ % DCCP_OPT_ALIGNMENT) > 0) //add padding
+		result += DCCP_OPT_ALIGNMENT - (size_ % DCCP_OPT_ALIGNMENT);
+	return result;
+}
+
+/* Start a walk through the options. */	
+void DCCPOptions::startOptionWalk(){
+	current_ = 0;
+}
+
+/* Return the next option in the option walk
+ * arg: type    - Option type found
+ *      data    - Array to copy option data to
+ *      maxSize - Maximum size of data array
+ * ret: like getOption() but also
+ *      DCCP_OPT_ERR_WALK if option walk is not initiated.
+ */
+int DCCPOptions::nextOption(u_int8_t* type, u_char* data, u_int8_t maxSize){
+	if (current_ == DCCP_OPT_ERR_WALK)
+		return DCCP_OPT_ERR_WALK;
+	if (current_ >= size_)
+		return DCCP_OPT_ERR_NOT_FOUND;
+
+	if (options_[current_] < DCCP_OPT_SINGLE_BYTE_LIMIT) {  //single byte option
+		*type = options_[current_];
+		current_++;
+	} else {  //multi byte option
+		int dataSize = options_[current_+1]-2;
+		current_ += 2;
+		if (maxSize >= dataSize){
+			*type = options_[current_-2];
+			for(int i = current_; i < current_+dataSize; i++)
+				data[i-current_] = options_[i];
+			current_ += dataSize;
+			return dataSize;
+		} else {
+			current_ -= 2;
+			return DCCP_OPT_ERR_SIZE;
+		}
+	}
+	return DCCP_OPT_NO_ERR;
+}
+
+/* Print all options and state (for debug) */
+void DCCPOptions::print(){
+	fprintf(stdout, "DCCPOptions :: size %d, max_size %d, current %d\n", size_, max_size_, current_);
+	if (size_ == 0)
+		fprintf(stdout, "No option is present\n");
+	else {
+		fprintf(stdout, "Option buffer:\n");
+		for(int i = 0; i < size_; i++){
+			fprintf(stdout, "%d ", options_[i]);
+			if ( (i != 0 && (i+1) % DCCP_OPT_PRINT_ALIGNMENT == 0) || i == size_-1)
+				fprintf(stdout, "\n");
+		}
+	}
+	fflush(stdout);
+}
diff -urNU5 ns-2.33/dccp/dccp_opt.h ns-2.33-dccp/dccp/dccp_opt.h
--- ns-2.33/dccp/dccp_opt.h	1970-01-01 10:00:00.000000000 +1000
+++ ns-2.33-dccp/dccp/dccp_opt.h	2008-05-05 17:17:43.000000000 +1000
@@ -0,0 +1,141 @@
+/* -*-	Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
+
+/* Copyright (c) 2004  Nils-Erik Mattsson 
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: ns-233-dccp-1.patch 210 2008-05-13 03:43:55Z omehani $ */
+
+#ifndef ns_dccp_opt_h
+#define ns_dccp_opt_h
+
+#include "config.h"
+#include "dccp_types.h"
+
+//options types less than this limit consist of a single byte
+#define DCCP_OPT_SINGLE_BYTE_LIMIT 32
+#define DCCP_OPT_CC_START 128         //CCID specific options starts here
+
+//total size is padded to this byte boundary
+#define DCCP_OPT_ALIGNMENT 4          
+#define DCCP_OPT_MAX_LENGTH 255       //maximum length of one option
+
+#define DCCP_OPT_PRINT_ALIGNMENT 16   //print this number of option data/row
+
+//options errors
+#define DCCP_OPT_NO_ERR 0
+#define DCCP_OPT_ERR_SIZE -1
+#define DCCP_OPT_ERR_FULL -2
+#define DCCP_OPT_ERR_NOT_FOUND -3
+#define DCCP_OPT_ERR_TYPE -4
+#define DCCP_OPT_ERR_WALK -5
+
+//options
+#define DCCP_OPT_PADDING 0
+#define DCCP_OPT_QUIESCENCE 30    //experimental!!!
+#define DCCP_OPT_CHANGEL 33
+#define DCCP_OPT_CONFIRML 34
+#define DCCP_OPT_CHANGER 35
+#define DCCP_OPT_CONFIRMR 36
+#define DCCP_OPT_ACK_VECTOR_N0 37
+#define DCCP_OPT_ACK_VECTOR_N1 38
+#define DCCP_OPT_ELAPSED_TIME 46
+
+//units
+#define DCCP_OPT_ELAPSED_TIME_UNIT 0.0001
+
+/* Class DCCPOptions models dccp options in packets */
+class DCCPOptions {
+private:
+        u_char* options_;      //array with options
+	u_int16_t size_;       //size used in the array
+	u_int16_t max_size_;   //the maximum size of the array
+	int current_;          //current position in walk
+public:
+	/* Constructor 
+	 * arg: size - Maximum size for stored options
+	 * returns: a new DCCPOptions object
+	 */
+	DCCPOptions(int size);
+
+	/* Copy constructor */
+	DCCPOptions(const DCCPOptions&);
+
+	/* Destructor */
+	~DCCPOptions();
+
+	/* Add an option
+	 * arg: type     - Option type
+	 *      data     - Option data
+	 *      dataSize - Size of option data
+	 * ret: DCCP_OPT_NO_ERR   if successful
+	 *      DCCP_OPT_ERR_SIZE if the size of the option is wrong
+	 *      DCCP_OPT_ERR_FULL if max_size_ is reached
+	 */
+        int addOption(u_int8_t type, const u_char* data, u_int8_t dataSize);
+
+	/* Add a feature option
+	 * arg: type     - Option type
+	 *      feat_num - Feature number
+	 *      data     - Feature data
+	 *      dataSize - Size of feature data
+	 * ret: like addOption() but also
+	 *      DCCP_OPT_ERR_TYPE if type is not ChangeR/L or ConfirmR/L
+	 */
+	int addFeatureOption(u_int8_t type, u_int8_t feat_num, const u_char *data, u_int8_t dataSize);
+
+	/* Extract an option
+	 * arg: type     - Option type
+	 *      data     - Array to copy option data to
+	 *      maxSize  - Maximum size of data array
+	 * ret: DCCP_OPT_NO_ERR if successful (for single byte option)
+	 *      size of data obtained if successful for other options
+	 *      DCCP_OPT_ERR_SIZE if the size of the data array is to small
+	 *	DCCP_OPT_ERR_NOT_FOUND if the option is not found
+	 */	    
+	int getOption(u_int8_t type, u_char* data, u_int8_t maxSize);
+
+	/* Get the total size of options, including necessary padding.
+	 * ret: size of options
+	 */
+	u_int16_t getSize();
+
+	/* Start a walk through the options. */
+	void startOptionWalk();
+	
+	/* Return the next option in the option walk
+	 * arg: type    - Option type found
+	 *      data    - Array to copy option data to
+	 *      maxSize - Maximum size of data array
+	 * ret: like getOption() but also
+	 *      DCCP_OPT_ERR_WALK if option walk is not initiated.
+	 */
+	int nextOption(u_int8_t* type, u_char* data, u_int8_t maxSize);
+
+	/* Print all options and state (for debug) */
+	void print();
+};
+
+#endif
diff -urNU5 ns-2.33/dccp/dccp_packets.cc ns-2.33-dccp/dccp/dccp_packets.cc
--- ns-2.33/dccp/dccp_packets.cc	1970-01-01 10:00:00.000000000 +1000
+++ ns-2.33-dccp/dccp/dccp_packets.cc	2008-05-05 17:17:43.000000000 +1000
@@ -0,0 +1,116 @@
+/* -*-	Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
+
+/* Copyright (c) 2004  Nils-Erik Mattsson 
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: ns-233-dccp-1.patch 210 2008-05-13 03:43:55Z omehani $ */
+
+#include "packet.h"
+#include "dccp_packets.h"
+
+int hdr_dccp::offset_;
+int hdr_dccpack::offset_;
+int hdr_dccpreq::offset_;
+int hdr_dccpresp::offset_;
+int hdr_dccpdata::offset_;
+int hdr_dccpdataack::offset_;
+int hdr_dccpclose::offset_;
+int hdr_dccpclosereq::offset_;
+int hdr_dccpreset::offset_;
+
+//OTcl linkage for packet headers
+static class DCCPHeaderClass : public PacketHeaderClass {
+public:
+	DCCPHeaderClass() : PacketHeaderClass("PacketHeader/DCCP",
+					      sizeof(hdr_dccp)){
+		bind_offset(&hdr_dccp::offset_);
+	}
+} class_dccphdr;
+
+static class DCCPResetHeaderClass : public PacketHeaderClass {
+public:
+	DCCPResetHeaderClass() : PacketHeaderClass("PacketHeader/DCCP_RESET",
+					      sizeof(hdr_dccpreset)){
+		bind_offset(&hdr_dccpreset::offset_);
+	}
+} class_dccpresethdr;
+
+static class DCCPResponseHeaderClass : public PacketHeaderClass {
+public:
+	DCCPResponseHeaderClass() : PacketHeaderClass("PacketHeader/DCCP_RESP",
+					      sizeof(hdr_dccpresp)){
+		bind_offset(&hdr_dccpresp::offset_);
+	}
+} class_dccpresphdr;
+
+static class DCCPRequestHeaderClass : public PacketHeaderClass {
+public:
+	DCCPRequestHeaderClass() : PacketHeaderClass("PacketHeader/DCCP_REQ",
+					      sizeof(hdr_dccpreq)){
+		bind_offset(&hdr_dccpreq::offset_);
+	}
+} class_dccpreqhdr;
+
+static class DCCPAckHeaderClass : public PacketHeaderClass {
+public:
+	DCCPAckHeaderClass() : PacketHeaderClass("PacketHeader/DCCP_ACK",
+					      sizeof(hdr_dccpack)){
+		bind_offset(&hdr_dccpack::offset_);
+	}
+} class_dccpackhdr;
+
+static class DCCPDataAckHeaderClass : public PacketHeaderClass {
+public:
+	DCCPDataAckHeaderClass() : PacketHeaderClass("PacketHeader/DCCP_DATAACK",
+					      sizeof(hdr_dccpdataack)){
+		bind_offset(&hdr_dccpdataack::offset_);
+	}
+} class_dccpdataackhdr;
+
+static class DCCPDataHeaderClass : public PacketHeaderClass {
+public:
+	DCCPDataHeaderClass() : PacketHeaderClass("PacketHeader/DCCP_DATA",
+					      sizeof(hdr_dccpdata)){
+		bind_offset(&hdr_dccpdata::offset_);
+	}
+} class_dccpdatahdr;
+
+static class DCCPCloseHeaderClass : public PacketHeaderClass {
+public:
+	DCCPCloseHeaderClass() : PacketHeaderClass("PacketHeader/DCCP_CLOSE",
+					      sizeof(hdr_dccpclose)){
+		bind_offset(&hdr_dccpclose::offset_);
+	}
+} class_dccpclosehdr;
+
+static class DCCPCloseReqHeaderClass : public PacketHeaderClass {
+public:
+	DCCPCloseReqHeaderClass() : PacketHeaderClass("PacketHeader/DCCP_CLOSEREQ",
+					      sizeof(hdr_dccpclosereq)){
+		bind_offset(&hdr_dccpclosereq::offset_);
+	}
+} class_dccpclosereqhdr;
+
diff -urNU5 ns-2.33/dccp/dccp_packets.h ns-2.33-dccp/dccp/dccp_packets.h
--- ns-2.33/dccp/dccp_packets.h	1970-01-01 10:00:00.000000000 +1000
+++ ns-2.33-dccp/dccp/dccp_packets.h	2008-05-05 17:17:43.000000000 +1000
@@ -0,0 +1,137 @@
+/* -*-	Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
+
+/* Copyright (c) 2004  Nils-Erik Mattsson 
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: ns-233-dccp-1.patch 210 2008-05-13 03:43:55Z omehani $ */
+
+#ifndef ns_dccp_packets_h
+#define ns_dccp_packets_h
+
+#include "dccp_types.h"
+#include "dccp_opt.h"
+
+struct hdr_dccp {
+	//generic dccp header
+	dccp_packet_type type_;
+	u_int8_t ccval_;
+	u_int8_t ndp_;
+	u_int32_t seq_num_;
+	u_int8_t data_offset_;
+	u_int8_t cscov_;
+	
+	//options      
+	DCCPOptions *options_;  
+	
+	//ns-2 header offset
+	static int offset_;
+	inline static int& offset() { return offset_; }
+	inline static hdr_dccp* access(const Packet* p) {
+		return (hdr_dccp*) p->access(offset_);
+	}
+};
+
+struct hdr_dccpack {
+	u_int32_t ack_num_;
+
+	//ns-2 header offset
+	static int offset_;
+	inline static int& offset() { return offset_; }
+	inline static hdr_dccpack* access(const Packet* p) {
+		return (hdr_dccpack*) p->access(offset_);
+	}
+};
+
+struct hdr_dccpreset {
+	//reset packet info
+	dccp_reset_reason rst_reason_;
+	u_int8_t rst_data1_;
+	u_int8_t rst_data2_;
+	u_int8_t rst_data3_;
+
+	//ns-2 header offset
+	static int offset_;
+	inline static int& offset() { return offset_; }
+	inline static hdr_dccpreset* access(const Packet* p) {
+		return (hdr_dccpreset*) p->access(offset_);
+	}
+};
+
+struct hdr_dccpreq {
+	//ns-2 header offset
+	static int offset_;
+	inline static int& offset() { return offset_; }
+	inline static hdr_dccpreq* access(const Packet* p) {
+		return (hdr_dccpreq*) p->access(offset_);
+	}
+};
+
+struct hdr_dccpresp {
+	//ns-2 header offset
+	static int offset_;
+	inline static int& offset() { return offset_; }
+	inline static hdr_dccpresp* access(const Packet* p) {
+		return (hdr_dccpresp*) p->access(offset_);
+	}
+};
+
+struct hdr_dccpdata {
+	//ns-2 header offset
+	static int offset_;
+	inline static int& offset() { return offset_; }
+	inline static hdr_dccpdata* access(const Packet* p) {
+		return (hdr_dccpdata*) p->access(offset_);
+	}
+};
+
+struct hdr_dccpdataack {
+	//ns-2 header offset
+	static int offset_;
+	inline static int& offset() { return offset_; }
+	inline static hdr_dccpdataack* access(const Packet* p) {
+		return (hdr_dccpdataack*) p->access(offset_);
+	}
+};
+
+struct hdr_dccpclose {
+	//ns-2 header offset
+	static int offset_;
+	inline static int& offset() { return offset_; }
+	inline static hdr_dccpclose* access(const Packet* p) {
+		return (hdr_dccpclose*) p->access(offset_);
+	}
+};
+
+struct hdr_dccpclosereq {
+	//ns-2 header offset
+	static int offset_;
+	inline static int& offset() { return offset_; }
+	inline static hdr_dccpclosereq* access(const Packet* p) {
+		return (hdr_dccpclosereq*) p->access(offset_);
+	}
+};
+
+#endif
diff -urNU5 ns-2.33/dccp/dccp_sb.cc ns-2.33-dccp/dccp/dccp_sb.cc
--- ns-2.33/dccp/dccp_sb.cc	1970-01-01 10:00:00.000000000 +1000
+++ ns-2.33-dccp/dccp/dccp_sb.cc	2008-05-05 17:17:43.000000000 +1000
@@ -0,0 +1,123 @@
+/* -*-	Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
+
+/* Copyright (c) 2004  Nils-Erik Mattsson 
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: ns-233-dccp-1.patch 210 2008-05-13 03:43:55Z omehani $ */
+
+#include <stdio.h>
+#include "dccp_sb.h"
+
+/* Constructor
+ * arg: size - Maximum size of buffer
+ * ret: a new DCCPSendBuffer
+ */
+DCCPSendBuffer::DCCPSendBuffer(int size): head_(0), tail_(0),
+	size_(size), empty_(true) {
+	if (size_ <= 0)
+		size_ = 1;
+	
+	buf_ = new int[size_];
+}
+
+/* Destructor */
+DCCPSendBuffer::~DCCPSendBuffer(){
+	delete [] buf_;
+}
+
+/* Add an element to the buffer
+ * arg: size - size of element
+ * ret: true if successful, false if full
+ */
+bool DCCPSendBuffer::add(int packet_size){
+	if (empty_) {
+		buf_[head_] = packet_size;
+		empty_ = false;
+	} else if ( (tail_+1) % size_ == head_)  //buffer is full
+		return false;
+	else {
+		tail_ = (tail_ + 1) % size_;
+		buf_[tail_] = packet_size;
+	}
+	return true;
+}
+
+/* Check if the buffer is full
+ * ret: true if full, otherwise false
+ */
+bool DCCPSendBuffer::full(){
+	return (!empty_ && ((tail_+1) % size_ == head_));
+}
+
+/* Check if the buffer is empty
+ * ret: true if empty, otherwise false
+ */
+bool DCCPSendBuffer::empty(){
+	return empty_;
+}
+
+/* Return the top element (without removing it)
+ * ret: the top element. If empty, return 0.
+ */
+int DCCPSendBuffer::top(){
+	int result = 0;
+	if (!empty_)
+		result = buf_[head_];
+	return result;
+}
+
+/* Return and remove the top element
+ * ret: the top element. If empty, return 0.
+ */
+int DCCPSendBuffer::remove(){
+	int result = 0;
+	if (!empty_){
+		result = buf_[head_];
+		//remove element
+		if (head_ != tail_)
+			head_ = (head_+1) % size_;
+		else
+			empty_ = true;
+	}
+	return result;
+}
+
+/* Print send buffer contents and state (for debug) */
+void DCCPSendBuffer::print(){
+	int walker_ = head_;
+	if (empty_)
+		fprintf(stdout, "DCCPSendBuffer :: Buffer is empty (size %d, head %d, tail %d)\n", size_, head_, tail_);
+	else {
+		fprintf(stdout, "DCCPSendBuffer :: Buffer (size %d, head %d, tail %d): ", size_, head_, tail_);
+		while(walker_ != tail_){
+			fprintf(stdout, "%d ",buf_[walker_]);
+			walker_ = (walker_ + 1) % size_;
+		}
+		fprintf(stdout, "%d\n",buf_[walker_]);
+	}
+	fflush(stdout);
+}
+
diff -urNU5 ns-2.33/dccp/dccp_sb.h ns-2.33-dccp/dccp/dccp_sb.h
--- ns-2.33/dccp/dccp_sb.h	1970-01-01 10:00:00.000000000 +1000
+++ ns-2.33-dccp/dccp/dccp_sb.h	2008-05-05 17:17:43.000000000 +1000
@@ -0,0 +1,88 @@
+/* -*-	Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
+
+/* Copyright (c) 2004  Nils-Erik Mattsson 
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: ns-233-dccp-1.patch 210 2008-05-13 03:43:55Z omehani $ */
+
+#ifndef ns_dccp_sb_h
+#define ns_dccp_sb_h
+
+/* A (circular) send buffer consisting of packet sizes */
+class DCCPSendBuffer {
+private:
+	int* buf_;                 //buffer
+	int head_,tail_;           //head and tail of circular buffer
+	int size_;                 //maximum size of buffer
+	bool empty_;               //if its empty or not
+public:
+	/* Constructor
+	 * arg: size - Maximum size of buffer
+	 * ret: a new DCCPSendBuffer
+	 */
+	DCCPSendBuffer(int size);
+
+	/* Destructor */
+	~DCCPSendBuffer();
+
+	/* Add an element to the buffer
+	 * arg: size - size of element
+	 * ret: true if successful, false if full
+	 */
+	bool add(int size);
+
+	/* Check if the buffer is full
+	 * ret: true if full, otherwise false
+	 */
+	bool full();
+
+	/* Check if the buffer is empty
+	 * ret: true if empty, otherwise false
+	 */
+	bool empty();
+
+	/* Return the top element (without removing it)
+	 * ret: the top element. If empty, return 0.
+	 */
+	int top();
+
+	/* Return and remove the top element
+	 * ret: the top element. If empty, return 0.
+	 */
+	int remove();
+
+	/* Print send buffer contents and state (for debug) */
+	void print();
+};
+
+#endif
+
+
+
+
+
+
+
diff -urNU5 ns-2.33/dccp/dccp_tcplike.cc ns-2.33-dccp/dccp/dccp_tcplike.cc
--- ns-2.33/dccp/dccp_tcplike.cc	1970-01-01 10:00:00.000000000 +1000
+++ ns-2.33-dccp/dccp/dccp_tcplike.cc	2008-05-05 17:17:43.000000000 +1000
@@ -0,0 +1,1232 @@
+/* -*-	Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
+
+/* Copyright (c) 2004  Nils-Erik Mattsson 
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: ns-233-dccp-1.patch 210 2008-05-13 03:43:55Z omehani $ */
+
+#include "ip.h"
+#include "dccp_tcplike.h"
+#include "flags.h"
+
+#define DCCP_TCPLIKE_IN_WINDOW 1
+#define DCCP_TCPLIKE_AFTER_WINDOW 0
+
+//OTcl linkage for DCCP TCPlike agent
+static class DCCPTCPlikeClass : public TclClass {
+public:
+	DCCPTCPlikeClass() : TclClass("Agent/DCCP/TCPlike") {};
+	TclObject* create(int argc, const char*const* argv){
+		return (new DCCPTCPlikeAgent());
+	}
+} class_dccptcplike;
+
+//methods for timer classes
+
+/* Constructor
+ * arg: agent - the owning agent (to notify about timeout)
+ * ret: A new DCCPTCPlikeTOTimer
+ */
+DCCPTCPlikeTOTimer::DCCPTCPlikeTOTimer(DCCPTCPlikeAgent* agent) : TimerHandler(){
+	agent_ = agent;
+}
+
+/* Called when the timer has expired
+ * arg: e - The event that happened (i.e. the timer expired)
+ */
+void DCCPTCPlikeTOTimer::expire(Event *e){
+	agent_->timeout(DCCP_TCPLIKE_TIMER_TO);
+}
+
+/* Constructor
+ * arg: agent - the owning agent (to notify about timeout)
+ * ret: A new DCCPTCPlikeDelayedAckTimer
+ */
+DCCPTCPlikeDelayedAckTimer::DCCPTCPlikeDelayedAckTimer(DCCPTCPlikeAgent* agent) : TimerHandler(){
+	agent_ = agent;
+}
+
+/* Called when the timer has expired
+ * arg: e - The event that happened (i.e. the timer expired)
+ */
+void DCCPTCPlikeDelayedAckTimer::expire(Event *e){
+	agent_->timeout(DCCP_TCPLIKE_TIMER_DACK);
+}
+
+//private methods
+
+
+/* Clear the send history */
+inline void DCCPTCPlikeAgent::clearSendHistory(){
+	struct dccp_tcplike_send_hist_entry *elm, *elm2;
+
+	/* Empty packet history */
+	elm = STAILQ_FIRST(&send_hist_);
+	while (elm != NULL) {
+		elm2 = STAILQ_NEXT(elm, linfo_);
+		delete elm;
+		elm = elm2;
+	}
+	
+	STAILQ_INIT(&send_hist_);
+}
+
+/* Find a specific packet in the send history
+ * arg: seq_num - sequence number of packet to find
+ *      start_elm - start searching from this element
+ * ret: pointer to the correct element if the element is found
+ *      otherwise the closest packet with lower seq num is returned
+ *      which can be NULL.
+ */
+inline struct dccp_tcplike_send_hist_entry* DCCPTCPlikeAgent::findPacketInSendHistory(u_int32_t seq_num, dccp_tcplike_send_hist_entry* start_elm){
+	struct dccp_tcplike_send_hist_entry *elm = start_elm;
+	while (elm != NULL && elm->seq_num_ > seq_num)
+		elm = STAILQ_NEXT(elm, linfo_);
+	return elm;
+}
+
+/* Remove packets from send history
+ * arg: trim_to - remove packets with lower sequence numbers than this
+ * Note: if trim_to does not exist in the history, trim_to is set to the next
+ *       lower sequence number found before trimming. 
+ */
+void DCCPTCPlikeAgent::trimSendHistory(u_int32_t trim_to){
+	if (trim_to > hist_last_seq_){
+		struct dccp_tcplike_send_hist_entry *elm, *elm2;
+		//find packet corresponding to trim_to
+		elm = findPacketInSendHistory(trim_to, STAILQ_FIRST(&send_hist_));
+		if (elm != NULL){
+			//remove older packets
+			elm2 = STAILQ_NEXT(elm, linfo_);	
+			while (elm2 != NULL){
+				STAILQ_REMOVE(&send_hist_,elm2,dccp_tcplike_send_hist_entry,linfo_);
+				delete elm2;
+				elm2 = STAILQ_NEXT(elm, linfo_);	
+			}
+		}
+		hist_last_seq_ = trim_to;
+	}
+}
+
+/* Prints the contents of the send history */
+void DCCPTCPlikeAgent::printSendHistory(){
+	struct dccp_tcplike_send_hist_entry *elm = STAILQ_FIRST(&send_hist_);
+	if (elm == NULL)
+		fprintf(stdout, "Packet history is empty (send)\n");
+	else {
+		fprintf(stdout, "Packet history (send):\n");
+		while(elm != NULL){
+			fprintf(stdout,"Packet: seq %d, t_sent %f, ecn %d\n", elm->seq_num_, elm->t_sent_, elm->ecn_);
+			elm = STAILQ_NEXT(elm, linfo_);
+		}
+	}
+}
+
+/* Clear the history of received packets */
+inline void DCCPTCPlikeAgent::clearSendRecvHistory(){
+	struct dccp_tcplike_send_recv_hist_entry *elm, *elm2;
+
+	/* Empty packet history */
+	elm = STAILQ_FIRST(&send_recv_hist_);
+	while (elm != NULL) {
+		elm2 = STAILQ_NEXT(elm, linfo_);
+		delete elm;
+		elm = elm2;
+	}
+	
+	STAILQ_INIT(&send_recv_hist_);
+}
+
+/* Insert a packet in the receive history
+ * Will not insert "lost" packets or duplicates.
+ * arg: packet - entry representing the packet to insert
+ * ret: true if packet was inserted, otherwise false.
+ */
+bool DCCPTCPlikeAgent::insertInSendRecvHistory(dccp_tcplike_send_recv_hist_entry *packet){
+	struct dccp_tcplike_send_recv_hist_entry *elm, *elm2;
+	int num_later = 0;
+	
+	if (STAILQ_EMPTY(&send_recv_hist_)){  //history is empty
+		STAILQ_INSERT_HEAD(&send_recv_hist_, packet, linfo_);
+	} else {  //history contains at least one entry
+		elm = STAILQ_FIRST(&send_recv_hist_);
+		if (packet->seq_num_ > elm->seq_num_)  //insert first in history
+			STAILQ_INSERT_HEAD(&send_recv_hist_, packet, linfo_);
+		else if (packet->seq_num_ == elm->seq_num_) //duplicate
+			return false;
+		else {  //packet should be inserted somewhere after the head
+			num_later = 1;
+
+			//walk through the history to find the correct place
+			elm2 = STAILQ_NEXT(elm,linfo_);
+			while(elm2 != NULL){
+				if (packet->seq_num_ > elm2->seq_num_){
+					STAILQ_INSERT_AFTER(&send_recv_hist_, elm, packet, linfo_);
+					break;
+				} else if (packet->seq_num_ == elm2->seq_num_) {
+					return false;  //duplicate
+				}
+				
+				elm = elm2;
+				elm2 = STAILQ_NEXT(elm,linfo_);
+				
+				num_later++;
+				
+				if (num_later == num_dup_acks_){  //packet is "lost"
+					return false;
+				}
+			}
+			
+			if(elm2 == NULL && num_later < num_dup_acks_){
+				STAILQ_INSERT_TAIL(&send_recv_hist_, packet, linfo_);
+			}
+			
+		}
+	}
+	return true;
+}
+
+/* Prints the contents of the receive history */
+void DCCPTCPlikeAgent::printSendRecvHistory(){
+	struct dccp_tcplike_send_recv_hist_entry *elm = STAILQ_FIRST(&send_recv_hist_);
+	if (elm == NULL)
+		fprintf(stdout, "Packet history is empty (send recv)\n");
+	else {
+		fprintf(stdout, "Packet history (send recv):\n");
+		while(elm != NULL){
+			fprintf(stdout,"Packet: seq %d, type %s, ndp %d\n", elm->seq_num_, packetTypeAsStr(elm->type_), elm->ndp_);
+			elm = STAILQ_NEXT(elm, linfo_);
+		}
+	}	
+}
+
+/* Detects packet loss in recv history.
+ * Trims the history to num_dup_acks_+1 length.
+ * arg: seq_start, seq_end - the lost packet is in [start,end]
+ * ret: true if a packet loss was detected, otherwise false.
+ */
+bool DCCPTCPlikeAgent::detectLossSendRecv(u_int32_t *seq_start, u_int32_t *seq_end){
+	struct dccp_tcplike_send_recv_hist_entry *before = STAILQ_FIRST(&send_recv_hist_);
+	int num_later = 1;
+	bool result = false;
+	//find the packet before the num_dup_acks_ limit
+	while (before != NULL && num_later < num_dup_acks_){
+		num_later++;
+		before = STAILQ_NEXT(before, linfo_);
+	}
+	
+	struct dccp_tcplike_send_recv_hist_entry *after = NULL;
+	//find the packet after the limit
+	if (before != NULL)
+		after = STAILQ_NEXT(before, linfo_);
+	
+	if (before == NULL || after == NULL)
+		return false;
+	
+	if (before->seq_num_ - after->seq_num_ != 1){
+		//we have loss, check if it includes ack packet by comparing ndp values
+		result =  (before->type_ == DCCP_ACK ? ((before->ndp_ - 1 + ndp_limit_) % ndp_limit_ != after->ndp_) : ( before->ndp_ != after->ndp_));
+		
+		if (result){  //we found a loss of an ack packet
+			*seq_start = before->seq_num_ - 1;
+			*seq_end = after->seq_num_ + 1;
+		}
+	}
+
+	//trim history
+	if (after != NULL){
+		before = after;
+		after = STAILQ_NEXT(before, linfo_);
+		while(after != NULL){
+			STAILQ_REMOVE(&send_recv_hist_,after,dccp_tcplike_send_recv_hist_entry,linfo_);
+			delete after;
+			after = STAILQ_NEXT(before, linfo_);	
+		}
+	}
+	return result;
+}
+
+/* Check the constraints on the ack ratio (recv_ack_ratio_)
+ * ret: true if the ack ratio was changed due to constraints
+ *      false otherwise
+ */
+bool DCCPTCPlikeAgent::checkAckRatio(){
+	bool result = false;
+	int temp = cwnd_ / 2;
+	if (cwnd_ % 2 > 0)
+		temp++;
+
+	//ackratio is never greater than half cwnd (rounded up)
+	if(recv_ack_ratio_ > temp){  
+		recv_ack_ratio_ = temp;
+		result = true;
+	}
+	//ack ratio always >= 2 for cwnd >= 4
+	if (cwnd_ >= 4 && recv_ack_ratio_ < 2){
+		recv_ack_ratio_ = 2;
+		result = true;
+	} else if (recv_ack_ratio_ == 0){  //always an integer > 0
+		recv_ack_ratio_ = 1;
+		result = true;
+	}
+
+	return result;
+}
+
+/* Compares recv_ack_ratio_ with ack_ratio_remote_ and
+ * tries to change the feauture if they differ.
+ */
+void DCCPTCPlikeAgent::changeRemoteAckRatio(){
+	if (recv_ack_ratio_ != ack_ratio_remote_ && changeFeature(DCCP_FEAT_ACK_RATIO,DCCP_FEAT_LOC_REMOTE)){
+		debug("%f, DCCP/TCPlike(%s)::changeRemoteAckRatio() - Changed Remote ack ratio: before %d, after %d\n",now(),name(),ack_ratio_remote_,recv_ack_ratio_);
+		ack_ratio_remote_ = recv_ack_ratio_;
+	}
+}
+
+/* Update the ack ratio
+ * arg: num_ack - number of newly acknowledged packets
+ */
+void DCCPTCPlikeAgent::updateAckRatio(int num_ack){
+	debug("%f, DCCP/TCPlike(%s)::updateAckRatio() - Before: num_ack %d, in_win %d, wins %d, cwnd %d, ack_ratio %d\n", now(), name(), num_ack, num_ack_in_win_, num_win_acked_, (int) cwnd_, recv_ack_ratio_);
+	if (recv_ack_ratio_ == 1){ //if ack ration is 1, we can't decrease it more
+		num_ack_in_win_ = 0;
+		num_win_acked_ = 0;
+	} else {
+		num_ack_in_win_ += num_ack;
+		//only check limit when a whole window has been acked
+		if (num_ack > 0 && num_ack_in_win_ >= cwnd_){
+			num_win_acked_++;
+			num_ack_in_win_ -= cwnd_;
+			
+			double ack_ratio_dec = ((double) cwnd_)/((double) (recv_ack_ratio_*(recv_ack_ratio_ - 1)));
+
+			if (num_win_acked_ > ack_ratio_dec){
+				debug("%f, DCCP/TCPlike(%s)::updateAckRatio() - Ack ratio decreased since num_win_acked_ > ack_ratio_dec\n", now(), name());
+				recv_ack_ratio_--;
+				checkAckRatio();
+				num_win_acked_ = 0;
+			}
+		}
+	}
+	debug("%f, DCCP/TCPlike(%s)::updateAckRatio() - After: num_ack %d, in_win %d, wins %d, cwnd %d, ack_ratio %d\n", now(), name(), num_ack, num_ack_in_win_, num_win_acked_, (int) cwnd_, recv_ack_ratio_);
+}
+
+/* Take action on lost or marked ack packet */
+void DCCPTCPlikeAgent::lostOrMarkedAck(){
+	ack_win_start_ = seq_num_;
+	num_win_acked_ = 0;
+	num_ack_in_win_ = 0;
+	skip_ack_loss_ = true;
+	recv_ack_ratio_ *= 2;
+	checkAckRatio();
+}
+
+/* Update the congestion window
+ * arg: num_inc_cwnd - number of newly acknowledged packets
+ */
+void DCCPTCPlikeAgent::updateCwnd(int num_inc_cwnd){
+	debug("%f, DCCP/TCPlike(%s)::updateCwnd() - Before: num_inc_cwnd %d,  cwnd_ %d, cwnd_frac_ %d, ssthresh_ %d, ack_ratio_remote_ %d\n", now(),name(), num_inc_cwnd, (int) cwnd_, (int) cwnd_frac_,(int) ssthresh_, ack_ratio_remote_);
+	int old_cwnd = cwnd_;
+
+	if (cwnd_ < ssthresh_){ //slow start
+		if (num_inc_cwnd > ack_ratio_remote_){
+			cwnd_ += ack_ratio_remote_;
+			num_inc_cwnd -= ack_ratio_remote_;
+		} else {
+			cwnd_ += num_inc_cwnd;
+			num_inc_cwnd = 0;
+		}
+		
+		if (cwnd_ <  ssthresh_)
+			num_inc_cwnd = 0;
+		else {
+			num_inc_cwnd += (cwnd_ - ssthresh_);
+			cwnd_ = ssthresh_;
+		}
+		if (cwnd_ == ssthresh_){ //we passed ssthresh_
+			cwnd_frac_ = 0;
+			//check quiescence and send ack of ack if needed
+			if (detectQuiescence()){ 
+				//output_ = true;
+				send_ack_ = true;
+				ack_num_ = seq_num_recv_;
+			}
+		}
+	}
+	
+	if (num_inc_cwnd > 0 && cwnd_ >= ssthresh_){ //congestion avoidance
+		cwnd_frac_ += num_inc_cwnd;
+		while (cwnd_frac_ >= cwnd_){
+			cwnd_frac_ -= cwnd_;
+			cwnd_++;
+		}
+
+		//check quiescence and send ack of ack if needed
+		if (cwnd_ != old_cwnd && detectQuiescence()){
+			//output_ = true;
+			send_ack_ = true;
+			ack_num_ = seq_num_recv_;
+		} 
+	}
+
+	if (old_cwnd < cwnd_)
+		if (checkAckRatio())
+			debug("%f, DCCP/TCPlike(%s)::updateCwnd() - Ack ratio changed! old_cwnd %d cwnd_ %d\n", now(), name(), old_cwnd, (int) cwnd_);
+	
+	debug("%f, DCCP/TCPlike(%s)::updateCwnd() - After: num_inc_cwnd %d, cwnd_ %d, cwnd_frac_ %d, ssthresh_ %d, ack_ratio_remote_ %d\n", now(), name(), num_inc_cwnd, (int) cwnd_, (int) cwnd_frac_, (int) ssthresh_, ack_ratio_remote_);
+}
+
+/* Take action on lost or marked data packet */
+void DCCPTCPlikeAgent::lostOrMarkedData(){
+	if (cwnd_ >= 2)  //i.e . cwnd_ != 1
+		cwnd_ = cwnd_ / 2;
+	cwnd_frac_ = 0;
+	ssthresh_ = cwnd_;
+	seq_win_start_ = seq_num_;
+	debug("%f, DCCP/TCPlike(%s)::lostOrMarkedData() - updated cwnd and ssthresh to: cwnd_ %d, ssthresh_ %d, seq_win_start %d\n", now(), name(), (int) cwnd_, (int) ssthresh_, seq_win_start_);
+}
+
+/* Detects quiescence of the corresponding sender
+ * ret: true if sender is quiescent
+ *      false otherwise
+ */
+bool DCCPTCPlikeAgent::detectQuiescence(){
+	debug("%f, DCCP/TCPlike(%s)::detectQuiescence() - scheme %d, seq high data %d, last in vect %d, time now %f, time high data %f, srtt %f\n", now(), name(), q_scheme_, q_high_data_recv_, ackv_->getLastSeqNum(),now(),q_t_data_,(double) srtt_);
+
+	if (q_scheme_ == DCCP_Q_SCHEME_Q_OPT){
+		if(sender_quiescent_)
+			debug("%f, DCCP/TCPlike(%s)::detectQuiescence() - Receiver detected that the corresponding sender is quiescent (Q_OPT)\n", now(),name());
+		return sender_quiescent_;
+	} else if (q_scheme_ == DCCP_Q_SCHEME_Q_FEAT){
+		if (q_local_)
+			debug("%f, DCCP/TCPlike(%s)::detectQuiescence() - Receiver detected that the corresponding sender is quiescent (Q_FEAT)\n", now(),name());
+		return q_local_;
+	}
+	
+	if (srtt_ <= 0.0)
+		return false;
+	
+	double t = q_min_t_;
+	if (t < 2*srtt_)  
+		t = 2*srtt_; 
+	if (ackv_->getLastSeqNum() > q_high_data_recv_ && now()-q_t_data_ >= t)
+		debug("%f, DCCP/TCPlike(%s)::detectQuiescence() - Receiver detected that the corresponding sender is quiescent (NORMAL)\n", now(), name());
+	return (ackv_->getLastSeqNum() > q_high_data_recv_ && now()-q_t_data_ >= t);
+}
+
+//protected methods
+
+/* Methods inherited from DCCPAgent.
+ * See dccp.h For detailed information regarding arguments etc.
+ */
+
+void DCCPTCPlikeAgent::delay_bind_init_all(){
+	delay_bind_init_one("initial_cwnd_");
+	delay_bind_init_one("cwnd_timeout_");
+	delay_bind_init_one("initial_ssthresh_");
+	delay_bind_init_one("cwnd_");
+	delay_bind_init_one("cwnd_frac_");
+	delay_bind_init_one("ssthresh_");
+	delay_bind_init_one("pipe_");
+	delay_bind_init_one("initial_rto_");
+	delay_bind_init_one("min_rto_");
+	delay_bind_init_one("rto_");
+	delay_bind_init_one("srtt_");
+	delay_bind_init_one("rttvar_");
+	delay_bind_init_one("rtt_sample_");
+	delay_bind_init_one("alpha_");
+	delay_bind_init_one("beta_");
+	delay_bind_init_one("k_");
+	delay_bind_init_one("g_");
+	delay_bind_init_one("num_dup_acks_");
+	delay_bind_init_one("q_min_t_");
+	delay_bind_init_one("dack_delay_");
+	delay_bind_init_one("q_opt_ratio_");
+	delay_bind_init_one("ackv_size_lim_");
+	DCCPAgent::delay_bind_init_all();
+}
+
+int DCCPTCPlikeAgent::delay_bind_dispatch(const char *varName, const char *localName, TclObject *tracer){
+	if (delay_bind(varName, localName, "initial_cwnd_", &initial_cwnd_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "cwnd_timeout_", &cwnd_timeout_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "initial_ssthresh_", &initial_ssthresh_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "cwnd_", &cwnd_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "cwnd_frac_", &cwnd_frac_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "ssthresh_", &ssthresh_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "pipe_", &pipe_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "initial_rto_", &initial_rto_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "min_rto_", &min_rto_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "rto_", &rto_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "srtt_", &srtt_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "rttvar_", &rttvar_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "rtt_sample_", &rtt_sample_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "alpha_", &alpha_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "beta_", &beta_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "k_", &k_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "g_", &g_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "num_dup_acks_", &num_dup_acks_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "q_min_t_", &q_min_t_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "dack_delay_", &dack_delay_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "q_opt_ratio_", &q_opt_ratio_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "ackv_size_lim_", &ackv_size_lim_, tracer)) return TCL_OK;
+	return DCCPAgent::delay_bind_dispatch(varName, localName, tracer);
+}
+
+
+void DCCPTCPlikeAgent::reset(){
+	DCCPAgent::reset();
+	
+	cwnd_ = initial_cwnd_;
+	cwnd_frac_ = 0;
+	ssthresh_ = initial_ssthresh_;
+	pipe_ = 0;
+	clearSendHistory();
+	clearSendRecvHistory();
+
+	t_last_data_sent_ = (double) (-q_min_t_)*2;
+	q_packets_wo_opt_ = 0;
+	
+	rto_ = initial_rto_;
+	srtt_ = -1.0;
+	rttvar_ = 0.0;
+	rtt_sample_ = 0.0;
+
+	hist_last_seq_ = 0;
+	high_ack_recv_ = 0;
+	
+	high_seq_recv_ = 0;
+	high_ndp_recv_ = -1;
+	unacked_ = 0;
+
+	delete stored_ackv_;
+	stored_ackv_ = new DCCPAckVector(ackv_size_);
+	seq_all_done_ = 0;
+	seq_win_start_ = 0;
+	seq_pipe_start_ = 0;
+	num_ack_in_win_ = 0;
+	num_win_acked_ = 0;
+	ack_win_start_ = 0;
+	skip_ack_loss_ = false;
+	recv_ack_ratio_ = ack_ratio_remote_;
+
+	q_high_data_recv_ = 0;
+	q_t_data_ = 0.0;
+	ackv_lim_seq_ = 0;
+
+	sender_quiescent_ = false;
+	t_high_recv_ = 0.0;
+}
+
+void DCCPTCPlikeAgent::cancelTimers(){
+	timer_to_->force_cancel();
+	timer_dack_->force_cancel();
+	DCCPAgent::cancelTimers();
+}
+
+/* Process incoming options.
+ * This function will process:
+ *      ack vectors (verify ECN Nonce Echo)
+ *      quiescence option
+ */
+bool DCCPTCPlikeAgent::processOption(u_int8_t type, u_char* data, u_int8_t size, Packet *pkt){
+	bool result = DCCPAgent::processOption(type, data, size, pkt);
+	if (result){
+		switch(type){
+		case DCCP_OPT_ACK_VECTOR_N0:
+		case DCCP_OPT_ACK_VECTOR_N1:
+			//check if we received a new ack vector
+			if (ackv_recv_ != NULL && ackv_recv_->getFirstSeqNum() >= high_ack_recv_){
+				//check if we got all needed packets in the history
+				if(hist_last_seq_ <= ackv_recv_->getLastSeqNum()){
+					
+					u_int8_t ene = 0;
+
+					u_int32_t seqnum;
+					dccp_packet_state state;
+					
+					struct dccp_tcplike_send_hist_entry *elm = STAILQ_FIRST(&send_hist_);
+					//walk through the ack vector and compute the ECN Nonce Echo
+					ackv_recv_->startPacketWalk();
+					while(ackv_recv_->nextPacket(&seqnum, &state)){
+						if (state == DCCP_PACKET_RECV){
+							elm = findPacketInSendHistory(seqnum,elm);
+							if (elm != NULL && elm->seq_num_ == seqnum){
+								ene = ene ^ elm->ecn_;
+							} else if (elm == NULL)
+								break;
+						}
+					}
+					//compare with the received echo
+					if (ene != ackv_recv_->getENE()){
+						fprintf(stdout,"%f, DCCP/TCPlike(%s)::processOption() - ECN check failed! \n", now(), name());
+						sendReset(DCCP_RST_AGG_PEN,0,0,0);
+						result = false;
+					}
+				} else
+					debug("%f, DCCP/TCPlike(%s)::processOption() - Ack vector includes packets not in history. Skipping ecn check for now...\n", now(), name());
+			} else if (ackv_recv_ != NULL)
+				debug("%f, DCCP/TCPlike(%s)::processOption() - Old ack detected. Skipping ecn check\n", now(), name());
+			break;
+		case DCCP_OPT_QUIESCENCE:
+			sender_quiescent_ = true;
+			break;
+		}
+	}
+	return result;
+}
+
+
+bool DCCPTCPlikeAgent::send_askPermToSend(int dataSize, Packet *pkt){
+	ack_num_ = seq_num_recv_;
+	bool result = ( pipe_ < cwnd_ || dataSize == 0);
+	u_int32_t el_time32 = (u_int32_t) ((now() - t_high_recv_)/DCCP_OPT_ELAPSED_TIME_UNIT);
+	double t;
+	if (q_scheme_ == DCCP_Q_SCHEME_Q_OPT && !infinite_send_ && dataSize == 0){
+		t = q_min_t_;
+		if (t < 2*srtt_)  
+			t = 2*srtt_;
+		if (now() - t_last_data_sent_ > t && sb_->empty()){
+			q_packets_wo_opt_++;
+			if (q_packets_wo_opt_ >= q_opt_ratio_){
+				opt_->addOption(DCCP_OPT_QUIESCENCE,NULL,0);
+				q_packets_wo_opt_ = 0;
+			}
+		}
+
+	} else if (q_scheme_ == DCCP_Q_SCHEME_Q_FEAT && !infinite_send_){
+		if(dataSize > 0 && q_remote_){
+			if (changeFeature(DCCP_FEAT_Q,DCCP_FEAT_LOC_REMOTE))
+				q_remote_ = 0;
+		} else if (dataSize == 0) {
+			t = q_min_t_;
+			if (t < 2*srtt_)  
+				t = 2*srtt_;
+			if (now() - t_last_data_sent_ > t && sb_->empty() && !q_remote_){
+				if (changeFeature(DCCP_FEAT_Q,DCCP_FEAT_LOC_REMOTE))
+					q_remote_ = 1;
+					
+			}
+		}
+		
+	}
+				
+	//add elapsed time on acknowledgments if needed
+	if(result && send_ack_ && el_time32 > 0){
+		debug("%f, DCCP/TCPlike(%s)::send_askPermToSend() - Ack is delayed by %d (t_high_recv_ %f)\n", now(), name(),el_time32,t_high_recv_);
+		if (el_time32 > 0 && el_time32 <= 0xFFFF){
+			u_int16_t el_time16 = (u_int16_t) el_time32;
+			opt_->addOption(DCCP_OPT_ELAPSED_TIME,((u_char*) &el_time16), 2);
+		} else if (el_time32 > 0)
+			opt_->addOption(DCCP_OPT_ELAPSED_TIME,((u_char*) &el_time32), 4); 
+	}
+		
+	return (result);
+}
+
+void DCCPTCPlikeAgent::send_packetSent(Packet *pkt, bool moreToSend, int dataSize){
+	struct dccp_tcplike_send_hist_entry *new_packet;
+	int result;
+	hdr_dccp *dccph = hdr_dccp::access(pkt);
+
+	switch(dccph->type_){
+	case DCCP_DATA:
+	case DCCP_DATAACK:
+		if (q_scheme_ == DCCP_Q_SCHEME_Q_OPT)
+			q_packets_wo_opt_ = 0;
+		t_last_data_sent_ = now();
+		//add data packets to send history
+		new_packet = new struct dccp_tcplike_send_hist_entry;
+		new_packet->t_sent_ = now();
+		new_packet->seq_num_ = dccph->seq_num_;
+		result = getNonce(pkt);
+		new_packet->ecn_ = (result >= 0 ? result : 0);
+		STAILQ_INSERT_HEAD(&(send_hist_), new_packet, linfo_);
+		pipe_++;
+		if (timer_to_->status() != TIMER_PENDING)
+			timer_to_->resched(rto_);
+		break;
+	default:
+		;
+	}
+}
+
+void DCCPTCPlikeAgent::send_packetRecv(Packet *pkt, int dataSize){
+	hdr_dccp *dccph = hdr_dccp::access(pkt);
+	hdr_dccpack *dccpah = hdr_dccpack::access(pkt);
+	bool lost_ack = false;
+	struct dccp_tcplike_send_recv_hist_entry *packet;
+	packet = new struct dccp_tcplike_send_recv_hist_entry;
+	packet->type_ = dccph->type_;
+	packet->seq_num_ = dccph->seq_num_;
+
+	packet->ndp_ = dccph->ndp_;
+
+	//insert in the history over received packets
+	if(!insertInSendRecvHistory(packet)){
+		debug("%f, DCCP/TCPlike(%s)::send_packetRecv() - Insertion in send recv history failed for seqnum %d\n", now(), name(), packet->seq_num_);
+		delete packet;
+	} else {
+		u_int32_t seq_start;
+		u_int32_t seq_end;
+		//detect loss
+		if(detectLossSendRecv(&seq_start, &seq_end)){
+			debug("%f, DCCP/TCPlike(%s)::send_packetRecv() - Ack loss detected (send recv) in %d - %d\n" , now(), name(), seq_start, seq_end);
+			lost_ack = true;
+		}
+	}
+
+	switch(dccph->type_){
+	case DCCP_DATA:
+		if (!skip_ack_loss_ && lost_ack)
+			lostOrMarkedAck();
+		break;
+	case DCCP_ACK:
+	case DCCP_DATAACK:
+		skip_ack_loss_ = (dccpah->ack_num_ < ack_win_start_);
+
+		//check if ack is marked
+		if(!lost_ack && getECNCodePoint(pkt) == ECN_CE){
+			debug("%f, DCCP/TCPlike(%s)::send_packetRecv() - Ack packet is marked %d\n", now(), name(), dccph->seq_num_);
+			lost_ack = true;
+		}
+		
+		//check if we got an ack vector (if not, ignore packet)
+		if (ackv_recv_ != NULL && ackv_recv_->getSize() > 0){
+			
+			struct dccp_tcplike_send_hist_entry *elm = findPacketInSendHistory(dccpah->ack_num_,STAILQ_FIRST(&send_hist_));
+			if (elm != NULL && elm->seq_num_ == dccpah->ack_num_) {
+				//the ack regards a data packet
+				//update rtt
+				rtt_sample_ = now() - elm->t_sent_ - elapsed_time_recv_*DCCP_OPT_ELAPSED_TIME_UNIT;
+				
+				if (srtt_ < 0){
+					srtt_ = rtt_sample_;
+					rttvar_ = rtt_sample_/2.0;
+				} else {
+					rttvar_ = (1 - beta_) * rttvar_
+						+ beta_ * fabs(srtt_ - rtt_sample_);
+					srtt_ = (1- alpha_) * srtt_ + alpha_*rtt_sample_;
+				}
+
+				rto_ = srtt_ + (k_*rttvar_ > g_ ? k_*rttvar_ : g_);
+				if(rto_ < min_rto_)
+					rto_ = min_rto_;
+				
+				debug("%f, DCCP/TCPlike(%s)::send_packetRecv() - RTT measurement updated: elapsed time %d sample %f, rto %f, srtt %f, rttvar %f\n", now(), name(), elapsed_time_recv_, (double) rtt_sample_, (double) rto_, (double) srtt_, (double) rttvar_);
+			}
+			
+			if (dccpah->ack_num_ > high_ack_recv_)
+				high_ack_recv_ = dccpah->ack_num_;
+			else if (dccpah->ack_num_ == high_ack_recv_)
+				debug("%f, DCCP/TCPlike(%s)::send_packetRecv() - Duplicate acknowledgment received ack_num_ %d\n", now(), name(), dccpah->ack_num_);
+			else if (!skip_ack_loss_ && lost_ack){
+				lostOrMarkedAck();
+				break;
+			} else
+				break;
+
+			if (dccpah->ack_num_ < high_ack_recv_){
+				fprintf(stderr,"%f, DCCP/TCPlike(%s)::send_packetRecv() - ack_num %d is less than high_ack_recv_ %d!\n", now(), name(), dccpah->ack_num_, high_ack_recv_);
+				fflush(stdout);
+				abort();
+			}
+
+			//init the stored ack vector if it is empty
+			if (stored_ackv_->getSize() == 0){
+				stored_ackv_->addPacket(ackv_recv_->getLastSeqNum(), DCCP_PACKET_NOT_RECV);
+				stored_ackv_->addPacket(ackv_recv_->getFirstSeqNum(), DCCP_PACKET_NOT_RECV);
+				if (seq_all_done_ == 0) //first ack vector recv
+					seq_all_done_ = ackv_recv_->getLastSeqNum()-1;
+				else //stored ack vector is zero because of a timeout
+					debug("%f, DCCP/TCPlike(%s)::send_packetRecv() - seq_all_done_ %d is not zero (stored ackv == 0)\n",now(), name(),seq_all_done_);
+			}
+			
+			debug("%f, DCCP/TCPlike(%s)::send_packetRecv() - high_ack_recv_ %d, hist_last_seq_ %d, seq_all_done_ %d, seq_win_start_ %d\n",now(),name(),high_ack_recv_, hist_last_seq_, seq_all_done_, seq_win_start_);
+			
+			int num_lost[2];
+			int num_marked[2];
+			int num_ok[2];
+			int num_ok_mark[2];
+			int num_ack[2];
+			int num_pipe[2];
+			for (int i = 0; i < 2; i++){
+				num_lost[i] = 0;
+				num_marked[i] = 0;
+				num_ok[i] = 0;
+				num_ok_mark[i] = 0;
+				num_ack[i] = 0;
+				num_pipe[i] = 0;
+			}
+			
+			int num_packets = 0;
+			u_int32_t new_seq_all_done = 0;
+
+			bool ackv_recv_empty = false;
+			u_int32_t first_stored = stored_ackv_->getFirstSeqNum();
+			u_int32_t seqnum_old;
+			u_int32_t seqnum_new;
+		        dccp_packet_state state_old;
+			dccp_packet_state state_new;
+
+			if (hist_last_seq_ > seq_all_done_){
+				fprintf(stderr,"%f, DCCP/TCPlike(%s)::send_packetRecv() - Last packet in history %d is newer than seq_all_done %d\n", now(), name(), hist_last_seq_, seq_all_done_);
+				fflush(stdout);
+				abort();
+			}
+			
+			//process the ack vector information
+			
+			ackv_recv_->startPacketWalk();
+			stored_ackv_->startPacketWalk();
+			
+			if (!ackv_recv_->nextPacket(&seqnum_new, &state_new)){
+				fprintf(stderr,"%f, DCCP/TCPlike(%s)::send_packetRecv() - ackv_recv_ is empty!\n", now(), name());
+				fflush(stdout);
+				abort();
+			}
+
+			if (seqnum_new > first_stored){
+				state_old = DCCP_PACKET_NOT_RECV;
+				seqnum_old = seqnum_new;
+			} else if (!(stored_ackv_->nextPacket(&seqnum_old, &state_old)) ||
+				   seqnum_old != seqnum_new){
+				fprintf(stderr,"%f, DCCP/TCPlike(%s)::send_packetRecv() - Stored ackv is empty or seqnum_old != seqnum_new!\n", now(), name());
+				fflush(stdout);
+				abort();
+			}
+			
+			do {
+
+				if (seqnum_new <= seq_all_done_)
+					break;
+
+				if (new_seq_all_done == 0 && num_packets == num_dup_acks_)
+					new_seq_all_done = seqnum_new;
+				
+				elm = findPacketInSendHistory(seqnum_new,elm);
+				state_new = stored_ackv_->ackv_cons_[state_old][state_new];
+				
+				if ((elm != NULL) && (elm->seq_num_ == seqnum_new)){ //if data packet
+										
+					if (state_new != state_old){
+						if (state_old == DCCP_PACKET_NOT_RECV &&
+						    state_new == DCCP_PACKET_RECV){
+							num_ok[(int) (seqnum_new >= seq_win_start_)]++;
+							num_ack[(int) (seqnum_new >= ack_win_start_)]++;
+							num_pipe[(int) (seqnum_new >= seq_pipe_start_)]++;
+						} else if (state_old == DCCP_PACKET_NOT_RECV &&
+							   state_new == DCCP_PACKET_ECN){
+							num_marked[(int) (seqnum_new >= seq_win_start_)]++;
+							num_ack[(int) (seqnum_new >= ack_win_start_)]++;
+							num_pipe[(int) (seqnum_new >= seq_pipe_start_)]++;
+						} else if (state_old == DCCP_PACKET_RECV &&
+							   state_new == DCCP_PACKET_ECN) {
+							num_marked[(int) (seqnum_new >= seq_win_start_)]++;
+							num_ok_mark[(int) (seqnum_new >= seq_win_start_)]++;
+						}
+						
+					} else if (state_new == DCCP_PACKET_NOT_RECV){
+						if (num_packets >= num_dup_acks_){
+							num_lost[(int) (seqnum_new >= seq_win_start_)]++;
+							num_ack[(int) (seqnum_new >= ack_win_start_)]++;
+							num_pipe[(int) (seqnum_new >= seq_pipe_start_)]++;
+						}
+					}
+				}
+
+				if (state_new != DCCP_PACKET_NOT_RECV)
+					num_packets++;
+				
+				if (!ackv_recv_->nextPacket(&seqnum_new, &state_new)){
+					seqnum_new--;
+					ackv_recv_empty = true;
+				}
+
+				if (seqnum_new == seq_all_done_)
+					break;
+				else if (seqnum_new > first_stored){
+					
+					state_old = DCCP_PACKET_NOT_RECV;
+					seqnum_old = seqnum_new;
+				} else if (!(stored_ackv_->nextPacket(&seqnum_old, &state_old))){
+					fprintf(stderr,"%f, DCCP/TCPlike(%s)::send_packetRecv() - Stored ack vector is empty when it shouldn't be!\n", now(), name());
+					fflush(stdout);
+					abort();
+				}
+				
+				if (ackv_recv_empty){
+					state_new = state_old;
+				}				
+
+			} while (true);
+		       
+			debug("%f, DCCP/TCPlike(%s)::send_packetRecv() - in window: ok %d, marked %d, lost %d, ok_mark %d\n",now(), name(), num_ok[1],num_marked[1],num_lost[1],num_ok_mark[1]);
+			debug("%f, DCCP/TCPlike(%s)::send_packetRecv() - after window: ok %d, marked %d, lost %d, ok_mark %d\n",now(), name(), num_ok[0],num_marked[0],num_lost[0],num_ok_mark[0]);
+			debug("%f, DCCP/TCPlike(%s)::send_packetRecv() - new_seq_all_done %d, seq_all_done_ %d\n",now(), name(), new_seq_all_done,seq_all_done_);
+			debug("%f, DCCP/TCPlike(%s)::send_packetRecv() - (ack) in window: %d, not in window %d\n",now(), name(), num_ack[1],num_ack[0]);
+
+			if (new_seq_all_done > seq_all_done_)
+				seq_all_done_ = new_seq_all_done;
+
+			stored_ackv_->mergeWith(ackv_recv_);
+			stored_ackv_->removePackets(seq_all_done_);
+
+			
+			//trim history to seq = min(last in recv ackvector, seq_all_done);
+			u_int32_t trim_to = ackv_recv_->getLastSeqNum();
+			if (seq_all_done_ < trim_to)
+			       trim_to = seq_all_done_;
+
+			trimSendHistory(trim_to);
+			
+			int num_inc_cwnd =
+				num_ok[DCCP_TCPLIKE_IN_WINDOW] + num_marked[DCCP_TCPLIKE_IN_WINDOW] -
+				num_ok_mark[DCCP_TCPLIKE_IN_WINDOW] +
+				num_ok[DCCP_TCPLIKE_AFTER_WINDOW] + num_marked[DCCP_TCPLIKE_AFTER_WINDOW] -
+				num_ok_mark[DCCP_TCPLIKE_AFTER_WINDOW];
+			
+
+			debug("%f, DCCP/TCPlike(%s)::send_packetRecv() - Update pipe (before): pipe_ %d\n", now(), name(), (int) pipe_);
+			pipe_ = pipe_ - num_pipe[DCCP_TCPLIKE_IN_WINDOW];
+			
+			debug("%f, DCCP/TCPlike(%s)::send_packetRecv() - Update pipe (after): pipe_ %d\n", now(), name(), (int) pipe_);
+
+			if (pipe_ < 0) {
+				fprintf(stderr,"%f, DCCP/TCPlike(%s)::send_packetRecv() - Pipe is less than zero! (%i)\n", now(), name(), (int) pipe_);
+				fflush(stdout);
+				abort();
+			} else if (pipe_ == 0) {
+				timer_to_->force_cancel();
+				debug("%f, DCCP/TCPlike(%s)::send_packetRecv() - Pipe is zero, cancels timer\n", now(), name());
+			} else if (num_inc_cwnd > 0){
+				debug("%f, DCCP/TCPlike(%s)::send_packetRecv() - Newly acked packets, rescheduling timer. rto %f\n", now(), name(),(double) rto_);
+				timer_to_->resched(rto_);
+			}
+
+			updateCwnd(num_inc_cwnd);
+			
+			if (num_lost[DCCP_TCPLIKE_IN_WINDOW] > 0 ||
+			    num_marked[DCCP_TCPLIKE_IN_WINDOW] > 0){
+				lostOrMarkedData();
+				num_ack_in_win_ = 0;				
+				if (checkAckRatio()){
+					debug("%f, DCCP/TCPlike(%s)::send_packetRecv() - Ackratio changed because of data loss\n", now(), name());
+					num_win_acked_ = 0;
+					ack_win_start_ =  seq_num_;
+					num_ack[DCCP_TCPLIKE_IN_WINDOW] = 0;
+				}
+				
+				if (detectQuiescence()){
+					//output_ = true;
+					send_ack_ = true;
+					ack_num_ = seq_num_recv_;
+				}
+			}
+
+			if (!skip_ack_loss_ && lost_ack){
+				lostOrMarkedAck();
+			} else {
+				updateAckRatio(num_ack[DCCP_TCPLIKE_IN_WINDOW]);
+			} 
+
+			if (pipe_ < cwnd_)
+				output_ = true;
+
+			//check if ackv_size_lim_ is reached
+			if (ackv_size_lim_ > 0
+			    && ackv_recv_->getSize() > ackv_size_lim_ 
+			    && ackv_lim_seq_ < dccpah->ack_num_
+			    && detectQuiescence()){
+			       debug("%f, DCCP/TCPlike(%s)::send_packet_recv() - Ack vector size limit reached during quiescence. Sending ack of ack. (lim %u, size %u, lim_seq %u, seq_num_ %u\n", now(),name(),ackv_size_lim_,ackv_recv_->getSize(),ackv_lim_seq_,seq_num_);
+				send_ack_ = true;
+				ack_num_ = seq_num_recv_;
+				ackv_lim_seq_ = seq_num_;
+			}
+			
+			
+		} else {
+			fprintf(stdout,"%f, DCCP/TCPlike(%s)::send_packetRecv() - No ack vector on acknowledgment!\n", now(), name());
+			if (lost_ack)
+				lostOrMarkedAck();
+		}
+		break;
+	default:
+		;
+	}
+
+	changeRemoteAckRatio();
+	
+}
+
+void DCCPTCPlikeAgent::recv_packetRecv(Packet *pkt, int dataSize){
+	hdr_dccp *dccph = hdr_dccp::access(pkt);
+
+	if (q_t_data_ == 0.0)
+		q_t_data_ = now();
+	
+	if(dccph->type_ == DCCP_DATA || dccph->type_ == DCCP_DATAACK){
+		//start dack timer if idle
+		if (timer_dack_->status() == TIMER_IDLE){
+			//printf("TIMER is IDLE\n");
+			timer_dack_->sched(dack_delay_);
+		}
+		unacked_++;
+		q_t_data_ = now();
+		if (dccph->seq_num_ > q_high_data_recv_)
+			q_high_data_recv_ = dccph->seq_num_;
+		sender_quiescent_ = false;
+	} else if (high_ndp_recv_ >= 0 && (int) (dccph->seq_num_ - high_seq_recv_) > 1){
+		//some packet is missing
+		if ( (int) (dccph->seq_num_ - high_seq_recv_) >
+		     ((dccph->ndp_ - high_ndp_recv_ + ndp_limit_) % ndp_limit_)
+		     ){ //data packet is "lost"
+			debug("%f, DCCP/TCPlike(%s)::recv_packetRecv() - Data loss detected by receiver seq_num %d - ndp %d,  high_seq_recv %d - ndp %d\n",now(),name(), dccph->seq_num_, dccph->ndp_,high_seq_recv_, high_ndp_recv_);
+			q_t_data_ = now();
+			if (dccph->seq_num_-1 > q_high_data_recv_)
+				q_high_data_recv_ = dccph->seq_num_-1;
+			sender_quiescent_ = false;
+		}
+	}
+
+	if (dccph->seq_num_ > high_seq_recv_){
+		high_seq_recv_ = dccph->seq_num_;
+		high_ndp_recv_ = dccph->ndp_;
+		t_high_recv_ = now();
+	}
+	
+	if (unacked_ >= ack_ratio_local_){
+		timer_dack_->force_cancel();
+		send_ack_ = true;
+		ack_num_ = seq_num_recv_;
+		unacked_= 0;
+		output_ = true;
+		output_flag_ = true;
+	}
+
+}
+
+/* Variable tracing */
+
+void DCCPTCPlikeAgent::traceAll() {
+	char wrk[500];
+
+	sprintf(wrk,"%f %d %d %d %d %f %f %f %f\n",
+		now(), (int) cwnd_, (int) cwnd_frac_, (int) ssthresh_,
+		(int) pipe_, (double) rto_, (double) srtt_, (double) rttvar_,
+		(double) rtt_sample_);
+
+	if (channel_)
+		Tcl_Write(channel_, wrk, strlen(wrk));
+}
+
+
+void DCCPTCPlikeAgent::traceVar(TracedVar* v) 
+{
+	char wrk[500];
+
+	if (!strcmp(v->name(), "cwnd_") ||
+	    !strcmp(v->name(), "cwnd_frac_") ||
+	    !strcmp(v->name(), "ssthresh_") ||
+	    !strcmp(v->name(), "pipe_")){
+		sprintf(wrk,"%f %d %s\n", now(), int(*((TracedInt*) v)), v->name());
+		if (channel_)
+			Tcl_Write(channel_, wrk, strlen(wrk));
+	} else if (!strcmp(v->name(), "rto_") ||
+		   !strcmp(v->name(), "srtt_") ||
+		   !strcmp(v->name(), "rttvar_") ||
+		   !strcmp(v->name(), "rtt_sample_")){
+		sprintf(wrk,"%f %f %s\n", now(), double(*((TracedDouble*) v)), v->name());
+		if (channel_)
+			Tcl_Write(channel_, wrk, strlen(wrk));
+	} else
+		DCCPAgent::traceVar(v);	
+}
+
+//public methods
+
+/* Constructor
+ * ret: a new DCCPTCPlikeAgent
+ */
+DCCPTCPlikeAgent::DCCPTCPlikeAgent() : DCCPAgent() {
+	ccid_ = DCCP_TCPLIKE_CCID;
+
+	initial_cwnd_ = DCCP_TCPLIKE_INIT_CWND;
+	initial_ssthresh_ = DCCP_TCPLIKE_INIT_SSTHRESH;
+	initial_rto_ = DCCP_TCPLIKE_INIT_RTO;
+	cwnd_timeout_ = DCCP_TCPLIKE_CWND_TO;
+
+	cwnd_ = initial_cwnd_;
+	cwnd_frac_ = 0;
+	ssthresh_ = initial_ssthresh_;
+	pipe_ = 0;
+
+	t_last_data_sent_ = (double) (-DCCP_TCPLIKE_MIN_T)*2;
+	q_opt_ratio_ = DCCP_TCPLIKE_QUIESCENCE_OPT_RATIO;
+	q_packets_wo_opt_ = 0;
+	
+	rto_ = initial_rto_;
+	srtt_ = -1.0;
+	rttvar_ = 0.0;
+	rtt_sample_ = 0.0;
+	k_ = DCCP_TCPLIKE_K;
+	g_ = DCCP_TCPLIKE_G;
+	alpha_ = DCCP_TCPLIKE_ALPHA;
+	beta_ = DCCP_TCPLIKE_BETA;
+
+	min_rto_ = DCCP_TCPLIKE_MIN_RTO;
+	
+	num_dup_acks_ = DCCP_NUM_DUP_ACKS;
+
+	STAILQ_INIT(&send_hist_);
+	STAILQ_INIT(&send_recv_hist_);
+	
+	timer_to_ = new DCCPTCPlikeTOTimer(this);
+	timer_dack_ = new DCCPTCPlikeDelayedAckTimer(this);
+	
+	hist_last_seq_ = 0;
+	high_ack_recv_ = 0;
+	
+	high_seq_recv_ = 0;
+	high_ndp_recv_ = -1;
+	unacked_ = 0;
+
+	stored_ackv_ = new DCCPAckVector(ackv_size_);
+	stored_ackv_->ackv_cons_[DCCP_PACKET_RECV][DCCP_PACKET_RECV]         = DCCP_PACKET_RECV;
+	stored_ackv_->ackv_cons_[DCCP_PACKET_RECV][DCCP_PACKET_ECN]          = DCCP_PACKET_ECN;
+	stored_ackv_->ackv_cons_[DCCP_PACKET_RECV][DCCP_PACKET_RESERVED]     = DCCP_PACKET_RESERVED;
+	stored_ackv_->ackv_cons_[DCCP_PACKET_RECV][DCCP_PACKET_NOT_RECV]     = DCCP_PACKET_RECV;
+	stored_ackv_->ackv_cons_[DCCP_PACKET_ECN][DCCP_PACKET_RECV]          = DCCP_PACKET_ECN;
+	stored_ackv_->ackv_cons_[DCCP_PACKET_ECN][DCCP_PACKET_ECN]           = DCCP_PACKET_ECN;
+	stored_ackv_->ackv_cons_[DCCP_PACKET_ECN][DCCP_PACKET_RESERVED]      = DCCP_PACKET_RESERVED;
+	stored_ackv_->ackv_cons_[DCCP_PACKET_ECN][DCCP_PACKET_NOT_RECV]      = DCCP_PACKET_ECN;
+	stored_ackv_->ackv_cons_[DCCP_PACKET_RESERVED][DCCP_PACKET_RECV]     = DCCP_PACKET_RESERVED;
+	stored_ackv_->ackv_cons_[DCCP_PACKET_RESERVED][DCCP_PACKET_ECN]      = DCCP_PACKET_RESERVED;
+	stored_ackv_->ackv_cons_[DCCP_PACKET_RESERVED][DCCP_PACKET_RESERVED] = DCCP_PACKET_RESERVED;
+	stored_ackv_->ackv_cons_[DCCP_PACKET_RESERVED][DCCP_PACKET_NOT_RECV] = DCCP_PACKET_RESERVED;
+	stored_ackv_->ackv_cons_[DCCP_PACKET_NOT_RECV][DCCP_PACKET_RECV]     = DCCP_PACKET_RECV;
+	stored_ackv_->ackv_cons_[DCCP_PACKET_NOT_RECV][DCCP_PACKET_ECN]      = DCCP_PACKET_ECN;
+	stored_ackv_->ackv_cons_[DCCP_PACKET_NOT_RECV][DCCP_PACKET_RESERVED] = DCCP_PACKET_RESERVED;
+	stored_ackv_->ackv_cons_[DCCP_PACKET_NOT_RECV][DCCP_PACKET_NOT_RECV] = DCCP_PACKET_NOT_RECV;
+	seq_all_done_ = 0;
+	seq_win_start_ = 0;
+	seq_pipe_start_ = 0;
+	
+	num_win_acked_ = 0;
+	num_ack_in_win_ = 0;
+	ack_win_start_ = 0;
+	skip_ack_loss_ = false;
+	recv_ack_ratio_ = ack_ratio_remote_;
+
+	q_high_data_recv_ = 0;
+	q_t_data_ = 0.0;
+	q_min_t_ = DCCP_TCPLIKE_MIN_T;
+
+	ackv_size_lim_ = DCCP_TCPLIKE_ACKV_SIZE_LIM; 
+	ackv_lim_seq_ = 0; 
+
+	sender_quiescent_ = false;
+	
+	dack_delay_ = DCCP_TCPLIKE_DACK_DELAY;
+	t_high_recv_ = 0.0;
+
+	//test conversion from bool to int
+	if (!((int) (cwnd_ >= cwnd_frac_) == 0 || (int) (cwnd_ >= cwnd_frac_) == 1)){
+		fprintf(stderr,"DCCP/TCPlike::DCCPTCPlikeAgent() - The conversion between bool and int is not as expected ((int) (%d >= %d) = %d)!\n", (int) cwnd_, (int) cwnd_frac_, (int) (cwnd_ >= cwnd_frac_));
+		fflush(stdout);
+		abort();
+	} else if (!((int) (cwnd_ < cwnd_frac_) == 0 || (int) (cwnd_ < cwnd_frac_) == 1)){
+		fprintf(stderr,"DCCP/TCPlike::DCCPTCPlikeAgent() - The conversion between bool and int is not as expected ((int) (%d < %d) = %d)!\n", (int) cwnd_, (int) cwnd_frac_, (int) (cwnd_ < cwnd_frac_));
+		fflush(stdout);
+		abort();
+	}
+		
+}
+
+/* Destructor */
+DCCPTCPlikeAgent::~DCCPTCPlikeAgent(){
+	clearSendHistory();
+	clearSendRecvHistory();
+	delete stored_ackv_;
+	delete timer_to_;
+	delete timer_dack_;
+}
+
+int DCCPTCPlikeAgent::command(int argc, const char*const* argv){
+	return DCCPAgent::command(argc,argv);
+}
+
+/* A timeout has occured
+ * arg: tno - id of timeout event
+ * Handles: Delayed acknowledgement timer - DCCP_TCPLIKE_TIMER_DACK
+ *          Timeout timer - DCCP_TCPLIKE_TIMER_TO
+ */
+void DCCPTCPlikeAgent::timeout(int tno){
+	switch (tno){
+	case DCCP_TCPLIKE_TIMER_TO:
+		debug("%f, DCCP/TCPlike(%s)::timeout() - Timeout\n", now(), name());
+		ssthresh_ = cwnd_ / 2;
+		if (ssthresh_ == 0)
+			ssthresh_ = 1;
+		
+		cwnd_ = cwnd_timeout_;
+		pipe_ = 0;
+		
+		seq_pipe_start_ = seq_num_;
+		
+		seq_win_start_ = seq_num_;
+		cwnd_frac_ = 0;
+
+		num_ack_in_win_ = 0;
+		num_win_acked_ = 0;
+		ack_win_start_ = seq_num_;
+		recv_ack_ratio_ = 1;
+		checkAckRatio();
+		changeRemoteAckRatio();
+		rto_ = rto_ * 2;
+		output();
+		break;
+	case DCCP_TCPLIKE_TIMER_DACK:
+		debug("%f, DCCP/TCPlike(%s)::timeout() - Delayed ack timer expired\n", now(), name());
+		send_ack_ = true;
+		ack_num_ = seq_num_recv_;
+		unacked_ = 0;
+		output(true);
+		break;
+	default:
+	        DCCPAgent::timeout(tno);
+	}
+}
+
+
+
+
+
+
+
+
+
+
+
diff -urNU5 ns-2.33/dccp/dccp_tcplike.h ns-2.33-dccp/dccp/dccp_tcplike.h
--- ns-2.33/dccp/dccp_tcplike.h	1970-01-01 10:00:00.000000000 +1000
+++ ns-2.33-dccp/dccp/dccp_tcplike.h	2008-05-05 17:17:43.000000000 +1000
@@ -0,0 +1,347 @@
+/* -*-	Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
+
+/* Copyright (c) 2004  Nils-Erik Mattsson 
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: ns-233-dccp-1.patch 210 2008-05-13 03:43:55Z omehani $ */
+
+#ifndef ns_dccp_tcplike_h
+#define ns_dccp_tcplike_h
+
+#include "dccp.h"
+#include "bsd_queue.h"
+
+// Use tracevars for window and rtt variables
+#define DCCP_TCPLIKE_USE_TRACED_VARS
+
+#define DCCP_TCPLIKE_CCID 2
+
+//initial values
+#define DCCP_TCPLIKE_INIT_CWND 3     //rfc2581 says 2 but rfc3390 allows more
+#define DCCP_TCPLIKE_CWND_TO 1       //cwnd is set to this value on timeout
+#define DCCP_TCPLIKE_INIT_SSTHRESH 0xFFFF
+
+//RTO parameters - rfc 2988
+#define DCCP_TCPLIKE_INIT_RTO 3
+#define DCCP_TCPLIKE_ALPHA 0.125
+#define DCCP_TCPLIKE_BETA 0.25
+#define DCCP_TCPLIKE_K 4
+#define DCCP_TCPLIKE_G 0.010
+#define DCCP_TCPLIKE_MIN_RTO 1.0
+
+//Timers
+#define DCCP_TCPLIKE_TIMER_TO 128
+#define DCCP_TCPLIKE_TIMER_DACK 129
+
+#define DCCP_TCPLIKE_DACK_DELAY 0.2  //delay for delayed acknowledgments
+#define DCCP_TCPLIKE_MIN_T 0.2       //T value for quiescence detection 
+
+//Quiescence
+#define DCCP_TCPLIKE_QUIESCENCE_OPT_RATIO 1 
+#define DCCP_TCPLIKE_ACKV_SIZE_LIM 10   //ack an ack when recv ackv > this
+
+//forward decleration of class DCCPTCPlikeAgent
+class DCCPTCPlikeAgent;
+
+//The DCCPTCPlikeTOTimer is similar to TCP's retransmission timeouts
+class DCCPTCPlikeTOTimer : public TimerHandler {
+protected:
+	DCCPTCPlikeAgent *agent_;    //the owning agent
+public:
+	/* Constructor
+	 * arg: agent - the owning agent (to notify about timeout)
+	 * ret: A new DCCPTCPlikeTOTimer
+	 */
+	DCCPTCPlikeTOTimer(DCCPTCPlikeAgent* agent);
+
+	/* Called when the timer has expired
+	 * arg: e - The event that happened (i.e. the timer expired)
+	 */
+	virtual void expire(Event *e);
+};
+
+/* The DCCPTCPlikeDelayedAckTimer expires when a data packet has not been
+ * acknowledged within dack_delay_ s of its arrival */ 
+class DCCPTCPlikeDelayedAckTimer : public TimerHandler {
+protected:
+	DCCPTCPlikeAgent *agent_;    //the owning agent
+public:
+	/* Constructor
+	 * arg: agent - the owning agent (to notify about timeout)
+	 * ret: A new DCCPTCPlikeDelayedAckTimer
+	 */
+	DCCPTCPlikeDelayedAckTimer(DCCPTCPlikeAgent* agent);
+
+	/* Called when the timer has expired
+	 * arg: e - The event that happened (i.e. the timer expired)
+	 */
+	virtual void expire(Event *e);
+};
+
+//packet history of sent data packets
+STAILQ_HEAD(dccp_tcplike_send_hist,dccp_tcplike_send_hist_entry); 
+
+
+struct dccp_tcplike_send_hist_entry {
+	STAILQ_ENTRY(dccp_tcplike_send_hist_entry) linfo_;    
+	u_int32_t seq_num_;     //sequence number
+	double t_sent_;         //timestamp of sent packet
+	u_int8_t ecn_;          //ecn nonce (0 or 1) sent
+};
+
+//packet history over received packets
+STAILQ_HEAD(dccp_tcplike_send_recv_hist,dccp_tcplike_send_recv_hist_entry); 
+
+struct dccp_tcplike_send_recv_hist_entry {
+	STAILQ_ENTRY(dccp_tcplike_send_recv_hist_entry) linfo_;    
+	u_int32_t seq_num_;     //sequence number
+	dccp_packet_type type_; //packet type
+	u_int8_t ndp_;          //ndp value
+};
+
+/* The class DCCPTCPlikeAgent implements a two way DCCP agent using
+ * TCP-like (CCID 2) congestion control mechanism.
+ * If changes are made to tcl variables, the agent should be reset
+ * to enable all changes.
+ * Conforms to the October 2003 drafts.
+ */ 
+class DCCPTCPlikeAgent : public DCCPAgent {
+private:
+	//sender
+
+	int initial_cwnd_;        //initial congestion window
+	int cwnd_timeout_;        //initial value for the cwnd after a timeout
+	int initial_ssthresh_;    //initial value for slow start threshold
+	double initial_rto_;      //initial rto value
+
+#ifdef DCCP_TCPLIKE_USE_TRACED_VARS
+	TracedInt cwnd_;          //congestion window
+	TracedInt cwnd_frac_;     //fractional part of cwnd (in unit of 1/cwnd)
+	TracedInt ssthresh_;      //slow start threshold
+	TracedInt pipe_;          //outstanding packets in the network
+	TracedDouble rto_;        //"retransmission" timeout value
+	TracedDouble srtt_;       //smoothed rtt
+	TracedDouble rttvar_;     //rtt variance
+	TracedDouble rtt_sample_; //latest rtt sample
+#else
+	int cwnd_;
+	int cwnd_frac_;
+	int ssthresh_;
+	int pipe_;
+	double rto_;
+	double srtt_;
+	double rttvar_;
+	double rtt_sample_;
+#endif
+	double alpha_;            //smoothing factor for rtt/rto calculations
+	double beta_;             //smoothing factor for rtt/rto calculations
+	double g_;                //timer granularity
+	int k_;                   //k value
+
+	double min_rto_;          //minimum rto allowed
+	
+	/* The number of packets with higher sequence number needed before
+	 * a delayed packet is considered lost (similiar to NUMDUPACKS) */
+	int num_dup_acks_;        
+
+	//congestion control on data packets related attributes
+	
+	struct dccp_tcplike_send_hist send_hist_;  //history over sent packets
+	u_int32_t hist_last_seq_; //last sequence number in history
+
+	DCCPAckVector *stored_ackv_;  //state information about recv packets
+	
+	u_int32_t high_ack_recv_; //highest ack received so far
+	u_int32_t seq_all_done_;  //seq nums <= this number have been processed
+
+	/* The sequence number that started the new window after the
+	 * last congestion event */
+	u_int32_t seq_win_start_; 
+
+	/* Decrease pipe for all packets acknowledged after and including
+	 * this sequence number */
+	u_int32_t seq_pipe_start_;
+	
+	//ack ratio related attributes
+	int num_ack_in_win_;      //number of packets acknowledged
+	int num_win_acked_;       //number of cwnd acked without lost/marked acks
+	/* The sequence number that started the new window after the
+	 * last congestion event regarding acks */
+	u_int32_t ack_win_start_;
+	
+	bool skip_ack_loss_;      //if true, ack loss is ignored
+	u_int16_t recv_ack_ratio_;//the ackratio to report to the receiver 
+
+	//history over received packets
+	struct dccp_tcplike_send_recv_hist send_recv_hist_;
+
+	DCCPTCPlikeTOTimer *timer_to_;  //timeout timer
+
+	//quiescence
+	double t_last_data_sent_;  //timestamp of when last data pkt was sent 
+	int q_opt_ratio_;          //add Q opt on each opt ratio acks sent
+	int q_packets_wo_opt_;     //ack packets sent without Q opt
+
+	int ackv_size_lim_;        //send an ack of ack if recv ackv >= this
+	u_int32_t ackv_lim_seq_;   //sequencenumber of last ack of ack sent due to size limit
+	
+	/* Clear the send history */
+	void clearSendHistory();
+
+	/* Find a specific packet in the send history
+	 * arg: seq_num - sequence number of packet to find
+	 *      start_elm - start searching from this element
+	 * ret: pointer to the correct element if the element is found
+	 *      otherwise the closest packet with lower seq num is returned
+	 *      which can be NULL.
+	 */
+	struct dccp_tcplike_send_hist_entry* findPacketInSendHistory(u_int32_t seq_num, dccp_tcplike_send_hist_entry* start_elm);
+
+	/* Remove packets from send history
+	 * arg: trim_to - remove packets with lower sequence numbers than this
+	 * Note: if trim_to does not exist in the history, trim_to is set
+	 *       to the next lower sequence number found before trimming. 
+	 */
+	void trimSendHistory(u_int32_t trim_to);
+	
+	/* Prints the contents of the send history */
+	void printSendHistory();
+
+	/* Clear the history of received packets */
+	void clearSendRecvHistory();
+
+	/* Insert a packet in the receive history
+	 * Will not insert "lost" packets or duplicates.
+	 * arg: packet - entry representing the packet to insert
+	 * ret: true if packet was inserted, otherwise false.
+	 */
+	bool insertInSendRecvHistory(dccp_tcplike_send_recv_hist_entry *packet);
+	/* Prints the contents of the receive history */
+	void printSendRecvHistory();
+	
+	/* Detects packet loss in recv history.
+	 * Trims the history to num_dup_acks_+1 length.
+	 * arg: seq_start, seq_end - the lost packet is in [start,end]
+	 * ret: true if a packet loss was detected, otherwise false.
+	 */
+	bool detectLossSendRecv(u_int32_t *seq_start, u_int32_t *seq_end);
+
+	/* Check the constraints on the ack ratio (recv_ack_ratio_)
+	 * ret: true if the ack ratio was changed due to constraints
+	 *      false otherwise
+	 */
+	bool checkAckRatio();
+
+	/* Compares recv_ack_ratio_ with ack_ratio_remote_ and
+	 * tries to change the feauture if they differ.
+         */
+	void changeRemoteAckRatio();
+
+	/* Update the ack ratio
+	 * arg: num_ack - number of newly acknowledged packets
+	 */
+	void updateAckRatio(int num_ack);
+
+	/* Take action on lost or marked ack packet */
+	void lostOrMarkedAck();
+
+	/* Update the congestion window
+	 * arg: num_inc_cwnd - number of newly acknowledged packets
+	 */
+	void updateCwnd(int num_inc_cwnd);
+
+	/* Take action on lost or marked data packet */
+	void lostOrMarkedData();
+	
+	//receiver
+
+	u_int32_t high_seq_recv_; //highest sequence number received 
+	int high_ndp_recv_;       //ndp value of high_seq_recv_ 
+	double t_high_recv_;      //timestamp of high_seq_recv_
+	int unacked_;             //number of unacknowledged data packets
+
+	//quiescence
+	u_int32_t q_high_data_recv_;  //highest data packet received 
+	double q_min_t_;           //T value for quiescence detection
+	double q_t_data_;          //timestamp of last data pkt observed
+
+	bool sender_quiescent_;      //the sender is quiescent (q opt recv)
+	
+	double dack_delay_;        //delay for delayed acknowledgments
+	DCCPTCPlikeDelayedAckTimer *timer_dack_;   //delayed acknowledgments timer
+	/* Detects quiescence of the corresponding sender
+	 * ret: true if sender is quiescent
+	 *      false otherwise
+	 */ 
+	bool detectQuiescence();
+protected:
+	
+	/* Methods inherited from DCCPAgent.
+	 * See dccp.h For detailed information regarding arguments etc.
+	 */
+	
+	virtual void delay_bind_init_all();
+        virtual int delay_bind_dispatch(const char *varName, const char *localName, TclObject *tracer);
+	
+	virtual void reset();
+	virtual void cancelTimers();
+
+	/* Process incoming options.
+	 * This function will process:
+	 *      ack vectors (verify ECN Nonce Echo)
+	 *      quiescence option
+	 */
+	virtual bool processOption(u_int8_t type, u_char* data, u_int8_t size, Packet *pkt);
+
+	virtual bool send_askPermToSend(int dataSize, Packet *pkt);
+	virtual void send_packetSent(Packet *pkt, bool moreToSend, int dataSize);
+	virtual void send_packetRecv(Packet *pkt, int dataSize);
+	virtual void recv_packetRecv(Packet *pkt, int dataSize);
+
+	virtual void traceAll();
+	virtual void traceVar(TracedVar* v);
+public:
+	/* Constructor
+	 * ret: a new DCCPTCPlikeAgent
+	 */
+	DCCPTCPlikeAgent();
+	
+	/* Destructor */
+	virtual ~DCCPTCPlikeAgent();
+
+	int command(int argc, const char*const* argv);
+
+	/* A timeout has occured
+	 * arg: tno - id of timeout event
+	 * Handles: Delayed acknowledgement timer - DCCP_TCPLIKE_TIMER_DACK
+	 *          Timeout timer - DCCP_TCPLIKE_TIMER_TO
+	 */
+	virtual void timeout(int tno);
+
+};
+
+#endif
+
diff -urNU5 ns-2.33/dccp/dccp_tfrc.cc ns-2.33-dccp/dccp/dccp_tfrc.cc
--- ns-2.33/dccp/dccp_tfrc.cc	1970-01-01 10:00:00.000000000 +1000
+++ ns-2.33-dccp/dccp/dccp_tfrc.cc	2008-05-05 17:17:43.000000000 +1000
@@ -0,0 +1,2194 @@
+/* -*-	Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
+
+/* Copyright (c) 2004  Nils-Erik Mattsson 
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: ns-233-dccp-1.patch 210 2008-05-13 03:43:55Z omehani $ */
+
+#include "ip.h"
+#include "dccp_tfrc.h"
+#include "flags.h"
+
+
+//OTcl linkage for DCCPTFRC agent
+static class DCCPTFRCClass : public TclClass {
+public:
+	DCCPTFRCClass() : TclClass("Agent/DCCP/TFRC") {};
+	TclObject* create(int argc, const char*const* argv){
+		return (new DCCPTFRCAgent());
+	}
+} class_dccptfrc;
+
+//methods for timer classes
+
+/* Constructor
+ * arg: agent - the owning agent (to notify about timeout)
+ * ret: A new DCCPTFRCSendTimer
+ */
+DCCPTFRCSendTimer::DCCPTFRCSendTimer(DCCPTFRCAgent* agent) : TimerHandler(){
+	agent_ = agent;
+}
+
+/* Called when the timer has expired
+ * arg: e - The event that happened (i.e. the timer expired)
+ */
+void DCCPTFRCSendTimer::expire(Event *e){
+	agent_->timeout(DCCP_TFRC_TIMER_SEND);
+}
+
+/* Constructor
+ * arg: agent - the owning agent (to notify about timeout)
+ * ret: A new DCCPTFRCNoFeedbackTimer
+ */
+DCCPTFRCNoFeedbackTimer::DCCPTFRCNoFeedbackTimer(DCCPTFRCAgent* agent) : TimerHandler(){
+	agent_ = agent;
+}
+
+/* Called when the timer has expired
+ * arg: e - The event that happened (i.e. the timer expired)
+ */
+void DCCPTFRCNoFeedbackTimer::expire(Event *e){
+	agent_->timeout(DCCP_TFRC_TIMER_NO_FEEDBACK);
+}
+
+//private methods
+
+/* Clear the send history */
+inline void DCCPTFRCAgent::clearSendHistory(){
+	struct s_hist_entry *elm, *elm2;
+
+	/* Empty packet history */
+	elm = STAILQ_FIRST(&s_hist_);
+	while (elm != NULL) {
+		elm2 = STAILQ_NEXT(elm, linfo_);
+		delete elm;
+		elm = elm2;
+	}
+	
+	STAILQ_INIT(&s_hist_);
+}
+
+/* Find a specific packet in the send history
+ * arg: seq_num - sequence number of packet to find
+ *      start_elm - start searching from this element
+ * ret: pointer to the correct element if the element is found
+ *      otherwise the closest packet with lower seq num is returned
+ *      which can be NULL.
+ */
+inline struct s_hist_entry* DCCPTFRCAgent::findPacketInSendHistory(u_int32_t seq_num, s_hist_entry* start_elm){
+	struct s_hist_entry *elm = start_elm;
+	while (elm != NULL && elm->seq_num_ > seq_num)
+		elm = STAILQ_NEXT(elm, linfo_);
+	return elm;
+}
+
+/* Remove packets from send history
+ * arg: trim_to - remove packets with lower sequence numbers than this
+ * Note: if trim_to does not exist in the history, trim_to is set to the next
+ *       lower sequence number found before trimming. 
+ */
+void DCCPTFRCAgent::trimSendHistory(u_int32_t trim_to){
+	if (trim_to > s_hist_last_seq_){
+		struct s_hist_entry *elm, *elm2;
+		//find packet corresponding to trim_to
+		elm = findPacketInSendHistory(trim_to, STAILQ_FIRST(&s_hist_));
+		if (elm != NULL){
+			//remove older packets
+			elm2 = STAILQ_NEXT(elm, linfo_);	
+			while (elm2 != NULL){
+				STAILQ_REMOVE(&s_hist_,elm2,s_hist_entry,linfo_);
+				delete elm2;
+				elm2 = STAILQ_NEXT(elm, linfo_);	
+			}
+		}
+		s_hist_last_seq_ = trim_to;
+	}
+}
+
+/* Prints the contents of the send history */
+void DCCPTFRCAgent::printSendHistory(){
+	struct s_hist_entry *elm = STAILQ_FIRST(&s_hist_);
+	if (elm == NULL)
+		fprintf(stdout, "Packet history is empty (send)\n");
+	else {
+		fprintf(stdout, "Packet history (send):\n");
+		while(elm != NULL){
+			fprintf(stdout,"Packet: seq %d, t_sent %f, ecn %d, wincount %u\n", elm->seq_num_, elm->t_sent_, elm->ecn_, elm->win_count_);
+			elm = STAILQ_NEXT(elm, linfo_);
+		}
+	}
+}
+
+/* Clear the history of received packets */
+inline void DCCPTFRCAgent::clearRecvHistory(){
+	struct r_hist_entry *elm, *elm2;
+
+	/* Empty packet history */
+	elm = STAILQ_FIRST(&r_hist_);
+	while (elm != NULL) {
+		elm2 = STAILQ_NEXT(elm, linfo_);
+		delete elm;
+		elm = elm2;
+	}
+	
+	STAILQ_INIT(&r_hist_);
+}
+
+/* Insert a packet in the receive history
+ * Will not insert "lost" packets or duplicates.
+ * arg: packet - entry representing the packet to insert
+ * ret: true if packet was inserted, otherwise false.
+ */
+bool DCCPTFRCAgent::insertInRecvHistory(r_hist_entry *packet){
+	struct r_hist_entry *elm, *elm2;
+	int num_later = 0;
+	fflush(stdout);
+	if (STAILQ_EMPTY(&r_hist_)){  //history is empty
+		STAILQ_INSERT_HEAD(&r_hist_, packet, linfo_);
+		if (packet->type_ != DCCP_ACK)
+				r_last_data_pkt_ = packet;
+	} else {  //history contains at least one entry
+		elm = STAILQ_FIRST(&r_hist_);
+		if (packet->seq_num_ > elm->seq_num_){  //insert first in history
+			STAILQ_INSERT_HEAD(&r_hist_, packet, linfo_);
+			if (packet->type_ != DCCP_ACK)
+				r_last_data_pkt_ = packet;
+		} else if (packet->seq_num_ == elm->seq_num_) //duplicate
+			return false;
+		else {  //packet should be inserted somewhere after the head
+			num_later = 1;
+
+			//walk through the history to find the correct place
+			elm2 = STAILQ_NEXT(elm,linfo_);
+			while(elm2 != NULL){
+				if (packet->seq_num_ > elm2->seq_num_){
+					STAILQ_INSERT_AFTER(&r_hist_, elm, packet, linfo_);
+					if (packet->type_ != DCCP_ACK)
+						r_last_data_pkt_ = packet;
+					
+					break;
+				} else if (packet->seq_num_ == elm2->seq_num_) {
+					return false;  //duplicate
+				}
+				
+				elm = elm2;
+				elm2 = STAILQ_NEXT(elm,linfo_);
+				
+				num_later++;
+				
+				if (num_later == num_dup_acks_){  //packet is "lost"
+					return false;
+				}
+			}
+			
+			if(elm2 == NULL && num_later < num_dup_acks_){
+				STAILQ_INSERT_TAIL(&r_hist_, packet, linfo_);
+				if (packet->type_ != DCCP_ACK)
+					r_last_data_pkt_ = packet;
+			}
+			
+		}
+	}
+
+	removeAcksRecvHistory();
+	
+	return true;
+}
+
+/* Prints the contents of the receive history */
+void DCCPTFRCAgent::printRecvHistory(){
+	struct r_hist_entry *elm = STAILQ_FIRST(&r_hist_);
+	if (elm == NULL)
+		fprintf(stdout, "Packet history is empty (recv)\n");
+	else {
+		fprintf(stdout, "Packet history (recv):\n");
+		while(elm != NULL){
+			fprintf(stdout,"Packet: seq %d, type %s, ndp %d, size %d, win_count %d, t_recv %f\n", elm->seq_num_, packetTypeAsStr(elm->type_), elm->ndp_, elm->size_, elm->win_count_, elm->t_recv_);
+			elm = STAILQ_NEXT(elm, linfo_);
+		}
+	}	
+}
+
+/* Trim receive history
+ * arg: time - remove packet with recv time less than this
+ *      seq_num - remove packet with seq num less than this
+ * Note: both of the above condition must be true for a packet
+ *       to be removed. Furthermore, the function always keeps
+ *       at least num_dup_acks_ packets in the history.
+ */
+void DCCPTFRCAgent::trimRecvHistory(double time, u_int32_t seq_num){
+	struct r_hist_entry *elm, *elm2;
+	int num_later = 1;
+	elm = STAILQ_FIRST(&r_hist_);
+
+	//find the packet after the num_dup_acks_ limit
+	while (elm != NULL && num_later <= num_dup_acks_){
+		num_later++;
+		elm = STAILQ_NEXT(elm, linfo_);
+	}
+
+        if (elm != NULL){
+		//ensure that there exist atleast one data packet after num_dup_acks+1 limit (for loss event detection)
+		elm = findDataPacketInRecvHistory(STAILQ_NEXT(elm,linfo_));
+
+		if (elm != NULL){
+			elm2 = STAILQ_NEXT(elm, linfo_);
+			while(elm2 != NULL){
+				if (elm2->seq_num_ < seq_num && elm2->t_recv_ < time){
+					STAILQ_REMOVE(&r_hist_,elm2,r_hist_entry,linfo_);
+				        delete elm2;
+				} else 
+					elm = elm2;
+				elm2 = STAILQ_NEXT(elm, linfo_);
+			}
+		}
+	}
+}
+
+/* Remove all acks after the num_dup_acks_ limit */
+void DCCPTFRCAgent::removeAcksRecvHistory(){
+	struct r_hist_entry *elm1 = STAILQ_FIRST(&r_hist_);
+	struct r_hist_entry *elm2;
+	
+	int num_later = 1;
+	//find the packet after the num_dup_acks_ limit
+	while (elm1 != NULL && num_later <= num_dup_acks_){
+		num_later++;
+		elm1 = STAILQ_NEXT(elm1, linfo_);
+	}
+
+	if(elm1 == NULL)
+		return;
+	
+	elm2 = STAILQ_NEXT(elm1, linfo_);
+	while(elm2 != NULL){
+		if (elm2->type_ == DCCP_ACK){
+			STAILQ_REMOVE(&r_hist_,elm2,r_hist_entry,linfo_);
+			delete elm2;
+		} else {
+			elm1 = elm2;
+		}
+		elm2 = STAILQ_NEXT(elm1, linfo_);
+	}
+}
+
+/* Find a data packet in the receive history
+ * arg: start - pointer to the first packet to search from
+ * ret: pointer to the found data packet or
+ *      or NULL if none is found.
+ */
+inline r_hist_entry *DCCPTFRCAgent::findDataPacketInRecvHistory(r_hist_entry *start){
+	while(start != NULL && start->type_ == DCCP_ACK)
+		start = STAILQ_NEXT(start,linfo_);
+	return start;
+}
+
+/* Detects packet loss in recv history.
+ * arg: seq_start, seq_end - the lost packet is in [start,end]
+ *      win_count          - window counter of packet before the loss
+ * ret: true if a packet loss was detected, otherwise false.
+ */
+bool DCCPTFRCAgent::detectLossRecv(u_int32_t *seq_start, u_int32_t *seq_end, u_int8_t *win_count){
+	bool result = false;
+	struct r_hist_entry *before = STAILQ_FIRST(&r_hist_);
+	int num_later = 1;
+	//find the packet before the num_dup_acks_ limit
+	while (before != NULL && num_later < num_dup_acks_){
+		num_later++;
+		before = STAILQ_NEXT(before, linfo_);
+	}
+	
+	struct r_hist_entry *after = NULL;
+	//find the packet after the limit
+	if (before != NULL)
+		after = STAILQ_NEXT(before, linfo_);
+	
+	if (before == NULL || after == NULL)
+		return false;
+
+	u_int32_t dist = before->seq_num_ - after->seq_num_;
+	
+	if (dist == 1)  //no loss
+		return false;
+
+	//we have loss, check if it includes a data packet by comparing ndp values
+	/* check no data packets */
+	if(before->type_ == DCCP_DATA || before->type_ == DCCP_DATAACK)
+		dist -= 1;
+
+	if(dist % DCCP_NDP_LIMIT != (u_int32_t) ((int) before->ndp_ - (int) after->ndp_+DCCP_NDP_LIMIT) % DCCP_NDP_LIMIT){
+		result = true;
+		*seq_start = before->seq_num_ - 1;
+		*seq_end = after->seq_num_ + 1;
+		after = findDataPacketInRecvHistory(after);
+		if (after == NULL)
+			*win_count = 0;
+		else
+			*win_count = after->win_count_;
+	}
+
+	return result;
+}
+
+/* Detect packet marks in recv history before num_dup_ack limit.
+ * arg: seq_num - sequence number of marked packet (if any)
+ *      win_count - win_count of marked packet (if any)
+ * ret: true if a packet mark was found, otherwise false.
+ */
+bool DCCPTFRCAgent::detectECNRecv(u_int32_t *seq_num, u_int8_t *win_count){
+	struct r_hist_entry *elm;
+	int num_later = 1;
+	elm = STAILQ_FIRST(&r_hist_);
+
+	//walk through all packets <= num_dup_acks_
+	while (elm != NULL && num_later <= num_dup_acks_){
+		if ((elm->type_ == DCCP_DATA || elm->type_ == DCCP_DATAACK)
+		    && elm->ecn_ == ECN_CE){
+			elm->ecn_ = ECN_NOT_ECT;
+			*seq_num = elm->seq_num_;
+			*win_count = elm->win_count_;
+			return true;
+		}
+		num_later++;
+		elm = STAILQ_NEXT(elm, linfo_);
+	}
+	return false;
+}
+
+/* Calculate the total amount of data in recent packets.
+ * arg: time - sum data in packets received later than this time
+ * ret: total amount of data
+ */
+u_int32_t DCCPTFRCAgent::sumPktSizes(double time){
+	struct r_hist_entry *walker = STAILQ_FIRST(&r_hist_);
+	u_int32_t sum = 0;
+	walker = findDataPacketInRecvHistory(walker);
+
+	while(walker != NULL){
+		if (walker->t_recv_ >= time)
+			sum += walker->size_;
+		walker = findDataPacketInRecvHistory(STAILQ_NEXT(walker,linfo_));
+	}
+	return sum;
+}
+
+/* Sample the round trip time
+ * arg: rtt - the obtained rtt
+ *      last_seq - sequence number of oldest packet used
+ * ret: true if the rtt could succesfully be estimated from wc
+ *      false otherwise. Note that rtt above is always valid.
+ * Note: If not enough packets exist to use wc to estimate rtt,
+ *       the rtt measured on handshake packets are used.
+ *       The function will disregard packets with wc >= max_wc_inc_. 
+ */
+bool DCCPTFRCAgent::sampleRTT(double *rtt, u_int32_t *last_seq){
+	*last_seq = 0;
+	if (r_last_data_pkt_ == NULL){
+		*rtt = rtt_conn_est_;
+		return false;
+	}
+
+	struct r_hist_entry *elm, *elm2;
+	struct r_hist_entry *last = NULL;
+
+	elm = findDataPacketInRecvHistory(STAILQ_NEXT(r_last_data_pkt_, linfo_));
+	int prev_wc = r_last_data_pkt_->win_count_;
+       
+	while (elm != NULL) {
+		last = elm;
+		if ((prev_wc - (int)(elm->win_count_) + ccval_limit_) % ccval_limit_ >= max_wc_inc_) {
+			debug("%f, DCCP/TFRC(%s)::sampleRTT() - Win count distance of %d between to packets is too large (r_rtt_ %f)\n", now(), name(),(prev_wc - (int)(elm->win_count_) + ccval_limit_) % ccval_limit_, (double) r_rtt_);
+			//printRecvHistory();
+			if (r_rtt_ > 0.0){  //we already have an rtt estimate
+				*rtt = r_rtt_;
+				*last_seq = last->seq_num_;
+			} else {  //first estimation
+				*rtt = rtt_conn_est_;
+			}
+			return false;
+		}
+		prev_wc = (int)(elm->win_count_);
+		
+		if (((int) r_last_data_pkt_->win_count_ - (int)(elm->win_count_) + ccval_limit_) % ccval_limit_ > win_count_per_rtt_){
+			
+			elm2 = findDataPacketInRecvHistory(STAILQ_NEXT(elm,linfo_));
+			while(elm2 != NULL){
+				if(elm2->win_count_ == last->win_count_ && elm2->t_recv_ > last->t_recv_)
+					last = elm2;
+				else if (elm2->win_count_ != last->win_count_)
+					break;
+				elm2 = findDataPacketInRecvHistory(STAILQ_NEXT(elm2,linfo_));
+			}
+			break;
+		}
+
+		elm = findDataPacketInRecvHistory(STAILQ_NEXT(elm, linfo_));
+	}
+
+	if (last == NULL){
+		*rtt = rtt_conn_est_;
+		return false;
+	}
+
+	int d = ((int) r_last_data_pkt_->win_count_ - (int) (last->win_count_) + ccval_limit_) % ccval_limit_;
+	if (d <= win_count_per_rtt_){
+		debug("%f, DCCP/TFRC(%s)::sampleRTT() - Win count distance of %d is too small (r_rtt_ %f)\n", now(), name(), d, (double) r_rtt_);
+		if (r_rtt_ > 0.0){  //we already have an rtt estimate
+			*rtt = r_rtt_;
+			*last_seq = last->seq_num_;
+		} else {  //first estimation
+			*rtt = rtt_conn_est_;
+		}
+		return false;
+	}
+	
+	*last_seq = last->seq_num_;
+	*rtt = ((double) win_count_per_rtt_)*(r_last_data_pkt_->t_recv_ - last->t_recv_)/(double) (d);
+
+	return (elm != NULL);
+}
+
+/* Calculate the receive rate to send on feedbacks
+ * ret: the receive rate
+ */
+double DCCPTFRCAgent::calcXrecv(){
+	u_int32_t size = 0;
+	double t = now() - r_t_last_feedback_;
+	if (t < r_rtt_){
+		size = sumPktSizes(now()-r_rtt_);
+		t = r_rtt_;
+		debug("%f, DCCP/TFRC(%s)::calcXrecv() - Used rtt %f as t -> xrecv = %f\n", now(), name(), t, ((double) size) / t);
+	} else {
+		size = r_bytes_recv_;
+		debug("%f, DCCP/TFRC(%s)::calcXrecv() - Used time since last feedback %f as t -> xrecv = %f\n", now(), name(), t, ((double) size) / t);
+	}
+	return ( ((double) size) / t);
+}
+
+/* Clear the loss event history */
+void DCCPTFRCAgent::clearLIHistory(){
+	struct li_hist_entry *li_elm,*li_elm2;
+	/* Empty loss interval history */
+	li_elm = TAILQ_FIRST(&(r_li_hist_));
+	while (li_elm != NULL) {
+		li_elm2 = TAILQ_NEXT(li_elm, linfo_);
+		delete li_elm;
+		li_elm = li_elm2;
+	}
+	TAILQ_INIT(&(r_li_hist_));
+}
+
+/* Print the loss event history */
+void DCCPTFRCAgent::printLIHistory(){
+	struct li_hist_entry *li_elm;
+
+	if (TAILQ_EMPTY(&r_li_hist_))
+		printf("Loss interval history is empty\n");
+	else {
+		printf("Loss interval history:\n");
+		li_elm = TAILQ_FIRST(&(r_li_hist_));
+		while (li_elm != NULL) {
+			printf("Length %d, start %d, win_count %d\n",li_elm->interval_,li_elm->seq_num_,li_elm->win_count_);
+			li_elm = TAILQ_NEXT(li_elm, linfo_);
+		}
+	}
+}
+
+/* Detects quiescence of the corresponding sender
+ * ret: true if sender is quiescent
+ *      false otherwise
+ */
+bool DCCPTFRCAgent::detectQuiescence(){
+	debug("%f, DCCP/TFRC(%s)::detectQuiescence() - scheme %d, time now %f, time high data %f, rtt %f\n", now(), name(), q_scheme_, now(), r_q_t_data_,(double) r_rtt_);
+
+	if (q_scheme_ == DCCP_Q_SCHEME_Q_OPT){
+		if(r_sender_quiescent_)
+			debug("%f, DCCP/TFRC(%s)::detectQuiescence() - Receiver detected that the corresponding sender is quiescent (Q_OPT)\n", now(),name());
+		return r_sender_quiescent_;
+	} else if (q_scheme_ == DCCP_Q_SCHEME_Q_FEAT){
+		if (q_local_)
+			debug("%f, DCCP/TFRC(%s)::detectQuiescence() - Receiver detected that the corresponding sender is quiescent (Q_FEAT)\n", now(),name());
+		return q_local_;
+	}
+	
+	if (r_rtt_ <= 0.0)
+		return false;
+	
+	double t = q_min_t_;
+	if (t < 2*r_rtt_)  
+		t = 2*r_rtt_; 
+	if (now()-r_q_t_data_ >= t)
+		debug("%f, DCCP/TFRC(%s)::detectQuiescence() - Receiver detected that the corresponding sender is quiescent (NORMAL)\n", now(), name());
+	return (now()-r_q_t_data_ >= t);
+}
+
+//protected methods
+
+/* OTcl binding of variables */
+void DCCPTFRCAgent::delay_bind_init_all(){
+	delay_bind_init_one("use_loss_rate_local_");
+	delay_bind_init_one("use_loss_rate_remote_");
+	delay_bind_init_one("rtt_scheme_local_");
+	delay_bind_init_one("rtt_scheme_remote_");
+	delay_bind_init_one("num_dup_acks_");
+	delay_bind_init_one("p_tol_");
+	delay_bind_init_one("win_count_per_rtt_");
+	delay_bind_init_one("max_wc_inc_");
+	delay_bind_init_one("s_use_osc_prev_");
+	delay_bind_init_one("s_smallest_p_");
+	delay_bind_init_one("s_rtt_q_");
+	delay_bind_init_one("s_rtt_q2_");
+	delay_bind_init_one("s_t_mbi_");
+	delay_bind_init_one("s_os_time_gran_");
+	delay_bind_init_one("s_s_");
+	delay_bind_init_one("s_initial_x_");
+	delay_bind_init_one("s_initial_rto_");
+	delay_bind_init_one("s_x_");
+	delay_bind_init_one("s_x_inst_");
+	delay_bind_init_one("s_x_recv_");
+	delay_bind_init_one("s_r_sample_");
+	delay_bind_init_one("s_rtt_");
+	delay_bind_init_one("s_r_sqmean_");
+	delay_bind_init_one("s_p_");
+	delay_bind_init_one("s_q_opt_ratio_");
+	delay_bind_init_one("r_s_");
+	delay_bind_init_one("r_rtt_");
+	delay_bind_init_one("r_p_");
+	delay_bind_init_one("q_min_t_");
+	DCCPAgent::delay_bind_init_all();
+}
+
+int DCCPTFRCAgent::delay_bind_dispatch(const char *varName, const char *localName, TclObject *tracer){
+	if (delay_bind(varName, localName, "use_loss_rate_local_", &use_loss_rate_local_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "use_loss_rate_remote_", &use_loss_rate_remote_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "rtt_scheme_local_", &rtt_scheme_local_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "rtt_scheme_remote_", &rtt_scheme_remote_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "num_dup_acks_", &num_dup_acks_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "p_tol_", &p_tol_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "win_count_per_rtt_", &win_count_per_rtt_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "max_wc_inc_", &max_wc_inc_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "s_use_osc_prev_", &s_use_osc_prev_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "s_smallest_p_", &s_smallest_p_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "s_rtt_q_", &s_rtt_q_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "s_rtt_q2_", &s_rtt_q2_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "s_t_mbi_", &s_t_mbi_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "s_os_time_gran_", &s_os_time_gran_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "s_s_", &s_s_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "s_initial_x_", &s_initial_x_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "s_initial_rto_", &s_initial_rto_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "s_x_", &s_x_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "s_x_inst_", &s_x_inst_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "s_x_recv_", &s_x_recv_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "s_r_sample_", &s_r_sample_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "s_rtt_", &s_rtt_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "s_p_", &s_p_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "s_r_sqmean_", &s_r_sqmean_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "s_q_opt_ratio_", &s_q_opt_ratio_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "r_s_", &r_s_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "r_rtt_", &r_rtt_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "r_p_", &r_p_, tracer)) return TCL_OK;
+	if (delay_bind(varName, localName, "q_min_t_", &q_min_t_, tracer)) return TCL_OK;
+	return DCCPAgent::delay_bind_dispatch(varName, localName, tracer);
+}
+
+void DCCPTFRCAgent::reset(){
+	DCCPAgent::reset();
+	cancelTimers();
+
+	s_t_last_data_sent_ = (-q_min_t_)*2;
+	s_q_packets_wo_opt_ = 0;
+
+	//sender
+	s_hist_last_seq_ = 0;
+	
+	clearSendHistory();
+	
+	s_x_ = s_initial_x_;
+	s_x_inst_ = s_initial_x_;  
+	s_x_recv_ = 0.0;
+	s_x_calc_ = 0.0;
+	
+	s_r_sample_ = 0.0;
+	s_rtt_ = 0.0;
+	s_r_sqmean_ = 0.0;
+	s_p_ = 0.0;
+	
+	s_t_ld_ = -1.0;
+
+	s_last_win_count_ = 0;
+	s_t_last_win_count_ = -1.0;
+	s_wc_ = 0;
+	s_recv_wc_ = 0;
+		
+	s_idle_ = 0;
+	s_t_rto_ = 0.0;
+
+	s_t_nom_ = 0.0;
+	s_t_ipi_ = 0.0;
+	s_delta_ = 0.0;
+	
+	/* init packet history */
+	STAILQ_INIT(&(s_hist_));
+	
+	s_state_ = TFRC_S_STATE_NO_SENT;
+
+	//receiver
+
+	clearRecvHistory();
+	clearLIHistory();
+
+	r_high_seq_recv_ = 0;
+	r_high_ndp_recv_ = -1;
+	r_t_high_recv_ = 0.0;
+	
+	r_rtt_ = 0.0;
+	r_p_ = 0.0;
+	
+	r_last_counter_ = 0;
+	r_seq_last_counter_ = 0;
+	
+	r_t_last_feedback_ = 0.0;
+	r_bytes_recv_ = 0;	
+
+	r_q_t_data_ = 0.0;
+	r_sender_quiescent_ = false;
+	
+	/* init packet history */
+	STAILQ_INIT(&(r_hist_));
+	
+	/* init loss interval history */
+	TAILQ_INIT(&(r_li_hist_));
+	
+	r_state_ = TFRC_R_STATE_NO_DATA;
+	r_last_data_pkt_ = NULL;
+}
+
+void DCCPTFRCAgent::cancelTimers(){
+	s_timer_send_->force_cancel();
+	s_timer_no_feedback_->force_cancel();
+	DCCPAgent::cancelTimers();
+}
+
+bool DCCPTFRCAgent::processOption(u_int8_t type, u_char* data, u_int8_t size, Packet *pkt){
+	bool result = DCCPAgent::processOption(type, data, size, pkt);
+	u_int32_t ui32;
+	if (result){
+		switch(type){
+		case DCCP_OPT_ACK_VECTOR_N0:
+		case DCCP_OPT_ACK_VECTOR_N1:
+			//check if we received a new ack vector
+			if (ackv_recv_ != NULL){//&& ackv_recv_->getFirstSeqNum() >= s_high_ack_recv_){
+				//check if we got all needed packets in the history
+				if(s_hist_last_seq_ <= ackv_recv_->getLastSeqNum()){
+					
+					u_int8_t ene = 0;
+					u_int32_t seqnum;
+					dccp_packet_state state;
+					struct s_hist_entry *elm = STAILQ_FIRST(&s_hist_);
+
+					//walk through the ack vector and compute the ECN Nonce Echo
+					ackv_recv_->startPacketWalk();
+					while(ackv_recv_->nextPacket(&seqnum, &state)){
+						if (state == DCCP_PACKET_RECV){
+							elm = findPacketInSendHistory(seqnum,elm);
+							if (elm != NULL && elm->seq_num_ == seqnum){
+								ene = ene ^ (elm->ecn_);
+							} else if (elm == NULL)
+								break;
+						}
+					}
+					//compare with the received echo
+					if (ene != ackv_recv_->getENE()){
+						printSendHistory();
+						ackv_recv_->printPackets();
+						  
+						fprintf(stdout,"%f, DCCP/TFRC(%s)::processOption() - ECN check failed! \n", now(), name());
+						sendReset(DCCP_RST_AGG_PEN,0,0,0);
+						result = false;
+					}
+					
+					//trim send history
+					trimSendHistory(ackv_recv_->getLastSeqNum());
+				} else
+					debug("%f, DCCP/TFRC(%s)::processOption() - Ack vector includes packets not in history. Skipping ecn check for now...\n", now(), name());
+			} 
+			break;
+		case DCCP_OPT_QUIESCENCE:
+			r_sender_quiescent_ = true;
+			break;
+		case DCCP_TFRC_OPT_RTT:
+			if (size == 4) {
+				((u_char*) &ui32)[0] = data[0];
+				((u_char*) &ui32)[1] = data[1];
+				((u_char*) &ui32)[2] = data[2];
+				((u_char*) &ui32)[3] = data[3];
+			        r_rtt_ = ((double) (ui32))*DCCP_TFRC_OPT_RTT_UNIT;
+			} else {
+				fprintf(stdout,"%f, DCCP/TFRC(%s)::processOption() - RTT option with wrong size %d received\n",now(), name(), size);
+			}
+			break;
+		}
+	}
+	return result;
+}
+
+void DCCPTFRCAgent::buildInitialFeatureList(){
+	DCCPAgent::buildInitialFeatureList();
+	changeFeature(DCCP_TFRC_FEAT_LOSS_EVENT_RATE, DCCP_FEAT_LOC_LOCAL);
+	changeFeature(DCCP_TFRC_FEAT_LOSS_EVENT_RATE, DCCP_FEAT_LOC_REMOTE);
+	changeFeature(DCCP_TFRC_FEAT_RTT_SCHEME, DCCP_FEAT_LOC_LOCAL);
+	changeFeature(DCCP_TFRC_FEAT_RTT_SCHEME, DCCP_FEAT_LOC_REMOTE);
+}
+
+int DCCPTFRCAgent::setFeature(u_int8_t num, dccp_feature_location location,
+	       u_char* data, u_int8_t size, bool testSet){
+	switch(num){
+	case DCCP_TFRC_FEAT_LOSS_EVENT_RATE:
+		if (size == 1){
+			if (location == DCCP_FEAT_LOC_LOCAL){
+				if (use_loss_rate_local_ && data[0] ||
+				    !(use_loss_rate_local_ || data[0]))
+					return DCCP_FEAT_OK;
+				else
+					return DCCP_FEAT_NOT_PREFERED;
+			
+			} else {
+				if (use_loss_rate_remote_ && data[0] ||
+				    !(use_loss_rate_remote_ || data[0]))
+					return DCCP_FEAT_OK;
+				else
+					return DCCP_FEAT_NOT_PREFERED;
+			}	
+		} else
+			return DCCP_FEAT_ERR_SIZE;
+		break;
+	case DCCP_TFRC_FEAT_RTT_SCHEME:
+		if (size == 1){
+			if (location == DCCP_FEAT_LOC_LOCAL){
+				if (rtt_scheme_local_ == data[0])
+					return DCCP_FEAT_OK;
+				else
+					return DCCP_FEAT_NOT_PREFERED;
+			} else {
+				if (rtt_scheme_remote_ == data[0])
+					return DCCP_FEAT_OK;
+				else
+					return DCCP_FEAT_NOT_PREFERED;
+			}
+		} else
+			return DCCP_FEAT_ERR_SIZE;
+		break;
+	default:
+		return DCCPAgent::setFeature(num, location, data, size); 
+	}
+}
+
+int DCCPTFRCAgent::getFeature(u_int8_t num, dccp_feature_location location,
+	       u_char* data, u_int8_t maxSize){
+
+	switch(num){
+	case DCCP_TFRC_FEAT_LOSS_EVENT_RATE:
+		if (maxSize > 0){
+			if (location == DCCP_FEAT_LOC_LOCAL)
+				data[0] = (u_int8_t) use_loss_rate_local_;
+			else
+				data[0] = (u_int8_t) use_loss_rate_remote_;
+				
+			return 1;
+		} else
+			return DCCP_FEAT_ERR_SIZE;
+		break;
+	case DCCP_TFRC_FEAT_RTT_SCHEME:
+		if (maxSize > 0){
+			if (location == DCCP_FEAT_LOC_LOCAL)
+				data[0] = (u_int8_t) rtt_scheme_local_;
+			else
+				data[0] = (u_int8_t) rtt_scheme_remote_;
+			return 1;
+		} else
+			return DCCP_FEAT_ERR_SIZE;
+		break;
+	default:
+		return DCCPAgent::getFeature(num, location, data, maxSize);
+	}
+}
+
+dccp_feature_type DCCPTFRCAgent::getFeatureType(u_int8_t num){
+	switch(num){
+	case DCCP_TFRC_FEAT_LOSS_EVENT_RATE:
+	case DCCP_TFRC_FEAT_RTT_SCHEME:
+		return DCCP_FEAT_TYPE_SP;
+		break;
+	default:
+		return DCCPAgent::getFeatureType(num);
+	}
+}
+
+bool DCCPTFRCAgent::send_askPermToSend(int dataSize, Packet *pkt){
+	ack_num_ = seq_num_recv_;
+	bool result = ( tfrc_send_packet(dataSize) > 0 );
+
+	if (result && dataSize == 0){  //no ecn on pure acks 
+		hdr_flags* flagsh = hdr_flags::access(pkt);
+		flagsh->ce() = 0;
+		flagsh->ect() = 0;
+	}
+	
+	u_int32_t el_time32 = (u_int32_t) ((now() - r_t_high_recv_)/DCCP_OPT_ELAPSED_TIME_UNIT);
+	double t;
+	if (q_scheme_ == DCCP_Q_SCHEME_Q_OPT && !infinite_send_ && dataSize == 0){
+		t = q_min_t_;
+		if (t < 2*s_rtt_)  
+			t = 2*s_rtt_;
+		if (now() - s_t_last_data_sent_ > t && sb_->empty()){
+			s_q_packets_wo_opt_++;
+			if (s_q_packets_wo_opt_ >= s_q_opt_ratio_){
+				opt_->addOption(DCCP_OPT_QUIESCENCE,NULL,0);
+				s_q_packets_wo_opt_ = 0;
+			}
+		}
+	} else if (q_scheme_ == DCCP_Q_SCHEME_Q_FEAT && !infinite_send_){
+		if(dataSize > 0 && q_remote_){
+			if (changeFeature(DCCP_FEAT_Q,DCCP_FEAT_LOC_REMOTE))
+				q_remote_ = 0;
+		} else if (dataSize == 0) {
+			t = q_min_t_;
+			if (t < 2*s_rtt_)  
+				t = 2*s_rtt_;
+			if (now() - s_t_last_data_sent_ > t && sb_->empty() && !q_remote_){
+				if (changeFeature(DCCP_FEAT_Q,DCCP_FEAT_LOC_REMOTE))
+					q_remote_ = 1;
+					
+			}
+		}
+		
+	}
+	
+	//add elapsed time on acknowledgments if needed
+	if(result && send_ack_ && el_time32 > 0){
+		debug("%f, DCCP/TFRC(%s)::send_askPermToSend() - Ack is delayed by %d (t_high_recv_ %f)\n", now(), name(),el_time32,r_t_high_recv_);
+		if (el_time32 > 0 && el_time32 <= 0xFFFF){
+			u_int16_t el_time16 = (u_int16_t) el_time32;
+			opt_->addOption(DCCP_OPT_ELAPSED_TIME,((u_char*) &el_time16), 2);
+		} else if (el_time32 > 0)
+			opt_->addOption(DCCP_OPT_ELAPSED_TIME,((u_char*) &el_time32), 4); 
+	}
+	return result;
+}
+
+void DCCPTFRCAgent::send_packetSent(Packet *pkt, bool moreToSend, int dataSize){
+	hdr_dccp *dccph = hdr_dccp::access(pkt);
+
+	switch(dccph->type_){
+	case DCCP_DATA:
+	case DCCP_DATAACK:
+		if (q_scheme_ == DCCP_Q_SCHEME_Q_OPT)
+			s_q_packets_wo_opt_ = 0;
+		s_t_last_data_sent_ = now();
+		break;
+	default:
+		;
+	}
+	
+	tfrc_send_packet_sent(pkt,(int) moreToSend, dataSize);
+}
+
+void DCCPTFRCAgent::send_packetRecv(Packet *pkt, int dataSize){
+	tfrc_send_packet_recv(pkt);
+}
+
+void DCCPTFRCAgent::recv_packetRecv(Packet *pkt, int dataSize){
+	hdr_dccp *dccph = hdr_dccp::access(pkt);
+
+	if (r_q_t_data_ == 0.0)
+		r_q_t_data_ = now();
+
+	if(dccph->type_ == DCCP_DATA || dccph->type_ == DCCP_DATAACK){
+		r_q_t_data_ = now();
+		r_sender_quiescent_ = false;
+	} else if (r_high_ndp_recv_ >= 0 && (int) (dccph->seq_num_ - r_high_seq_recv_) > 1){
+		//some packet is missing
+		if ( (int) (dccph->seq_num_ - r_high_seq_recv_) >
+		     ((dccph->ndp_ - r_high_ndp_recv_ + DCCP_NDP_LIMIT) % DCCP_NDP_LIMIT)
+		     ){ //data packet is "lost"
+			debug("%f, DCCP/TFRC(%s)::recv_packetRecv() - Data loss detected by receiver seq_num %d - ndp %d,  high_seq_recv %d - ndp %d\n",now(),name(), dccph->seq_num_, dccph->ndp_,r_high_seq_recv_, r_high_ndp_recv_);
+			r_q_t_data_ = now();
+			r_sender_quiescent_ = false;
+		}
+	}
+	
+	if (dccph->seq_num_ > r_high_seq_recv_){
+		r_high_seq_recv_ = dccph->seq_num_;
+		r_high_ndp_recv_ = dccph->ndp_;
+		r_t_high_recv_ = now();
+	}
+	tfrc_recv_packet_recv(pkt, dataSize);
+}
+
+/* Variable tracing */
+
+void DCCPTFRCAgent::traceAll() {
+	char wrk[500];
+
+	sprintf(wrk,"%f %f %f %f %f %f %f %f %f %f\n",
+		now(), (double) s_x_, (double) s_x_inst_,(double) s_x_recv_,
+		(double) s_r_sample_, (double) s_rtt_, (double) s_r_sqmean_,
+		(double) s_p_, (double) r_rtt_, (double) r_p_);
+
+	if (channel_)
+		Tcl_Write(channel_, wrk, strlen(wrk));
+}
+
+
+void DCCPTFRCAgent::traceVar(TracedVar* v) 
+{
+	char wrk[500];
+	
+	if (!strcmp(v->name(), "s_x_") ||
+	    !strcmp(v->name(), "s_x_inst_") ||
+	    !strcmp(v->name(), "s_x_recv_") ||
+	    !strcmp(v->name(), "s_r_sample_") ||
+	    !strcmp(v->name(), "s_rtt_") ||
+	    !strcmp(v->name(), "s_r_sample_") ||
+	    !strcmp(v->name(), "s_rtt_") ||
+	    !strcmp(v->name(), "s_r_sqmean_") ||
+	    !strcmp(v->name(), "s_p_") ||
+	    !strcmp(v->name(), "r_rtt_") ||
+	    !strcmp(v->name(), "r_p_")){
+		sprintf(wrk,"%f %f %s\n", now(), double(*((TracedDouble*) v)), v->name());
+		if (channel_)
+			Tcl_Write(channel_, wrk, strlen(wrk));
+	} else
+		DCCPAgent::traceVar(v);
+}
+
+
+//public methods
+
+/* Constructor
+ * ret: a new DCCPTCPlikeAgent
+ */
+DCCPTFRCAgent::DCCPTFRCAgent() : DCCPAgent() {
+
+	ccid_ = DCCP_TFRC_CCID;
+	use_ecn_local_ = 1;
+	use_ecn_remote_ = 1;
+	use_ackv_local_ = 1;
+	use_ackv_remote_ = 1;
+	use_loss_rate_local_ = DCCP_TFRC_FEAT_DEF_LOSS_EVENT_RATE;
+	use_loss_rate_remote_ = DCCP_TFRC_FEAT_DEF_LOSS_EVENT_RATE;
+	rtt_scheme_local_ = DCCP_TFRC_FEAT_DEF_RTT_SCHEME;
+	rtt_scheme_remote_ = DCCP_TFRC_FEAT_DEF_RTT_SCHEME;
+	win_count_per_rtt_ = DCCP_TFRC_WIN_COUNT_PER_RTT;
+
+	q_min_t_ = DCCP_TFRC_MIN_T;
+
+	p_tol_ = DCCP_TFRC_P_TOLERANCE;
+	
+	s_t_last_data_sent_ = (-q_min_t_)*2;
+	s_q_opt_ratio_ = DCCP_TFRC_QUIESCENCE_OPT_RATIO;
+	s_q_packets_wo_opt_ = 0;
+	
+	s_timer_send_ = new DCCPTFRCSendTimer(this);
+	s_timer_no_feedback_ = new DCCPTFRCNoFeedbackTimer(this);
+
+	s_initial_x_ = DCCP_TFRC_INIT_SEND_RATE;
+	s_initial_rto_ = DCCP_TFRC_INIT_RTO;
+
+	s_rtt_q_ = DCCP_TFRC_RTT_Q;
+	s_rtt_q2_ = DCCP_TFRC_RTT_Q2;
+	s_t_mbi_ = DCCP_TFRC_MBI;
+	
+	s_s_ = DCCP_TFRC_STD_PACKET_SIZE;
+	s_x_ = s_initial_x_;
+	s_x_inst_ = s_initial_x_;
+	
+	s_use_osc_prev_ = 1;  
+	
+	s_x_recv_ = 0.0;
+	s_x_calc_ = 0.0;
+	
+	s_r_sample_ = 0.0;
+	s_rtt_ = 0.0;
+	s_r_sqmean_ = 0.0;
+	s_p_ = 0.0;
+	s_smallest_p_ = DCCP_TFRC_SMALLEST_P;
+	
+	s_t_ld_ = -1.0;
+
+	s_last_win_count_ = 0;
+	s_t_last_win_count_ = -1.0;
+	s_wc_ = 0;
+	s_recv_wc_ = 0;
+	
+	s_idle_ = 0;
+	s_t_rto_ = 0.0;
+
+	s_t_nom_ = 0.0;
+	s_t_ipi_ = 0.0;
+	s_delta_ = 0.0;
+	s_os_time_gran_ = DCCP_TFRC_OPSYS_TIME_GRAN;
+	
+	/* init packet history */
+	STAILQ_INIT(&(s_hist_));
+	
+	s_state_ = TFRC_S_STATE_NO_SENT;
+
+	max_wc_inc_ = DCCP_TFRC_MAX_WC_INC;
+
+	s_hist_last_seq_ = 0;
+	
+	//receiver
+	 
+	r_rtt_ = 0.0;
+	r_p_ = 0.0;
+	
+	r_last_counter_ = 0;
+	r_seq_last_counter_ = 0;
+	
+	r_t_last_feedback_ = 0.0;
+	r_bytes_recv_ = 0;	
+
+	r_s_ = DCCP_TFRC_STD_PACKET_SIZE;
+
+	r_num_w_ = DCCP_TFRC_NUM_W; 
+
+	try {
+		r_w_ = new double[r_num_w_];
+	} catch (...) {
+		fprintf(stderr, "DCCP/TFRC::DCCPTFRCAgent() - Out of memory\n");
+		fflush(stdout);
+		abort();
+	}
+	int r_num_w_half = r_num_w_/2;
+
+	/* Init weights */
+	for (int i = 0; i < r_num_w_; i++) {
+		if (i < r_num_w_half)
+			r_w_[i] = 1.0;
+		else
+			r_w_[i] = 1.0 - ((double) (i-(r_num_w_half - 1)))/(r_num_w_half + 1.0);
+	}
+
+	/* init packet history */
+	STAILQ_INIT(&(r_hist_));
+	
+	/* init loss interval history */
+	TAILQ_INIT(&(r_li_hist_));
+	
+	r_state_ = TFRC_R_STATE_NO_DATA;
+	r_last_data_pkt_ = NULL;
+	
+	r_high_seq_recv_ = 0;
+	r_high_ndp_recv_ = -1;
+	r_t_high_recv_ = 0.0;
+
+	r_q_t_data_ = 0.0;
+	r_sender_quiescent_ = false;
+}
+	
+/* Destructor */
+DCCPTFRCAgent::~DCCPTFRCAgent(){
+	/* uninit sender */
+	
+	/* unschedule timers */
+	cancelTimers();
+
+	/* Empty packet history */
+
+	clearSendHistory();
+
+	clearRecvHistory();
+	clearLIHistory();
+
+	delete [] r_w_;
+	delete s_timer_send_;
+	delete s_timer_no_feedback_;
+}
+
+/* Process a "function call" from OTCl
+ * 
+ * Supported function call handled by this agent:
+ * weights <count>+<w1>+<w2>....  - set the weights for avg li calc.
+ * example  $dccp weights 8+1.0+1.0+1.0+1.0+0.8+0.6+0.4+0.2
+ */
+int DCCPTFRCAgent::command(int argc, const char*const* argv){
+	if (argc == 3) {
+		if (strcmp(argv[1], "weights") == 0) {
+			int len = strlen(argv[2])+1;
+			if (len < 4)
+				return TCL_ERROR;
+			char *temp;
+			try {
+				temp = new char[len];
+				strcpy(temp, argv[2]);
+				r_num_w_ = atoi(strtok(temp, "+"));
+				if (r_num_w_ <= 0){
+					fprintf(stderr, "%f, DCCP/TFRC(%s)::command()/weights - Number of weights is invalid (num weights %i)\n",now(),name(),r_num_w_);
+					return TCL_ERROR;
+				}
+				delete r_w_;
+				r_w_ = new double[r_num_w_];
+			} catch (...) {
+				fprintf(stderr, "%f, DCCP/TFRC(%s)::command()/weights - Out of memory (num weights %i)\n",now(), name(), r_num_w_);
+				return TCL_ERROR;
+			}
+			
+			char *weight;
+			for (int i = 0; i < r_num_w_; i++){
+				weight = strtok(NULL, "+");
+				if (weight == NULL){
+					fprintf(stderr, "%f, DCCP/TFRC(%s)::command()/weights - Missing weight %i\n",now(),name(), i+1);
+					return TCL_ERROR;
+				}
+				r_w_[i] = atof(weight);
+			}
+			delete [] temp;
+
+			printf("%f, DCCP/TFRC(%s)::command() - Weights:",now(), name());
+			for (int i = 0; i < r_num_w_; i++) {
+				printf(" %f", r_w_[i]);
+			}
+			
+			printf(" (tot %i)\n", r_num_w_);
+			fflush(stdout);
+			return TCL_OK;
+		}
+	}
+	return (DCCPAgent::command(argc, argv));
+}
+
+/* A timeout has occured
+ * arg: tno - id of timeout event
+ * Handles: Send timer - DCCP_TFRC_TIMER_SEND
+ *          No feedback timer - DCCP_TFRC_TIMER_NO_FEEDBACK
+ */
+void DCCPTFRCAgent::timeout(int tno){
+	switch (tno){
+	case DCCP_TFRC_TIMER_SEND:
+		debug("%f, DCCP/TFRC(%s)::timeout() - Send timer expired\n", now(), name());
+		output(false);
+		//make sure we schedule next send time
+		tfrc_send_packet_sent(NULL,0,-1); 
+		break;
+	case DCCP_TFRC_TIMER_NO_FEEDBACK:
+		debug("%f, DCCP/TFRC(%s)::timeout() - No feedback timer expired\n", now(), name());
+		tfrc_time_no_feedback();
+		break;
+	default:
+	        DCCPAgent::timeout(tno);
+	}
+}
+
+/* Sender side */
+
+/* Calculate new t_ipi (inter packet interval) by
+ *    t_ipi = s/X_inst; 
+ * Note: No check for x=0 -> t_ipi ={0xFFF...,0xFFF}
+ */
+#define CALCNEWTIPI(ccbp)                              \
+        do{                                            \
+           s_t_ipi_ = ((double) s_s_) / s_x_inst_;      \
+        }while (0)
+
+/* Calculate new delta by 
+ *    delta = min(t_ipi/2, t_gran/2);
+ */
+#define CALCNEWDELTA(ccbp)                             \
+         do {                                          \
+            s_delta_ = s_os_time_gran_ / 2.0;                  \
+            if (s_t_ipi_ < s_os_time_gran_){     \
+	       s_delta_ = s_t_ipi_/2.0;              \
+	    }                                          \
+	 } while (0)
+
+
+/* Calculate sending rate from the throughput equation
+ * arg: s - packet size (in bytes)
+ *      R - round trip time (int seconds)
+ *      p - loss event rate
+ * ret: maximum allowed sending rate
+ */
+inline double DCCPTFRCAgent::tfrc_calcX(u_int16_t s, double R, double p){
+	double temp = R*sqrt(2*p/3) + (4*R*(3*sqrt(3*p/8))*p*(1+32*p*p));
+	
+	return  (((double) s) / temp);
+}
+
+/* Find the loss event rate corresponding to a send rate
+ * in the TCP throughput eq.
+ * args: s - packet size (in bytes)
+ *       R - Round trip time  (in seconds)
+ *       x - send rate (in bytes/s)
+ * returns:  the loss eventrate accurate to 5% with resp. to x
+ */
+double DCCPTFRCAgent::tfrc_calcP(u_int16_t s, double R, double x){
+	double p0 = 0.5;
+	double dp = 0.25;
+	double p, res;
+	int i = 0;
+	p = p0;
+	if (x <= tfrc_calcX(s,R,1.0)){
+	  return 1.0;
+	}
+	
+	while (i < 50){
+		res = tfrc_calcX(s,R,p);
+		if (res > (1.0-p_tol_)*x && res < (1.0+p_tol_)*x)
+			return p;
+		else if (res > x)
+			p += dp;
+		else
+			p -= dp;
+		dp = dp/2;
+		i++;
+	}
+	debug("%f, DCCP/TFRC(%s)::tfrc_calcP() - Max iterations reached\n", now(), name());
+	return p;
+}
+
+/* Set the send timer
+ * arg: t_now - time now
+ */
+void DCCPTFRCAgent::tfrc_set_send_timer(double t_now){
+	double t_temp;
+	
+	/* set send timer to expire in t_ipi - (t_now-t_nom_old) 
+	 * or in other words after t_nom - t_now */
+	t_temp = s_t_nom_-t_now;
+	
+	if(t_temp < 0) {
+		fprintf(stderr,"%f, DCCP/TFRC(%s)::tfrc_set_send_timer() - Scheduled a negative time!\n", now(), name());
+		fflush(stdout);
+		abort();
+	}
+	debug("%f, DCCP/TFRC(%s)::tfrc_set_send_timer() - Send timer is scheduled to expire in %f s\n", now(), name(), t_temp);
+
+	s_timer_send_->resched(t_temp);
+}
+
+/*
+ * Update X by
+ *    If (p > 0)
+ *       x_calc = calcX(s,R,p);
+ *       X = max(min(X_calc, 2*X_recv), s/t_mbi);
+ *    Else
+ *       If (t_now - tld >= R)
+ *          X = max(min("2*X, 2*X_recv),s/R);
+ *          tld = t_now;
+ *   t_now - time now
+ */ 
+void DCCPTFRCAgent::tfrc_updateX(double t_now){
+	double temp = 0;
+	double t_temp = 0;
+	
+	if (s_p_ >= s_smallest_p_){     /* to avoid large error in calcX */
+		s_x_calc_ = tfrc_calcX(s_s_, s_rtt_, s_p_);
+		temp = 2*s_x_recv_;
+		if (s_x_calc_ < temp)
+			temp = s_x_calc_;
+		s_x_ = temp;
+		if(temp < ((double) s_s_)/s_t_mbi_)
+			s_x_ = ((double) s_s_)/s_t_mbi_;
+		
+		debug("%f, DCCP/TFRC(%s)::tfrc_updateX() - Updated send rate to %f bytes/s (p > 0, %f)\n", now(), name(), (double) s_x_, (double) s_p_);
+
+		if (s_use_osc_prev_){
+			s_x_inst_ = s_x_ * s_r_sqmean_ / sqrt(s_r_sample_);
+			debug("%f, DCCP/TFRC(%s)::tfrc_updateX() - Oscillation prevention adjusted send rate to %f bytes/s (p > 0, %f)\n", now(), name(), (double) s_x_inst_, (double) s_p_);
+		} else
+			s_x_inst_ = s_x_;
+	} else {
+		t_temp = t_now-s_t_ld_;
+		if (t_temp >= s_rtt_) {
+			temp = 2*s_x_recv_;
+			if (2*s_x_ < temp)
+				temp = 2*s_x_;
+			s_x_ = ((double)(s_s_))/s_rtt_;
+			if(temp > s_x_)
+				s_x_ = temp;
+			s_t_ld_ = t_now;
+			s_x_inst_ = s_x_;
+			debug("%f, DCCP/TFRC(%s)::tfrc_updateX() - Updated send rate to %f bytes/s (p == 0, %f)\n", now(), name(), (double) s_x_, (double) s_p_);
+		} else
+			debug("%f, DCCP/TFRC(%s)::tfrc_updateX() - Did not update send rate (p == 0, %f)\n", now(), name(), (double) s_p_);
+	} 
+}
+
+/* Halve the sending rate when no feedback timer expires */
+void DCCPTFRCAgent::tfrc_time_no_feedback(){
+	double next_time_out = -1.0;
+	
+	switch(s_state_){
+	case TFRC_S_STATE_NO_FBACK:
+		debug("%f, DCCP/TFRC(%s)::tfrc_time_no_feedback() - No feedback timer expired state NO_FBACK\n", now(), name());
+		
+		/* half send rate */
+		s_x_ = s_x_ / 2.0;
+		if (s_x_ < ((double) s_s_) / s_t_mbi_)
+			s_x_ = ((double) s_s_) / s_t_mbi_;
+
+		s_x_inst_ = s_x_;
+		debug("%f, DCCP/TFRC(%s)::tfrc_time_no_feedback() - Updated send rate to %f bytes/s\n", now(), name(), (double) s_x_);
+    
+		/* calculate next time out */
+		
+		next_time_out = 2.0*((double) (s_s_))/ s_x_;
+				 
+		if (next_time_out < s_initial_rto_)
+			next_time_out = s_initial_rto_;
+		break;
+	case TFRC_S_STATE_FBACK:
+		/* Check if IDLE since last timeout and recv rate is less than 4 packets per RTT */ 
+		
+		if(!(s_idle_) || (s_x_recv_ >= 4.0 * ((double) s_s_) / s_rtt_)){
+			debug("%f, DCCP/TFRC(%s)::tfrc_time_no_feedback() - No feedback timer expired, state FBACK, not idle\n", now(), name());
+
+			/* Half sending rate */
+			
+			/*  If (X_calc > 2* X_recv)
+			 *    X_recv = max(X_recv/2, s/(2*t_mbi));
+			 *  Else
+			 *    X_recv = X_calc/4;
+			 */
+			if(s_p_ >= s_smallest_p_ && s_x_calc_ == 0.0){
+				fprintf(stderr,"%f, DCCP/TFRC(%s)::tfrc_time_no_feedback() - X_calc is zero while p = %f > 0\n", now(), name(), (double) s_p_);
+				fflush(stdout);
+				abort();
+			}
+			
+			
+			/* check also if p i zero -> x_calc is infinity ?? */
+			if(s_p_ < s_smallest_p_ || s_x_calc_ > 2*s_x_recv_){
+				s_x_recv_ = s_x_recv_ / 2;
+				if (s_x_recv_ < ((double)s_s_)/(2*s_t_mbi_))
+					s_x_recv_ = ((double)s_s_)/(2*s_t_mbi_);
+			} else {
+				s_x_recv_ = s_x_calc_ / 4.0;
+			}
+
+			/* Update sending rate */
+			tfrc_updateX(now());
+		} 
+		
+		/* Schedule no feedback timer to
+		 * expire in max(4*R, 2*s/X) 
+		 */
+		next_time_out = 2.0*((double) s_s_)/ s_x_;
+		if (next_time_out < s_t_rto_)
+			next_time_out = s_t_rto_;
+    
+		break;
+	default:
+		fprintf(stderr,"%f, DCCP/TFRC(%s)::tfrc_time_no_feedback() - Illegal state!\n", now(), name());
+		fflush(stdout);
+		abort();
+		break;
+	}
+	
+	/* Set timer */
+	
+	if (next_time_out <= 0.0){
+		fprintf(stderr,"%f, DCCP/TFRC(%s)::tfrc_time_no_feedback() - About to schedule no feedback timer in %f s.\n", now(), name(), next_time_out);
+		fflush(stdout);
+		abort();
+	}
+	
+	debug("%f, DCCP/TFRC(%s)::tfrc_time_no_feedback() - Scheduled no feedback timer to expire in %f s\n", now(), name(), next_time_out);
+
+	s_timer_no_feedback_->resched(next_time_out);
+	
+	/* set idle flag */
+	s_idle_ = 1;
+}
+
+
+
+/* Similar to send_askPermToSend() */
+int DCCPTFRCAgent::tfrc_send_packet(int datasize){
+	u_int8_t answer = 0;
+	u_int8_t win_count = 0;
+	u_int32_t uw_win_count = 0;
+	double t_temp;
+	
+	/* check if pure ACK */
+	if(datasize == 0){
+		return 1;
+	}
+	
+	switch (s_state_){
+	case TFRC_S_STATE_NO_SENT :
+		debug("%f, DCCP/TFRC(%s)::tfrc_send_packet() - DCCP asks for permission to send the first data packet\n", now(), name());
+		
+		s_t_nom_ = now();  /* set nominal send time for initial packet */
+		
+		/* init feedback timer */
+		
+		s_timer_no_feedback_->sched((double) s_initial_rto_);
+
+		s_t_last_win_count_ = now();
+		debug("%f, DCCP/TFRC(%s)::tfrc_send_packet() - TFRC - Permission granted. Scheduled no feedback timer (initial) to expire in %f s\n", now(), name(),(double) s_initial_rto_); 
+
+		/* start send timer */
+	
+		/* Calculate new t_ipi */
+		CALCNEWTIPI(cb);
+		s_t_nom_ += s_t_ipi_;  /* t_nom += t_ipi */
+
+		/* Calculate new delta */
+		CALCNEWDELTA(cb);
+		tfrc_set_send_timer(now());   /* schedule sendtimer */
+		s_state_ = TFRC_S_STATE_NO_FBACK;
+		answer = 1;
+		break;
+	case TFRC_S_STATE_NO_FBACK :
+	case TFRC_S_STATE_FBACK :
+		//if(!(s_ch_stimer.callout)){
+		if (s_timer_send_->status() != TIMER_PENDING){
+			t_temp = now() + s_delta_;
+			
+			//if (( timevalcmp(&(t_temp),&(s_t_nom_),>))){
+			if (t_temp > s_t_nom_){
+				/* Packet can be sent */
+
+				if (s_t_last_win_count_ == -1.0){
+					fprintf(stderr,"%f, DCCP/TFRC(%s)::tfrc_send_packet() - t_last_win_count unitialized!\n", now(), name());
+					fflush(stdout);
+					abort();
+				}
+
+				t_temp = now()-s_t_last_win_count_;
+	
+				/* calculate win_count option */
+				if(s_state_ == TFRC_S_STATE_NO_FBACK){
+					/* Assume RTT= t_rto(initial)/4 */
+					uw_win_count = (u_int32_t) (t_temp / ((double) s_initial_rto_/(4.0*((double)win_count_per_rtt_))));
+				}else{
+					uw_win_count = (u_int32_t) (t_temp / (s_rtt_/((double)win_count_per_rtt_)));
+				}
+				/* don't increse wc with more than max_wc_inc_*/
+				debug("%f, DCCP/TFRC(%s)::tfrc_send_packet() - window counter update:  time since last wc %f, rtt %f, inc %d\n", now(), name(), t_temp, (double) s_rtt_, uw_win_count);
+				if(uw_win_count > (u_int32_t) max_wc_inc_)
+					uw_win_count = max_wc_inc_;
+				uw_win_count += s_last_win_count_;
+
+				if (s_rtt_ > 0.0 && uw_win_count < s_recv_wc_ + win_count_per_rtt_) {
+					debug("%f, DCCP/TFRC(%s)::tfrc_send_packet() - window counter changed due to last acked wc restriction: wc before %d (%d) last wc %d (%d)\n", now(), name(), uw_win_count, uw_win_count % ccval_limit_, s_recv_wc_, s_recv_wc_ % ccval_limit_);
+					uw_win_count = s_recv_wc_ + win_count_per_rtt_;
+				}
+				s_wc_ = uw_win_count;
+
+				win_count = uw_win_count % ccval_limit_;
+				answer = 1;
+			} else {
+				answer = 0;
+			}
+		} else {
+			answer = 0;
+		}
+		break;
+	default:
+		fprintf(stderr,"%f, DCCP/TFRC(%s)::tfrc_send_packet() - Illegal state!\n", now(), name());
+		fflush(stdout);
+		abort();
+		break;
+	}
+	
+	/* can we send? if so add options and add to packet history */
+	if(answer){
+		ccval_ = win_count;
+		if (rtt_scheme_local_ == DCCP_TFRC_RTT_SCHEME_OPTION && s_rtt_ > 0){
+			u_int32_t temp_rtt = (u_int32_t) (s_rtt_/DCCP_TFRC_OPT_RTT_UNIT);
+			opt_->addOption(DCCP_TFRC_OPT_RTT,((u_char*) &temp_rtt), 4);
+		}
+	}
+	return answer;
+}
+
+/* Similar to send_packetSent() */
+void DCCPTFRCAgent::tfrc_send_packet_sent(Packet *pkt, int moreToSend, int datasize){
+	hdr_dccp *dccph = (pkt == NULL ? NULL : hdr_dccp::access(pkt));
+	double t_temp;
+	struct s_hist_entry *packet;
+	int result;
+
+	/* check if we have sent a data packet */
+	if(datasize > 0){
+		/* add packet to history */
+		packet = new struct s_hist_entry;
+
+		packet->t_sent_ = now();
+		packet->seq_num_ = dccph->seq_num_;
+		result = getNonce(pkt);
+		
+		packet->ecn_ = (result >= 0 ? result : 0);
+		packet->win_count_ = s_wc_;
+
+		STAILQ_INSERT_HEAD(&(s_hist_), packet, linfo_);
+		
+		/* check if win_count have changed */
+		if(s_wc_ != s_last_win_count_){
+			s_t_last_win_count_ = now();
+			s_last_win_count_ = s_wc_;
+		}
+		debug("%f, DCCP/TFRC(%s)::tfrc_send_packet_sent() - Packet sent (seq: %u,win_count: %u (%u),t_sent %f )\n", now(), name(), packet->seq_num_,packet->win_count_, packet->win_count_ % ccval_limit_,packet->t_sent_);
+		s_idle_ = 0;
+	}
+
+	/* if timer is running, do nothing */
+
+	if(s_timer_send_->status() == TIMER_PENDING)
+		return;
+
+	switch (s_state_){
+	case TFRC_S_STATE_NO_SENT :
+		/* if first was pure ack */ 
+		if(datasize == 0){
+			return; //goto sps_release;
+		} else {
+			fprintf(stderr,"%f, DCCP/TFRC(%s)::tfrc_send_packet_sent() - Packet sent in state NO_SENT included data!\n", now(), name());
+			fflush(stdout);
+			abort();
+		}
+		break;
+	case TFRC_S_STATE_NO_FBACK :
+	case TFRC_S_STATE_FBACK :
+		if(datasize <= 0){ /* we have ack (which never can have more to send?!?!?!?) (or simulate a sent packet to schedule send timer) */
+			moreToSend = 0;
+		} else {
+			/* Calculate new t_ipi */
+			CALCNEWTIPI(cb);
+			s_t_nom_ += s_t_ipi_;  /* t_nom += t_ipi */
+			/* Calculate new delta */
+			CALCNEWDELTA(cb);
+		}
+
+		if(!moreToSend){
+			/* loop until we find a send time in the future */
+
+			t_temp = now()+s_delta_; 
+
+			//while((timevalcmp(&(t_temp),&(s_t_nom_),>))){
+			while(t_temp > s_t_nom_){
+				/* Calculate new t_ipi */
+				CALCNEWTIPI(cb);
+				s_t_nom_ += s_t_ipi_; 
+				/* Calculate new delta */
+				CALCNEWDELTA(cb);
+				
+				t_temp = now() + s_delta_; 
+			}
+			tfrc_set_send_timer(now());
+		} else {
+			t_temp = now() + s_delta_; 
+			/* Check if next packet can not be sent immediately */
+
+			if(!(t_temp > s_t_nom_)){
+				tfrc_set_send_timer(now());   /* if so schedule sendtimer */
+			}
+		}
+		break;
+	default:
+		fprintf(stderr,"%f, DCCP/TFRC(%s)::tfrc_send_packet_sent() - Illegal state!\n", now(), name());
+		fflush(stdout);
+		abort();
+		break;
+	}
+}
+
+/* Similar to send_packetRecv() */
+void DCCPTFRCAgent::tfrc_send_packet_recv(Packet *pkt){
+	hdr_dccp *dccph = hdr_dccp::access(pkt);
+	hdr_dccpack *dccpah = hdr_dccpack::access(pkt);
+	double next_time_out; 
+	int res;
+	u_int32_t pinv = 0;
+	u_int32_t x_recv = 0;
+	
+	struct s_hist_entry *elm; //,*elm2;
+	bool gotP;
+	bool gotXrecv;
+	
+	/* we are only interested in ACKs */
+	if (!(dccph->type_ == DCCP_ACK || dccph->type_ == DCCP_DATAACK))
+		return;
+	
+	res = dccph->options_->getOption(DCCP_TFRC_OPT_LOSS_EVENT_RATE,(u_char *) &pinv,4);
+	gotP = (res == 4);
+        res = dccph->options_->getOption(DCCP_TFRC_OPT_RECV_RATE,(u_char *) &x_recv,4);
+	gotXrecv = (res == 4);
+	
+	if (!gotP || !gotXrecv){
+		debug("%f, DCCP/TFRC(%s)::tfrc_send_packet_recv() - Missing options: gotP %u, gotXrecv %u\n", now(), name(), (int) gotP, (int) gotXrecv);
+		return;
+	}
+
+	debug("%f, DCCP/TFRC(%s)::tfrc_send_packet_recv() - Received options on seq %u, ack %u: pinv=%u, t_elapsed=%u, x_recv=%u\n",now(),name(),dccph->seq_num_, dccpah->ack_num_,pinv,elapsed_time_recv_,x_recv);
+  
+
+	switch (s_state_){
+	case TFRC_S_STATE_NO_FBACK :
+	case TFRC_S_STATE_FBACK :
+		/* Calculate new round trip sample by
+		 * R_sample = (t_now - t_recvdata)-t_delay;
+		 */
+
+		/* get t_recvdata from history */
+		elm = STAILQ_FIRST(&(s_hist_));
+		while (elm != NULL) {
+			if (elm->seq_num_ == dccpah->ack_num_)
+				break;
+			elm = STAILQ_NEXT(elm, linfo_);
+		}
+		
+		if(elm == NULL){  //probably an ack-of-ack (but with feedback)
+			debug("%f, DCCP/TFRC(%s)::tfrc_send_packet_recv() - Acked packet (ack: %d) does not exist in history.\n", now(), name(),dccpah->ack_num_);
+
+		} else {
+			//store wc on acked packet
+
+			s_recv_wc_ = elm->win_count_;
+			
+			/* Update RTT */
+			
+			s_r_sample_ = now() - (elm->t_sent_) - ((double) elapsed_time_recv_)*DCCP_OPT_ELAPSED_TIME_UNIT;
+			
+			/* Update RTT estimate by 
+			 * If (No feedback recv)
+			 *    R = R_sample;
+			 * Else
+			 *    R = q*R+(1-q)*R_sample;
+			 */
+			if (s_state_ == TFRC_S_STATE_NO_FBACK){
+				s_state_ = TFRC_S_STATE_FBACK;
+				s_rtt_ = s_r_sample_;
+
+				if (s_use_osc_prev_)
+					s_r_sqmean_ = sqrt(s_r_sample_);
+			} else {
+				s_rtt_ = s_rtt_q_ * s_rtt_ + (1-s_rtt_q_)* s_r_sample_;
+				if (s_use_osc_prev_)
+					s_r_sqmean_ = s_rtt_q2_*s_r_sqmean_ + (1-s_rtt_q2_)*sqrt(s_r_sample_);
+			}
+			
+			debug("%f, DCCP/TFRC(%s)::tfrc_send_packet_recv() - New RTT estimate %f (last sample %f)\n", now(), name(), (double) s_rtt_, (double) s_r_sample_);
+
+			if (s_use_osc_prev_)
+				debug("%f, DCCP/TFRC(%s)::tfrc_send_packet_recv() - New Long term RTT estimate %f (last sample %f)\n", now(), name(), (double) s_r_sqmean_, (double) s_r_sample_);
+			/* Update timeout interval */
+			s_t_rto_ = 4*s_rtt_;
+		}
+
+		/* Update receive rate */
+		s_x_recv_ = (double) x_recv;   /* x_recv in bytes per second */
+
+		/* Update loss event rate */
+		if (pinv == 0)
+			s_p_ = 0;
+		else {
+			s_p_ = 1.0 / ((double) pinv);
+			
+			if(s_p_ < s_smallest_p_){
+				s_p_ = s_smallest_p_;
+				
+				debug("%f, DCCP/TFRC(%s)::tfrc_send_packet_recv() - Smallest value of p is used!\n", now(), name());
+			}
+		}
+    
+		/* unschedule no feedback timer */
+		s_timer_no_feedback_->cancel();
+
+		/* Update sending rate */
+		tfrc_updateX(now());
+
+		/* Update next send time */
+		s_t_nom_ -= s_t_ipi_;   /* revert to previous send time */
+		
+		/* Calculate new t_ipi */
+		CALCNEWTIPI(cb);
+		s_t_nom_ += s_t_ipi_; /* a new next send time */
+		/* Calculate new delta */
+		CALCNEWDELTA(cb);
+
+    
+		s_timer_send_->cancel();
+
+		if(detectQuiescence()){
+			send_ack_ = true;
+		}
+		output(false);
+		tfrc_send_packet_sent(NULL,0,-1); /* make sure we schedule next send time */
+  
+		/* remove all packets older than the one acked from history */
+		/* elm points to acked package! */
+
+		if(!use_ackv_remote_)
+			trimSendHistory(elm->seq_num_);
+		
+		/* Schedule no feedback timer to
+		 * expire in max(4*R, 2*s/X) 
+		 */
+		next_time_out = 2*((double) s_s_) / s_x_;
+
+		if (next_time_out < s_t_rto_)
+			next_time_out = s_t_rto_;
+
+		if (next_time_out <= 0.0){
+			fprintf(stderr,"%f, DCCP/TFRC(%s)::tfrc_send_packet_recv() - About to schedule no feedback timer in %f s.\n", now(), name(), next_time_out);
+			fflush(stdout);
+			abort();
+		}
+
+		s_timer_no_feedback_->sched(next_time_out);
+
+		debug("%f, DCCP/TFRC(%s)::tfrc_send_packet_recv() - Scheduled no feedback timer to expire in %f s\n", now(), name(), next_time_out);
+
+		/* set idle flag */
+		s_idle_ = 1;
+
+		break;
+	default:
+		fprintf(stderr,"%f, DCCP/TFRC(%s)::tfrc_send_packet_recv() - Illegal state!\n", now(), name());
+		fflush(stdout);
+		abort();
+		break;
+  }
+}
+
+/* Receiver side */
+
+/* Find a data packet in history
+ * args:  cb - ccb of receiver
+ *        elm - pointer to element (variable)
+ *        num - number in history (variable)
+ * returns:  elm points to found packet, otherwise NULL
+ */
+#define TFRC_RECV_FINDDATAPACKET(cb,elm,num) \
+  do{ \
+    elm = STAILQ_FIRST(&(r_hist_)); \
+      while((elm) != NULL){ \
+        if((elm)->type_ == DCCP_DATA || (elm)->type_ == DCCP_DATAACK) \
+          (num)--; \
+        if(num == 0) \
+          break; \
+        elm = STAILQ_NEXT((elm), linfo_); \
+      } \
+  } while (0)
+
+/* Calculate the average loss interval
+ * ret: average loss interval (1/p)
+ */
+double DCCPTFRCAgent::tfrc_calcImean(){
+	struct li_hist_entry *elm;
+	double I_tot;
+	double I_tot0 = 0.0;
+	double I_tot1 = 0.0;
+	double W_tot = 0.0;
+	int i;
+	elm = TAILQ_FIRST(&(r_li_hist_));
+
+	for (i = 0; i< r_num_w_; i++) {
+		if (elm == NULL)
+			goto I_panic;
+
+		I_tot0 = I_tot0 + (elm->interval_ * r_w_[i]);
+		W_tot = W_tot + r_w_[i];
+		elm = TAILQ_NEXT(elm, linfo_);
+	}
+	
+	elm = TAILQ_FIRST(&(r_li_hist_));
+	elm = TAILQ_NEXT(elm, linfo_);
+
+	for (i = 1; i <= r_num_w_; i++) {
+		if (elm == NULL)
+			goto I_panic;
+
+		I_tot1 = I_tot1 + (elm->interval_ * r_w_[i-1]);
+		elm = TAILQ_NEXT(elm, linfo_);
+	}
+
+	I_tot = I_tot0;       /* I_tot = max(I_tot0, I_tot1) */
+	if (I_tot0 < I_tot1)
+		I_tot = I_tot1;
+	
+	debug("%f, DCCP/TFRC(%s)::tfrc_calcImean() - I_tot0 %f, I_tot1 %f -> I_tot %f\n", now(), name(), I_tot0, I_tot1, I_tot);
+
+	if(I_tot < W_tot) 
+		I_tot = W_tot;
+	
+	return (I_tot/W_tot);
+
+ I_panic: fprintf(stderr,"%f, DCCP/TFRC(%s)::tfrc_calcImean() - Loss interval history is corrupt!\n", now(), name());
+	fflush(stdout);
+	abort();
+	return 0;
+}
+
+/* Prepare and send a feedback packet */
+void DCCPTFRCAgent::tfrc_recv_send_feedback(){
+	u_int32_t x_recv, pinv;
+	//u_int16_t t_elapsed;
+	struct r_hist_entry *elm;
+	int num;
+
+	if (r_p_ < 0.00000000025)  /* -> 1/p > 4 000 000 000 */
+		pinv = 0;
+	else
+		pinv = (u_int32_t) ((double) 1.0 / r_p_);
+
+	switch (r_state_){
+	case TFRC_R_STATE_NO_DATA :
+		x_recv = 0;
+		break;
+	case TFRC_R_STATE_DATA :
+		/* Calculate x_recv */
+		x_recv = (u_int32_t) calcXrecv();
+		break;
+	default:
+		fprintf(stderr,"%f, DCCP/TFRC(%s)::tfrc_recv_send_feedback() - Illegal state!\n", now(), name());
+		fflush(stdout);
+		abort();	
+		break;
+	}
+ 
+	/* Find largest win_count so far (data packet with highest seqnum so far) */
+	num = 1;
+	TFRC_RECV_FINDDATAPACKET(cb,elm,num);
+  
+	if(elm == NULL){
+		fprintf(stderr,"%f, DCCP/TFRC(%s)::tfrc_recv_send_feedback() - No data packet in history!\n", now(), name());
+		fflush(stdout);
+		abort();
+	}
+	
+	/* add options from variables above */
+	if(opt_->addOption(DCCP_TFRC_OPT_LOSS_EVENT_RATE, (u_char*) &pinv, 4) != DCCP_OPT_NO_ERR 
+	   || opt_->addOption(DCCP_TFRC_OPT_RECV_RATE, (u_char*) &x_recv, 4) != DCCP_OPT_NO_ERR){
+		debug("%f, DCCP/TFRC(%s)::tfrc_recv_send_feedback() - Can't add options. No feedback sent\n", now(), name());
+		//todo: remove option
+		return;
+	}
+
+	send_ack_ = true;
+
+	r_last_counter_ = elm->win_count_;  
+	r_seq_last_counter_ = elm->seq_num_;
+	r_t_last_feedback_ = now();   
+	r_bytes_recv_ = 0;
+
+	debug("%f, DCCP/TFRC(%s)::tfrc_recv_send_feedback() - Sending a feedback packet with pinv %u, x_recv %u, ack=%u (elm %u)\n",now(),name(),pinv, x_recv,seq_num_recv_, elm->seq_num_);
+
+	output_ = true;
+	output_flag_ = true;
+}
+
+
+/* Approximate the length of the first loss interval
+ * ret: the length of the first loss interval
+ */
+u_int32_t DCCPTFRCAgent::tfrc_recv_calcFirstLI(){
+	double x_recv, p;
+	u_int32_t temp, pinv;
+
+	//if we haven't got an r_rtt_ approximation yet
+	if (r_rtt_ == 0.0){
+		if (rtt_scheme_remote_ == DCCP_TFRC_RTT_SCHEME_WIN_COUNT){
+			double temp_rtt = r_rtt_;
+			sampleRTT(&temp_rtt, &temp);
+			r_rtt_ = temp_rtt;
+		} else
+			r_rtt_ = rtt_conn_est_;
+	}
+	
+	x_recv = calcXrecv();
+
+	debug("%f, DCCP/TFRC(%s)::tfrc_recv_calcFirstLI() - Receive rate: %f bytes/s\n", now(), name(), x_recv);
+
+	p = tfrc_calcP(r_s_,r_rtt_, x_recv);
+	pinv = (u_int32_t) ceil(1/p);
+
+	debug("%f, DCCP/TFRC(%s)::tfrc_recv_calcFirstLI() - Approximated p to %f -> pinv = interval length = %u  (xcalc/xrecv = %f)\n", now(), name(), p, pinv, tfrc_calcX(r_s_,r_rtt_,p) / x_recv);
+	
+	return pinv;
+}
+
+/* Update the loss interval history */
+void DCCPTFRCAgent::tfrc_recv_updateLI(){
+	struct r_hist_entry *elm;
+	struct li_hist_entry *li_elm = NULL;
+	u_int32_t seq_temp = 0;
+	u_int8_t win_start;
+	u_int8_t win_loss;
+	int debug_info = 0;
+	u_int32_t seq_start;
+	u_int32_t seq_end;
+	u_int32_t seq_loss;
+	int i = 0;
+	while(i < 2){
+		i++;
+		if(i == 1 && detectLossRecv(&seq_start, &seq_end, &win_loss)){
+			/* we have found a packet loss! */
+			seq_loss = seq_end;
+			debug("%f, DCCP/TFRC(%s)::tfrc_recv_updateLI() - Loss found: seqloss=%d, winloss=%d\n", now(), name(), seq_loss, win_loss);
+		} else if (i == 1) {
+			continue;
+		} else if (i == 2 && detectECNRecv(&seq_end, &win_loss)) {
+			seq_loss = seq_end;
+			debug("%f, DCCP/TFRC(%s)::tfrc_recv_updateLI() - ECN mark found: seqloss=%d, winloss=%d\n", now(), name(), seq_loss, win_loss);
+		} else
+			break;
+	
+		if(TAILQ_EMPTY(&(r_li_hist_))){
+			debug_info = 1;
+			/* first loss detected */
+			debug("%f, DCCP/TFRC(%s)::tfrc_recv_updateLI() - First loss event detected\n", now(), name());
+			
+			/* create history */
+			try{
+				for(i=0; i< r_num_w_+1; i++){
+					li_elm = new struct li_hist_entry;
+					
+					li_elm->interval_ = 0;
+					li_elm->seq_num_ = 0;
+					li_elm->win_count_ = 0;
+					TAILQ_INSERT_HEAD(&(r_li_hist_),li_elm,linfo_);
+				}
+			} catch (...) {
+				debug("%f, DCCP/TFRC(%s)::tfrc_recv_updateLI() - Not enough memory for loss interval history!\n", now(), name());
+				clearLIHistory();
+				return;
+			}
+			
+			li_elm->seq_num_ = seq_loss;
+			li_elm->win_count_ = win_loss;
+			
+			li_elm = TAILQ_NEXT(li_elm,linfo_);
+			/* add approx interval */
+			li_elm->interval_ = tfrc_recv_calcFirstLI();
+			
+		} else {  /* we have a loss interval history */
+			debug_info = 2;
+			/* Check if the loss is in the same loss event as interval start */
+			if ((TAILQ_FIRST(&(r_li_hist_)))->seq_num_ > seq_loss)
+				continue;
+			
+			win_start = (TAILQ_FIRST(&(r_li_hist_)))->win_count_;
+			if ((win_loss > win_start 
+			     && win_loss - win_start > win_count_per_rtt_) ||
+			    (win_loss < win_start
+			     && win_start - win_loss < ccval_limit_-win_count_per_rtt_)){
+				/* new loss event detected */
+				/* calculate last interval length */
+				if (seq_loss <= TAILQ_FIRST(&(r_li_hist_))->seq_num_){
+					fprintf(stderr, "seq_loss is less than last interval start\n");
+					fflush(stdout);
+					abort();
+				}
+				
+				seq_temp = seq_loss - TAILQ_FIRST(&(r_li_hist_))->seq_num_;
+
+				(TAILQ_FIRST(&(r_li_hist_)))->interval_ = seq_temp;
+				
+				debug("%f, DCCP/TFRC(%s)::tfrc_recv_updateLI() - New loss event detected\n", now(), name());
+				
+				/* Remove oldest interval */
+				li_elm = TAILQ_LAST(&(r_li_hist_),li_hist_head);
+				TAILQ_REMOVE(&(r_li_hist_),li_elm,linfo_);
+				
+				/* Create the newest interval */
+				li_elm->seq_num_ = seq_loss;
+				li_elm->win_count_ = win_loss;
+				
+				/* insert it into history */
+				TAILQ_INSERT_HEAD(&(r_li_hist_),li_elm,linfo_);	
+			} else
+				debug("%f, DCCP/TFRC(%s)::tfrc_recv_updateLI() - Loss belongs to previous loss event\n", now(), name());
+		}
+	}
+	
+	if(TAILQ_FIRST(&(r_li_hist_)) != NULL){
+		/* calculate interval to last loss event */
+
+		elm = STAILQ_FIRST(&r_hist_);
+		if (elm->seq_num_ < TAILQ_FIRST(&(r_li_hist_))->seq_num_){
+			fprintf(stderr, "updating the recent li : seq_num_%d < last_loss_start %d\n",elm->seq_num_, TAILQ_FIRST(&(r_li_hist_))->seq_num_);
+			fflush(stdout);
+			abort();
+		}
+		seq_temp = elm->seq_num_-
+			TAILQ_FIRST(&(r_li_hist_))->seq_num_;
+
+		(TAILQ_FIRST(&(r_li_hist_)))->interval_ = seq_temp;
+		if (debug_info > 0){
+			debug("%f, DCCP/TFRC(%s)::tfrc_recv_updateLI() - Highest data packet received %u\n", now(), name(), elm->seq_num_);
+
+		}
+
+	}
+}
+
+
+/* Similar to recv_packetRecv */
+void DCCPTFRCAgent::tfrc_recv_packet_recv(Packet* pkt, int dataSize){
+	hdr_dccp *dccph = hdr_dccp::access(pkt);
+	//hdr_dccpack *dccpah = hdr_dccpack::access(pkt);
+	struct r_hist_entry *packet;
+	u_int8_t win_count = 0;
+	double p_prev; 
+	bool ins = false;
+	u_int32_t trim_to;
+	double temp_rtt;
+	if(!(r_state_ == TFRC_R_STATE_NO_DATA || r_state_ == TFRC_R_STATE_DATA)){
+		fprintf(stderr,"%f, DCCP/TFRC(%s)::tfrc_recv_packet_recv() - Illegal state!\n", now(), name());
+		fflush(stdout);
+		abort();	
+		return;
+	}
+
+	if (r_rtt_ <= 0.0){  //initiate the rtt estimate
+		if (rtt_scheme_remote_ == DCCP_TFRC_RTT_SCHEME_WIN_COUNT){
+			temp_rtt = r_rtt_;
+			sampleRTT(&temp_rtt, &trim_to);
+			r_rtt_ = temp_rtt;
+		} else {
+			r_rtt_ = rtt_conn_est_;
+			trim_to = dccph->seq_num_;
+		}
+	}
+	
+	/* Check which type */
+	switch(dccph->type_){
+	case DCCP_ACK:
+		if(r_state_ == TFRC_R_STATE_NO_DATA)
+			return;
+		break;
+	case DCCP_DATA:
+	case DCCP_DATAACK:
+		break;
+	default:
+		fprintf(stderr,"%f, DCCP/TFRC(%s)::tfrc_recv_packet_recv() - Received wrong packet type!\n", now(), name());
+		fflush(stdout);
+		abort();	
+		return;
+	}
+	
+	/* Add packet to history */
+	
+	packet = new struct r_hist_entry;
+	
+	if (packet == NULL){
+		debug("%f, DCCP/TFRC(%s)::tfrc_recv_packet_recv() - Not enough memory to add received packet to history (consider it lost)!\n", now(), name());
+		return;
+	}
+	
+	packet->t_recv_ = now();
+	packet->seq_num_ = dccph->seq_num_;
+	packet->type_ = dccph->type_;
+	packet->ndp_ = dccph->ndp_;
+	packet->size_ = dataSize;
+	packet->ecn_ = getECNCodePoint(pkt);
+	win_count = dccph->ccval_;
+	packet->win_count_ = dccph->ccval_; 
+
+	ins = insertInRecvHistory(packet);
+
+	if (!ins){  //packet insertion failed
+		delete packet;
+		return;
+	}
+       
+		
+	if (dccph->type_ != DCCP_ACK){
+		if (rtt_scheme_remote_ == DCCP_TFRC_RTT_SCHEME_WIN_COUNT){
+			temp_rtt = r_rtt_;
+			sampleRTT(&temp_rtt, &trim_to);
+			r_rtt_ = temp_rtt;
+		} else {
+			r_rtt_ = rtt_conn_est_;
+			trim_to = dccph->seq_num_;
+		}
+		debug("%f, DCCP/TFRC(%s)::tfrc_recv_packet_recv() - RTT estimated to %f (last seq %d)\n", now(), name(), (double) r_rtt_, trim_to);
+	}
+	        switch (r_state_){
+		case TFRC_R_STATE_NO_DATA :
+			if (dccph->type_ != DCCP_ACK){
+				debug("%f, DCCP/TFRC(%s)::tfrc_recv_packet_recv() - Sending the initial feedback packet\n", now(), name());
+				tfrc_recv_send_feedback();
+				r_state_ = TFRC_R_STATE_DATA;
+			}
+			break;
+		case TFRC_R_STATE_DATA : 
+			r_bytes_recv_ = r_bytes_recv_ + dataSize;
+
+			/* find loss events */
+			tfrc_recv_updateLI();
+			p_prev = r_p_;
+			
+			/* Calculate loss event rate */
+			if(!TAILQ_EMPTY(&(r_li_hist_))){
+				r_p_ = 1/tfrc_calcImean();
+			}  
+			/* check send conditions then send */
+			if(r_p_ > p_prev){
+				debug("%f, DCCP/TFRC(%s)::tfrc_recv_packet_recv() - Sending a feedback packet because p>p_prev\n", now(), name());
+				tfrc_recv_send_feedback();
+				trimRecvHistory(now() - r_rtt_,trim_to);
+			} else if (dccph->type_ != DCCP_ACK) {
+				if (dccph->seq_num_ > r_seq_last_counter_){ 
+					/* the sequence number is newer than seq_last_count */
+					if ((win_count > r_last_counter_ 
+					     && win_count-r_last_counter_ >= win_count_per_rtt_) ||
+					    (win_count < r_last_counter_
+					     && r_last_counter_ - win_count <= ccval_limit_-win_count_per_rtt_)){
+						debug("%f, DCCP/TFRC(%s)::tfrc_recv_packet_recv() - Sending a feedback packet because one rtt has passed since last packet (diff in win_count %i)\n", now(), name(),(win_count-r_last_counter_+ccval_limit_) % ccval_limit_);
+						
+						tfrc_recv_send_feedback();
+						trimRecvHistory(now() - r_rtt_,trim_to);
+					}
+				}  
+			}  
+			break;
+		default:
+			fprintf(stderr,"%f, DCCP/TFRC(%s)::tfrc_recv_packet_recv() - Illegal state!\n", now(), name());
+			fflush(stdout);
+			abort();
+			break;
+		}
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff -urNU5 ns-2.33/dccp/dccp_tfrc.h ns-2.33-dccp/dccp/dccp_tfrc.h
--- ns-2.33/dccp/dccp_tfrc.h	1970-01-01 10:00:00.000000000 +1000
+++ ns-2.33-dccp/dccp/dccp_tfrc.h	2008-05-05 17:17:43.000000000 +1000
@@ -0,0 +1,539 @@
+/* -*-	Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
+
+/* Copyright (c) 2004  Nils-Erik Mattsson 
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: ns-233-dccp-1.patch 210 2008-05-13 03:43:55Z omehani $ */
+
+#ifndef ns_dccp_tfrc_h
+#define ns_dccp_tfrc_h
+
+#include "dccp.h"
+#include "bsd_queue.h"
+
+/* use traced variables */
+#define DCCP_TFRC_USE_TRACED_VARS
+
+#define DCCP_TFRC_CCID 3
+
+/* features */
+#define DCCP_TFRC_FEAT_LOSS_EVENT_RATE 192
+#define DCCP_TFRC_FEAT_RTT_SCHEME 191      /* experimental */
+
+/* rtt schemes (experimental) */
+#define DCCP_TFRC_RTT_SCHEME_WIN_COUNT 0
+#define DCCP_TFRC_RTT_SCHEME_OPTION 1
+
+#define DCCP_TFRC_FEAT_DEF_LOSS_EVENT_RATE 1
+#define DCCP_TFRC_FEAT_DEF_RTT_SCHEME DCCP_TFRC_RTT_SCHEME_WIN_COUNT
+
+/* options */
+#define DCCP_TFRC_OPT_LOSS_EVENT_RATE 192
+#define DCCP_TFRC_OPT_RECV_RATE 194
+#define DCCP_TFRC_OPT_RTT 191             /* experimental */
+#define DCCP_TFRC_OPT_RTT_UNIT 0.000001
+
+#define DCCP_TFRC_TIMER_SEND 128
+#define DCCP_TFRC_TIMER_NO_FEEDBACK 129
+
+#define DCCP_TFRC_MAX_WC_INC 5              /* limit increase in wc to this between two packets */
+#define DCCP_TFRC_WIN_COUNT_PER_RTT  4
+
+//quiescence
+#define DCCP_TFRC_MIN_T 0.2          //T value for quiescence detection
+#define DCCP_TFRC_QUIESCENCE_OPT_RATIO 1
+
+#define DCCP_TFRC_STD_PACKET_SIZE    500     /* standard packet size*/
+
+
+/* 
+ * TFRC sender 
+ */
+
+/* TFRC sender states */
+#define DCCP_TFRC_NUM_S_STATES 3
+enum dccp_tfrc_s_state { TFRC_S_STATE_NO_SENT = 0,
+			 TFRC_S_STATE_NO_FBACK = 1,
+			 TFRC_S_STATE_FBACK = 2 };
+
+/* Mechanism parameters */
+
+/* initial sending rate rfc 3448 */
+#define DCCP_TFRC_INIT_SEND_RATE DCCP_TFRC_STD_PACKET_SIZE
+
+#define DCCP_TFRC_OPSYS_TIME_GRAN    0.01    /* operating system timer granularity in s */
+#define DCCP_TFRC_SMALLEST_P         0.00001 /* smallest value of p allowed */
+
+#define DCCP_TFRC_RTT_Q   0.9   /* RTT Filter constant */ 
+#define DCCP_TFRC_RTT_Q2  0.9   /* Long term RTT filter constant */
+#define DCCP_TFRC_MBI  64.0     /* max backoff interval */
+#define DCCP_TFRC_INIT_RTO  2.0 /* initial rto value */
+
+
+/* Packet history */
+STAILQ_HEAD(s_hist_head,s_hist_entry); 
+ 
+struct s_hist_entry {
+	STAILQ_ENTRY(s_hist_entry) linfo_;   /* Tail queue. */
+	u_int32_t seq_num_;        /* Sequence number */
+	double t_sent_;            /* When the packet was sent */
+	u_int32_t win_count_;      /* Windowcounter for packet */
+	u_int8_t ecn_;             /* ecn nonce (0 or 1) sent */
+};
+
+
+/* 
+ * TFRC Receiver 
+ */
+
+/* TFRC receiver states */
+#define DCCP_TFRC_NUM_R_STATES 2
+enum dccp_tfrc_r_state { TFRC_R_STATE_NO_DATA = 0,
+			 TFRC_R_STATE_DATA = 1};
+
+/* Receiver mechanism parameters */
+#define DCCP_TFRC_NUM_W  8          /* length(w[]) */
+#define DCCP_TFRC_P_TOLERANCE 0.05  /* tolerance allowed when inverting the throughput equation */
+
+/* Packet history */
+STAILQ_HEAD(r_hist_head,r_hist_entry); 
+ 
+struct r_hist_entry {
+	STAILQ_ENTRY(r_hist_entry) linfo_;  /* Tail queue. */
+	u_int32_t seq_num_;        /* Sequence number */
+	double t_recv_;            /* When the packet was received */
+	u_int8_t win_count_;       /* Window counter for that packet */
+	dccp_packet_type type_;    /* Packet type received */
+	u_int8_t ndp_;             /* no data packets value */
+	u_int16_t size_;           /* size of data in packet */
+	dccp_ecn_codepoint ecn_;   /* ecn codepoint */
+};
+
+/* Loss interval history */
+TAILQ_HEAD(li_hist_head,li_hist_entry); 
+ 
+struct li_hist_entry {
+	TAILQ_ENTRY(li_hist_entry) linfo_;   /* Tail queue. */
+	u_int32_t interval_;       /* Loss interval */
+	u_int32_t seq_num_;        /* Sequence number of the packet that started the interval */
+	u_int8_t win_count_;       /* Window counter for previous received packet */
+};
+
+//forward decleration of class DCCPTCPlikeAgent
+class DCCPTFRCAgent;
+
+//The DCCPTFRCSendTimer sends packets according to a predetermined sending rate
+class DCCPTFRCSendTimer : public TimerHandler {
+protected:
+	DCCPTFRCAgent *agent_;    //the owning agent
+public:
+	/* Constructor
+	 * arg: agent - the owning agent (to notify about timeout)
+	 * ret: A new DCCPTFRCSendTimer
+	 */
+	DCCPTFRCSendTimer(DCCPTFRCAgent* agent);
+
+	/* Called when the timer has expired
+	 * arg: e - The event that happened (i.e. the timer expired)
+	 */
+	virtual void expire(Event *e);
+};
+
+/* The DCCPTFRCNoFeedbackTimer expires when no feedback has been received */ 
+class DCCPTFRCNoFeedbackTimer : public TimerHandler {
+protected:
+	DCCPTFRCAgent *agent_;    //the owning agent
+public:
+	/* Constructor
+	 * arg: agent - the owning agent (to notify about timeout)
+	 * ret: A new DCCPTFRCNoFeedbackTimer
+	 */
+	DCCPTFRCNoFeedbackTimer(DCCPTFRCAgent* agent);
+
+	/* Called when the timer has expired
+	 * arg: e - The event that happened (i.e. the timer expired)
+	 */
+	virtual void expire(Event *e);
+};
+
+/* The DCCPTFRC agent is based on the TFRC code from the FreeBSD
+ * implementation at www.dccp.org.
+ * If changes are made to tcl variables, the agent should be reset
+ * to enable all changes.
+ * Conforms to the October 2003 drafts.
+ */
+class DCCPTFRCAgent : public DCCPAgent {
+private:
+	/* The number of packets with higher sequence number needed before
+	 * a delayed packet is considered lost (similiar to NUMDUPACKS) */
+	int num_dup_acks_;
+
+	double p_tol_;              /* tolerance in p when inverting thrp eq */
+
+	//features
+	int use_loss_rate_local_;
+	int use_loss_rate_remote_;
+
+	int rtt_scheme_local_;
+	int rtt_scheme_remote_;
+	
+	int win_count_per_rtt_;     /* Number of wincount ticks in one RTT */
+	int max_wc_inc_;            /* Maximum increment of win count */
+	
+	double q_min_t_;            /* T value for quiescence detection */
+	//sender
+
+#ifdef DCCP_TFRC_USE_TRACED_VARS
+	TracedDouble s_x_;                /* Current sending rate (bytes/s) */
+	TracedDouble s_x_inst_;           /* Instantaneous send rate */
+	TracedDouble s_x_recv_;           /* Receive rate  (bytes/s) */
+	TracedDouble s_r_sample_;         /* Last rtt sample */
+	TracedDouble s_rtt_;              /* Estimate of current round trip time (s) */
+	TracedDouble s_r_sqmean_;         /* Long term rtt */
+	TracedDouble s_p_;                /* Current loss event rate */
+#else
+	double s_x_;                /* Current sending rate (bytes/s) */
+	double s_x_inst_;           /* Instantaneous send rate */
+	double s_x_recv_;           /* Receive rate  (bytes/s) */
+	double s_r_sample_;         /* Last rtt sample */
+	double s_rtt_;              /* Estimate of current round trip time (s) */
+	double s_r_sqmean_;         /* Long term rtt */
+	double s_p_;                /* Current loss event rate */
+#endif
+	double s_initial_x_;        /* Initial send rate (in bytes/s) */
+	double s_initial_rto_;      /* Initial timeout (in s) */
+	double s_rtt_q_;            /* RTT Filter constant */ 
+	double s_rtt_q2_;           /* Long term RTT filter constant */
+	double s_t_mbi_;            /* Max back-off interval (in s) */
+
+	int s_use_osc_prev_;        /* Use oscillation prevention? */
+
+	/* Timers */
+	DCCPTFRCSendTimer *s_timer_send_;
+	DCCPTFRCNoFeedbackTimer	*s_timer_no_feedback_;
+
+	dccp_tfrc_s_state s_state_; /* Sender state */
+	
+	double   s_x_calc_;         /* Calculated send rate (bytes/s) */ 
+	
+	int      s_s_;              /* Packet size (bytes) */
+
+	double   s_smallest_p_;     /* Smallest p value */
+	
+	u_int32_t s_last_win_count_; /* Last window counter sent */
+	u_int32_t s_wc_;             /* Window counter */
+	u_int32_t s_recv_wc_;        /* Last window counter of last ack packet */
+	double s_t_last_win_count_; /* Timestamp of earliest packet with
+				        last_win_count value sent */
+	u_int8_t s_idle_;
+	double   s_t_rto_;          /* Time out value = 4*rtt */
+	double   s_t_ld_;           /* Time last doubled during slow start */
+	
+	double   s_t_nom_,          /* Nominal send time of next packet */
+		 s_t_ipi_,          /* Interpacket (send) interval */
+		 s_delta_;          /* Send timer delta */    
+
+	double   s_os_time_gran_;   /* Operating system timer granularity */
+	
+	struct s_hist_head s_hist_; /* Packet history */
+	
+	u_int32_t s_hist_last_seq_; /* last sequence number in history */
+
+	
+	//quiescence
+	double s_t_last_data_sent_;  /* timestamp of when last data pkt was sent */ 
+	int s_q_opt_ratio_;          /* add Q opt on each opt ratio acks sent */
+	int s_q_packets_wo_opt_;     /* ack packets sent without Q opt */
+
+	/* Clear the send history */
+	void clearSendHistory();
+
+	/* Find a specific packet in the send history
+	 * arg: seq_num - sequence number of packet to find
+	 *      start_elm - start searching from this element
+	 * ret: pointer to the correct element if the element is found
+	 *      otherwise the closest packet with lower seq num is returned
+	 *      which can be NULL.
+	 */
+	struct s_hist_entry* findPacketInSendHistory(u_int32_t seq_num, s_hist_entry* start_elm);
+
+	/* Remove packets from send history
+	 * arg: trim_to - remove packets with lower sequence numbers than this
+	 * Note: if trim_to does not exist in the history, trim_to is set
+	 *       to the next lower sequence number found before trimming. 
+	 */
+	void trimSendHistory(u_int32_t trim_to);
+	
+	/* Prints the contents of the send history */
+	void printSendHistory();
+	
+	/* from project (slightly modified) */
+	
+	/* Halve the sending rate when no feedback timer expires */
+	void  tfrc_time_no_feedback();
+
+	/* Set the send timer
+	 * arg: t_now - time now
+	 */
+	void  tfrc_set_send_timer(double t_now);
+
+	/* Update the sending rate
+	 * arg: t_now - time now
+	 */
+	void  tfrc_updateX(double t_now);
+
+	/* Calculate sending rate from the throughput equation
+	 * arg: s - packet size (in bytes)
+	 *      R - round trip time (int seconds)
+	 *      p - loss event rate
+	 * ret: maximum allowed sending rate
+	 */
+	double tfrc_calcX(u_int16_t s, double R, double p);
+
+	/* Find the loss event rate corresponding to a send rate
+	 * in the TCP throughput eq.
+	 * args: s - packet size (in bytes)
+	 *       R - Round trip time  (in seconds)
+	 *       x - send rate (in bytes/s)
+	 * returns:  the loss eventrate accurate to 5% with resp. to x
+	 */
+	double tfrc_calcP(u_int16_t s, double R, double x);
+
+	/* Similar to send_askPermToSend(), send_packetSent(), send_packetRecv() */
+	int tfrc_send_packet(int datasize);
+	void tfrc_send_packet_sent(Packet *pkt, int moreToSend, int datasize);
+	void tfrc_send_packet_recv(Packet *pkt);
+
+	//receiver
+
+#ifdef DCCP_TFRC_USE_TRACED_VARS
+	TracedDouble    r_rtt_;          //receivers estimation of rtt
+	TracedDouble    r_p_;            /* Loss event rate */
+#else
+	double    r_rtt_;                //receivers estimation of rtt
+	double    r_p_;                  /* Loss event rate */
+#endif
+	dccp_tfrc_r_state r_state_;      /* Receiver state */
+	
+	struct li_hist_head r_li_hist_;  /* Loss interval history */
+	
+	u_int8_t  r_last_counter_;       /* Highest value of the window counter
+                                            received when last feedback was sent */
+	u_int32_t r_seq_last_counter_;   /* Sequence number of the packet above */
+	
+	double    r_t_last_feedback_;    /* Timestamp of when last feedback was sent */
+	u_int32_t r_bytes_recv_;         /* Bytes received since t_last_feedback */
+	
+	struct r_hist_head r_hist_;      /* Packet history */
+	
+	int       r_s_;                  /* Packet size */
+
+	int r_num_w_;                    /* Number of weights */
+	double *r_w_;                    /* Weights */
+	
+	u_int32_t r_high_seq_recv_;      //highest sequence number received 
+	int       r_high_ndp_recv_;      //ndp value of high_seq_recv_ 
+	double    r_t_high_recv_;        //timestamp of high_seq_recv_
+	r_hist_entry *r_last_data_pkt_;  //pointer to last data packet recv
+	
+	//quiescence
+	double r_q_t_data_;             //timestamp of last data pkt observed
+	bool r_sender_quiescent_;      //the sender is quiescent (q opt recv)
+
+	/* Clear the history of received packets */
+	void clearRecvHistory();
+
+	/* Insert a packet in the receive history
+	 * Will not insert "lost" packets or duplicates.
+	 * arg: packet - entry representing the packet to insert
+	 * ret: true if packet was inserted, otherwise false.
+	 */
+	bool insertInRecvHistory(r_hist_entry *packet);
+
+	/* Prints the contents of the receive history */
+	void printRecvHistory();
+
+	/* Trim receive history
+	 * arg: time - remove packet with recv time less than this
+	 *      seq_num - remove packet with seq num less than this
+	 * Note: both of the above condition must be true for a packet
+	 *       to be removed. Furthermore, the function always keeps
+	 *       at least num_dup_acks_ packets in the history.
+	 */
+	void trimRecvHistory(double time, u_int32_t seq_num);
+
+	/* Remove all acks after the num_dup_acks_ limit */
+	void removeAcksRecvHistory();
+
+	/* Find a data packet in the receive history
+	 * arg: start - pointer to the first packet to search from
+	 * ret: pointer to the found data packet or
+	 *      or NULL if none is found.
+         */
+	r_hist_entry *findDataPacketInRecvHistory(r_hist_entry *start);
+
+	/* Detects packet loss in recv history.
+	 * arg: seq_start, seq_end - the lost packet is in [start,end]
+	 *      win_count          - window counter of packet before the loss
+	 * ret: true if a packet loss was detected, otherwise false.
+	 */
+	bool detectLossRecv(u_int32_t *seq_start, u_int32_t *seq_end, u_int8_t *win_count);
+
+	/* Detect packet marks in recv history before num_dup_ack limit.
+	 * arg: seq_num - sequence number of marked packet (if any)
+	 *      win_count - win_count of marked packet (if any)
+	 * ret: true if a packet mark was found, otherwise false.
+	 */
+	bool detectECNRecv(u_int32_t *seq_num, u_int8_t *win_count);
+
+	/* Calculate the total amount of data in recent packets.
+	 * arg: time - sum data in packets received later than this time
+	 * ret: total amount of data
+	 */
+	u_int32_t sumPktSizes(double time);
+
+	/* Sample the round trip time
+	 * arg: rtt - the obtained rtt
+	 *      last_seq - sequence number of oldest packet used
+	 * ret: true if the rtt could succesfully be estimated from wc
+	 *      false otherwise. Note that rtt above is always valid.
+	 * Note: If not enough packets exist to use wc to estimate rtt,
+	 *       the rtt measured on handshake packets are used.
+	 *       The function will disregard packets with wc >= max_wc_inc_. 
+	 */
+	bool sampleRTT(double *rtt, u_int32_t *last_seq);
+
+
+	/* Calculate the receive rate to send on feedbacks
+	 * ret: the receive rate
+	 */
+	double calcXrecv();
+
+	/* Clear the loss event history */
+	void clearLIHistory();
+
+	/* Print the loss event history */
+	void printLIHistory();
+	
+	/* Detects quiescence of the corresponding sender
+	 * ret: true if sender is quiescent
+	 *      false otherwise
+	 */ 
+	bool detectQuiescence();
+
+	/* from project (slightly modified) */
+
+	/* Calculate the average loss interval
+	 * ret: average loss interval (1/p)
+	 */
+	double tfrc_calcImean();
+
+	/* Prepare and send a feedback packet */
+	void tfrc_recv_send_feedback();
+
+	/* Approximate the length of the first loss interval
+	 * ret: the length of the first loss interval
+	 */
+	u_int32_t tfrc_recv_calcFirstLI();
+
+	/* Update the loss interval history */
+	void tfrc_recv_updateLI();
+
+	/* Similar to recv_packetRecv */
+	void tfrc_recv_packet_recv(Packet* pkt, int dataSize);
+	
+protected:
+	
+	/* Methods inherited from DCCPAgent.
+	 * See dccp.h For detailed information regarding arguments etc.
+	 */
+	
+	virtual void delay_bind_init_all();
+        virtual int delay_bind_dispatch(const char *varName, const char *localName, TclObject *tracer);
+	
+	virtual void reset();
+	virtual void cancelTimers();
+
+	/* Process incoming options.
+	 * This function will process:
+	 *      ack vectors (verify ECN Nonce Echo)
+	 *      quiescence option
+	 *      rtt option
+	 */
+	virtual bool processOption(u_int8_t type, u_char* data, u_int8_t size, Packet *pkt);
+
+	virtual void buildInitialFeatureList();
+
+	virtual int setFeature(u_int8_t num, dccp_feature_location location,
+			       u_char* data, u_int8_t size, bool testSet = false);
+
+	virtual int getFeature(u_int8_t num, dccp_feature_location location,
+			       u_char* data, u_int8_t maxSize);
+	
+	virtual dccp_feature_type getFeatureType(u_int8_t num);
+	
+	virtual bool send_askPermToSend(int dataSize, Packet *pkt);
+	virtual void send_packetSent(Packet *pkt, bool moreToSend, int dataSize);
+	virtual void send_packetRecv(Packet *pkt, int dataSize);
+	virtual void recv_packetRecv(Packet *pkt, int dataSize);
+
+	virtual void traceAll();
+	virtual void traceVar(TracedVar* v);
+public:
+	/* Constructor
+	 * ret: a new DCCPTCPlikeAgent
+	 */
+	DCCPTFRCAgent();
+	
+	/* Destructor */
+	virtual ~DCCPTFRCAgent();
+
+	/* Process a "function call" from OTCl
+         * 
+	 * Supported function call handled by this agent:
+	 * weights <count>+<w1>+<w2>....  - set the weights for avg li calc.
+	 * example  $dccp weights 8+1.0+1.0+1.0+1.0+0.8+0.6+0.4+0.2
+	 */
+	int command(int argc, const char*const* argv);
+
+	/* A timeout has occured
+	 * arg: tno - id of timeout event
+	 * Handles: Send timer - DCCP_TFRC_TIMER_SEND
+	 *          No feedback timer - DCCP_TFRC_TIMER_NO_FEEDBACK
+	 */
+	virtual void timeout(int tno);
+
+};
+#endif
+
+
+
+
+
+
+
+
+
diff -urNU5 ns-2.33/dccp/dccp_types.h ns-2.33-dccp/dccp/dccp_types.h
--- ns-2.33/dccp/dccp_types.h	1970-01-01 10:00:00.000000000 +1000
+++ ns-2.33-dccp/dccp/dccp_types.h	2008-05-05 17:17:43.000000000 +1000
@@ -0,0 +1,100 @@
+/* -*-	Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
+
+/* Copyright (c) 2004  Nils-Erik Mattsson 
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: ns-233-dccp-1.patch 210 2008-05-13 03:43:55Z omehani $ */
+
+#ifndef ns_dccp_types_h
+#define ns_dccp_types_h
+
+#define DCCP_NUM_PTYPES 8
+
+enum dccp_packet_type {
+     DCCP_REQUEST = 0, DCCP_RESPONSE = 1, DCCP_DATA = 2,
+     DCCP_ACK = 3, DCCP_DATAACK = 4, DCCP_CLOSEREQ = 5,
+     DCCP_CLOSE = 6, DCCP_RESET = 7
+};
+
+#define DCCP_IP_HDR_SIZE 20
+#define DCCP_GEN_HDR_SIZE 12+DCCP_IP_HDR_SIZE
+
+#define DCCP_REQ_HDR_SIZE   4+DCCP_GEN_HDR_SIZE
+#define DCCP_RESP_HDR_SIZE  4+DCCP_GEN_HDR_SIZE
+#define DCCP_DATA_HDR_SIZE  0+DCCP_GEN_HDR_SIZE
+#define DCCP_ACK_HDR_SIZE   4+DCCP_GEN_HDR_SIZE
+#define DCCP_DACK_HDR_SIZE  4+DCCP_GEN_HDR_SIZE
+#define DCCP_CREQ_HDR_SIZE  4+DCCP_GEN_HDR_SIZE
+#define DCCP_CLOSE_HDR_SIZE 4+DCCP_GEN_HDR_SIZE
+#define DCCP_RESET_HDR_SIZE 8+DCCP_GEN_HDR_SIZE
+
+#define DCCP_NDP_LIMIT 8
+#define DCCP_CCVAL_LIMIT 16
+
+#define DCCP_NUM_RESET_REASONS 17
+
+enum dccp_reset_reason {
+	DCCP_RST_UNSPEC = 0, DCCP_RST_CLOSED = 1,
+	DCCP_RST_INVALID_PKT = 2, DCCP_RST_OPT_ERR = 3,
+	DCCP_RST_FEATURE_ERR = 4, DCCP_RST_CONN_REF = 5,
+	DCCP_RST_BAD_SNAME = 6, DCCP_RST_TOO_BUSY = 7,
+	DCCP_RST_BAD_INITC = 8, DCCP_RST_UNANSW_CHAL = 10,
+	DCCP_RST_FLESS_NEG = 11, DCCP_RST_AGG_PEN = 12,
+	DCCP_RST_NO_CONN = 13, DCCP_RST_ABORTED = 14,
+	DCCP_RST_EXT_SEQ = 15, DCCP_RST_MANDATORY = 16
+};
+
+#define DCCP_NUM_STATES 7
+
+enum dccp_state { DCCP_STATE_CLOSED, DCCP_STATE_LISTEN,
+		  DCCP_STATE_RESPOND, DCCP_STATE_REQUEST,
+		  DCCP_STATE_OPEN, DCCP_STATE_CLOSEREQ,
+		  DCCP_STATE_CLOSING //, DCCP_STATE_TIMEWAIT
+};
+
+#define DCCP_NUM_FEAT_LOCS 2
+
+enum dccp_feature_location { DCCP_FEAT_LOC_LOCAL = 0,
+			     DCCP_FEAT_LOC_REMOTE = 1 };
+
+enum dccp_feature_type { DCCP_FEAT_TYPE_SP = 0,
+			 DCCP_FEAT_TYPE_NN = 1,
+                         DCCP_FEAT_TYPE_UNKNOWN = 3};
+
+#define DCCP_NUM_PACKET_STATES 4
+
+enum dccp_packet_state { DCCP_PACKET_RECV = 0, DCCP_PACKET_ECN = 1,
+			 DCCP_PACKET_RESERVED = 2, DCCP_PACKET_NOT_RECV = 3};
+
+enum dccp_ecn_codepoint { ECN_ECT0 = 0, ECN_ECT1 = 1,
+			   ECN_NOT_ECT = 2, ECN_CE = 3 };
+
+#endif
+
+
+
+
+
diff -urNU5 ns-2.33/Makefile.in ns-2.33-dccp/Makefile.in
--- ns-2.33/Makefile.in	2008-04-01 13:00:08.000000000 +1100
+++ ns-2.33-dccp/Makefile.in	2008-05-05 17:18:48.000000000 +1000
@@ -208,10 +208,17 @@
 	sctp/sctp-timestamp.o sctp/sctp-hbAfterRto.o \
 	sctp/sctp-multipleFastRtx.o sctp/sctp-mfrHbAfterRto.o \
 	sctp/sctp-mfrTimestamp.o \
 	sctp/sctp-cmt.o \
 	sctp/sctpDebug.o \
+ 	dccp/dccp_sb.o \
+ 	dccp/dccp_opt.o \
+ 	dccp/dccp_ackv.o \
+ 	dccp/dccp_packets.o \
+ 	dccp/dccp.o \
+ 	dccp/dccp_tcplike.o \
+ 	dccp/dccp_tfrc.o \
 	tools/integrator.o tools/queue-monitor.o \
 	tools/flowmon.o tools/loss-monitor.o \
 	queue/queue.o queue/drop-tail.o \
 	adc/simple-intserv-sched.o queue/red.o \
 	queue/semantic-packetqueue.o queue/semantic-red.o \
diff -urNU5 ns-2.33/tcl/lib/ns-default.tcl ns-2.33-dccp/tcl/lib/ns-default.tcl
--- ns-2.33/tcl/lib/ns-default.tcl	2008-04-01 13:00:23.000000000 +1100
+++ ns-2.33-dccp/tcl/lib/ns-default.tcl	2008-05-05 17:22:01.000000000 +1000
@@ -1448,10 +1448,130 @@
 
 # Quick Start definitions end here
 
 Delayer set debug_ false
 
+# DCCP
+# A description of each parameter can be found in the agents' header files
+# i.e.  dccp/dccp.h  dccp/dccp_tcplike.h  dccp/dccp_tfrc.h
+
+Agent/DCCP set packetSize_ 500
+
+Agent/DCCP set initial_rtx_to_ 3.0
+Agent/DCCP set max_rtx_to_ 75.0
+Agent/DCCP set resp_to_ 75.0
+
+Agent/DCCP set sb_size_ 1000
+Agent/DCCP set opt_size_ 512
+Agent/DCCP set feat_size_ 24
+Agent/DCCP set ackv_size_ 20
+
+Agent/DCCP set ccid_ 0
+Agent/DCCP set use_ecn_local_ 0
+Agent/DCCP set use_ecn_remote_ 0
+Agent/DCCP set ack_ratio_local_ 2
+Agent/DCCP set ack_ratio_remote_ 2
+Agent/DCCP set use_ackv_local_ 0
+Agent/DCCP set use_ackv_remote_ 0
+Agent/DCCP set q_scheme_ 0
+Agent/DCCP set q_local_ 0
+Agent/DCCP set q_remote_ 0
+
+Agent/DCCP set snd_delay_ 0.0001
+
+Agent/DCCP set nam_tracevar_ false
+Agent/DCCP set trace_all_oneline_ false
+
+Agent/DCCP set allow_mult_neg_ 0
+Agent/DCCP set ndp_limit_ 8
+Agent/DCCP set ccval_limit_ 16
+
+Agent/DCCP set cscov_ 0
+
+Agent/DCCP set num_data_pkt_ 0
+Agent/DCCP set num_ack_pkt_ 0
+Agent/DCCP set num_dataack_pkt_ 0
+
+Agent/DCCP/TCPlike set ccid_ 2
+Agent/DCCP/TCPlike set use_ecn_local_ 1
+Agent/DCCP/TCPlike set use_ecn_remote_ 1
+Agent/DCCP/TCPlike set use_ackv_local_ 1
+Agent/DCCP/TCPlike set use_ackv_remote_ 1
+
+Agent/DCCP/TCPlike set initial_cwnd_ 3
+Agent/DCCP/TCPlike set cwnd_timeout_ 1
+Agent/DCCP/TCPlike set initial_ssthresh_ 65535
+Agent/DCCP/TCPlike set cwnd_ 2
+Agent/DCCP/TCPlike set cwnd_frac_ 0
+Agent/DCCP/TCPlike set ssthresh_ 20
+Agent/DCCP/TCPlike set pipe_ 0
+
+Agent/DCCP/TCPlike set initial_rto_ 3.0
+Agent/DCCP/TCPlike set min_rto_ 1.0
+Agent/DCCP/TCPlike set rto_ 3.0
+Agent/DCCP/TCPlike set srtt_ -1.0
+Agent/DCCP/TCPlike set rttvar_ 0.0
+Agent/DCCP/TCPlike set rtt_sample_ 0.0
+Agent/DCCP/TCPlike set alpha_ 0.125
+Agent/DCCP/TCPlike set beta_ 0.25
+Agent/DCCP/TCPlike set k_ 4
+Agent/DCCP/TCPlike set g_ 0.01
+Agent/DCCP/TCPlike set num_dup_acks_ 3
+
+Agent/DCCP/TCPlike set q_min_t_ 0.2
+Agent/DCCP/TCPlike set q_opt_ratio_ 1
+Agent/DCCP/TCPlike set dack_delay_ 0.2
+
+Agent/DCCP/TCPlike set ackv_size_lim_ 10
+
+Agent/DCCP/TFRC set ccid_ 3
+Agent/DCCP/TFRC set use_ecn_local_ 1
+Agent/DCCP/TFRC set use_ecn_remote_ 1
+Agent/DCCP/TFRC set use_ackv_local_ 1
+Agent/DCCP/TFRC set use_ackv_remote_ 1
+Agent/DCCP/TFRC set use_loss_rate_local_ 1
+Agent/DCCP/TFRC set use_loss_rate_remote_ 1
+Agent/DCCP/TFRC set rtt_scheme_local_ 0
+Agent/DCCP/TFRC set rtt_scheme_remote_ 0
+
+Agent/DCCP/TFRC set num_dup_acks_ 3
+Agent/DCCP/TFRC set p_tol_ 0.05
+Agent/DCCP/TFRC set win_count_per_rtt_ 4
+Agent/DCCP/TFRC set max_wc_inc_ 5
+
+Agent/DCCP/TFRC set s_use_osc_prev_ 1
+
+Agent/DCCP/TFRC set s_x_ 500.0
+Agent/DCCP/TFRC set s_x_inst_ 500.0
+Agent/DCCP/TFRC set s_x_recv_ 0.0
+Agent/DCCP/TFRC set s_r_sample_ 0.0
+Agent/DCCP/TFRC set s_rtt_ 0.0
+Agent/DCCP/TFRC set s_r_sqmean_ 0.0
+
+Agent/DCCP/TFRC set s_smallest_p_ 0.00001
+Agent/DCCP/TFRC set s_rtt_q_ 0.9
+Agent/DCCP/TFRC set s_rtt_q2_ 0.9
+Agent/DCCP/TFRC set s_t_mbi_ 64.0
+Agent/DCCP/TFRC set s_os_time_gran_ 0.01
+
+Agent/DCCP/TFRC set s_s_ 500
+Agent/DCCP/TFRC set s_initial_x_ 500.0
+Agent/DCCP/TFRC set s_initial_rto_ 2.0
+Agent/DCCP/TFRC set s_x_ 500.0
+Agent/DCCP/TFRC set s_x_inst_ 500.0
+Agent/DCCP/TFRC set s_x_recv_ 0.0
+Agent/DCCP/TFRC set s_r_sample_ 0.0
+Agent/DCCP/TFRC set s_rtt_ 0.0
+Agent/DCCP/TFRC set s_r_sqmean_ 0.0
+Agent/DCCP/TFRC set s_p_ 0.0
+Agent/DCCP/TFRC set s_q_opt_ratio_ 1
+
+Agent/DCCP/TFRC set r_s_ 500
+Agent/DCCP/TFRC set r_rtt_ 0.0
+Agent/DCCP/TFRC set r_p_ 0.0
+Agent/DCCP/TFRC set q_min_t_ 0.2
+
 Agent/TCP/Linux set rtxcur_init_ 3
 Agent/TCP/Linux set maxrto_ 120
 Agent/TCP/Linux set minrto_ 0.2
 Agent/TCP/Linux set ts_resetRTO_ true
 Agent/TCP/Linux set next_pkts_in_flight_ 0
diff -urNU5 ns-2.33/tcl/lib/ns-packet.tcl ns-2.33-dccp/tcl/lib/ns-packet.tcl
--- ns-2.33/tcl/lib/ns-packet.tcl	2008-04-01 13:00:23.000000000 +1100
+++ ns-2.33-dccp/tcl/lib/ns-packet.tcl	2008-05-05 17:17:43.000000000 +1000
@@ -148,10 +148,19 @@
 	TCP 	# TCP, transport protocol
 	TCPA 	# Asymmetric TCP, transport protocol
 	TFRC 	# TFRC, transport protocol
 	TFRC_ACK 	# TFRC, transport protocol
 	XCP 	# XCP, transport protocol
+	DCCP            # DCCP, transport protocol
+	DCCP_ACK        # DCCP, transport protocol
+	DCCP_RESET      # DCCP, transport protocol
+	DCCP_REQ        # DCCP, transport protocol
+	DCCP_RESP       # DCCP, transport protocol
+	DCCP_DATA       # DCCP, transport protocol
+	DCCP_DATAACK    # DCCP, transport protocol
+	DCCP_CLOSE      # DCCP, transport protocol
+	DCCP_CLOSEREQ   # DCCP, transport protocol
 # Application-Layer Protocols:
 	Message # a protocol to carry text messages
 	Ping 	# Ping
     PBC     # PBC
 # Wireless:

