diff -NruF^f sys-orig/conf/files sys/conf/files
--- sys-orig/conf/files	Thu Apr 13 04:09:27 2006
+++ sys/conf/files	Thu Aug 24 06:32:15 2006
@@ -1628,6 +1628,10 @@ fs/unionfs/union_vnops.c	optional unionf
 netinet/tcp_timer.c		optional inet
 netinet/tcp_usrreq.c		optional inet
 netinet/udp_usrreq.c		optional inet
+netinet/dccp_usrreq.c   	optional inet
+netinet/dccp_cc_sw.c    	optional inet
+netinet/dccp_tfrc.c     	optional inet
+netinet/dccp_tcplike.c		optional inet
 netinet/libalias/alias.c	optional libalias
 netinet/libalias/alias_cuseeme.c optional libalias
 netinet/libalias/alias_db.c	optional libalias
diff -NruF^f sys-orig/i386/conf/GENERIC sys/i386/conf/GENERIC
--- sys-orig/i386/conf/GENERIC	Mon May  1 10:15:12 2006
+++ sys/i386/conf/GENERIC	Thu Aug 24 06:32:15 2006
@@ -22,7 +22,7 @@
 cpu		I486_CPU
 cpu		I586_CPU
 cpu		I686_CPU
-ident		GENERIC
+ident		GENERIC_DCCP
 
 # To statically compile in device wiring instead of /boot/device.hints
 #hints		"GENERIC.hints"		# Default places to look for devices.
diff -NruF^f sys-orig/kern/subr_witness.c sys/kern/subr_witness.c
--- sys-orig/kern/subr_witness.c	Thu Apr 20 02:00:05 2006
+++ sys/kern/subr_witness.c	Thu Aug 24 06:32:15 2006
@@ -323,6 +323,13 @@
 	{ "tcpinp", &lock_class_mtx_sleep },
 	{ "so_snd", &lock_class_mtx_sleep },
 	{ NULL, NULL },
+        /*
+	 * DCCP
+	 */
+        { "dccp", &lock_class_mtx_sleep },
+        { "dccpinp", &lock_class_mtx_sleep },
+        { "so_snd", &lock_class_mtx_sleep },
+        { NULL, NULL },
 	/*
 	 * SLIP
 	 */
+++ sys/netinet/dccp.h	Fri Aug 25 04:03:09 2006
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2003 Joacim Häggmark, Magnus Erixzon, 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: dccp.h,v 1.13 2003/07/31 11:14:41 joahag-9 Exp $
+ */
+
+#ifndef _NETINET_DCCP_H_
+#define _NETINET_DCCP_H_
+
+/*
+ * DCCP protocol header
+ * draft-ietf-dccp-spec-01.txt 
+ */
+struct dccphdr {
+	u_short		dh_sport;	/* source port */
+	u_short		dh_dport;	/* destination port */
+#if BYTE_ORDER == LITTLE_ENDIAN
+	u_int32_t	dh_res:4,	/* Reserved */
+			dh_type:4,	/* Type of message */
+			dh_seq:24;	/* Sequence number */
+#else
+	u_int32_t	dh_type:4,
+			dh_res:4,
+			dh_seq:24;	
+#endif
+
+	u_int8_t	dh_off;		/* Data offset */
+#if BYTE_ORDER == LITTLE_ENDIAN
+	u_int8_t	dh_cslen:4,	/* Checksum Length */
+			dh_ndp:4;	/* Number of non data packets */
+#else
+	u_int8_t	dh_ndp:4,
+			dh_cslen:4;
+#endif
+
+	u_short		dh_sum;		/* Checksum */
+};
+
+struct dccp_requesthdr {
+	u_int32_t	drqh_sname;	/* Service Name */
+};
+
+struct dccp_ackhdr {
+#if BYTE_ORDER == LITTLE_ENDIAN
+	u_int32_t	dah_res:8,	/* Reserved */
+			dah_ack:24;	/* Acknowledgement number */
+#else
+	u_int32_t	dah_ack:24,
+			dah_res:8;
+#endif
+};
+
+
+struct dccp_resethdr {
+#if BYTE_ORDER == LITTLE_ENDIAN
+	u_int32_t	drth_res:8,	/* Reserved */
+			drth_ack:24;	/* Acknowledgement number */
+#else
+	u_int32_t	drth_ack:24,
+			drth_res:8;
+#endif
+	u_int8_t	drth_reason;	/* Reason */
+	u_int8_t	drth_data1;	/* Data 1 */
+	u_int8_t	drth_data2;	/* Data 2 */
+	u_int8_t	drth_data3;	/* Data 3 */
+};
+
+#define DCCP_TYPE_REQUEST	0
+#define DCCP_TYPE_RESPONSE	1
+#define DCCP_TYPE_DATA		2
+#define DCCP_TYPE_ACK		3
+#define DCCP_TYPE_DATAACK	4
+#define DCCP_TYPE_CLOSEREQ	5
+#define DCCP_TYPE_CLOSE		6
+#define DCCP_TYPE_RESET		7
+#define DCCP_TYPE_MOVE		8
+
+#define DCCP_FEATURE_CC		1
+#define DCCP_FEATURE_ECN	2
+#define DCCP_FEATURE_ACKRATIO	3
+#define DCCP_FEATURE_ACKVECTOR	4
+#define DCCP_FEATURE_MOBILITY	5
+#define DCCP_FEATURE_LOSSWINDOW	6
+#define DCCP_FEATURE_CONN_NONCE	8
+#define DCCP_FEATURE_IDENTREG	7
+
+#define DCCP_OPT_PADDING	0
+#define DCCP_OPT_DATA_DISCARD	1
+#define DCCP_OPT_SLOW_RECV	2
+#define DCCP_OPT_BUF_CLOSED	3
+#define DCCP_OPT_IGNORED	32
+#define DCCP_OPT_CHANGE		33
+#define DCCP_OPT_PREFER		34
+#define DCCP_OPT_CONFIRM	35
+#define DCCP_OPT_INIT_COOKIE	36
+#define DCCP_OPT_ACK_VECTOR0	37
+#define DCCP_OPT_ACK_VECTOR1	38
+#define DCCP_OPT_RECV_BUF_DROPS 39
+#define DCCP_OPT_TIMESTAMP	40
+#define DCCP_OPT_TIMESTAMP_ECHO 41
+#define DCCP_OPT_IDENT		42
+#define DCCP_OPT_CHALLANGE	44
+
+#define DCCP_REASON_UNSPEC	0
+#define DCCP_REASON_CLOSED	1
+#define DCCP_REASON_INVALID	2
+#define DCCP_REASON_OPTION_ERR	3
+#define DCCP_REASON_FEA_ERR	4
+#define DCCP_REASON_CONN_REF	5
+#define DCCP_REASON_BAD_SNAME	6
+#define DCCP_REASON_BAD_COOKIE	7
+#define DCCP_REASON_INV_MOVE	8
+#define DCCP_REASON_UNANSW_CH	10
+#define DCCP_REASON_FRUITLESS_NEG	11
+
+#define DCCP_CCID		0x01
+#define DCCP_CSLEN		0x02
+#define DCCP_TFRC_AVGPSIZE	0x04
+#define DCCP_MAXSEG		0x08
+
+#define DCCP_NDP_LIMIT          16
+#define DCCP_SEQ_NUM_LIMIT      16777216
+#define DCCP_MAX_OPTIONS	32
+#define DCCP_CONNECT_TIMER	(75 * hz)
+#define DCCP_CLOSE_TIMER	(75 * hz)
+#define DCCP_TIMEWAIT_TIMER	(60 * hz)
+#endif
+++ sys/netinet/dccp6_var.h	Fri Aug 25 04:02:22 2006
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2003 Joacim Häggmark
+ * 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: dccp6_var.h,v 1.1 2003/07/31 21:34:16 joahag-9 Exp $
+ */
+
+#ifndef _NETINET_DCCP6_VAR_H_
+#define _NETINET_DCCP6_VAR_H_
+
+struct	dccpip6hdr {
+	struct 	ip6_hdr di_i6;		/* ip6 structure */
+	struct	dccphdr di_d;		/* dccp header */
+};
+
+#define di6_src		di_i6.ip6_src
+#define di6_dst		di_i6.ip6_dst
+#define di6_nxt		di_i6.ip6_nxt
+#define di6_len		di_i6.ip6_plen
+#define di6_flow	di_i6.ip6_flow
+#define di6_vfc		di_i6.ip6_vfc
+
+#ifdef _KERNEL
+SYSCTL_DECL(_net_inet6_dccp6);
+
+extern struct	pr_usrreqs dccp6_usrreqs;
+
+void	dccp6_ctlinput(int, struct sockaddr *, void *);
+int	dccp6_input(struct mbuf **, int *, int);
+
+#endif
+#endif
+++ sys/netinet/dccp_cc_sw.c	Fri Aug 25 04:02:22 2006
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2003  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: dccp_cc_sw.c,v 1.10 2003/05/14 08:14:46 nilmat-8 Exp $
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/domain.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/proc.h>
+#include <sys/protosw.h>
+#include <sys/signalvar.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/sx.h>
+#include <sys/sysctl.h>
+#include <sys/syslog.h>
+#include <sys/queue.h>
+
+#include <net/if.h>
+#include <net/route.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_pcb.h>
+#include <netinet/in_var.h>
+
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/icmp_var.h>
+#include <netinet/ip_var.h>
+
+#include <netinet/dccp.h>
+#include <netinet/dccp_var.h>
+#include <netinet/dccp_tfrc.h>
+#include <netinet/dccp_tcplike.h>
+#include <netinet/dccp_cc_sw.h>
+
+struct dccp_cc_sw cc_sw[] = {
+  {0,0,0,0,0,0,0,0},
+  {dccp_nocc_init,dccp_nocc_free,dccp_nocc_send_packet,dccp_nocc_send_packet_sent,dccp_nocc_packet_recv,
+   dccp_nocc_init,dccp_nocc_free,dccp_nocc_packet_recv},
+  {0,0,0,0,0,0,0,0},
+  {tcplike_send_init,tcplike_send_free,tcplike_send_packet,tcplike_send_packet_sent,
+   tcplike_send_packet_recv,
+   tcplike_recv_init,tcplike_recv_free,tcplike_recv_packet_recv},
+  {tfrc_send_init,tfrc_send_free,tfrc_send_packet,tfrc_send_packet_sent,
+   tfrc_send_packet_recv,
+   tfrc_recv_init,tfrc_recv_free,tfrc_recv_packet_recv}
+};
+++ sys/netinet/dccp_cc_sw.h	Fri Aug 25 04:02:22 2006
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2003  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: dccp_cc_sw.h,v 1.13 2003/05/13 15:31:50 nilmat-8 Exp $
+ */
+
+#ifndef _NETINET_DCCP_CC_SW_H_
+#define _NETINET_DCCP_CC_SW_H_
+
+/* All functions except inits has the ccb as first argument */
+
+/* Sender side */
+
+/* Init the sender side
+ * args: dccpcb of current connection
+ * returns: sender ccb
+ */
+typedef void*  cc_send_init_t     (struct dccpcb *);
+
+/* Free the sender side */
+typedef void   cc_send_free_t     (void*);
+
+/* Ask the cc mechanism if dccp is allowed to send a packet
+ * args: the packet size (0 == ACK)
+ * returns: 1 if allowed to send, otherwise 0
+ */
+typedef int    cc_send_packet_t   (void*, long);
+
+/* Inform the cc mechanism that a packet was sent
+ * args:  if there exists more to send or not
+ *        size of packet sent
+ */
+typedef void   cc_send_packet_sent_t (void*, int, long);
+
+/* Inform the cc mechanism (sender) that a packet has been received
+ * args:  options and option length
+ */
+typedef void   cc_send_packet_recv_t (void*,char *,int);
+
+
+/* Receiver side */
+
+/* Init the receiver side
+ * args: dccpcb of current connection
+ * returns: receiver ccb
+ */
+typedef void*  cc_recv_init_t   (struct dccpcb *);
+
+/* Free the receiver side */
+typedef void   cc_recv_free_t   (void*);
+
+/* Inform the cc mechanism (receiver) that a packet was received
+ * args:  options and option length
+ */
+typedef void   cc_recv_packet_recv_t (void*,char *,int);
+
+
+struct dccp_cc_sw {
+  /* Sender side */
+  cc_send_init_t   *cc_send_init;
+  cc_send_free_t   *cc_send_free;
+  cc_send_packet_t *cc_send_packet;
+  cc_send_packet_sent_t *cc_send_packet_sent;
+  cc_send_packet_recv_t *cc_send_packet_recv;
+  
+  /* Receiver side */
+  cc_recv_init_t   *cc_recv_init;
+  cc_recv_free_t   *cc_recv_free;
+  cc_recv_packet_recv_t   *cc_recv_packet_recv;
+};
+
+/* Max ccid (i.e. cc_sw has DCCP_CC_MAX_CCID+2 elements) */
+#define DCCP_CC_MAX_CCID 3
+
+#endif
+++ sys/netinet/dccp_tcplike.c	Fri Aug 25 04:02:22 2006
@@ -0,0 +1,1158 @@
+/*
+ * Copyright (c) 2003 Magnus Erixzon
+ * 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.
+ *
+ *
+ * TCP-like congestion control for DCCP
+ *
+ * Current Revision:
+ *
+ * $Source: /home/joahag-9/CVSROOT/dccp/src/sys/netinet/dccp_tcplike.c,v $
+ * $Revision: 1.48 $
+ * $Author: magerx-9 $
+ * $Date: 2003/06/08 14:48:18 $
+ *
+ * Revision history:
+ *
+ * $Log: dccp_tcplike.c,v $
+ * Revision 1.48  2003/06/08 14:48:18  magerx-9
+ * Added stats for TCPlike
+ *
+ * Revision 1.47  2003/06/01 19:49:03  magerx-9
+ * More or less ready for the World
+ *
+ * Revision 1.46  2003/06/01 13:16:29  magerx-9
+ * Correct(?) handling of Ack Ratio
+ *
+ * Revision 1.45  2003/05/31 23:30:49  magerx-9
+ * Not sure whats new.. Something is, I guess
+ *
+ * Revision 1.44  2003/05/29 09:38:09  magerx-9
+ * Minor improvement on congestion control
+ *
+ * Revision 1.43  2003/05/28 23:45:31  magerx-9
+ * No cwnd limit
+ *
+ * Revision 1.42  2003/05/28 21:45:04  magerx-9
+ * Another minor update
+ *
+ * Revision 1.41  2003/05/28 08:27:59  magerx-9
+ * cwndlist back to type charlist
+ *
+ * Revision 1.40  2003/05/27 02:08:13  magerx-9
+ * Now cwndlist will change
+ *
+ * Revision 1.39  2003/05/26 13:35:28  magerx-9
+ * checkin before i change cwndvector (again)
+ *
+ * Revision 1.38  2003/05/26 08:42:20  magerx-9
+ * fixars
+ *
+ * Revision 1.37  2003/05/26 08:19:27  magerx-9
+ * fixors
+ *
+ * Revision 1.36  2003/05/26 01:21:18  magerx-9
+ * bah
+ *
+ * Revision 1.33  2003/05/22 17:11:56  magerx-9
+ * Minor changes
+ *
+ * Revision 1.32  2003/05/19 15:09:23  joahag-9
+ * Changed syntax on dccp_output
+ *
+ * Revision 1.31  2003/05/16 09:44:12  magerx-9
+ * bugfree. (more or less)
+ *
+ * Revision 1.30  2003/05/15 19:46:44  magerx-9
+ * Dont halt
+ *
+ * Revision 1.29  2003/05/14 18:18:45  magerx-9
+ * Minor fix
+ *
+ * Revision 1.28  2003/05/13 15:15:02  magerx-9
+ * Changed name on some dccp_cc_sw functions
+ *
+ * Revision 1.27  2003/05/13 11:44:56  joahag-9
+ * Added copyright text
+ *
+ * Revision 1.26  2003/05/13 00:40:24  magerx-9
+ * Barf barf barf
+ *
+ * Revision 1.25  2003/05/06 11:25:54  magerx-9
+ * Minor updates to Ack handling
+ *
+ * Revision 1.24  2003/05/05 23:47:08  magerx-9
+ * Bug fixing. Redesign of cwndvector
+ *
+ * Revision 1.23  2003/04/25 15:48:09  nilmat-8
+ * DCCP: Fixed get_option, added buflen check
+ *       Exchange connection establishment och cc recv packet in dccp_input
+ * TFRC: Receiver sends feedback
+ * REST: Update type on cc_send_ack_recv
+ *
+ * Revision 1.22  2003/04/24 00:40:39  magerx-9
+ * AckVector action
+ *
+ * Revision 1.21  2003/04/23 15:58:47  magerx-9
+ * Changed def of cc_recv_packet. options is now an argument
+ *
+ * Revision 1.20  2003/04/23 14:22:36  magerx-9
+ * Changed definition of cc_recv_packet
+ *
+ * Revision 1.19  2003/04/23 00:29:59  magerx-9
+ * Send ackvector option
+ *
+ * Revision 1.18  2003/04/22 00:48:51  magerx-9
+ * Changed cwndvector
+ *
+ * Revision 1.17  2003/04/21 21:18:10  magerx-9
+ * Fix typo
+ *
+ * Revision 1.16  2003/04/21 11:59:06  magerx-9
+ * Updated generate_ackvector
+ *
+ * Revision 1.15  2003/04/21 11:46:44  nilmat-8
+ * Change type and meaning on cc_send_packet_sent.
+ *
+ * Revision 1.14  2003/04/21 01:39:44  magerx-9
+ * Minor updates
+ *
+ * Revision 1.13  2003/04/20 16:30:40  magerx-9
+ * Minor adjustments according to nilmat
+ *
+ * Revision 1.12  2003/04/20 15:33:18  magerx-9
+ * Adjustments to conform to new code standards
+ *
+ * Revision 1.10  2003/04/10 12:41:52  magerx-9
+ * compile error fix
+ *
+ * Revision 1.9  2003/04/10 10:35:55  magerx-9
+ * Minor updates on recv init
+ *
+ * Revision 1.8  2003/04/05 09:24:28  magerx-9
+ * Minor cv_list updates
+ *
+ * Revision 1.7  2003/04/04 22:36:08  magerx-9
+ * Initial server-side use of cwndvector_t
+ *
+ * Revision 1.6  2003/04/03 10:51:17  magerx-9
+ * bah
+ *
+ * Revision 1.5  2003/04/03 10:48:06  magerx-9
+ * blah
+ *
+ * Revision 1.4  2003/03/31 11:34:15  magerx-9
+ * Minor fixes, for initial compilation
+ *
+ * Revision 1.3  2003/03/31 11:29:20  magerx-9
+ * Minor fixes, for initial compilation
+ *
+ * Revision 1.2  2003/03/31 11:23:53  magerx-9
+ * Minor fixes, for initial compilation
+ *
+ * Revision 1.1  2003/03/31 11:05:42  magerx-9
+ * Initial revision
+ *
+ *
+ **/
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/domain.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/proc.h>
+#include <sys/protosw.h>
+#include <sys/signalvar.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/sx.h>
+#include <sys/sysctl.h>
+#include <sys/syslog.h>
+
+#include <net/if.h>
+#include <net/route.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_pcb.h>
+#include <netinet/in_var.h>
+
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/icmp_var.h>
+#include <netinet/ip_var.h>
+
+#include <netinet/dccp_tcplike.h>
+#include <netinet/dccp.h>
+#include <netinet/dccp_var.h>
+
+#define TCPLIKE_DEBUG(args)
+#define MALLOC_DEBUG(args) log args
+#define CWND_DEBUG(args)
+#define ACK_DEBUG(args)
+#define ACKRATIO_DEBUG(args)
+#define LOSS_DEBUG(args)
+#define TIMEOUT_DEBUG(args)
+
+/* Sender side */
+
+void tcplike_rto_timeout(void *ccb);
+void tcplike_rtt_sample(struct tcplike_send_ccb *cb, u_int16_t sample);
+void _add_to_cwndvector(struct tcplike_send_ccb *cb, u_int32_t seqnr);
+void _remove_from_cwndvector(struct tcplike_send_ccb *cb, u_int32_t seqnr);
+int _chop_cwndvector(struct tcplike_send_ccb *cb, u_int32_t seqnr);
+int _cwndvector_size(struct tcplike_send_ccb *cb);
+u_char _cwndvector_state(struct tcplike_send_ccb *cb, u_int32_t seqnr);
+
+void tcplike_send_term(void *ccb);
+void tcplike_recv_term(void *ccb);
+
+void _avlist_add(struct tcplike_recv_ccb *cb, u_int32_t localseq, u_int32_t ackthru);
+u_int32_t _avlist_get(struct tcplike_recv_ccb *cb, u_int32_t localseq);
+
+/* extern Ack Vector functions */
+extern void dccp_use_ackvector(struct dccpcb *dp);
+extern void dccp_update_ackvector(struct dccpcb *dp, u_int32_t seqno);
+extern void dccp_increment_ackvector(struct dccpcb *dp, u_int32_t seqno);
+extern u_int16_t dccp_generate_ackvector(struct dccpcb *dp, u_char *);
+extern u_char dccp_ackvector_state(struct dccpcb *dp, u_int32_t seqnr);
+
+extern int dccp_get_option(char *, int, int, char *,int);
+extern int dccp_add_feature(struct dccpcb *dp, u_int8_t type, u_int8_t feature, char *val, u_int8_t val_len);
+extern int dccp_remove_feature(struct dccpcb *dp, u_int8_t type, u_int8_t feature);
+
+/**
+ * RTO timer activated
+ **/
+void tcplike_rto_timeout(void *ccb)
+{
+	struct tcplike_send_ccb *cb = (struct tcplike_send_ccb *) ccb;
+	struct inpcb *inp;
+	int s;
+	
+	mtx_lock(&(cb->mutex));
+	
+	cb->ssthresh = cb->cwnd >>1;
+	cb->cwnd = 1; /* allowing 1 packet to be sent */
+	cb->outstanding = 0; /* is this correct? */
+	cb->rto_timer.callout = NULL;
+	cb->rto = cb->rto << 1;
+	TIMEOUT_DEBUG((LOG_INFO, "RTO Timeout. New RTO = %u\n", cb->rto));
+	
+	cb->sample_rtt = 0;
+	
+	cb->ack_last = 0;
+	cb->ack_miss = 0;
+
+	cb->rcvr_ackratio = 1; /* Constraint 2 & 3. We need ACKs asap */
+	dccp_remove_feature(cb->pcb, DCCP_OPT_CHANGE, DCCP_FEATURE_ACKRATIO);
+	dccp_add_feature(cb->pcb, DCCP_OPT_CHANGE, DCCP_FEATURE_ACKRATIO,
+				 (char *) &cb->rcvr_ackratio, 1);
+	cb->acked_in_win = 0;
+	cb->acked_windows = 0;
+	cb->oldcwnd_ts = cb->pcb->seq_snd;
+	
+	LOSS_DEBUG((LOG_INFO, "Timeout. CWND value: %u , OUTSTANDING value: %u\n",
+		    cb->cwnd, cb->outstanding));
+	mtx_unlock(&(cb->mutex));
+
+	/* lock'n run dccp_output */
+	s = splnet();
+	INP_INFO_RLOCK(&dccpbinfo);
+	inp = cb->pcb->d_inpcb;
+	INP_LOCK(inp);
+	INP_INFO_RUNLOCK(&dccpbinfo);
+	
+	dccp_output(cb->pcb, 1);
+	
+	INP_UNLOCK(inp);
+	splx(s);
+}
+
+void tcplike_rtt_sample(struct tcplike_send_ccb *cb, u_int16_t sample)
+{
+	u_int16_t err;
+	
+	if (cb->rtt == 0xffff) {
+		/* hmmmmm. */
+		cb->rtt = sample;
+		cb->rto = cb->rtt << 1;
+		return;
+	}
+
+	/* This is how the Linux implementation is doing it.. */
+	if (sample >= cb->rtt) {
+		err = sample - cb->rtt;
+		cb->rtt = cb->rtt + (err >> 3);
+	} else {
+		err = cb->rtt - sample;
+		cb->rtt = cb->rtt - (err >> 3);
+	}
+	cb->rtt_d = cb->rtt_d + ((err - cb->rtt_d) >> 2);
+	if (cb->rtt < TCPLIKE_MIN_RTT)
+		cb->rtt = TCPLIKE_MIN_RTT;
+	cb->rto = cb->rtt + (cb->rtt_d << 2);
+
+
+	/* 5 million ways to calculate RTT ...*/
+	/*
+	cb->srtt = ( 0.8 * cb->srtt ) + (0.2 * sample);
+	if (cb->srtt < TCPLIKE_MIN_RTT)
+		cb->srtt = TCPLIKE_MIN_RTT;
+	cb->rto = cb->srtt << 1;
+	*/
+	
+	LOSS_DEBUG((LOG_INFO, "RTT Sample: %u , New RTO: %u\n", sample, cb->rto));
+}
+
+/* Functions declared in struct dccp_cc_sw */
+
+/* Initialises the sender side
+ * returns: pointer to a tfrc_send_ccb struct on success, otherwise 0
+ */ 
+void *tcplike_send_init(struct dccpcb* pcb)
+{
+	struct tcplike_send_ccb *cb;
+	
+	TCPLIKE_DEBUG((LOG_INFO, "Entering tcplike_send_init()\n"));
+	
+	cb = malloc(sizeof (struct tcplike_send_ccb), M_PCB, M_DONTWAIT | M_ZERO);
+	if (cb == 0) {
+		TCPLIKE_DEBUG((LOG_INFO, "Unable to allocate memory for tcplike_send_ccb!\n"));
+		dccpstat.tcplikes_send_memerr++;
+		return 0;
+	}
+	
+	/* init sender */
+	cb->pcb = pcb;
+	
+	cb->cwnd = TCPLIKE_INITIAL_CWND;
+	cb->ssthresh = 0xafff; /* lim-> infinity */
+	cb->oldcwnd_ts = 0;
+	cb->outstanding = 0;
+	cb->rcvr_ackratio = 2; /* Ack Ratio */
+	cb->acked_in_win = 0;
+	cb->acked_windows = 0;
+	
+	CWND_DEBUG((LOG_INFO, "Init. CWND value: %u , OUTSTANDING value: %u\n",
+		    cb->cwnd, cb->outstanding));
+	cb->rtt = 0xffff;
+	cb->rto = TIMEOUT_UBOUND;
+	cb->rtt_d = 0;
+	cb->timestamp = 0;
+	
+	cb->sample_rtt = 1;
+
+	cb->cv_size = TCPLIKE_INITIAL_CWNDVECTOR;
+	/* 1 bit per entry */
+	cb->cwndvector = malloc(cb->cv_size/8, M_PCB, M_DONTWAIT | M_ZERO);
+	if (cb->cwndvector == NULL) {
+		MALLOC_DEBUG((LOG_INFO, "Unable to allocate memory for cwndvector\n"));
+		/* What to do now? */
+		cb->cv_size = 0;
+		dccpstat.tcplikes_send_memerr++;
+		return 0;
+	}
+	cb->cv_hs = cb->cv_ts = 0;
+	cb->cv_hp = cb->cwndvector;
+
+	cb->ack_last = 0;
+	cb->ack_miss = 0;
+	
+	mtx_init(&(cb->mutex), "TCPlike Sender mutex", NULL, MTX_DEF);
+	
+	TCPLIKE_DEBUG((LOG_INFO, "TCPlike sender initialised!\n"));
+	dccpstat.tcplikes_send_conn++;
+	return cb;
+} 
+
+void tcplike_send_term(void *ccb)
+{
+	struct tcplike_send_ccb *cb = (struct tcplike_send_ccb *) ccb;
+	if (ccb == 0)
+		return;
+	
+	mtx_destroy(&(cb->mutex));
+	free(cb, M_PCB);
+	TCPLIKE_DEBUG((LOG_INFO, "TCP-like sender is destroyed\n"));
+}
+
+/* Free the sender side
+ * args: ccb - ccb of sender
+ */
+void tcplike_send_free(void *ccb)
+{
+	struct tcplike_send_ccb *cb = (struct tcplike_send_ccb *) ccb;
+	
+	LOSS_DEBUG((LOG_INFO, "Entering tcplike_send_free()\n"));
+
+	if (ccb == 0)
+		return;
+	
+	mtx_lock(&(cb->mutex));
+	
+	free(cb->cwndvector, M_PCB);
+	cb->cv_hs = cb->cv_ts = 0;
+
+	/* untimeout any active timer */
+	if (cb->rto_timer.callout) {
+		TCPLIKE_DEBUG((LOG_INFO, "Untimeout RTO Timer\n"));
+		untimeout(tcplike_rto_timeout, (void*) cb, cb->rto_timer);
+	}
+	
+	mtx_unlock(&(cb->mutex));
+	timeout(tcplike_send_term, (void*)cb, 10*hz);
+}
+
+/* Ask TCPlike wheter one can send a packet or not 
+ * args: ccb  -  ccb block for current connection 
+ * returns: 0 if ok, else <> 0.
+ */ 
+int tcplike_send_packet(void *ccb, long datasize)
+{
+	/* check if one can send here */
+	struct tcplike_send_ccb *cb = (struct tcplike_send_ccb *) ccb;
+	long ticks;
+	char feature[1];
+	
+	TCPLIKE_DEBUG((LOG_INFO, "Entering tcplike_send_packet()\n"));
+
+	if (datasize == 0) {
+		TCPLIKE_DEBUG((LOG_INFO, "Sending pure ACK. Dont care about CC right now\n"));
+		return 1;
+	}
+
+	mtx_lock(&(cb->mutex));
+
+	if (cb->cwnd <= cb->outstanding) {
+		/* May not send. trigger RTO */
+		/*TIMEOUT_DEBUG((LOG_INFO, "cwnd (%d) < outstanding (%d)\n", cb->cwnd, cb->outstanding));*/
+		if (!cb->rto_timer.callout) {
+			LOSS_DEBUG((LOG_INFO, "Trigger TCPlike RTO timeout timer. Ticks = %u\n", cb->rto));
+			ticks = (long)cb->rto;
+			cb->rto_timer = timeout(tcplike_rto_timeout, (void *)cb, ticks);
+		}
+		mtx_unlock(&(cb->mutex));
+		return 0;
+	}
+	
+	/* We're allowed to send */
+
+	feature[0] = 1;
+	if (cb->pcb->remote_ackvector == 0) {
+		ACK_DEBUG((LOG_INFO, "Adding Change(Use Ack Vector, 1) to outgoing packet\n"));
+		dccp_remove_feature(cb->pcb, DCCP_OPT_CHANGE, DCCP_FEATURE_ACKVECTOR);
+		dccp_add_feature(cb->pcb, DCCP_OPT_CHANGE, DCCP_FEATURE_ACKVECTOR, feature, 1);
+	}
+	
+	/* untimeout any active timer */
+	if (cb->rto_timer.callout) {
+		LOSS_DEBUG((LOG_INFO, "Untimeout RTO Timer\n"));
+		untimeout(tcplike_rto_timeout, (void*) cb, cb->rto_timer);
+		cb->rto_timer.callout = NULL;
+	}
+
+	if (!cb->sample_rtt) {
+		struct timeval stamp;
+		microtime(&stamp);
+		cb->timestamp = ((stamp.tv_sec & 0x00000FFF) * 1000000) + stamp.tv_usec;
+		dccp_add_option(cb->pcb, DCCP_OPT_TIMESTAMP, (char*) &(cb->timestamp), 4);
+		/*LOSS_DEBUG((LOG_INFO, "Adding timestamp %u\n", cb->timestamp));*/
+		cb->sample_rtt = 1;
+	}
+	
+	mtx_unlock(&(cb->mutex));
+	return 1;
+	
+}
+
+/* Notify sender that a packet has been sent 
+ * args: ccb - ccb block for current connection
+ *	 moreToSend - if there exists more packets to send
+ */
+void tcplike_send_packet_sent(void *ccb, int moreToSend, long datasize)
+{
+	struct tcplike_send_ccb *cb = (struct tcplike_send_ccb *) ccb;
+	
+	TCPLIKE_DEBUG((LOG_INFO, "Entering tcplike_send_packet_sent(,%i,%i)\n",moreToSend,(int) datasize));
+	
+	if (datasize == 0) {
+		TCPLIKE_DEBUG((LOG_INFO, "Sent pure ACK. Dont care about cwnd-storing\n"));
+		return;
+	}
+
+	mtx_lock(&(cb->mutex));
+	
+	cb->outstanding++;
+	TCPLIKE_DEBUG((LOG_INFO, "SENT. cwnd: %d, outstanding: %d\n",cb->cwnd, cb->outstanding));
+
+	/* stash the seqnr in cwndvector */
+	/* Dont do this if we're only sending an ACK ! */
+	_add_to_cwndvector(cb, cb->pcb->seq_snd);
+	CWND_DEBUG((LOG_INFO, "Sent. CWND value: %u , OUTSTANDING value: %u\n",cb->cwnd, cb->outstanding));
+	
+	dccp_remove_feature(cb->pcb, DCCP_OPT_CHANGE, DCCP_FEATURE_ACKRATIO);
+	mtx_unlock(&(cb->mutex));
+}
+
+/**
+ * Notify that an ack package was received
+ * args: ccb  -  ccb block for current connection
+ **/
+void tcplike_send_packet_recv(void *ccb, char *options, int optlen)
+{
+	u_int32_t acknum, lastok;
+	u_int16_t numlostpackets, avsize, i, prev_size;
+	u_int8_t length, state, numokpackets, ackratiocnt;
+	u_char av[10];
+	struct tcplike_send_ccb *cb = (struct tcplike_send_ccb *) ccb;
+
+	TCPLIKE_DEBUG((LOG_INFO, "Entering tcplike_send_ack_recv()\n"));
+	mtx_lock(&(cb->mutex));
+
+	if (dccp_get_option(options, optlen, DCCP_OPT_TIMESTAMP_ECHO, av,10) > 0) {
+		u_int32_t echo, elapsed;
+
+		TCPLIKE_DEBUG((LOG_INFO, "Received TIMESTAMP ECHO\n"));
+		bcopy(av, &echo, 4);
+		bcopy(av + 4, &elapsed, 4);
+
+		if (echo == cb->timestamp) {
+			struct timeval time;
+			u_int32_t c_stamp;
+			u_int16_t diff;
+			
+			microtime(&time);
+			c_stamp = ((time.tv_sec & 0x00000FFF) * 1000000) + time.tv_usec;
+			
+			diff = (u_int16_t) c_stamp - cb->timestamp - elapsed;
+			diff = (u_int16_t)(diff / 1000);
+			TCPLIKE_DEBUG((LOG_INFO, "Got Timestamp Echo; Echo = %u, Elapsed = %u. DIFF = %u\n",
+				       echo, elapsed, diff));
+			tcplike_rtt_sample(cb, diff);
+		}
+	}
+
+	if (cb->pcb->ack_rcv == 0) {
+		/* There was no Ack. There is no spoon */
+
+		/* We'll clear the missingacks data here, since the other host
+		 * is also sending data.
+		 * I guess we could deal with this, using the NDP field in the
+		 * header. Let's stick a *TODO* mark here for now.
+		 * The missingacks mechanism will activate if other host goes to
+		 * only sending DCCP-Ack packets.
+		 */
+		cb->ack_last = 0;
+		cb->ack_miss = 0;
+		ACKRATIO_DEBUG((LOG_INFO, "Clear Missing Acks state!\n"));
+		mtx_unlock(&(cb->mutex));
+		return;
+	}
+
+	cb->sample_rtt = 0;
+	
+	/* check ackVector for lost packets. cmp with cv_list */
+	avsize = dccp_get_option(options, optlen, DCCP_OPT_ACK_VECTOR0, av,10);
+	if (avsize == 0)
+		avsize = dccp_get_option(options, optlen, DCCP_OPT_ACK_VECTOR1, av,10);
+
+	if (avsize > 0)
+		dccpstat.tcplikes_send_ackrecv++;
+	
+	acknum = cb->pcb->ack_rcv;
+	numlostpackets = 0;
+	numokpackets = 0;
+	lastok = 0;
+	prev_size = _cwndvector_size(cb);
+	
+	CWND_DEBUG((LOG_INFO, "Start removing from cwndvector\n"));
+	if (avsize == 0)
+		_remove_from_cwndvector(cb, acknum);
+	
+	for (i=0; i < avsize; i++) {
+		state = (av[i] & 0xc0) >> 6;
+		length = (av[i] & 0x3f) +1;
+		while (length > 0) {
+			if (state == 0) {
+				CWND_DEBUG((LOG_INFO, "Packet %u was OK\n", acknum));
+				numokpackets++;
+				lastok = acknum;
+				_remove_from_cwndvector(cb, acknum);
+			} else {
+				if (acknum > cb->oldcwnd_ts) {
+					LOSS_DEBUG((LOG_INFO, "Packet %u was lost\n", acknum));
+					numlostpackets++;
+					dccpstat.tcplikes_send_reploss++;
+				}
+			}
+			acknum--;
+			length--;
+		}
+	}
+	if (lastok)
+		if (_chop_cwndvector(cb, lastok-TCPLIKE_NUMDUPACK)) {
+			LOSS_DEBUG((LOG_INFO, "Packets were lost\n"));
+			if (lastok-TCPLIKE_NUMDUPACK > cb->oldcwnd_ts) {
+				numlostpackets++;
+				dccpstat.tcplikes_send_assloss++;
+			}
+		}
+
+	lastok = cb->cv_hs;
+	while (_cwndvector_state(cb, lastok) == 0x00 && lastok < cb->cv_ts)
+		lastok++;
+	if (lastok != cb->cv_hs)
+		_chop_cwndvector(cb, lastok);
+
+	cb->outstanding = _cwndvector_size(cb);
+	CWND_DEBUG((LOG_INFO, "Decrease outstanding. was = %u , now = %u\n", prev_size, cb->outstanding));
+	if (prev_size == cb->outstanding) {
+		/* Nothing dropped from cwndvector  */
+		mtx_unlock(&(cb->mutex));
+		return;
+	}
+	
+	cb->acked_in_win += numokpackets;
+	
+	if (cb->cwnd < cb->ssthresh) {
+		/* Slow start */
+
+		if (numlostpackets > 0) {
+			/* Packet loss */
+			LOSS_DEBUG((LOG_INFO, "Packet Loss in Slow Start\n"));
+			cb->cwnd = cb->cwnd>>1;
+			if (cb->cwnd < 1)
+				cb->cwnd = 1;
+			cb->ssthresh = cb->cwnd;
+			cb->acked_in_win = 0;
+			cb->acked_windows = 0;
+			cb->oldcwnd_ts = cb->pcb->seq_snd;
+			
+		} else {
+			cb->cwnd++;
+		}
+		
+	} else if (cb->cwnd >= cb->ssthresh) {
+		
+		if (numlostpackets > 0) {
+			/* Packet loss */
+			LOSS_DEBUG((LOG_INFO, "Packet Loss in action\n"));
+			cb->cwnd = cb->cwnd>>1;
+			if (cb->cwnd < 1)
+				cb->cwnd = 1;
+			cb->ssthresh = cb->cwnd;
+			cb->acked_in_win = 0;
+			cb->acked_windows = 0;
+			cb->oldcwnd_ts = cb->pcb->seq_snd;
+			
+		} else if (cb->acked_in_win > cb->cwnd) {
+			cb->cwnd++;
+		}
+	}
+
+	/* Ok let's check if there are missing Ack packets */
+	ACKRATIO_DEBUG((LOG_INFO, "Check Ack. seq_rcv: %u ,ack_last: %u ,ack_miss: %u\n",
+			cb->pcb->seq_rcv, cb->ack_last, cb->ack_miss));
+	
+	if (cb->ack_last == 0) {
+		/* First received ack (or first after Data packet). Yey */
+		cb->ack_last = cb->pcb->seq_rcv;
+		cb->ack_miss = 0;
+	} else if (cb->pcb->seq_rcv == (cb->ack_last + 1)) {
+		/* This is correct, non-congestion, in-order behaviour */
+		cb->ack_last = cb->pcb->seq_rcv;
+
+	} else if (cb->pcb->seq_rcv < (cb->ack_last + 1)) {
+		/* Might be an Ack we've been missing */
+		/* This code has a flaw; If we miss 2 Ack packets, we only care
+		 * about the older one. This means that the next-to-oldest one could
+		 * be lost without any action beeing taken.
+		 * Time will tell if that is going to be a Giant Problem(r)
+		 */
+		if (cb->pcb->seq_rcv == cb->ack_miss) {
+			/* Yea it was. great */
+			cb->ack_miss = 0;
+		}
+		
+	} else if (cb->pcb->seq_rcv > (cb->ack_last + 1)) {
+		/* There is a jump in Ack seqnums.. */
+		cb->ack_miss = cb->ack_last + 1;
+		cb->ack_last = cb->pcb->seq_rcv;
+	}
+
+	if (cb->ack_miss && ((cb->ack_miss + TCPLIKE_NUMDUPACK) < cb->ack_last)) {
+		/* Alert! Alert! Ack packets are MIA.
+		 * Decrease Ack Ratio
+		 */
+		cb->rcvr_ackratio = cb->rcvr_ackratio<<1;
+		if (cb->rcvr_ackratio > (cb->cwnd>>1)) {
+			/* Constraint 2 */
+			cb->rcvr_ackratio = cb->cwnd>>1;
+		}
+		if (cb->rcvr_ackratio == 0)
+			cb->rcvr_ackratio = 1;
+		ACKRATIO_DEBUG((LOG_INFO, "Increase Ack Ratio. Now = %u. (cwnd = %u)\n", cb->rcvr_ackratio, cb->cwnd));
+		dccp_remove_feature(cb->pcb, DCCP_OPT_CHANGE, DCCP_FEATURE_ACKRATIO);
+		dccp_add_feature(cb->pcb, DCCP_OPT_CHANGE, DCCP_FEATURE_ACKRATIO,
+				 (char *) &cb->rcvr_ackratio, 1);
+
+		cb->ack_miss = 0;
+		cb->acked_windows = 0;
+		cb->acked_in_win = 0;
+		dccpstat.tcplikes_send_missack++;
+		
+	} else if (cb->acked_in_win > cb->cwnd) {
+		cb->acked_in_win = 0;
+		cb->acked_windows++;
+		if (cb->rcvr_ackratio == 1) {
+			/* Ack Ratio is 1. We cant decrease it more.. Lets wait for some
+			 * heavy congestion so we can increase it
+			 */
+			cb->acked_windows = 0;
+		}
+	}
+	
+	if (cb->acked_windows >= 1) {
+		ackratiocnt = (cb->cwnd / ((cb->rcvr_ackratio*cb->rcvr_ackratio) - cb->rcvr_ackratio));
+		if (cb->acked_windows >= ackratiocnt) {
+			if (cb->rcvr_ackratio > 2 && cb->cwnd >= 4) {
+				/* Constraint 3 - AckRatio at least 2 for a cwnd >= 4 */
+				cb->rcvr_ackratio--;
+				ACKRATIO_DEBUG((LOG_INFO, "Decrease ackratio by 1, now: %u\n", cb->rcvr_ackratio));
+				dccp_remove_feature(cb->pcb, DCCP_OPT_CHANGE, DCCP_FEATURE_ACKRATIO);
+				dccp_add_feature(cb->pcb, DCCP_OPT_CHANGE, DCCP_FEATURE_ACKRATIO,
+						 (char *) &cb->rcvr_ackratio, 1);
+			}
+			cb->acked_in_win = 0;
+			cb->acked_windows = 0;
+		}
+	}
+	
+	CWND_DEBUG((LOG_INFO, "Recvd. CWND value: %u , OUTSTANDING value: %u\n",
+		    cb->cwnd, cb->outstanding));
+
+	if (cb->cwnd > cb->outstanding && cb->rto_timer.callout) {
+                LOSS_DEBUG((LOG_INFO, "Force DCCP_OUTPUT, CWND = %u Outstanding = %u\n",
+                            cb->cwnd, cb->outstanding));
+		untimeout(tcplike_rto_timeout, (void*) cb, cb->rto_timer);
+		cb->rto_timer.callout = NULL;
+		
+		mtx_unlock(&(cb->mutex));
+                dccp_output(cb->pcb, 1);
+		return;
+        }
+	mtx_unlock(&(cb->mutex));
+}
+
+int _cwndvector_size(struct tcplike_send_ccb *cb)
+{
+	u_int32_t gap, offset, seqnr, cnt;
+	u_char *t;
+
+	TCPLIKE_DEBUG((LOG_INFO, "Enter cwndvector_size\n"));
+	cnt = 0;
+	for (seqnr = cb->cv_hs; seqnr < cb->cv_ts; seqnr++) {
+		gap = seqnr - cb->cv_hs;
+
+		offset = gap % 8;
+		t = cb->cv_hp + (gap/8);
+		if (t >= (cb->cwndvector + (cb->cv_size/8)))
+			t -= (cb->cv_size / 8); /* wrapped */
+	
+		if(((*t & (0x01 << offset)) >> offset) == 0x01)
+			cnt++;
+	}
+	return cnt;
+}
+
+u_char _cwndvector_state(struct tcplike_send_ccb *cb, u_int32_t seqnr)
+{
+	u_int32_t gap, offset;
+	u_char *t;
+
+	/* Check for wrapping */
+	if (seqnr >= cb->cv_hs) {
+		/* Not wrapped */
+		gap = seqnr - cb->cv_hs;
+	} else {
+		/* Wrapped */
+		gap = seqnr + 0x1000000 - cb->cv_hs; /* seq nr = 24 bits */
+	}
+
+	if (gap >= cb->cv_size) {
+		/* gap is bigger than cwndvector size? baaad */
+		return 0x01;
+	}
+
+	offset = gap % 8;
+	t = cb->cv_hp + (gap/8);
+	if (t >= (cb->cwndvector + (cb->cv_size/8)))
+		t -= (cb->cv_size / 8); /* wrapped */
+
+	return ((*t & (0x01 << offset)) >> offset);
+}
+
+void _add_to_cwndvector(struct tcplike_send_ccb *cb, u_int32_t seqnr)
+{
+	u_int32_t offset, dc;
+	int32_t gap;
+	u_char *t, *n;
+	
+	TCPLIKE_DEBUG((LOG_INFO, "Entering add_to_cwndvector\n"));
+	
+	if (cb->cv_hs == cb->cv_ts) {
+		/* Empty cwndvector */
+		cb->cv_hs = cb->cv_ts = seqnr;
+	}
+
+	/* Check for wrapping */
+	if (seqnr >= cb->cv_hs) {
+		/* Not wrapped */
+		gap = seqnr - cb->cv_hs;
+	} else {
+		/* Wrapped */
+		gap = seqnr + 0x1000000 - cb->cv_hs; /* seq nr = 24 bits */
+	}
+
+	if (gap >= cb->cv_size) {
+		/* gap is bigger than cwndvector size? baaad */
+		/* maybe we should increase the cwndvector here */
+		CWND_DEBUG((LOG_INFO, "add cwndvector error. gap: %d, cv_size: %d, seqnr: %d\n",
+			    gap, cb->cv_size, seqnr));
+		dccpstat.tcplikes_send_badseq++;
+		return;
+	}
+	
+	offset = gap % 8; /* bit to mark */
+	t = cb->cv_hp + (gap/8);
+	if (t >= (cb->cwndvector + (cb->cv_size/8)))
+		t -= (cb->cv_size / 8); /* cwndvector wrapped */
+	
+	*t = *t | (0x01 << offset); /* turn on bit */
+
+	cb->cv_ts = seqnr+1;
+	if (cb->cv_ts == 0x1000000)
+		cb->cv_ts = 0;
+
+	if (gap > (cb->cv_size - 128)) {
+		MALLOC_DEBUG((LOG_INFO, "INCREASE cwndVECTOR\n"));
+		n = malloc(cb->cv_size/4, M_PCB, M_DONTWAIT); /* old size * 2 */
+		if (n == NULL) {
+			MALLOC_DEBUG((LOG_INFO, "Increase cwndvector FAILED\n"));
+			dccpstat.tcplikes_send_memerr++;
+			return;
+		}
+		memset (n+cb->cv_size/8,0x00,cb->cv_size/8); /* new half all missing */
+		dc = (cb->cwndvector + (cb->cv_size/8)) - cb->cv_hp;
+		memcpy (n,cb->cv_hp, dc); /* tail to end */
+		memcpy (n+dc,cb->cwndvector,cb->cv_hp - cb->cwndvector); /* start to tail */
+		cb->cv_size = cb->cv_size * 2; /* counted in items, so it';s a doubling */
+		free (cb->cwndvector, M_PCB);
+		cb->cv_hp = cb->cwndvector = n;
+	}
+}
+
+void _remove_from_cwndvector(struct tcplike_send_ccb *cb, u_int32_t seqnr)
+{
+	u_int32_t offset;
+	int32_t gap;
+	u_char *t;
+	
+	TCPLIKE_DEBUG((LOG_INFO, "Entering remove_from_cwndvector\n"));
+	
+	if (cb->cv_hs == cb->cv_ts) {
+		/* Empty cwndvector */
+		return;
+	}
+
+	/* Check for wrapping */
+	if (seqnr >= cb->cv_hs) {
+		/* Not wrapped */
+		gap = seqnr - cb->cv_hs;
+	} else {
+		/* Wrapped */
+		gap = seqnr + 0x1000000 - cb->cv_hs; /* seq nr = 24 bits */
+	}
+
+	if (gap >= cb->cv_size) {
+		/* gap is bigger than cwndvector size. has already been chopped */
+		return;
+	}
+	
+	offset = gap % 8; /* hi or low 2 bits to mark */
+	t = cb->cv_hp + (gap/8);
+	if (t >= (cb->cwndvector + (cb->cv_size/8)))
+		t -= (cb->cv_size / 8); /* cwndvector wrapped */
+	
+	*t = *t & (~(0x01 << offset)); /* turn off bits */
+}
+
+int _chop_cwndvector(struct tcplike_send_ccb *cb, u_int32_t seqnr)
+{
+	int32_t gap, bytegap;
+	u_char *t;
+
+	CWND_DEBUG((LOG_INFO,"Chop cwndvector at: %u\n", seqnr));
+
+	if (cb->cv_hs == cb->cv_ts)
+		return 0;
+	
+	if (seqnr > cb->cv_hs) {
+		gap = seqnr - cb->cv_hs;
+	} else {
+		/* We received obsolete information */
+		return 0;
+	}
+
+	bytegap = gap/8;
+	if (bytegap == 0)
+		return 0;
+	
+	t = cb->cv_hp + bytegap;
+	if (t >= (cb->cwndvector + (cb->cv_size/8)))
+		t -= (cb->cv_size / 8); /* ackvector wrapped */
+	cb->cv_hp = t;
+	cb->cv_hs += bytegap*8;
+	return 1;
+}
+
+
+/* Receiver side */
+
+
+/* Functions declared in struct dccp_cc_sw */
+
+/* Initialises the receiver side
+ * returns: pointer to a tcplike_recv_ccb struct on success, otherwise 0
+ */ 
+void *tcplike_recv_init(struct dccpcb *pcb)
+{
+	struct tcplike_recv_ccb *ccb;
+  
+	TCPLIKE_DEBUG((LOG_INFO, "Entering tcplike_recv_init()\n"));
+  
+	ccb = malloc(sizeof (struct tcplike_recv_ccb), M_PCB, M_DONTWAIT | M_ZERO);
+	if (ccb == 0) {
+		TCPLIKE_DEBUG((LOG_INFO, "Unable to allocate memory for tcplike_recv_ccb!\n"));
+		dccpstat.tcplikes_recv_memerr++;
+		return 0;
+	}
+	
+	ccb->pcb = pcb;
+	ccb->unacked = 0;
+	ccb->pcb->ack_ratio = 2;
+
+	ccb->pcb->remote_ackvector = 1;
+	dccp_use_ackvector(ccb->pcb);
+	
+	mtx_init(&(ccb->mutex), "TCPlike Receiver mutex", NULL, MTX_DEF);
+	
+	TCPLIKE_DEBUG((LOG_INFO, "TCPlike receiver initialised!\n"));
+	dccpstat.tcplikes_recv_conn++;
+	return ccb;
+}
+
+void tcplike_recv_term(void *ccb)
+{
+	struct tcplike_recv_ccb *cb = (struct tcplike_recv_ccb *) ccb;
+	if (ccb == 0)
+		return;
+	
+	mtx_destroy(&(cb->mutex));
+	free(cb, M_PCB);
+	TCPLIKE_DEBUG((LOG_INFO, "TCP-like receiver is destroyed\n"));
+}
+
+/* Free the receiver side
+ * args: ccb - ccb of recevier
+ */
+void tcplike_recv_free(void *ccb)
+{
+	struct ack_list *a;
+	LOSS_DEBUG((LOG_INFO, "Entering tcplike_recv_free()\n"));
+	struct tcplike_recv_ccb *cb = (struct tcplike_recv_ccb *) ccb;
+
+	if (ccb == 0)
+		return;
+	
+	mtx_lock(&(cb->mutex));
+
+	a = cb->av_list;
+	while (a) {
+		cb->av_list = a->next;
+		free(a, M_TEMP);
+		a = cb->av_list;
+	}
+
+	cb->pcb->av_size = 0;
+	free(cb->pcb->ackvector, M_PCB);
+	
+	mtx_unlock(&(cb->mutex));
+	timeout(tcplike_recv_term, (void*)cb, 10*hz);
+}
+
+/*
+ * Tell TCPlike that a packet has been received
+ * args: ccb  -  ccb block for current connection 
+ */
+void tcplike_recv_packet_recv(void *ccb, char *options, int optlen)
+{
+	struct tcplike_recv_ccb *cb = (struct tcplike_recv_ccb *) ccb;
+	u_char ackvector[16];
+	u_int16_t avsize;
+	u_char av_rcv[10];
+	
+	TCPLIKE_DEBUG((LOG_INFO, "Entering tcplike_recv_packet()\n"));
+
+	mtx_lock(&(cb->mutex));
+
+	if (cb->pcb->type_rcv == DCCP_TYPE_DATA ||
+	    cb->pcb->type_rcv == DCCP_TYPE_DATAACK)
+		dccpstat.tcplikes_recv_datarecv++;
+	
+	/* Grab Ack Vector 0 or 1 */
+	avsize = dccp_get_option(options, optlen, DCCP_OPT_ACK_VECTOR0, av_rcv,10);
+	if (avsize == 0)
+		avsize = dccp_get_option(options, optlen, DCCP_OPT_ACK_VECTOR1, av_rcv,10);
+
+	/* We are only interested in acks-on-acks here.
+	 * The "real" ack handling is done be the sender */
+	if (avsize == 0 && cb->pcb->ack_rcv) {
+		u_int32_t ackthru;
+		/* We got an Ack without an ackvector.
+		 * This would mean it's an ack on an ack.
+		 */
+		ackthru = _avlist_get(cb, cb->pcb->ack_rcv);
+		ACK_DEBUG((LOG_INFO, "GOT Ack without Ackvector; Ackthru: %u\n", ackthru));
+		if (ackthru) {
+			dccp_update_ackvector(cb->pcb, ackthru);
+			dccpstat.tcplikes_recv_ackack++;
+		}
+	} else if (avsize > 0 && cb->pcb->ack_rcv) {
+		/* We received an AckVector */
+		u_int32_t acknum, ackthru;
+		int i;
+		ACK_DEBUG((LOG_INFO, "GOT Ack with Ackvector\n"));
+		/* gotta loop through the ackvector */
+		acknum = cb->pcb->ack_rcv;
+		for (i=0; i<avsize; i++) {
+			u_int8_t state, len;
+			state = (av_rcv[i] & 0xc0) >> 6;
+			len = (av_rcv[i] & 0x2f) + 1;
+			if (state != 0) {
+				/* Drops in ackvector! Will be noted and taken care of by the sender part */
+				ACK_DEBUG((LOG_INFO, "Packets %u - %u are FUCKED\n",acknum-len, acknum));
+				continue;
+			}
+			
+			while (len>0) {
+				ackthru = _avlist_get(cb, acknum);
+				ACK_DEBUG((LOG_INFO, "Ackthru: %u\n", ackthru));
+				if (ackthru) {
+					dccp_update_ackvector(cb->pcb, ackthru);
+					dccpstat.tcplikes_recv_ackack++;
+				}
+				acknum--;
+				len--;
+			} 
+		}
+	}
+
+	ACK_DEBUG((LOG_INFO, "Adding %u to local ackvector\n", cb->pcb->seq_rcv));
+	dccp_increment_ackvector(cb->pcb, cb->pcb->seq_rcv);
+	cb->unacked++;
+
+	if (cb->unacked >= cb->pcb->ack_ratio) {
+		/* Time to send an Ack */
+		
+		avsize = dccp_generate_ackvector(cb->pcb, ackvector);
+		cb->unacked = 0;
+		if (avsize > 0) {
+			dccp_add_option(cb->pcb, DCCP_OPT_ACK_VECTOR0, ackvector, avsize);
+			cb->pcb->ack_snd = cb->pcb->seq_rcv;
+			_avlist_add(cb, cb->pcb->seq_snd+1, cb->pcb->ack_snd);
+			ACK_DEBUG((LOG_INFO, "Recvr: Sending Ack (%u) w/ Ack Vector\n", cb->pcb->ack_snd));
+			dccpstat.tcplikes_recv_acksent++;
+			dccp_output(cb->pcb, 1);
+		}
+	}
+	mtx_unlock(&(cb->mutex));
+}
+
+void _avlist_add(struct tcplike_recv_ccb *cb, u_int32_t localseq, u_int32_t ackthru)
+{
+	struct ack_list *a;
+	ACK_DEBUG((LOG_INFO,"Adding localseq %u - ackthru %u to avlist\n", localseq, ackthru));
+	/*MALLOC_DEBUG((LOG_INFO, "New ack_list, %u\n", sizeof (struct ack_list)));*/
+	a = malloc(sizeof(struct ack_list), M_TEMP, M_DONTWAIT);
+	if (a == NULL) {
+		MALLOC_DEBUG((LOG_INFO, "avlist_add: FAILED\n"));
+		dccpstat.tcplikes_recv_memerr++;
+		return;
+	}
+	a->localseq = localseq;
+	a->ackthru = ackthru;
+	a->next = cb->av_list;
+	cb->av_list = a;
+}
+
+/**
+ * Searches the av_list. if 'localseq' found, drop it from list and return ackthru
+ **/
+u_int32_t _avlist_get(struct tcplike_recv_ccb *cb, u_int32_t localseq)
+{
+	struct ack_list *a, *n, *p;
+	u_int32_t ackthru;
+
+	ACK_DEBUG((LOG_INFO,"Getting localseq %u from avlist\n", localseq));
+	a = cb->av_list;
+	p = 0;
+	while (a) {
+		n = a->next;
+		if (a->localseq == localseq) {
+			if (p)
+				p->next = n;
+			else
+				cb->av_list = n;
+			ackthru = a->ackthru;
+			/*MALLOC_DEBUG((LOG_INFO, "Freeing element %u in ack_list\n", a->localseq));*/
+			free(a, M_TEMP);
+			return ackthru;
+		}
+		p = a;
+		a = n;
+	}
+	/* Not found. return 0 */
+	return 0;
+}
+
+/*
+int tcplike_option_recv();
+*/
+++ sys/netinet/dccp_tcplike.h	Fri Aug 25 04:02:22 2006
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 2003 Magnus Erixzon
+ * 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.
+ *
+ *
+ * Headerfile for TCP-like congestion control for DCCP
+ *
+ * Current Revision:
+ *
+ * $Source: /home/joahag-9/CVSROOT/dccp/src/sys/netinet/dccp_tcplike.h,v $
+ * $Revision: 1.27 $
+ * $Author: magerx-9 $
+ * $Date: 2003/06/01 13:16:30 $
+ *
+ * Revision history:
+ *
+ * $Log: dccp_tcplike.h,v $
+ * Revision 1.27  2003/06/01 13:16:30  magerx-9
+ * Correct(?) handling of Ack Ratio
+ *
+ * Revision 1.26  2003/05/31 23:30:49  magerx-9
+ * Not sure whats new.. Something is, I guess
+ *
+ * Revision 1.25  2003/05/29 09:38:09  magerx-9
+ * Minor improvement on congestion control
+ *
+ * Revision 1.24  2003/05/28 08:27:59  magerx-9
+ * cwndlist back to type charlist
+ *
+ * Revision 1.23  2003/05/26 13:35:28  magerx-9
+ * checkin before i change cwndvector (again)
+ *
+ * Revision 1.22  2003/05/26 08:19:28  magerx-9
+ * fixors
+ *
+ * Revision 1.21  2003/05/26 01:21:18  magerx-9
+ * bah
+ *
+ * Revision 1.19  2003/05/15 19:46:44  magerx-9
+ * Dont halt
+ *
+ * Revision 1.18  2003/05/13 15:15:02  magerx-9
+ * Changed name on some dccp_cc_sw functions
+ *
+ * Revision 1.17  2003/05/13 11:49:22  joahag-9
+ * Added copyright text
+ *
+ * Revision 1.16  2003/05/13 00:40:24  magerx-9
+ * Barf barf barf
+ *
+ * Revision 1.15  2003/05/05 23:47:08  magerx-9
+ * Bug fixing. Redesign of cwndvector
+ *
+ * Revision 1.14  2003/04/25 15:48:09  nilmat-8
+ * DCCP: Fixed get_option, added buflen check
+ *       Exchange connection establishment och cc recv packet in dccp_input
+ * TFRC: Receiver sends feedback
+ * REST: Update type on cc_send_ack_recv
+ *
+ * Revision 1.13  2003/04/23 15:58:47  magerx-9
+ * Changed def of cc_recv_packet. options is now an argument
+ *
+ * Revision 1.12  2003/04/23 14:22:36  magerx-9
+ * Changed definition of cc_recv_packet
+ *
+ * Revision 1.11  2003/04/22 00:48:51  magerx-9
+ * Changed cwndvector
+ *
+ * Revision 1.10  2003/04/21 11:46:44  nilmat-8
+ * Change type and meaning on cc_send_packet_sent.
+ *
+ * Revision 1.9  2003/04/21 01:39:44  magerx-9
+ * Minor updates
+ *
+ * Revision 1.8  2003/04/20 16:30:40  magerx-9
+ * Minor adjustments according to nilmat
+ *
+ * Revision 1.7  2003/04/20 15:33:18  magerx-9
+ * Adjustments to conform to new code standards
+ *
+ * Revision 1.6  2003/04/04 22:35:41  magerx-9
+ * Added cwndvector_t
+ *
+ * Revision 1.5  2003/04/02 23:26:09  magerx-9
+ * Removed unused vars and defines
+ *
+ * Revision 1.4  2003/03/31 11:34:16  magerx-9
+ * Minor fixes, for initial compilation
+ *
+ * Revision 1.3  2003/03/31 11:30:40  magerx-9
+ * Minor fixes, for initial compilation
+ *
+ * Revision 1.2  2003/03/31 11:29:21  magerx-9
+ * Minor fixes, for initial compilation
+ *
+ * Revision 1.1  2003/03/31 11:06:48  magerx-9
+ * Initial revision
+ *
+ *
+ **/
+
+#ifndef _NETINET_DCCP_TCPLIKE_H_
+#define _NETINET_DCCP_TCPLIKE_H_
+
+/* 
+ * TCPlike sender 
+ */
+
+/* Parameter to decide when a packet is considered lost */
+#define TCPLIKE_NUMDUPACK 3
+/* Upperbound timeout value */
+#define TIMEOUT_UBOUND 30*hz
+#define TCPLIKE_MIN_RTT (hz >> 3)
+#define TCPLIKE_INITIAL_CWND 3
+#define TCPLIKE_INITIAL_CWNDVECTOR 512
+
+/* TCPlike sender congestion control block (ccb) */
+struct tcplike_send_ccb
+{
+	struct mtx mutex;
+	struct dccpcb *pcb; /* Pointer to associated dccpcb */
+	u_int32_t cwnd; /* congestion window */
+	u_int32_t ssthresh;
+	u_int32_t oldcwnd_ts; /* old cwnd tail seqnr */
+	
+	u_int16_t rtt; /* estimated round trip-time */
+	u_int16_t rto; /* Timeout value */
+	u_int16_t rtt_d;
+	
+	int16_t outstanding; /* Number of unacked packets sent */
+	u_int16_t rcvr_ackratio; /* Receiver ack ratio */
+
+	u_int16_t acked_in_win; /* No of acked packets in the window */
+	u_int8_t acked_windows; /* No of acked windows with no lost Acks */
+
+	u_int32_t ack_last; /* Last ok Ack packet */
+	u_int32_t ack_miss; /* oldest missing Ack packet */
+	
+	struct callout_handle rto_timer;
+
+	u_char *cwndvector;  /* 2 bits per packet */
+	u_char *cv_hp;  /* head ptr for cwndvector */
+	u_int16_t cv_size;
+	u_int32_t cv_hs, cv_ts; /* lowest/highest seq no in cwndvector */
+
+	u_int8_t sample_rtt;
+	u_int32_t timestamp;
+
+	u_int32_t rcvd_ack, lost_ack;
+};
+
+#ifdef _KERNEL
+
+/* Functions declared in struct dccp_cc_sw */
+
+/* Initialises the sender side
+ * args: pcb  - pointer to dccpcb of associated connection
+ * returns: pointer to a tcplike_send_ccb struct on success, otherwise 0
+ */ 
+void *tcplike_send_init(struct dccpcb *pcb); 
+
+/* Free the sender side
+ * args: ccb - ccb of sender
+ */
+void tcplike_send_free(void *ccb);
+
+/* Ask TCPlike wheter one can send a packet or not 
+ * args: ccb  -  ccb block for current connection
+ * returns: 0 if ok, else <> 0.
+ */ 
+int tcplike_send_packet(void *ccb, long datasize);
+void tcplike_send_packet_sent(void *ccb, int moreToSend, long datasize);
+
+/* Notify that an ack package was received
+ * args: ccb  -  ccb block for current connection
+ */
+void tcplike_send_packet_recv(void *ccb, char *, int);
+
+#endif
+
+/* 
+ * TFRC Receiver 
+ */
+
+struct ack_list
+{
+	u_int32_t localseq, ackthru;
+	struct ack_list *next;
+};
+
+/* TCPlike receiver congestion control block (ccb) */
+struct tcplike_recv_ccb {
+	struct mtx mutex;
+	struct dccpcb *pcb;               /* Pointer to associated dccpcb */
+	/* No ack ratio or vector here. it's a global feature */
+	struct ack_list *av_list;
+	u_int16_t unacked; /* no of unacked packets */
+};
+
+#ifdef _KERNEL
+
+/* Functions declared in struct dccp_cc_sw */
+
+/* Initialises the receiver side
+ * args: pcb  -  pointer to dccpcb of associated connection
+ * returns: pointer to a tcplike_recv_ccb struct on success, otherwise 0
+ */ 
+void *tcplike_recv_init(struct dccpcb *pcb); 
+
+/* Free the receiver side
+ * args: ccb - ccb of recevier
+ */
+void tcplike_recv_free(void *ccb);
+
+/*
+ * Tell TCPlike that a packet has been received
+ * args: ccb  -  ccb block for current connection 
+ */
+void tcplike_recv_packet_recv(void *ccb, char *, int);
+
+/*
+int tcplike_option_recv();
+*/
+#endif
+
+#endif
+++ sys/netinet/dccp_tfrc.c	Fri Aug 25 04:03:09 2006
@@ -0,0 +1,1599 @@
+/*
+ * Copyright (c) 2003  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: dccp_tfrc.c,v 1.47 2003/05/28 17:36:15 nilmat-8 Exp $
+ */
+
+/* This implementation conforms to the drafts of DCCP dated Mars 2003. The options used are window counter, elapsed time, loss event rate and receive rate.  No support for history discounting or oscillation prevention. */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/domain.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/proc.h>
+#include <sys/protosw.h>
+#include <sys/signalvar.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/sx.h>
+#include <sys/sysctl.h>
+#include <sys/syslog.h>
+#include <sys/queue.h>
+
+#include <net/if.h>
+#include <net/route.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_pcb.h>
+#include <netinet/in_var.h>
+
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/icmp_var.h>
+#include <netinet/ip_var.h>
+
+#include <netinet/dccp_tfrc.h>
+#include <netinet/dccp.h>
+#include <netinet/dccp_var.h>
+
+/*#define TFRCDEBUG
+  #define TFRCDEBUGTIMERS*/
+
+#include <netinet/dccp_tfrc_lookup.h>
+
+/*#define NOTFRCSENDER
+#define NOTFRCRECV*/
+
+#ifdef TFRCDEBUG
+#define TFRC_DEBUG(args) log args
+#else
+#define TFRC_DEBUG(args)
+#endif
+
+#ifdef TFRCDEBUGTIMERS
+#define TFRC_DEBUG_TIME(args) log args
+#else
+#define TFRC_DEBUG_TIME(args)
+#endif
+
+#include <netinet/dccp_tfrc_print.h>
+
+/* Timeval operations */
+const struct timeval delta_half = {0,TFRC_OPSYS_TIME_GRAN/2};
+
+/*
+ * Half time value struct (accurate to +- 0.5us)
+ * args:  tvp  -  pointer to timeval structure
+ * Tested u:OK
+ */
+#define HALFTIMEVAL(tvp) \
+        do { \
+            if((tvp)->tv_sec & 1) \
+	      (tvp)->tv_usec += 1000000; \
+	    (tvp)->tv_sec = (tvp)->tv_sec >> 1; \
+	    (tvp)->tv_usec = (tvp)->tv_usec >> 1; \
+        }while(0)
+
+/* Sender side */
+
+/* Calculate new t_ipi (inter packet interval) by
+ *    t_ipi = s/X_inst; 
+ * args:  ccbp - pointer to sender ccb block
+ * Tested u:OK - Note: No check for x=0 -> t_ipi ={0xFFF...,0xFFF}
+ */
+#define CALCNEWTIPI(ccbp)                              \
+        do{                                            \
+           ccbp->t_ipi.tv_sec = (long) ( ((double) (ccbp->s)) / (ccbp->x) );                    \
+           ccbp->t_ipi.tv_usec = (long) (( ((double)(ccbp->s)) / (ccbp->x) - ccbp->t_ipi.tv_sec)*((double)1000000.0));   \
+        }while (0)
+
+/* Calculate new delta by 
+ *    delta = min(t_ipi/2, t_gran/2);
+ * args: ccbp - pointer to sender ccb block 
+ * Tested u:OK
+ */
+#define CALCNEWDELTA(ccbp)                             \
+         do {                                          \
+            ccbp->delta = delta_half;                  \
+            if (ccbp->t_ipi.tv_sec == 0 && ccbp->t_ipi.tv_usec < TFRC_OPSYS_TIME_GRAN){     \
+	       ccbp->delta = ccbp->t_ipi;              \
+	       HALFTIMEVAL(&(ccbp->delta));            \
+	    }                                          \
+	 } while (0)
+
+/* External declarations */
+extern int dccp_get_option(char *, int, int, char *,int);
+
+/* Forward declarations */
+void  tfrc_time_no_feedback(void *ccb);
+void  tfrc_time_send(void *ccb);
+void  tfrc_set_send_timer(struct tfrc_send_ccb *cb, struct timeval t_now);
+void  tfrc_updateX(struct tfrc_send_ccb *cb, struct timeval t_now);
+double tfrc_calcX(u_int16_t s, u_int32_t R, double p);
+void  tfrc_send_term(void *ccb);
+
+/* Calculate the send rate according to TCP throughput eq.
+ * args: s - packet size (in bytes)
+ *       R - Round trip time  (in micro seconds)
+ *       p - loss event rate  (0<=p<=1)
+ * returns:  calculated send rate (in bytes per second)
+ * Tested u:OK
+ */
+__inline double tfrc_calcX(u_int16_t s, u_int32_t R, double p){
+  FLOOKUPTEST(p);
+  return  ( ((double) (s)) * 1000000.0 / ( ((double) R) * FLOOKUP(p)) );
+}
+
+/* 
+ * Function called by the send timer (to send packet)
+ * args: cb -  sender congestion control block
+ */
+void tfrc_time_send(void *ccb){
+  struct tfrc_send_ccb *cb = (struct tfrc_send_ccb *) ccb;
+  int s;
+  struct inpcb *inp;
+
+  if(cb->state == TFRC_SSTATE_TERM){
+    TFRC_DEBUG((LOG_INFO,"TFRC - Send timer is ordered to terminate. (tfrc_time_send)\n"));
+    return;
+  }
+
+  if(cb->ch_stimer.callout == NULL || callout_pending(cb->ch_stimer.callout)){
+    TFRC_DEBUG((LOG_INFO,"TFRC - Callout pending. (tfrc_time_send)\n"));
+    return;
+  }
+
+  /* aquire locks for dccp_output */
+  s = splnet();
+  INP_INFO_RLOCK(&dccpbinfo);
+  inp = cb->pcb->d_inpcb;
+  INP_LOCK(inp);
+  INP_INFO_RUNLOCK(&dccpbinfo); 
+
+  cb->ch_stimer.callout = NULL;
+  dccp_output(cb->pcb, 1);
+  tfrc_send_packet_sent(cb,0,-1); /* make sure we schedule next send time */
+
+  /* release locks */
+  INP_UNLOCK(inp);
+    splx(s);
+}
+
+/*
+ * Calculate and set when the send timer should expire
+ * args: cb -  sender congestion control block
+ *       t_now - timeval struct containing actual time
+ * Tested u:OK
+ */
+void tfrc_set_send_timer(struct tfrc_send_ccb *cb, struct timeval t_now){
+  struct timeval t_temp;
+  long t_ticks;
+  /* set send timer to fire in t_ipi - (t_now-t_nom_old) 
+   * or in other words after t_nom - t_now */
+  t_temp = cb->t_nom;
+  timevalsub(&(t_temp),&(t_now));
+
+#ifdef TFRCDEBUG
+  if(t_temp.tv_sec < 0 || t_temp.tv_usec < 0)
+    panic("TFRC - scheduled a negative time! (tfrc_set_send_timer)\n");
+#endif 
+
+  t_ticks = (t_temp.tv_usec + 1000000*t_temp.tv_sec) / (1000000/hz);
+  if (t_ticks == 0)
+    t_ticks = 1;
+  TFRC_DEBUG_TIME((LOG_INFO,"TFRC scheduled send timer to expire in %i ticks (hz=%u)\n",(int) t_ticks,hz));
+  cb->ch_stimer = timeout(tfrc_time_send,(void *) cb,t_ticks);  
+}
+
+/*
+ * 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;
+ * args: cb -  sender congestion control block
+ *       t_now - timeval struct containing actual time
+ * Tested u:OK
+ */ 
+void tfrc_updateX(struct tfrc_send_ccb *cb, struct timeval t_now){
+  double temp;
+  struct timeval t_temp,t_rtt = {0,0};
+  if (cb->p >= TFRC_SMALLEST_P){     /* to avoid large error in calcX */
+    cb->x_calc = tfrc_calcX(cb->s, cb->rtt, cb->p);
+    temp = 2*cb->x_recv;
+    if (cb->x_calc < temp)
+      temp = cb->x_calc;
+    cb->x = temp;
+    if(temp < ((double) (cb->s))/TFRC_MAX_BACK_OFF_TIME)
+      cb->x = ((double) (cb->s))/TFRC_MAX_BACK_OFF_TIME;
+    TFRC_DEBUG((LOG_INFO,"TFRC updated send rate to "));
+    PRINTFLOAT(cb->x);
+    TFRC_DEBUG((LOG_INFO," bytes/s (tfrc_updateX, p>0)\n"));
+  } else {
+    t_rtt.tv_usec = cb->rtt % 1000000;
+    t_rtt.tv_sec = cb->rtt / 1000000;
+    t_temp = t_now;
+    timevalsub(&t_temp, &(cb->t_ld));
+    if (timevalcmp(&t_temp, &t_rtt, >=)) {
+      temp = 2*cb->x_recv;
+      if (2*cb->x < temp)
+	temp = 2*cb->x;
+      cb->x = ((double)(cb->s))*1000000.0/((double) (cb->rtt));
+      if(temp > cb->x)
+	cb->x = temp;
+      cb->t_ld = t_now;
+      TFRC_DEBUG((LOG_INFO,"TFRC updated send rate to "));
+      PRINTFLOAT(cb->x);
+      TFRC_DEBUG((LOG_INFO," bytes/s (tfrc_updateX, p==0)\n"));
+    } else
+      TFRC_DEBUG((LOG_INFO,"TFRC didn't update send rate! (tfrc_updateX, p==0)\n"));
+  } 
+}
+
+/* 
+ * Function called by the no feedback timer
+ * args:  cb -  sender congestion control block
+ * Tested u:OK
+ */
+void tfrc_time_no_feedback(void *ccb){
+  u_int32_t next_time_out = 1;  /* remove init! */
+  struct timeval t_now;
+  struct tfrc_send_ccb *cb = (struct tfrc_send_ccb *) ccb;
+  mtx_lock(&(cb->mutex));
+
+  if(cb->state == TFRC_SSTATE_TERM){
+    TFRC_DEBUG((LOG_INFO,"TFRC - No feedback timer is ordered to terminate\n"));
+    goto nf_release;
+  }
+
+  if(cb->ch_nftimer.callout == NULL || callout_pending(cb->ch_nftimer.callout)){
+    TFRC_DEBUG((LOG_INFO,"TFRC - Callout pending, exiting...(tfrc_time_no_feedback)\n"));
+    goto nf_release;
+  }
+  
+  cb->ch_nftimer.callout = NULL;
+  switch(cb->state){
+  case TFRC_SSTATE_NO_FBACK:
+    TFRC_DEBUG((LOG_INFO, "TFRC - no feedback timer expired, state NO_FBACK\n"));
+    /* half send rate */
+    cb->x = cb->x / 2;
+    if (cb->x < ((double) (cb->s)) / TFRC_MAX_BACK_OFF_TIME)
+      cb->x = ((double) (cb->s)) / TFRC_MAX_BACK_OFF_TIME;
+
+    TFRC_DEBUG((LOG_INFO,"TFRC updated send rate to "));
+    PRINTFLOAT(cb->x);
+    TFRC_DEBUG((LOG_INFO," bytes/s (tfrc_time_no_feedback\n"));
+
+    /* reschedule next time out */
+
+    next_time_out = (u_int32_t) ((2.0*((double) (cb->s))/ cb->x)*1000000.0);
+    if (next_time_out < TFRC_INITIAL_TIMEOUT*1000000)
+      next_time_out = TFRC_INITIAL_TIMEOUT*1000000;
+    break;
+  case TFRC_SSTATE_FBACK:
+    /* Check if IDLE since last timeout and recv rate is less than 4 packets per RTT */ 
+ 
+    if(!(cb->idle) || (cb->x_recv >= 4.0 * ((double)(cb->s)) / ((double) (cb->rtt))* 1000000.0)){
+      TFRC_DEBUG((LOG_INFO, "TFRC - no feedback timer expired, state FBACK, not idle\n"));
+      /* 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(cb->p >= TFRC_SMALLEST_P && cb->x_calc == 0.0)
+	panic("TFRC - X_calc is zero! (tfrc_time_no_feedback)\n");
+
+      /* check also if p i zero -> x_calc is infinity ?? */
+      if(cb->p < TFRC_SMALLEST_P || cb->x_calc > 2*cb->x_recv){
+	cb->x_recv = cb->x_recv / 2;
+	if (cb->x_recv < ((double)cb->s)/(2*TFRC_MAX_BACK_OFF_TIME))
+	  cb->x_recv = ((double)cb->s)/(2*TFRC_MAX_BACK_OFF_TIME);
+      } else {
+	cb->x_recv = cb->x_calc / 4;
+      }
+
+      /* Update sending rate */
+      microtime(&t_now);
+      tfrc_updateX(cb,t_now);
+    } 
+
+    /* Schedule no feedback timer to
+     * expire in max(4*R, 2*s/X) 
+     */
+    next_time_out = (u_int32_t) ((2.0*((double) (cb->s))/ cb->x)*1000000.0);
+    if (next_time_out < cb->t_rto)
+      next_time_out = cb->t_rto;
+    
+    break;
+  default:
+    panic("tfrc_no_feedback: Illegal state!");
+    break;
+  }
+
+  /* Set timer */
+
+  next_time_out = next_time_out/(1000000/hz);
+  if (next_time_out == 0)
+    next_time_out = 1;
+
+  TFRC_DEBUG_TIME((LOG_INFO,"TFRC scheduled no feedback timer to expire in %u ticks (hz=%u)\n",next_time_out,hz));
+
+  cb->ch_nftimer = timeout(tfrc_time_no_feedback, (void*)cb, next_time_out);
+
+  /* set idle flag */
+  cb->idle = 1;
+nf_release:  
+  mtx_unlock(&(cb->mutex));
+}
+
+/* Removes ccb from memory
+ * args: ccb - ccb of sender
+ */
+void tfrc_send_term(void *ccb){
+  struct tfrc_send_ccb *cb = (struct tfrc_send_ccb *) ccb;
+  
+  if(ccb == 0)
+    panic("TFRC - Sender ccb is null! (free)");
+
+  /* free sender */
+
+  mtx_destroy(&(cb->mutex));
+  
+  free(cb, M_PCB);
+  TFRC_DEBUG((LOG_INFO, "TFRC sender is destroyed\n"));
+}
+
+
+/* Functions declared in struct dccp_cc_sw */
+
+/* Initialises the sender side
+ * args:  pcb - dccp protocol control block
+ * returns: pointer to a tfrc_send_ccb struct on success, otherwise 0
+ * Tested u:OK
+ */ 
+void *tfrc_send_init(struct dccpcb* pcb){
+  struct tfrc_send_ccb *ccb;
+
+  ccb = malloc(sizeof (struct tfrc_send_ccb), M_PCB, M_DONTWAIT | M_ZERO);
+  if (ccb == 0){
+    TFRC_DEBUG((LOG_INFO, "Unable to allocate memory for tfrc_send_ccb!\n"));
+    return 0;
+  }
+
+  /* init sender */
+  
+  mtx_init(&(ccb->mutex), "TFRC Sender mutex", NULL, MTX_DEF | MTX_RECURSE);
+
+  ccb->pcb = pcb;
+  if (ccb->pcb->avgpsize >= TFRC_MIN_PACKET_SIZE && ccb->pcb->avgpsize <= TFRC_MAX_PACKET_SIZE)
+    ccb->s = (u_int16_t) ccb->pcb->avgpsize;
+  else
+    ccb->s = TFRC_STD_PACKET_SIZE;
+
+  TFRC_DEBUG((LOG_INFO,"TFRC - Sender is using packet size %u\n",ccb->s));
+  
+  ccb->x = (double) ccb->s;        /* set transmissionrate to 1 packet per second */
+  ccb->t_ld.tv_sec = -1;
+  ccb->t_ld.tv_usec = 0;
+
+#ifdef TFRCDEBUG
+  ccb->t_last_win_count.tv_sec = -1;
+#endif
+
+  /* init packet history */
+  STAILQ_INIT(&(ccb->hist));
+
+  ccb->state = TFRC_SSTATE_NO_SENT;
+  
+  TFRC_DEBUG((LOG_INFO, "TFRC sender initialised!\n"));
+  dccpstat.tfrcs_send_conn++;
+  return ccb;
+} 
+
+/* Free the sender side
+ * args: ccb - ccb of sender
+ * Tested u:OK
+ */
+void tfrc_send_free(void *ccb){
+  struct s_hist_entry *elm,*elm2;
+  struct tfrc_send_ccb *cb = (struct tfrc_send_ccb *) ccb;
+
+  TFRC_DEBUG((LOG_INFO, "TFRC send free called!\n"));
+  
+  if(ccb == 0)
+    panic("TFRC - Sender ccb is null! (free)");
+
+  /* uninit sender */
+
+  /* get mutex */
+  mtx_lock(&(cb->mutex));
+  cb->state = TFRC_SSTATE_TERM;
+  /* unschedule timers */
+  if (cb->ch_stimer.callout)
+    untimeout(tfrc_time_send, (void*) cb, cb->ch_stimer);
+  if (cb->ch_nftimer.callout)
+    untimeout(tfrc_time_no_feedback, (void*) cb, cb->ch_nftimer);
+  
+  /* Empty packet history */
+  elm = STAILQ_FIRST(&(cb->hist));
+  while (elm != NULL) {
+    elm2 = STAILQ_NEXT(elm, linfo);
+    free(elm, M_TEMP); /* M_TEMP ?? */
+    elm = elm2;
+  }
+  STAILQ_INIT(&(cb->hist));
+  
+  mtx_unlock(&(cb->mutex));
+
+  /* schedule the removal of ccb */
+  timeout(tfrc_send_term, (void*)cb, TFRC_SEND_WAIT_TERM*hz); 
+}
+
+
+/* Ask TFRC whether one can send a packet or not 
+ * args: ccb  -  ccb block for current connection 
+ * returns: 1 if ok, else 0.
+ * Tested u:OK
+ */ 
+int tfrc_send_packet(void *ccb, long datasize){
+  struct s_hist_entry *new_packet;
+  u_int8_t answer = 0;
+  u_int8_t win_count = 0;
+  u_int32_t uw_win_count = 0;
+  struct timeval t_now, t_temp;
+  struct tfrc_send_ccb *cb = (struct tfrc_send_ccb *) ccb;
+#ifdef NOTFRCSENDER
+  return 1;
+#endif
+
+  /* check if pure ACK or Terminating */
+  if(datasize == 0 || cb->state == TFRC_SSTATE_TERM){
+    return 1;
+  } else if (cb->state == TFRC_SSTATE_TERM) {
+    TFRC_DEBUG((LOG_INFO,"TFRC - Asked to send packet when terminating!\n"));
+    return 0;
+  }
+
+  /* we have data to send */
+  mtx_lock(&(cb->mutex));
+
+  /* check to see if we already have allocated memory last time */
+  new_packet = STAILQ_FIRST(&(cb->hist));
+
+  if((new_packet != NULL && new_packet->t_sent.tv_sec >= 0) || new_packet == NULL){  
+    /* check to see if we have memory to add to packet history */
+    new_packet = malloc(sizeof (struct s_hist_entry), M_TEMP, M_DONTWAIT); /*M_TEMP??*/
+    if(new_packet == NULL){
+      TFRC_DEBUG((LOG_INFO,"TFRC - Not enough memory to add packet to packet history (send refused)! (tfrc_send_packet)\n"));
+      answer = 0;
+      dccpstat.tfrcs_send_nomem++;
+      goto sp_release;
+    }
+    new_packet->t_sent.tv_sec = -1; /* mark as unsent */
+    STAILQ_INSERT_HEAD(&(cb->hist), new_packet, linfo);
+  }
+  
+  switch (cb->state){
+  case TFRC_SSTATE_NO_SENT :
+    TFRC_DEBUG((LOG_INFO,"TFRC - DCCP ask permission to send first data packet (tfrc_send_packet)\n"));
+    microtime(&(cb->t_nom));  /* set nominal send time for initial packet */
+    t_now = cb->t_nom;
+    
+    
+    /* init feedback timer */
+    
+    cb->ch_nftimer = timeout(tfrc_time_no_feedback, (void *) cb, 
+			     TFRC_INITIAL_TIMEOUT*hz);
+    win_count = 0;
+    cb->t_last_win_count = t_now;
+    TFRC_DEBUG((LOG_INFO, "TFRC - Permission granted. Scheduled no feedback timer (initial) to expire in %u ticks (hz=%u) (tfrc_send_packet)\n",TFRC_INITIAL_TIMEOUT*hz,hz)); 
+    /* start send timer */
+
+    /* Calculate new t_ipi */
+    CALCNEWTIPI(cb);
+    timevaladd(&(cb->t_nom),&(cb->t_ipi));  /* t_nom += t_ipi */
+    /* Calculate new delta */
+    CALCNEWDELTA(cb);
+    tfrc_set_send_timer(cb,t_now);   /* if so schedule sendtimer */
+    cb->state = TFRC_SSTATE_NO_FBACK;
+    answer = 1;
+    break;
+  case TFRC_SSTATE_NO_FBACK :
+  case TFRC_SSTATE_FBACK :
+    if(!(cb->ch_stimer.callout)){
+       microtime(&t_now);
+       
+       t_temp = t_now;
+       timevaladd(&(t_temp),&(cb->delta)); /* t_temp = t_now+delta */
+       
+       if (( timevalcmp(&(t_temp),&(cb->t_nom),>))){
+	 /* Packet can be sent */
+
+#ifdef TFRCDEBUG
+	 if (cb->t_last_win_count.tv_sec == -1)
+	   panic("TFRC - t_last_win_count unitialized (tfrc_send_packet)\n");
+#endif
+	t_temp = t_now;
+	timevalsub(&t_temp, &(cb->t_last_win_count));
+	
+	/* calculate win_count option */
+	if(cb->state == TFRC_SSTATE_NO_FBACK){
+	  /* Assume RTT= t_rto(initial)/4 */
+	  uw_win_count = (((double) (t_temp.tv_sec)) + (((double) (t_temp.tv_usec))/1000000.0))/ (TFRC_INITIAL_TIMEOUT/(4.0*TFRC_WIN_COUNT_PER_RTT));
+	}else{
+	  uw_win_count = (((double) (t_temp.tv_sec)) + (((double) (t_temp.tv_usec))/1000000.0))/ (((double) (cb->rtt))/(1000000.0*TFRC_WIN_COUNT_PER_RTT));
+	}
+	uw_win_count += cb->last_win_count; 
+	win_count = uw_win_count % TFRC_WIN_COUNT_LIMIT;
+	answer = 1;
+       } else {
+	 answer = 0;
+       }
+    } else {
+      answer = 0;
+    }
+    break;
+  default:
+    panic("tfrc_send_packet: Illegal state!");
+    break;
+  }
+  
+  /* can we send? if so add options and add to packet history */
+  if(answer){
+    /* Add packet to history */
+    
+    new_packet->win_count = win_count;
+    
+    /* todo: remove old option */
+    
+    /* add option */
+    if(dccp_add_option(cb->pcb, TFRC_OPT_WINDOW_COUNT,(char *) &win_count, 1)){
+      TFRC_DEBUG((LOG_INFO,"TFRC - Add window counter option failed, send refused! (tfrc_send_packet)!\n"));
+      answer = 0;
+      dccpstat.tfrcs_send_erropt++;
+    }
+  }
+sp_release:  
+  mtx_unlock(&(cb->mutex));
+  return answer;
+}
+
+/* Notify sender that a packet has been sent 
+ * args: ccb - ccb block for current connection
+ *	 moreToSend - if there exists more packets to send
+ *       dataSize -   packet size
+ */
+void tfrc_send_packet_sent(void *ccb, int moreToSend, long datasize){
+  struct timeval t_now, t_temp;
+  struct s_hist_entry *packet;
+  struct tfrc_send_ccb *cb = (struct tfrc_send_ccb *) ccb;
+
+#ifdef NOTFRCSENDER
+  return;
+#endif 
+
+  if (cb->state == TFRC_SSTATE_TERM) {
+    TFRC_DEBUG((LOG_INFO,"TFRC - Packet sent when terminating!\n"));
+    return;
+  }
+  
+  mtx_lock(&(cb->mutex));
+  microtime(&t_now);
+  
+  /* check if we have sent a data packet */
+  if(datasize > 0){
+    /* add send time to history */
+    packet = STAILQ_FIRST(&(cb->hist));
+    if(packet == NULL)
+      panic("TFRC - Packet does not exist in history! (tfrc_send_packet_sent)");
+    else if(packet != NULL && packet->t_sent.tv_sec >= 0)
+      panic("TFRC - No unsent packet in history! (tfrc_send_packet_sent)");
+    packet->t_sent = t_now;
+    packet->seq = cb->pcb->seq_snd;
+    /* check if win_count have changed */
+    if(packet->win_count != cb->last_win_count){
+      cb->t_last_win_count = t_now;
+      cb->last_win_count = packet->win_count;
+    }
+    TFRC_DEBUG((LOG_INFO, "TFRC - Packet sent (%u,%u,(",packet->seq,packet->win_count));
+    PRINTTIMEVALu(&(packet->t_sent));
+    TFRC_DEBUG((LOG_INFO, ")) (tfrc_send_packet_sent)\n"));
+      cb->idle = 0;
+  }
+
+  /* if timer is running, do nothing */
+  if(cb->ch_stimer.callout){
+    goto sps_release;
+  }
+  
+  switch (cb->state){
+  case TFRC_SSTATE_NO_SENT :
+    /* if first was pure ack */
+    if(datasize == 0){
+      goto sps_release;
+    } else
+      panic("TFRC - First packet sent is noted as a data packet in tfrc_send_packet_sent\n"); 
+    break;
+  case TFRC_SSTATE_NO_FBACK :
+  case TFRC_SSTATE_FBACK :
+    if(datasize <= 0){ /* we have ack (or simulate a sent packet which never can have moreToSend */
+      moreToSend = 0;
+    } else {
+      /* Calculate new t_ipi */
+      CALCNEWTIPI(cb);
+      timevaladd(&(cb->t_nom),&(cb->t_ipi));  /* t_nom += t_ipi */
+      /* Calculate new delta */
+      CALCNEWDELTA(cb);
+    }
+
+    if(!moreToSend){
+      /* loop until we find a send time in the future */
+      microtime(&t_now);
+      t_temp = t_now;
+      timevaladd(&(t_temp),&(cb->delta)); /* t_temp = t_now+delta */
+      while((timevalcmp(&(t_temp),&(cb->t_nom),>))){
+	 /* Calculate new t_ipi */
+	 CALCNEWTIPI(cb);
+         timevaladd(&(cb->t_nom),&(cb->t_ipi));  /* t_nom += t_ipi */
+	 /* Calculate new delta */
+	 CALCNEWDELTA(cb);
+ 
+	 microtime(&t_now);
+	 t_temp = t_now;
+	 timevaladd(&(t_temp),&(cb->delta)); /* t_temp = t_now+delta */
+      }
+      tfrc_set_send_timer(cb,t_now);
+    } else {
+      microtime(&t_now);
+      t_temp = t_now;
+      timevaladd(&(t_temp),&(cb->delta)); /* t_temp = t_now+delta */
+      /* Check if next packet can not be sent immediately */
+      if(!(timevalcmp(&(t_temp),&(cb->t_nom),>))){
+	tfrc_set_send_timer(cb,t_now);   /* if so schedule sendtimer */
+      }
+    }
+    break;
+  default:
+    panic("tfrc_send_packet_sent: Illegal state!");
+    break;
+  }
+
+ sps_release:
+  mtx_unlock(&(cb->mutex));
+}
+
+/* Notify that a an ack package was received (i.e. a feedback packet)
+ * args: ccb  -  ccb block for current connection
+ */ 
+void tfrc_send_packet_recv(void *ccb, char *options, int optlen){
+  u_int32_t  next_time_out; 
+  struct timeval t_now;
+  int res;
+  u_int16_t t_elapsed;
+  u_int32_t pinv;
+  u_int32_t x_recv;
+  
+  u_int32_t r_sample;
+  
+  struct s_hist_entry *elm,*elm2;
+  struct tfrc_send_ccb *cb = (struct tfrc_send_ccb *) ccb;
+
+#ifdef NOTFRCSENDER
+  return;
+#endif
+
+  if (cb->state == TFRC_SSTATE_TERM) {
+    TFRC_DEBUG((LOG_INFO,"TFRC - Sender received a packet when terminating!\n"));
+    return;
+  }
+   
+  /* we are only interested in ACKs */
+  if (!(cb->pcb->type_rcv == DCCP_TYPE_ACK || cb->pcb->type_rcv == DCCP_TYPE_DATAACK))
+    return;
+
+  res = dccp_get_option(options, optlen,TFRC_OPT_LOSS_RATE ,(char *) &pinv,4);
+  if (res == 0){
+    TFRC_DEBUG((LOG_INFO, "TFRC - Missing Loss rate option! (tfrc_send_packet_recv)\n"));
+    dccpstat.tfrcs_send_noopt++;
+    return;
+  }
+
+  res = dccp_get_option(options, optlen,TFRC_OPT_ELAPSED_TIME,(char *) &t_elapsed,2);
+
+  if (res == 0){
+    TFRC_DEBUG((LOG_INFO, "TFRC - Missing elapsed time option! (tfrc_send_packet_recv)\n"));
+    dccpstat.tfrcs_send_noopt++;
+    return;
+  }
+
+  res = dccp_get_option(options, optlen,TFRC_OPT_RECEIVE_RATE,(char *) &x_recv,4);
+  if (res == 0){
+    TFRC_DEBUG((LOG_INFO, "TFRC - Missing x_recv option! (tfrc_send_packet_recv)\n"));
+    dccpstat.tfrcs_send_noopt++;
+    return;
+  }
+
+  dccpstat.tfrcs_send_fbacks++;
+  /* change byte order */
+  t_elapsed = ntohs(t_elapsed);
+  x_recv = ntohl(x_recv);
+  pinv = ntohl(pinv);
+  
+  TFRC_DEBUG((LOG_INFO, "TFRC - Receieved options on ack %u: pinv=%u, t_elapsed=%u, x_recv=%u ! (tfrc_send_packet_recv)\n",cb->pcb->ack_rcv,pinv,t_elapsed,x_recv));
+  
+  mtx_lock(&(cb->mutex));
+
+  switch (cb->state){
+  case TFRC_SSTATE_NO_FBACK :
+  case TFRC_SSTATE_FBACK :
+    /* Calculate new round trip sample by
+     * R_sample = (t_now - t_recvdata)-t_delay;
+     */
+
+    /* get t_recvdata from history */
+    elm = STAILQ_FIRST(&(cb->hist));
+    while (elm != NULL) {
+      if (elm->seq == cb->pcb->ack_rcv)
+	break;
+      elm = STAILQ_NEXT(elm, linfo);
+    }
+
+    if(elm == NULL){
+      TFRC_DEBUG((LOG_INFO,"TFRC - Packet does not exist in history (seq=%u)! (tfrc_send_packet_recv)",cb->pcb->ack_rcv));
+      goto sar_release;
+    }
+
+    /* Update RTT */
+    microtime(&t_now);
+    timevalsub(&t_now, &(elm->t_sent));
+    r_sample = t_now.tv_sec*1000000+t_now.tv_usec;
+    r_sample = r_sample - ((u_int32_t)t_elapsed)*1000; /* t_elapsed in ms */
+    
+    /* Update RTT estimate by 
+     * If (No feedback recv)
+     *    R = R_sample;
+     * Else
+     *    R = q*R+(1-q)*R_sample;
+     */
+    if (cb->state == TFRC_SSTATE_NO_FBACK){
+      cb->state = TFRC_SSTATE_FBACK;
+      cb->rtt = r_sample;
+    } else {
+      cb->rtt =(u_int32_t)  ( TFRC_RTT_FILTER_CONST * ((double) (cb->rtt)) +
+	(1-TFRC_RTT_FILTER_CONST)* ((double) (r_sample)) );
+    }
+    
+    TFRC_DEBUG((LOG_INFO, "TFRC - New RTT estimate %u (tfrc_send_packet_recv)\n",cb->rtt));
+
+    /* Update timeout interval */
+    cb->t_rto = 4*cb->rtt;
+
+    /* Update receive rate */
+    cb->x_recv = ((double) x_recv)/8.0;   /* x_recv in bits per second*/
+
+    /* Update loss event rate */
+    if (pinv == 0)
+      cb->p = 0;
+    else {
+      cb->p = 1.0 / ((double) pinv);
+      
+      if(cb->p < TFRC_SMALLEST_P){
+	cb->p = TFRC_SMALLEST_P;
+	TFRC_DEBUG((LOG_INFO, "TFRC - Smallest p used!\n"));
+      }
+    }
+    
+    /* unschedule no feedback timer */
+    if(cb->ch_nftimer.callout != NULL){
+      untimeout(tfrc_time_no_feedback, (void *) cb, cb->ch_nftimer);
+    }
+
+    /* Update sending rate */
+    microtime(&t_now);
+    tfrc_updateX(cb, t_now);
+
+    /* Update next send time */
+    timevalsub(&(cb->t_nom), &(cb->t_ipi));
+
+    /* Calculate new t_ipi */
+    CALCNEWTIPI(cb);
+    timevaladd(&(cb->t_nom),&(cb->t_ipi));  /* t_nom += t_ipi */
+    /* Calculate new delta */
+    CALCNEWDELTA(cb);
+
+    
+    if (cb->ch_stimer.callout != NULL)
+      untimeout(tfrc_time_send,(void *) cb, cb->ch_stimer);
+
+    cb->ch_stimer.callout = NULL;
+    dccp_output(cb->pcb, 1);
+    tfrc_send_packet_sent(cb,0,-1); /* make sure we schedule next send time */
+  
+    /* remove all packets older than the one acked from history */
+    /* elm points to acked package! */
+    
+    elm2 = STAILQ_NEXT(elm,linfo);
+ 
+    while(elm2 != NULL){
+      STAILQ_REMOVE(&(cb->hist),elm2,s_hist_entry,linfo);
+      free(elm2,M_TEMP);
+      elm2 = STAILQ_NEXT(elm,linfo);
+    }
+
+    /* Schedule no feedback timer to
+     * expire in max(4*R, 2*s/X) 
+     */
+    next_time_out = (u_int32_t) (2*((double) (cb->s))*1000000 / cb->x) ;
+    if (next_time_out < cb->t_rto)
+	next_time_out = cb->t_rto;
+    TFRC_DEBUG_TIME((LOG_INFO, "TFRC - Scheduled no feedback timer to expire in %u ticks (%u us) (hz=%u)(tfrc_send_packet_recv)\n",next_time_out/(1000000/hz),next_time_out,hz)); 
+    next_time_out = next_time_out/(1000000/hz);
+    if(next_time_out == 0)
+      next_time_out = 1;
+    
+    cb->ch_nftimer = timeout(tfrc_time_no_feedback, (void*)cb, next_time_out);
+    /* set idle flag */
+    cb->idle = 1;   
+    break;
+  default:
+    panic("tfrc_send_packet_recv: Illegal state!");
+    break;
+  }
+sar_release:  
+  mtx_unlock(&(cb->mutex));
+}
+
+/* Receiver side */
+
+/* Forward declarations */
+double tfrc_calcImean(struct tfrc_recv_ccb *cb);
+void tfrc_recv_send_feedback(struct tfrc_recv_ccb *cb);
+int tfrc_recv_add_hist(struct tfrc_recv_ccb *cb, struct r_hist_entry *packet);
+void tfrc_recv_detectLoss(struct tfrc_recv_ccb *cb);
+u_int32_t tfrc_recv_calcFirstLI(struct tfrc_recv_ccb *cb);
+void tfrc_recv_updateLI(struct tfrc_recv_ccb *cb, long seq_loss, u_int8_t win_loss);
+
+/* Weights used to calculate loss event rate */
+const double tfrc_recv_w[] = {1, 1, 1, 1, 0.8, 0.6, 0.4, 0.2};
+
+/* 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
+ * Tested u:OK
+ */
+#define TFRC_RECV_FINDDATAPACKET(cb,elm,num) \
+  do{ \
+    elm = STAILQ_FIRST(&((cb)->hist)); \
+      while((elm) != NULL){ \
+        if((elm)->type == DCCP_TYPE_DATA || (elm)->type == DCCP_TYPE_DATAACK) \
+          (num)--; \
+        if(num == 0) \
+          break; \
+        elm = STAILQ_NEXT((elm), linfo); \
+      } \
+  } while (0)
+
+/* Find next data packet in history
+ * args:  cb - ccb of receiver
+ *        elm - pointer to element (variable)
+ * returns:  elm points to found packet, otherwise NULL
+ * Tested u:OK
+ */
+#define TFRC_RECV_NEXTDATAPACKET(cb,elm) \
+  do{ \
+    if(elm != NULL){ \
+      elm = STAILQ_NEXT(elm, linfo); \
+      while((elm) != NULL && (elm)->type != DCCP_TYPE_DATA && (elm)->type != DCCP_TYPE_DATAACK){ \
+        elm = STAILQ_NEXT((elm), linfo); \
+      } \
+    } \
+  } while (0)
+
+/*
+ * Calculate avarage loss Interval I_mean
+ * args: cb - ccb of receiver
+ * returns: avarage loss interval 
+ * Tested u:OK
+ */
+double tfrc_calcImean(struct tfrc_recv_ccb *cb){
+  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(&(cb->li_hist));
+
+  for (i = 0; i< TFRC_RECV_IVAL_F_LENGTH; i++) {
+#ifdef TFRCDEBUG
+    if (elm == 0)
+      goto I_panic;
+#endif
+    I_tot0 = I_tot0 + (elm->interval * tfrc_recv_w[i]);
+    W_tot = W_tot + tfrc_recv_w[i];
+    elm = TAILQ_NEXT(elm, linfo);
+  }
+
+  elm = TAILQ_FIRST(&(cb->li_hist));
+  elm = TAILQ_NEXT(elm, linfo);
+
+  for (i = 1; i <= TFRC_RECV_IVAL_F_LENGTH; i++) {
+#ifdef TFRCDEBUG
+    if (elm == 0)
+      goto I_panic;
+#endif
+    I_tot1 = I_tot1 + (elm->interval * tfrc_recv_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;
+
+  if(I_tot < W_tot) 
+    I_tot = W_tot;
+  
+  return (I_tot/W_tot);
+#ifdef TFRCDEBUG
+I_panic:  if (elm == NULL)
+    panic("TFRC - Missing entry in interval history! (tfrc_calcImean)");
+#endif
+}
+
+/*
+ * Send a feedback packet
+ * args: cb - ccb for receiver
+ * Tested u:OK
+ */
+void tfrc_recv_send_feedback(struct tfrc_recv_ccb *cb){
+  u_int32_t x_recv, pinv;
+  u_int16_t t_elapsed;
+  struct r_hist_entry *elm;
+  struct timeval t_now, t_temp;
+  int num;
+
+  if (cb->p < 0.00000000025)  /* -> 1/p > 4 000 000 000 */
+    pinv = 0;
+  else
+    pinv = (u_int32_t) ((double) 1.0 / cb->p);
+
+  switch (cb->state){
+  case TFRC_RSTATE_NO_DATA :
+    x_recv = 0;
+      break;
+  case TFRC_RSTATE_DATA :
+    /* Calculate x_recv */
+    microtime(&t_temp);
+    timevalsub(&t_temp,&(cb->t_last_feedback));
+
+    x_recv = (u_int32_t) (((double) (cb->bytes_recv*8)) / 
+      ( ((double) t_temp.tv_sec) + ((double) t_temp.tv_usec)/1000000.0));
+
+    break;
+  default:
+    panic("tfrc_recv_send_feedback: Illegal state!");
+    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)
+    panic("No data packet in history! (tfrc_recv_send_feedback)");
+
+  
+  microtime(&t_now);
+  timevalsub(&t_now, &(elm->t_recv));
+  t_elapsed = (u_int16_t)( t_now.tv_sec*1000 + t_now.tv_usec / 1000 );
+  
+  /* change byte order */
+  t_elapsed = htons(t_elapsed);
+  x_recv = htonl(x_recv);
+  pinv = htonl(pinv);
+
+  /* add options from variables above */
+  if(dccp_add_option(cb->pcb, TFRC_OPT_LOSS_RATE, (char*) &pinv, 4)
+     || dccp_add_option(cb->pcb, TFRC_OPT_ELAPSED_TIME, (char*) &t_elapsed, 2)
+     || dccp_add_option(cb->pcb, TFRC_OPT_RECEIVE_RATE, (char*) &x_recv, 4)){
+    TFRC_DEBUG((LOG_INFO,"TFRC - Can't add options, aborting send feedback (tfrc_send_feedback)"));
+    /* todo: remove options */
+    dccpstat.tfrcs_recv_erropt++;
+    return;
+  }
+
+
+  cb->pcb->ack_snd = elm->seq;
+  cb->last_counter = elm->win_count;
+  cb->seq_last_counter = elm->seq;
+  microtime(&(cb->t_last_feedback));   
+  cb->bytes_recv = 0;
+  TFRC_DEBUG((LOG_INFO, "TFRC - Sending a feedback packet with (t_elapsed %u,pinv %u, x_recv %u, ack=%u) (tfrc_recv_send_feedback)\n",ntohs(t_elapsed),ntohl(pinv), ntohl(x_recv),elm->seq));
+  dccpstat.tfrcs_recv_fbacks++;
+  dccp_output(cb->pcb, 1); 
+}
+
+
+/*
+ * Calculate first loss interval
+ * args: cb - ccb of the receiver
+ * returns: loss interval
+ * Tested u:OK
+ */
+u_int32_t tfrc_recv_calcFirstLI(struct tfrc_recv_ccb *cb){
+  struct r_hist_entry *elm,*elm2;
+  struct li_hist_entry *li_elm;
+  struct timeval t_temp;
+  double t_rtt;
+  int temp;
+  double x_recv,fval;
+  int win_count;
+
+  temp = 1;
+  TFRC_RECV_FINDDATAPACKET(cb,elm,temp);
+  
+  if(elm == NULL)
+    panic("Packet history contains no data packets! (tfrc_recv_calcFirstLI)\n");
+  t_temp = elm->t_recv;
+  win_count = elm->win_count;
+  elm2 = elm;
+  TFRC_RECV_NEXTDATAPACKET(cb,elm2); 
+  while(elm2 != NULL){
+    temp = win_count-(int) (elm2->win_count);
+    if(temp < 0)
+      temp = temp + TFRC_WIN_COUNT_LIMIT;
+
+    if(temp > 4)
+      break;
+    elm = elm2;
+    TFRC_RECV_NEXTDATAPACKET(cb,elm2); 
+  }
+  
+  if(elm2 == NULL){
+    TFRC_DEBUG((LOG_INFO,"TFRC - Could not find a win_count interval > 4 \n"));
+    elm2=elm;
+    if (temp == 0){
+      TFRC_DEBUG((LOG_INFO,"TFRC - Could not find a win_count interval > 0. Defaulting to 1 (tfrc_recv_calcFirstLI)\n"));
+      temp = 1;
+    }
+  }
+  PRINTRCCB(cb,elm,li_elm);
+  timevalsub(&t_temp, &(elm2->t_recv));
+  t_rtt = ((double) (t_temp.tv_sec))+ ((double)(t_temp.tv_usec))/((double) 1000000);
+
+  if (t_rtt < 0){
+    TFRC_DEBUG((LOG_INFO,"TFRC - Approximation of RTT is negative!\n"));
+    t_rtt = -t_rtt;
+  }
+
+  t_rtt = t_rtt*4/((double)(temp));
+
+  TFRC_DEBUG((LOG_INFO,"TFRC - Approximated rtt to "));
+  PRINTFLOAT(t_rtt);
+  TFRC_DEBUG((LOG_INFO, " s (tfrc_recv_calcFirstLI)\n"));
+
+  /* Calculate x_recv */
+  microtime(&t_temp);
+  timevalsub(&t_temp,&(cb->t_last_feedback));
+  x_recv = (((double) (cb->bytes_recv)) / 
+	( ((double) t_temp.tv_sec) + ((double) t_temp.tv_usec)/1000000.0));
+
+  TFRC_DEBUG((LOG_INFO,"TFRC - Receive rate "));
+  PRINTFLOAT(x_recv);
+  TFRC_DEBUG((LOG_INFO," bytes/s (tfrc_recv_calcFirstLI)\n"));
+  
+  fval = ((double)(cb->s))/(x_recv * t_rtt);
+  TFRC_DEBUG((LOG_INFO,"TFRC - Fvalue to locate "));
+  PRINTFLOAT(fval);
+  TFRC_DEBUG((LOG_INFO," (tfrc_recv_calcFirstLI)\n"));
+  fval = tfrc_flookup_reverse(fval);
+  TFRC_DEBUG((LOG_INFO,"TFRC - Lookup gives p= "));
+  PRINTFLOAT(fval);
+  TFRC_DEBUG((LOG_INFO," (tfrc_recv_calcFirstLI)\n"));
+  TFRC_DEBUG((LOG_INFO, "First interval length %u\n", (u_int32_t) (1.0/fval)));
+  if (fval == 0)
+    return (u_int32_t) 0xFFFFFFFF;
+  return (u_int32_t) (1.0/fval);
+}
+
+/* Add packet to recv history (sorted on seqnum)
+ * Do not add packets that are already lost
+ * args: cb - ccb of receiver
+ *       packet - packet to insert
+ * returns:  1 if the packet was considered lost, 0 otherwise
+ * Tested u:OK
+ */
+int tfrc_recv_add_hist(struct tfrc_recv_ccb *cb, struct r_hist_entry *packet){
+  struct r_hist_entry *elm,*elm2;
+  u_int8_t num_later = 0, win_count;
+  u_int32_t seq_num = packet->seq;
+  int temp;
+  
+  TFRC_DEBUG((LOG_INFO, "TFRC - Adding packet (seq=%u,win_count=%u,type=%u,ndp=%u) to history! (tfrc_recv_add_hist)\n",packet->seq,packet->win_count,packet->type,packet->ndp));
+
+  if (STAILQ_EMPTY(&(cb->hist))){
+    STAILQ_INSERT_HEAD(&(cb->hist), packet, linfo);
+  } else {
+    elm = STAILQ_FIRST(&(cb->hist));
+    if ((seq_num > elm->seq 
+	 && seq_num-elm->seq < TFRC_RECV_NEW_SEQ_RANGE) ||
+	(seq_num < elm->seq
+	 && elm->seq - seq_num > DCCP_SEQ_NUM_LIMIT - TFRC_RECV_NEW_SEQ_RANGE)){
+      STAILQ_INSERT_HEAD(&(cb->hist), packet, linfo);
+    } else {
+      if(elm->type == DCCP_TYPE_DATA || elm->type == DCCP_TYPE_DATAACK)
+	num_later = 1;
+      
+      elm2 = STAILQ_NEXT(elm,linfo);
+      while(elm2 != NULL){
+	if ((seq_num > elm2->seq 
+	     && seq_num-elm2->seq < TFRC_RECV_NEW_SEQ_RANGE) ||
+	    (seq_num < elm2->seq
+	     && elm2->seq - seq_num > DCCP_SEQ_NUM_LIMIT - TFRC_RECV_NEW_SEQ_RANGE)){
+	  STAILQ_INSERT_AFTER(&(cb->hist), elm, packet, linfo);
+	  break;
+	}
+	elm = elm2;
+	elm2 = STAILQ_NEXT(elm,linfo);
+
+	if(elm->type == DCCP_TYPE_DATA || elm->type == DCCP_TYPE_DATAACK)
+	  num_later++;
+
+	if (num_later == TFRC_RECV_NUM_LATE_LOSS){
+	  free(packet, M_TEMP);
+	  TFRC_DEBUG((LOG_INFO, "TFRC - Packet already lost! (tfrc_recv_add_hist)\n"));
+	  return 1;
+	  break;
+	}
+      }
+      
+      if(elm2 == NULL && num_later < TFRC_RECV_NUM_LATE_LOSS){
+	STAILQ_INSERT_TAIL(&(cb->hist), packet, linfo);
+      }
+    }
+  }
+
+  /* trim history (remove all packets after the NUM_LATE_LOSS+1 data packets)*/
+  if(TAILQ_FIRST(&(cb->li_hist)) != NULL){
+    num_later = TFRC_RECV_NUM_LATE_LOSS+1;
+    TFRC_RECV_FINDDATAPACKET(cb,elm,num_later);
+    if(elm != NULL){
+      elm2 = STAILQ_NEXT(elm,linfo);
+      while(elm2 != NULL){
+	STAILQ_REMOVE(&(cb->hist),elm2,r_hist_entry,linfo);
+	free(elm2,M_TEMP);
+	elm2 = STAILQ_NEXT(elm,linfo);
+      }
+    }
+  } else {
+    /* we have no loss interval history so we need at least one rtt:s of data packets to approximate rtt*/
+    num_later = TFRC_RECV_NUM_LATE_LOSS+1;
+    TFRC_RECV_FINDDATAPACKET(cb,elm2,num_later);
+    if(elm2 != NULL){
+      num_later = 1;
+      TFRC_RECV_FINDDATAPACKET(cb,elm,num_later);
+      win_count = elm->win_count;
+      
+      elm = elm2;
+      TFRC_RECV_NEXTDATAPACKET(cb,elm2);
+      while(elm2 != NULL){
+	temp = win_count-(int) (elm2->win_count);
+	if(temp < 0)
+	  temp = temp + TFRC_WIN_COUNT_LIMIT;
+	
+	if(temp > TFRC_WIN_COUNT_PER_RTT+1){
+	  /* we have found a packet older than one rtt
+	     remove the rest */
+	  elm = STAILQ_NEXT(elm2,linfo);
+	  
+	  while(elm != NULL){
+	    STAILQ_REMOVE(&(cb->hist),elm,r_hist_entry,linfo);
+	    free(elm,M_TEMP);
+	    elm = STAILQ_NEXT(elm2,linfo);
+	  }
+	  break;
+	}
+	elm = elm2;
+	TFRC_RECV_NEXTDATAPACKET(cb,elm2);
+      }
+    } /* end if(exist atleast 4 data packets) */
+  }
+  
+  return 0;
+}
+
+/*
+ * Detect loss events and update loss interval history
+ * args: cb - ccb of the receiver
+ * Tested u:OK
+ */
+void tfrc_recv_detectLoss(struct tfrc_recv_ccb *cb){
+  struct r_hist_entry *bLoss,*aLoss,*elm,*elm2;
+  u_int8_t num_later = TFRC_RECV_NUM_LATE_LOSS;
+  long seq_temp = 0;
+  long seq_loss = -1;
+  u_int8_t win_loss = 0;
+  
+  TFRC_RECV_FINDDATAPACKET(cb,bLoss,num_later);
+  
+  if(bLoss == NULL){
+    /* not enough packets yet to cause the first loss event */
+  } else {  /* bloss != NULL */
+    num_later = TFRC_RECV_NUM_LATE_LOSS+1; 
+    TFRC_RECV_FINDDATAPACKET(cb,aLoss,num_later);
+    if (aLoss == NULL){
+      if(TAILQ_EMPTY(&(cb->li_hist))){
+	/* no loss event have occured yet */
+
+	/* todo: find a lost data packet by comparing to initial seq num*/
+	
+      } else {
+	panic("Less than 4 data packets in history (tfrc_recv_detecLossEvent)\n");
+      }
+    } else {  /* aLoss != NULL */
+      /* locate a lost data packet */
+      elm = bLoss;
+      elm2 = STAILQ_NEXT(elm,linfo);
+      do{
+	seq_temp = ((long) (elm->seq)) - ((long) elm2->seq);
+	
+	if (seq_temp < 0)
+	  seq_temp = seq_temp + DCCP_SEQ_NUM_LIMIT;
+	
+	if(seq_temp != 1){
+	  /* check no data packets */
+	  if(elm->type == DCCP_TYPE_DATA || elm->type == DCCP_TYPE_DATAACK)
+	    seq_temp = seq_temp - 1;
+	    if(seq_temp % DCCP_NDP_LIMIT != ((int) elm->ndp - (int) elm2->ndp+DCCP_NDP_LIMIT) % DCCP_NDP_LIMIT)
+	  seq_loss = (elm2->seq + 1) % DCCP_SEQ_NUM_LIMIT;
+	}
+	elm = elm2;
+	elm2 = STAILQ_NEXT(elm2,linfo);
+      } while (elm != aLoss);
+
+      if(seq_loss != -1){
+	win_loss = aLoss->win_count;
+      }
+    }
+  } /* end if(bLoss == NULL) */
+  tfrc_recv_updateLI(cb,seq_loss,win_loss);
+}
+
+/* Updates the loss interval history
+ * cb   -  congestion control block
+ * seq_loss  -  sequence number of lost packet (-1 for none)
+ * win_loss  -  window counter for previous (from the lost packet view) packet
+ * Tested u:OK
+ */
+void tfrc_recv_updateLI(struct tfrc_recv_ccb *cb, long seq_loss, u_int8_t win_loss){
+  struct r_hist_entry *elm, *elm_temp;
+  struct li_hist_entry *li_elm, *li_elm2,*li_elm_temp;
+  u_int8_t num_later = TFRC_RECV_NUM_LATE_LOSS;
+  long seq_temp = 0;
+  int i;
+  u_int8_t win_start;
+  int debug_info = 0;
+  if(seq_loss != -1){   /* we have found a packet loss! */
+    dccpstat.tfrcs_recv_losts++;
+    TFRC_DEBUG((LOG_INFO, "TFRC - seqloss=%i, winloss=%i\n",(int) seq_loss, (int)win_loss));
+    if(TAILQ_EMPTY(&(cb->li_hist))){
+      debug_info = 1;
+      /* first loss detected */
+      TFRC_DEBUG((LOG_INFO, "TFRC - First loss event detected! (tfrc_recv_updateLI)\n"));
+      /* create history */
+      for(i=0; i< TFRC_RECV_IVAL_F_LENGTH+1; i++){
+	li_elm = malloc(sizeof (struct li_hist_entry),
+			M_TEMP, M_DONTWAIT | M_ZERO); /*M_TEMP??*/
+	if (li_elm == NULL){
+	  TFRC_DEBUG((LOG_INFO, "TFRC - Not enough memory for loss interval history!\n"));
+	  /* Empty loss interval history */
+	  li_elm = TAILQ_FIRST(&(cb->li_hist));
+	  while (li_elm != NULL) {
+	    li_elm2 = TAILQ_NEXT(li_elm, linfo);
+	    free(li_elm, M_TEMP); /* M_TEMP ?? */
+	    li_elm = li_elm2;
+	  }
+	  return;
+	}
+	TAILQ_INSERT_HEAD(&(cb->li_hist),li_elm,linfo);
+      }
+      
+      li_elm->seq = seq_loss;
+      li_elm->win_count = win_loss;
+      
+      li_elm = TAILQ_NEXT(li_elm,linfo);
+      /* add approx interval */
+      li_elm->interval = tfrc_recv_calcFirstLI(cb);
+      
+    } else {  /* we have a loss interval history */
+      debug_info = 2;
+      /* Check if the loss is in the same loss event as interval start */
+      win_start = (TAILQ_FIRST(&(cb->li_hist)))->win_count;
+      if ((win_loss > win_start 
+	   && win_loss - win_start > TFRC_WIN_COUNT_PER_RTT) ||
+	  (win_loss < win_start
+	   && win_start - win_loss < TFRC_WIN_COUNT_LIMIT-TFRC_WIN_COUNT_PER_RTT)){
+	/* new loss event detected */
+	/* calculate last interval length */
+	seq_temp = seq_loss - ((long) ((TAILQ_FIRST(&(cb->li_hist)))->seq));
+	if (seq_temp < 0)
+	  seq_temp = seq_temp + DCCP_SEQ_NUM_LIMIT;
+	
+	(TAILQ_FIRST(&(cb->li_hist)))->interval = seq_temp;
+	
+	TFRC_DEBUG((LOG_INFO, "TFRC - New loss event detected!, interval %i (tfrc_recv_updateLI)\n",(int)seq_temp));
+	/* Remove oldest interval */
+	li_elm = TAILQ_LAST(&(cb->li_hist),li_hist_head);
+	TAILQ_REMOVE(&(cb->li_hist),li_elm,linfo);
+	  
+	/* Create the newest interval */
+	li_elm->seq = seq_loss;
+	li_elm->win_count = win_loss;
+	
+	/* insert it into history */
+	TAILQ_INSERT_HEAD(&(cb->li_hist),li_elm,linfo);	
+      } else
+	TFRC_DEBUG((LOG_INFO, "TFRC - Loss belongs to previous loss event (tfrc_recv_updateLI)!\n"));
+    }
+  }
+
+  if(TAILQ_FIRST(&(cb->li_hist)) != NULL){
+    /* calculate interval to last loss event */
+    num_later = 1;
+    TFRC_RECV_FINDDATAPACKET(cb,elm,num_later);
+    
+    seq_temp = ((long) (elm->seq))-
+      ((long) ((TAILQ_FIRST(&(cb->li_hist)))->seq));
+    if (seq_temp < 0)
+      seq_temp = seq_temp + DCCP_SEQ_NUM_LIMIT;
+    
+    (TAILQ_FIRST(&(cb->li_hist)))->interval = seq_temp;
+    if (debug_info > 0){
+      TFRC_DEBUG((LOG_INFO,"TFRC - Highest data packet received %u (tfrc_recv_updateLI)\n",elm->seq));
+      if(debug_info == 1)
+	PRINTRCCB(cb,elm_temp,li_elm_temp);
+      else if (debug_info == 2)
+      PRINTLIHIST(cb,li_elm_temp);
+    }
+  }
+}
+
+
+/* Functions declared in struct dccp_cc_sw */
+/* Initialises the receiver side
+ * returns: pointer to a tfrc_recv_ccb struct on success, otherwise 0
+ * Tested u:OK
+ */ 
+void *tfrc_recv_init(struct dccpcb *pcb){
+  struct tfrc_recv_ccb *ccb;
+  
+  ccb = malloc(sizeof (struct tfrc_recv_ccb), M_PCB, M_DONTWAIT | M_ZERO);
+  if (ccb == 0){
+    TFRC_DEBUG((LOG_INFO, "TFRC - Unable to allocate memory for tfrc_recv_ccb!\n"));
+    return 0;
+  }
+  
+  /* init recv here */
+
+  mtx_init(&(ccb->mutex), "TFRC Receiver mutex", NULL, MTX_DEF);
+  
+  ccb->pcb = pcb;  
+
+  if (ccb->pcb->avgpsize >= TFRC_MIN_PACKET_SIZE && ccb->pcb->avgpsize <= TFRC_MAX_PACKET_SIZE)
+    ccb->s = (u_int16_t) ccb->pcb->avgpsize;
+  else
+    ccb->s = TFRC_STD_PACKET_SIZE;
+
+  TFRC_DEBUG((LOG_INFO,"TFRC - Receiver is using packet size %u\n",ccb->s));
+  
+  /* init packet history */
+  STAILQ_INIT(&(ccb->hist));
+
+  /* init loss interval history */
+  TAILQ_INIT(&(ccb->li_hist));
+
+  ccb->state = TFRC_RSTATE_NO_DATA;
+  TFRC_DEBUG((LOG_INFO, "TFRC receiver initialised!\n")); 
+  dccpstat.tfrcs_recv_conn++;
+  return ccb;
+}
+
+/* Free the receiver side
+ * args: ccb - ccb of recevier
+ * Tested u:OK
+ */
+void tfrc_recv_free(void *ccb){
+  struct r_hist_entry *elm,*elm2;
+  struct li_hist_entry *li_elm,*li_elm2;
+  struct tfrc_recv_ccb *cb = (struct tfrc_recv_ccb *) ccb;
+
+  if(ccb == 0)
+    panic("TFRC - Receiver ccb is null! (free)");
+
+  /* uninit recv here */
+
+  /* get mutex */
+
+  cb->state = TFRC_RSTATE_TERM;
+  mtx_lock(&(cb->mutex));
+  
+  /* Empty packet history */
+  elm = STAILQ_FIRST(&(cb->hist));
+  while (elm != NULL) {
+    elm2 = STAILQ_NEXT(elm, linfo);
+    free(elm, M_TEMP); /* M_TEMP ?? */
+    elm = elm2;
+  }
+  STAILQ_INIT(&(cb->hist));
+  
+  /* Empty loss interval history */
+  li_elm = TAILQ_FIRST(&(cb->li_hist));
+  while (li_elm != NULL) {
+    li_elm2 = TAILQ_NEXT(li_elm, linfo);
+    free(li_elm, M_TEMP); /* M_TEMP ?? */
+    li_elm = li_elm2;
+  }
+  TAILQ_INIT(&(cb->li_hist));
+
+  mtx_unlock(&(cb->mutex));
+  mtx_destroy(&(cb->mutex));
+  
+  free(ccb, M_PCB);
+  
+  TFRC_DEBUG((LOG_INFO, "TFRC receiver is destroyed\n"));
+}
+
+
+/*
+ * Tell TFRC that a packet has been received
+ * args: ccb  -  ccb block for current connection 
+ */
+void tfrc_recv_packet_recv(void *ccb, char *options, int optlen){
+  struct r_hist_entry *packet;
+  u_int8_t win_count = 0;
+  double p_prev; 
+  int ins;
+  struct tfrc_recv_ccb *cb = (struct tfrc_recv_ccb *) ccb;
+
+#ifdef NOTFRCRECV
+  return;  
+#endif
+  
+  if(!(cb->state == TFRC_RSTATE_NO_DATA || cb->state == TFRC_RSTATE_DATA)){
+    panic("TFRC - Illegal state! (tfrc_recv_packet_recv)\n");
+    return;
+  }
+
+  /* Check which type */
+  switch(cb->pcb->type_rcv){
+  case DCCP_TYPE_ACK:
+    if(cb->state == TFRC_RSTATE_NO_DATA)
+      return;
+    break;
+  case DCCP_TYPE_DATA:
+  case DCCP_TYPE_DATAACK:
+    break;
+  default:
+    TFRC_DEBUG((LOG_INFO,"TFRC - Received not data/dataack/ack packet! (tfrc_recv_packet_recv)"));
+    return;
+  }
+
+  mtx_lock(&(cb->mutex));
+
+  /* Add packet to history */
+  
+  packet = malloc(sizeof (struct r_hist_entry), M_TEMP, M_DONTWAIT); /*M_TEMP??*/
+  if (packet == NULL){
+    TFRC_DEBUG((LOG_INFO,"TFRC - Not enough memory to add received packet to history (consider it lost)! (tfrc_recv_packet_recv)"));
+    dccpstat.tfrcs_recv_nomem++;
+    goto rp_release;
+  }
+ 
+  microtime(&(packet->t_recv));
+  packet->seq = cb->pcb->seq_rcv;
+  packet->type = cb->pcb->type_rcv;
+  packet->ndp = cb->pcb->ndp_rcv;
+
+  ins = dccp_get_option(options, optlen, TFRC_OPT_WINDOW_COUNT, (char *)&win_count,1);
+  
+  if((packet->type == DCCP_TYPE_DATA || packet->type == DCCP_TYPE_DATAACK) &&
+     (ins != 1)){
+    TFRC_DEBUG((LOG_INFO,"TFRC - No window counter (size %i) option on data packet! (consider it lost)! (tfrc_recv_packet_recv)",ins));
+    free(packet,M_TEMP);
+    dccpstat.tfrcs_recv_noopt++;
+    goto rp_release;
+  }
+  
+  packet->win_count = win_count;
+
+  ins = tfrc_recv_add_hist(cb,packet);
+
+  /* check if we got a data packet */
+  if (cb->pcb->type_rcv != DCCP_TYPE_ACK){
+    
+    switch (cb->state){
+    case TFRC_RSTATE_NO_DATA :
+      TFRC_DEBUG((LOG_INFO, "TFRC - Send an inital feedback packet (tfrc_recv_packet_recv)\n"));
+      tfrc_recv_send_feedback(cb);
+      cb->state = TFRC_RSTATE_DATA;
+      break;
+    case TFRC_RSTATE_DATA : 
+      cb->bytes_recv = cb->bytes_recv + cb->pcb->len_rcv;
+      if(!ins){
+	/* find loss event */
+	tfrc_recv_detectLoss(cb);
+	p_prev = cb->p;
+	
+	/* Calculate loss event rate */
+	if(!TAILQ_EMPTY(&(cb->li_hist))){
+	  cb->p = 1/tfrc_calcImean(cb);
+	}  
+	  /* check send conditions then send */
+	  if(cb->p > p_prev){
+	    TFRC_DEBUG((LOG_INFO, "TFRC - Send a feedback packet because p>p_prev (tfrc_recv_packet_recv)\n"));
+	    tfrc_recv_send_feedback(cb);
+	  } else {
+	    if ((cb->pcb->seq_rcv > cb->seq_last_counter 
+		 && cb->pcb->seq_rcv - cb->seq_last_counter < TFRC_RECV_NEW_SEQ_RANGE) ||
+	      (cb->pcb->seq_rcv < cb->seq_last_counter
+	       && cb->seq_last_counter - cb->pcb->seq_rcv > DCCP_SEQ_NUM_LIMIT - TFRC_RECV_NEW_SEQ_RANGE)){
+
+	      /* the sequence number is newer than seq_last_count */
+	      if ((win_count > cb->last_counter 
+		   && win_count-cb->last_counter > TFRC_WIN_COUNT_PER_RTT) ||
+		  (win_count < cb->last_counter
+		   && cb->last_counter - win_count < TFRC_WIN_COUNT_LIMIT-TFRC_WIN_COUNT_PER_RTT)){
+
+		TFRC_DEBUG((LOG_INFO, "TFRC - Send a feedback packet (%i)(win_count larger) (tfrc_recv_packet_recv)\n",(win_count-cb->last_counter+TFRC_WIN_COUNT_LIMIT) % TFRC_WIN_COUNT_LIMIT));
+		
+		tfrc_recv_send_feedback(cb);
+	      }
+	    }  /* end newer seqnum */
+	  }  /* end p > p_prev */
+      
+    }
+      break;
+    default:
+      panic("tfrc_recv_packet_recv: Illegal state!");
+      break;
+    }
+
+  } /* end if not pure ack */
+ rp_release:
+  mtx_unlock(&(cb->mutex)); 
+}
+++ sys/netinet/dccp_tfrc.h	Fri Aug 25 04:03:09 2006
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2003  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: dccp_tfrc.h,v 1.34 2003/05/28 17:36:15 nilmat-8 Exp $
+ */
+
+
+#ifndef _NETINET_DCCP_TFRC_H_
+#define _NETINET_DCCP_TFRC_H_
+
+#define TFRC_STD_PACKET_SIZE    256
+#define TFRC_MIN_PACKET_SIZE    16
+#define TFRC_MAX_PACKET_SIZE    65535
+
+#define TFRC_OPSYS_TIME_GRAN    10000
+#define TFRC_WIN_COUNT_LIMIT    256
+#define TFRC_WIN_COUNT_PER_RTT  4
+#define TFRC_SMALLEST_P         0.00004
+/* 
+ * TFRC sender 
+ */
+
+/* TFRC specific dccp options */
+#define TFRC_OPT_WINDOW_COUNT	128
+
+/* TFRC sender states */
+#define TFRC_SSTATE_NO_SENT     1
+#define TFRC_SSTATE_NO_FBACK	2
+#define TFRC_SSTATE_FBACK	3
+#define TFRC_SSTATE_TERM	4
+
+/* Mechanism parameters */
+#define TFRC_INITIAL_TIMEOUT    2
+#define TFRC_MAX_BACK_OFF_TIME  64
+#define TFRC_RTT_FILTER_CONST   0.9
+#define TFRC_SEND_WAIT_TERM     20
+
+/* 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;            /* Sequence number */
+  struct timeval t_sent;    /* When the packet was sent */
+  u_int8_t win_count;       /* Windowcounter for packet */
+};
+
+
+/* TFRC sender congestion control block (ccb) */
+struct tfrc_send_ccb {
+  struct mtx mutex;        /* Lock for this structure */
+  struct dccpcb *pcb;       /* Pointer to associated dccpcb */
+  u_int8_t     state;      /* Sender state */
+
+  double        x;          /* Current sending rate */
+  double        x_recv;     /* Receive rate */
+  double        x_calc;     /* Calculated send (?) rate */ 
+
+  u_int16_t    s;          /* Packet size */
+ 
+  u_int32_t    rtt;        /* Estimate of current round trip time */
+  double        p;          /* Current loss event rate */  
+  u_int8_t     last_win_count; /* Last window counter sent */
+  struct timeval t_last_win_count; /* Timestamp of earliest packet with
+				      last_win_count value sent */
+  struct callout_handle ch_nftimer;  /* Handle to no feedback timer */
+  u_int8_t     idle;
+  u_int32_t    t_rto;      /* Time out value = 4*rtt */
+  struct timeval t_ld;        /* Time last doubled during slow start */
+
+  struct timeval t_nom,    /* Nominal send time of next packet */
+                 t_ipi,    /* Interpacket (send) interval */
+                 delta;    /* Send timer delta */    
+
+  struct callout_handle ch_stimer;  /* Handle to scheduled send timer */ 
+
+  struct s_hist_head hist;        /* Packet history */
+};
+
+#ifdef _KERNEL
+
+/* Functions declared in struct dccp_cc_sw */
+
+/* Initialises the sender side
+ * args: pcb  - pointer to dccpcb of associated connection
+ * returns: pointer to a tfrc_send_ccb struct on success, otherwise 0
+ */ 
+void *tfrc_send_init(struct dccpcb *pcb); 
+
+/* Free the sender side
+ * args: ccb - ccb of sender
+ */
+void tfrc_send_free(void *ccb);
+
+/* Ask TFRC wheter one can send a packet or not 
+ * args: ccb  -  ccb block for current connection
+ * returns: 1 if ok, else 0.
+ */ 
+int tfrc_send_packet(void *ccb, long datasize);
+
+/* Notify sender that a packet has been sent 
+ * args: ccb - ccb block for current connection
+ *	 moreToSend - if there exists more packets to send
+ *       datasize   - packet size
+ */
+void tfrc_send_packet_sent(void *ccb, int moreToSend, long datasize);
+
+/* Notify that a an ack package was received (i.e. a feedback packet)
+ * args: ccb  -  ccb block for current connection
+ */ 
+void tfrc_send_packet_recv(void *ccb,char *, int);
+
+#endif
+
+/* 
+ * TFRC Receiver 
+ */
+
+/* TFRC specific dccp options */
+#define TFRC_OPT_LOSS_RATE	192
+#define TFRC_OPT_ELAPSED_TIME	193
+#define TFRC_OPT_RECEIVE_RATE	194
+
+/* TFRC receiver states */
+#define TFRC_RSTATE_NO_DATA	1
+#define TFRC_RSTATE_DATA	2
+#define TFRC_RSTATE_TERM        127
+
+/* Receiver mechanism parameters */
+#define TFRC_RECV_NEW_SEQ_RANGE 10000000   /* seq_num x,y; 
+					      if y-x is smaller than this 
+					      number (note, wrap around)
+					      then y is newer than x */
+#define TFRC_RECV_NUM_LATE_LOSS 3          /* number of later packets received 
+					      before one is considered lost */
+					      
+#define TFRC_RECV_IVAL_F_LENGTH  8          /* length(w[]) */
+
+/* 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;            /* Sequence number */
+  struct timeval t_recv;    /* When the packet was received */
+  u_int8_t win_count;       /* Window counter for that packet */
+  u_int8_t type;            /* Packet type received */
+  u_int8_t ndp;             /* no data packets value */
+};
+
+/* 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;            /* Sequence number of the packet that started 
+			       the interval */
+  u_int8_t win_count;       /* Window counter for previous received packet */
+};
+
+/* TFRC receiver congestion control block (ccb) */
+struct tfrc_recv_ccb {
+  struct mtx mutex;                 /* Lock for this structure */
+  struct dccpcb *pcb;               /* Pointer to associated dccpcb */
+  u_int8_t     state;               /* Receiver state */
+
+  double        p;                   /* Loss event rate */
+ 
+  struct li_hist_head li_hist;      /* Loss interval history */
+
+  u_int8_t     last_counter;        /* Highest value of the window counter
+                                       received when last feedback was sent */
+  u_int32_t    seq_last_counter;    /* Sequence number of the packet above */
+
+  struct timeval t_last_feedback;   /* Timestamp of when last feedback was sent */
+  u_int32_t    bytes_recv;          /* Bytes received since t_last_feedback */
+
+  struct r_hist_head hist;          /* Packet history */
+
+  u_int16_t    s;                   /* Packet size */
+};
+
+#ifdef _KERNEL
+
+/* Functions declared in struct dccp_cc_sw */
+
+/* Initialises the receiver side
+ * args: pcb  -  pointer to dccpcb of associated connection
+ * returns: pointer to a tfrc_recv_ccb struct on success, otherwise 0
+ */ 
+void *tfrc_recv_init(struct dccpcb *pcb); 
+
+/* Free the receiver side
+ * args: ccb - ccb of recevier
+ */
+void tfrc_recv_free(void *ccb);
+
+/*
+ * Tell TFRC that a packet has been received
+ * args: ccb  -  ccb block for current connection 
+ */
+void tfrc_recv_packet_recv(void *ccb, char *, int);
+
+#endif
+
+#endif
+++ sys/netinet/dccp_tfrc_lookup.h	Fri Aug 25 04:03:09 2006
@@ -0,0 +1,1102 @@
+/*
+ * Copyright (c) 2003  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: dccp_tfrc_lookup.h,v 1.5 2003/05/28 17:37:43 nilmat-8 Exp $
+ */
+
+#ifndef _NETINET_DCCP_TFRC_LOOKUP_H_
+#define _NETINET_DCCP_TFRC_LOOKUP_H_
+
+const double fsmall_table[] ={
+  0,
+  0.00163305194960931,
+  0.00230956735363637,
+  0.00282873259487707,
+  0.00326645662574537,
+  0.00365214098377853,
+  0.00400086400001593,
+  0.00432158256340322,
+  0.00462013236858081,
+  0.00490056675498551,
+  0.00516583682704458,
+  0.00541817034936234,
+  0.00565929801070833,
+  0.00589059608718062,
+  0.00611318041778383,
+  0.00632797058060318,
+  0.00653573506415987,
+  0.00673712389086595,
+  0.00693269270671348,
+  0.0071229209166037,
+  0.00730822557103113,
+  0.00748897216079408,
+  0.00766548312170872,
+  0.00783804461648552,
+  0.00800691200203843,
+  0.00817231428085712,
+  0.00833445775806404,
+  0.00849352907081277,
+  0.00864969771687212,
+  0.00880311818001545,
+  0.0089539317281132,
+  0.00910226794349901,
+  0.00924824603277504,
+  0.00939197595370597,
+  0.009533559389484,
+  0.00967309059489451,
+  0.00981065713438519,
+  0.00994634052845154,
+  0.0100802168218855,
+  0.0102123570851299,
+  0.0103428278581192,
+  0.010471691544469,
+  0.0105990067626397,
+  0.0107248286596785,
+  0.0108492091922994,
+  0.0109721973793658,
+  0.0110938395292506,
+  0.0112141794450653,
+  0.0113332586103332,
+  0.0114511163573388,
+  0.0115677900200876,
+  0.0116833150735621,
+  0.011797725260745,
+  0.0119110527086984,
+  0.0120233280348285,
+  0.0121345804443331,
+  0.0122448378197079,
+  0.0123541268030903,
+  0.0124624728721277,
+  0.0125699004099823,
+  0.0126764327700174,
+  0.0127820923356504,
+  0.0128869005758063,
+  0.0129908780963614,
+  0.0130940446879258,
+  0.0131964193702772,
+  0.01329802043373,
+  0.0133988654776928,
+  0.0134989714466453,
+  0.0135983546637418,
+  0.0136970308622305,
+  0.0137950152148595,
+  0.0138923223614248,
+  0.0139889664346018,
+  0.0140849610841894,
+  0.0141803194998843,
+  0.0142750544326924,
+  0.0143691782150771,
+  0.0144627027799322,
+  0.0145556396784645,
+  0.0146480000970597,
+  0.014739794873203,
+  0.0148310345105165,
+  0.0149217291929752,
+  0.0150118887983524,
+  0.0151015229109484,
+  0.0151906408336458,
+  0.0152792515993363,
+  0.0153673639817576,
+  0.0154549865057777,
+  0.0155421274571605,
+  0.0156287948918437,
+  0.0157149966447599,
+  0.0158007403382266,
+  0.0158860333899315,
+  0.0159708830205358,
+  0.0160552962609193,
+  0.0161392799590851,
+  0.0162228407867464,
+  0.0163059852456097,
+  0.0163887196733746,
+  0.0164710502494631,
+  0.0165529830004946,
+  0.0166345238055199,
+  0.0167156784010267,
+  0.0167964523857295,
+  0.0168768512251538,
+  0.0169568802560266,
+  0.0170365446904829,
+  0.0171158496200964,
+  0.0171948000197448,
+  0.0172734007513173,
+  0.0173516565672713,
+  0.0174295721140473,
+  0.017507151935348,
+  0.0175844004752871,
+  0.017661322081417,
+  0.0177379210076372,
+  0.0178142014169926,
+  0.0178901673843644,
+  0.0179658228990597,
+  0.0180411718673042,
+  0.0181162181146423,
+  0.0181909653882486,
+  0.0182654173591552,
+  0.0183395776243984,
+  0.018413449709088,
+  0.0184870370684027,
+  0.0185603430895154,
+  0.0186333710934504,
+  0.0187061243368762,
+  0.0187786060138361,
+  0.0188508192574198,
+  0.0189227671413778,
+  0.0189944526816812,
+  0.0190658788380296,
+  0.019137048515308,
+  0.0192079645649969,
+  0.0192786297865344,
+  0.0193490469286358,
+  0.0194192186905687,
+  0.0194891477233888,
+  0.0195588366311352,
+  0.0196282879719884,
+  0.0196975042593915,
+  0.0197664879631372,
+  0.01983524151042,
+  0.0199037672868568,
+  0.0199720676374761,
+  0.0200401448676771,
+  0.02010800124416,
+  0.020175638995828,
+  0.0202430603146631,
+  0.0203102673565755,
+  0.0203772622422282,
+  0.0204440470578377,
+  0.0205106238559511,
+  0.0205769946562011,
+  0.0206431614460395,
+  0.0207091261814494,
+  0.0207748907876375,
+  0.020840457159707,
+  0.020905827163312,
+  0.0209710026352927,
+  0.0210359853842945,
+  0.0211007771913689,
+  0.0211653798105588,
+  0.0212297949694677,
+  0.0212940243698132,
+  0.0213580696879667,
+  0.0214219325754774,
+  0.0214856146595837,
+  0.0215491175437103,
+  0.0216124428079525,
+  0.0216755920095483,
+  0.0217385666833377,
+  0.0218013683422109,
+  0.0218639984775441,
+  0.0219264585596254,
+  0.0219887500380688,
+  0.0220508743422187,
+  0.0221128328815438,
+  0.022174627046021,
+  0.022236258206511,
+  0.0222977277151227,
+  0.0223590369055709,
+  0.0224201870935234,
+  0.0224811795769409,
+  0.0225420156364085,
+  0.0226026965354587,
+  0.0226632235208875,
+  0.0227235978230625,
+  0.022783820656224,
+  0.0228438932187787,
+  0.0229038166935873,
+  0.0229635922482444,
+  0.0230232210353529,
+  0.0230827041927913,
+  0.0231420428439758,
+  0.0232012380981154,
+  0.0232602910504621,
+  0.0233192027825551,
+  0.0233779743624595,
+  0.0234366068449998,
+  0.0234951012719883,
+  0.0235534586724479,
+  0.0236116800628313,
+  0.0236697664472338,
+  0.0237277188176025,
+  0.023785538153941,
+  0.0238432254245091,
+  0.0239007815860187,
+  0.0239582075838253,
+  0.0240155043521156,
+  0.0240726728140909,
+  0.0241297138821471,
+  0.0241866284580502,
+  0.024243417433109,
+  0.0243000816883436,
+  0.0243566220946503,
+  0.0244130395129642,
+  0.0244693347944169,
+  0.0245255087804923,
+  0.0245815623031787,
+  0.0246374961851176,
+  0.0246933112397499,
+  0.0247490082714593,
+  0.0248045880757123,
+  0.0248600514391958,
+  0.0249153991399521,
+  0.0249706319475108,
+  0.0250257506230185,
+  0.025080755919366,
+  0.0251356485813126,
+  0.0251904293456085,
+  0.0252450989411148,
+  0.0252996580889205,
+  0.0253541075024583,
+  0.0254084478876176,
+  0.0254626799428553,
+  0.025516804359305,
+  0.0255708218208836,
+  0.0256247330043961,
+  0.0256785385796388,
+  0.0257322392095,
+  0.0257858355500594,
+  0.025839328250685,
+  0.0258927179541294,
+  0.0259460052966225,
+  0.0259991909079647,
+  0.0260522754116166,
+  0.026105259424788,
+  0.0261581435585253,
+  0.0262109284177969,
+  0.0262636146015774,
+  0.0263162027029303,
+  0.0263686933090892,
+  0.0264210870015373,
+  0.0264733843560862,
+  0.0265255859429526,
+  0.0265776923268339,
+  0.0266297040669827,
+  0.0266816217172798,
+  0.026733445826306,
+  0.0267851769374128,
+  0.0268368155887916,
+  0.026888362313542,
+  0.0269398176397387,
+  0.0269911820904977,
+  0.0270424561840408,
+  0.0270936404337596,
+  0.0271447353482779,
+  0.0271957414315136,
+  0.0272466591827389,
+  0.0272974890966405,
+  0.0273482316633775,
+  0.0273988873686397,
+  0.027449456693704,
+  0.0274999401154902,
+  0.027550338106616,
+  0.0276006511354511,
+  0.02765087966617,
+  0.0277010241588047,
+  0.027751085069296,
+  0.0278010628495439,
+  0.027850957947458,
+  0.0279007708070058,
+  0.0279505018682618,
+  0.0280001515674544,
+  0.0280497203370128,
+  0.0280992086056135,
+  0.028148616798225,
+  0.0281979453361527,
+  0.028247194637083,
+  0.0282963651151265,
+  0.0283454571808605,
+  0.0283944712413708,
+  0.0284434077002936,
+  0.0284922669578557,
+  0.0285410494109145,
+  0.0285897554529981,
+  0.0286383854743433,
+  0.0286869398619349,
+  0.0287354189995426,
+  0.0287838232677585,
+  0.0288321530440338,
+  0.0288804087027148,
+  0.0289285906150784,
+  0.0289766991493673,
+  0.0290247346708242,
+  0.0290726975417263,
+  0.0291205881214181,
+  0.0291684067663454,
+  0.0292161538300869,
+  0.029263829663387,
+  0.0293114346141869,
+  0.0293589690276564,
+  0.029406433246224,
+  0.0294538276096075,
+  0.0295011524548438,
+  0.0295484081163186,
+  0.029595594925795,
+  0.0296427132124425,
+  0.029689763302865,
+  0.0297367455211288,
+  0.0297836601887898,
+  0.0298305076249208,
+  0.0298772881461383,
+  0.0299240020666283,
+  0.0299706496981729,
+  0.0300172313501756,
+  0.0300637473296863,
+  0.0301101979414268,
+  0.030156583487815,
+  0.0302029042689891,
+  0.0302491605828317,
+  0.0302953527249935,
+  0.0303414809889161,
+  0.0303875456658556,
+  0.0304335470449047,
+  0.0304794854130155,
+  0.0305253610550213,
+  0.0305711742536585,
+  0.030616925289588,
+  0.0306626144414165,
+  0.0307082419857174,
+  0.0307538081970513,
+  0.0307993133479868,
+  0.0308447577091201,
+  0.0308901415490953,
+  0.0309354651346236,
+  0.0309807287305032,
+  0.0310259325996379,
+  0.0310710770030561,
+  0.0311161621999296,
+  0.0311611884475917,
+  0.0312061560015558,
+  0.0312510651155326,
+  0.0312959160414486,
+  0.031340709029463,
+  0.0313854443279853,
+  0.031430122183692,
+  0.0314747428415438,
+  0.0315193065448019,
+  0.0315638135350446,
+  0.0316082640521835,
+  0.0316526583344794,
+  0.0316969966185581,
+  0.0317412791394264,
+  0.0317855061304867,
+  0.0318296778235532,
+  0.0318737944488663,
+  0.0319178562351077,
+  0.0319618634094152,
+  0.0320058161973967,
+  0.0320497148231454,
+  0.0320935595092531,
+  0.0321373504768247,
+  0.032181087945492,
+  0.032224772133427,
+  0.032268403257356,
+  0.0323119815325724,
+  0.0323555071729501,
+  0.0323989803909566,
+  0.0324424013976657,
+  0.0324857704027703,
+  0.0325290876145952,
+  0.032572353240109,
+  0.032615567484937,
+  0.0326587305533729,
+  0.032701842648391,
+  0.0327449039716579,
+  0.0327879147235444,
+  0.0328308751031372,
+  0.0328737853082498,
+  0.0329166455354347,
+  0.0329594559799936,
+  0.0330022168359894,
+  0.0330449282962565,
+  0.0330875905524119,
+  0.0331302037948658,
+  0.0331727682128323,
+  0.0332152839943397,
+  0.0332577513262411,
+  0.0333001703942243,
+  0.0333425413828221,
+  0.0333848644754222,
+  0.0334271398542773,
+  0.0334693677005146,
+  0.0335115481941457,
+  0.0335536815140761,
+  0.0335957678381145,
+  0.0336378073429825,
+  0.0336798002043235,
+  0.0337217465967119,
+  0.0337636466936625,
+  0.0338055006676391,
+  0.0338473086900635,
+  0.0338890709313242,
+  0.033930787560785,
+  0.033972458746794,
+  0.0340140846566914,
+  0.0340556654568185,
+  0.0340972013125256,
+  0.0341386923881805,
+  0.0341801388471764,
+  0.0342215408519403,
+  0.0342628985639403,
+  0.0343042121436941,
+  0.0343454817507766,
+  0.0343867075438276,
+  0.0344278896805592,
+  0.0344690283177636,
+  0.0345101236113208,
+  0.0345511757162053,
+  0.0345921847864941,
+  0.0346331509753735,
+  0.0346740744351467,
+  0.0347149553172402,
+  0.0347557937722115,
+  0.0347965899497558,
+  0.0348373439987127,
+  0.0348780560670734,
+  0.0349187263019868,
+  0.034959354849767,
+  0.0349999418558991,
+  0.0350404874650462,
+  0.035080991821056,
+  0.0351214550669666,
+  0.0351618773450133,
+  0.0352022587966348,
+  0.0352425995624795,
+  0.0352828997824113,
+  0.035323159595516,
+  0.0353633791401072,
+  0.0354035585537324,
+  0.0354436979731787,
+  0.0354837975344788,
+  0.0355238573729168,
+  0.0355638776230337,
+  0.0356038584186336,
+  0.0356437998927886,
+  0.0356837021778449,
+  0.0357235654054283,
+  0.0357633897064494,
+  0.0358031752111091,
+  0.035842922048904,
+  0.0358826303486317,
+  0.0359223002383961,
+  0.0359619318456125,
+  0.0360015252970127,
+  0.0360410807186503,
+  0.0360805982359056,
+  0.0361200779734907,
+  0.0361595200554543,
+  0.0361989246051867,
+  0.0362382917454249,
+  0.0362776215982569,
+  0.036316914285127,
+  0.0363561699268402,
+  0.0363953886435669,
+  0.0364345705548478,
+  0.036473715779598,
+  0.0365128244361123,
+  0.0365518966420688,
+  0.0365909325145341,
+  0.0366299321699675,
+  0.0366688957242252,
+  0.0367078232925648,
+  0.0367467149896497,
+  0.0367855709295533,
+  0.0368243912257629,
+  0.0368631759911844,
+  0.0369019253381463,
+  0.0369406393784034,
+  0.0369793182231416,
+  0.0370179619829813,
+  0.0370565707679816,
+  0.0370951446876444,
+  0.0371336838509182,
+  0.0371721883662021,
+  0.0371721883662021
+};
+
+
+
+const double flarge_table[] =
+  { 
+    243.315981116462,
+    243.315981116462,
+    23.9600361713695,
+    6.9139329716018,
+    3.16392425109494,
+    1.86371728900425,
+    1.27777777777778,
+    0.964508403261589,
+    0.77581442422356,
+    0.651853237448473,
+    0.564939170766789,
+    0.50087416614881,
+    0.451762665758072,
+    0.412917778678493,
+    0.381404155091771,
+    0.355299463329141,
+    0.333296455886513,
+    0.314477147580053,
+    0.298178842729622,
+    0.283911535127666,
+    0.271305240150892,
+    0.260075403532531,
+    0.249999578782356,
+    0.24090133037795,
+    0.232638888888889,
+    0.225097003008273,
+    0.218180986989316,
+    0.211812304114001,
+    0.205925243280314,
+    0.200464385692282,
+    0.195382650833982,
+    0.19063977276852,
+    0.186201099999877,
+    0.182036641362817,
+    0.178120300939,
+    0.174429259613497,
+    0.170943471418511,
+    0.16764525048842,
+    0.164518930106658,
+    0.161550579534251,
+    0.158727767472067,
+    0.156039363405452,
+    0.153475369911586,
+    0.151026780420806,
+    0.148685458018048,
+    0.146444031726265,
+    0.144295807386892,
+    0.142234690785429,
+    0.140255121094728,
+    0.13835201304867,
+    0.136520706532794,
+    0.1347569225002,
+    0.133056724301448,
+    0.131416483664691,
+    0.129832850683331,
+    0.128302727268412,
+    0.12682324360563,
+    0.125391737225632,
+    0.12400573435363,
+    0.122662933252459,
+    0.121361189313573,
+    0.12009850168457,
+    0.118873001250667,
+    0.117682939811998,
+    0.116526680319474,
+    0.115402688049678,
+    0.114309522614568,
+    0.113245830714757,
+    0.11221033955645,
+    0.111201850861809,
+    0.1102192354109,
+    0.109261428060689,
+    0.108327423192858,
+    0.107416270547744,
+    0.106527071406495,
+    0.105658975087763,
+    0.104811175728943,
+    0.103982909325178,
+    0.103173451002242,
+    0.102382112501895,
+    0.101608239860516,
+    0.100851211263824,
+    0.100110435062178,
+    0.0993853479325371,
+    0.0986754131745014,
+    0.097980119129101,
+    0.0972989777100651,
+    0.096631523038292,
+    0.0959773101711038,
+    0.0953359139186481,
+    0.0947069277405102,
+    0.0940899627162219,
+    0.0934846465839213,
+    0.0928906228419223,
+    0.0923075499084108,
+    0.0917351003348998,
+    0.0911729600694444,
+    0.0906208277659599,
+    0.0900784141362873,
+    0.0895454413419325,
+    0.0890216424226529,
+    0.0885067607592958,
+    0.088000549568501,
+    0.0875027714270677,
+    0.0870131978239609,
+    0.0865316087380871,
+    0.0860577922401151,
+    0.0855915441167475,
+    0.0851326675159692,
+    0.0846809726119106,
+    0.0842362762880613,
+    0.0837984018376643,
+    0.0833671786802068,
+    0.0829424420929991,
+    0.0825240329569059,
+    0.0821117975153618,
+    0.0817055871458615,
+    0.0813052581431724,
+    0.0809106715135683,
+    0.0805216927794322,
+    0.0801381917936175,
+    0.0797600425630009,
+    0.0793871230806953,
+    0.0790193151664281,
+    0.0786565043146194,
+    0.0782985795497303,
+    0.0779454332884719,
+    0.0775969612084976,
+    0.077253062123222,
+    0.0769136378624335,
+    0.0765785931583867,
+    0.0762478355370815,
+    0.0759212752144541,
+    0.0755988249972193,
+    0.0752804001881223,
+    0.0749659184953696,
+    0.0746552999460257,
+    0.0743484668031706,
+    0.0740453434866294,
+    0.0737458564970926,
+    0.0734499343434585,
+    0.0731575074732384,
+    0.0728685082058719,
+    0.0725828706688121,
+    0.0723005307362458,
+    0.0720214259703205,
+    0.0717454955647604,
+    0.0714726802907563,
+    0.0712029224450229,
+    0.070936165799922,
+    0.0706723555555556,
+    0.0704114382937376,
+    0.0701533619337587,
+    0.0698980756898617,
+    0.0696455300303507,
+    0.0693956766382614,
+    0.0691484683735212,
+    0.0689038592365337,
+    0.0686618043331262,
+    0.0684222598407987,
+    0.0681851829762186,
+    0.0679505319639075,
+    0.0677182660060694,
+    0.0674883452535098,
+    0.0672607307776018,
+    0.0670353845432538,
+    0.0668122693828371,
+    0.0665913489710335,
+    0.0663725878005655,
+    0.066155951158772,
+    0.0659414051049953,
+    0.0657289164487471,
+    0.0655184527286211,
+    0.0653099821919232,
+    0.0651034737749902,
+    0.0648988970841695,
+    0.0646962223774351,
+    0.0644954205466131,
+    0.0642964631001948,
+    0.064099322146713,
+    0.0639039703786617,
+    0.063710381056937,
+    0.0635185279957794,
+    0.0633283855482,
+    0.0631399285918708,
+    0.0629531325154621,
+    0.062767973205412,
+    0.0625844270331088,
+    0.0624024708424753,
+    0.0622220819379358,
+    0.0620432380727561,
+    0.0618659174377399,
+    0.0616900986502709,
+    0.061515760743686,
+    0.061342883156971,
+    0.0611714457247638,
+    0.0610014286676573,
+    0.0608328125827897,
+    0.0606655784347128,
+    0.0604997075465285,
+    0.060335181591285,
+    0.0601719825836224,
+    0.0600100928716606,
+    0.0598494951291204,
+    0.05969017234767,
+    0.0595321078294903,
+    0.0593752851800498,
+    0.0592196883010845,
+    0.0590653013837736,
+    0.0589121089021067,
+    0.0587600956064349,
+    0.0586092465171998,
+    0.0584595469188356,
+    0.0583109823538382,
+    0.058163538616995,
+    0.0580172017497721,
+    0.0578719580348524,
+    0.0577277939908204,
+    0.0575846963669894,
+    0.0574426521383656,
+    0.0573016485007461,
+    0.0571616728659458,
+    0.0570227128571493,
+    0.0568847563043846,
+    0.0567477912401137,
+    0.0566118058949378,
+    0.0564767886934124,
+    0.0563427282499708,
+    0.05620961336495,
+    0.0560774330207186,
+    0.0559461763779024,
+    0.0558158327717044,
+    0.0556863917083178,
+    0.0555578428614275,
+    0.0554301760687995,
+    0.0553033813289536,
+    0.0551774487979186,
+    0.0550523687860669,
+    0.0549281317550259,
+    0.0548047283146649,
+    0.0546821492201547,
+    0.0545603853690978,
+    0.0544394277987275,
+    0.0543192676831744,
+    0.0541998963307965,
+    0.0540813051815741,
+    0.0539634858045649,
+    0.0538464298954196,
+    0.0537301292739549,
+    0.0536145758817836,
+    0.0534997617799989,
+    0.0533856791469134,
+    0.0532723202758481,
+    0.0531596775729743,
+    0.0530477435552026,
+    0.0529365108481215,
+    0.0528259721839814,
+    0.0527161203997248,
+    0.0526069484350602,
+    0.0524984493305793,
+    0.0523906162259159,
+    0.0522834423579459,
+    0.0521769210590265,
+    0.052071045755275,
+    0.0519658099648841,
+    0.0518612072964751,
+    0.0517572314474861,
+    0.0516538762025956,
+    0.0515511354321798,
+    0.0514490030908028,
+    0.05134747321574,
+    0.0512465399255321,
+    0.0511461974185697,
+    0.0510464399717091,
+    0.0509472619389156,
+    0.0508486577499364,
+    0.0507506219090011,
+    0.0506531489935488,
+    0.0505562336529823,
+    0.0504598706074472,
+    0.0503640546466374,
+    0.0502687806286237,
+    0.0501740434787074,
+    0.0500798381882968,
+    0.0499861598138068,
+    0.0498930034755803,
+    0.0498003643568319,
+    0.0497082377026125,
+    0.0496166188187944,
+    0.0495255030710775,
+    0.0494348858840139,
+    0.0493447627400532,
+    0.0492551291786056,
+    0.0491659807951242,
+    0.0490773132402045,
+    0.0489891222187022,
+    0.0489014034888677,
+    0.0488141528614973,
+    0.0487273661991017,
+    0.0486410394150891,
+    0.0485551684729651,
+    0.0484697493855474,
+    0.0483847782141954,
+    0.048300251068055,
+    0.048216164103317,
+    0.0481325135224896,
+    0.048049295573685,
+    0.0479665065499194,
+    0.0478841427884249,
+    0.0478022006699761,
+    0.0477206766182274,
+    0.0476395670990636,
+    0.0475588686199625,
+    0.0474785777293681,
+    0.047398691016077,
+    0.0473192051086343,
+    0.0472401166747416,
+    0.0471614224206753,
+    0.0470831190907155,
+    0.0470052034665852,
+    0.0469276723668991,
+    0.0468505226466234,
+    0.0467737511965439,
+    0.0466973549427445,
+    0.0466213308460944,
+    0.0465456759017447,
+    0.0464703871386338,
+    0.0463954616190012,
+    0.0463208964379101,
+    0.0462466887227783,
+    0.0461728356329171,
+    0.0460993343590784,
+    0.0460261821230094,
+    0.0459533761770151,
+    0.0458809138035283,
+    0.045808792314687,
+    0.0457370090519191,
+    0.0456655613855335,
+    0.0455944467143193,
+    0.0455236624651509,
+    0.0454532060925998,
+    0.0453830750785534,
+    0.0453132669318397,
+    0.0452437791878588,
+    0.0451746094082199,
+    0.0451057551803846,
+    0.0450372141173166,
+    0.0449689838571361,
+    0.0449010620627813,
+    0.0448334464216739,
+    0.0447661346453912,
+    0.0446991244693435,
+    0.0446324136524557,
+    0.0445659999768557,
+    0.0444998812475661,
+    0.0444340552922024,
+    0.044368519960675,
+    0.0443032731248964,
+    0.0442383126784931,
+    0.044173636536522,
+    0.0441092426351912,
+    0.0440451289315857,
+    0.0439812934033966,
+    0.0439177340486556,
+    0.0438544488854725,
+    0.043791435951778,
+    0.0437286933050696,
+    0.0436662190221621,
+    0.0436040111989415,
+    0.0435420679501227,
+    0.0434803874090116,
+    0.0434189677272704,
+    0.0433578070746858,
+    0.0432969036389425,
+    0.0432362556253984,
+    0.0431758612568642,
+    0.0431157187733861,
+    0.0430558264320317,
+    0.0429961825066796,
+    0.0429367852878112,
+    0.0428776330823068,
+    0.0428187242132439,
+    0.0427600570196989,
+    0.0427016298565515,
+    0.0426434410942925,
+    0.0425854891188339,
+    0.0425277723313219,
+    0.0424702891479532,
+    0.0424130379997931,
+    0.0423560173325973,
+    0.0422992256066352,
+    0.0422426612965169,
+    0.0421863228910218,
+    0.0421302088929301,
+    0.0420743178188567,
+    0.0420186481990879,
+    0.0419631985774193,
+    0.0419079675109974,
+    0.0418529535701626,
+    0.0417981553382947,
+    0.0417435714116607,
+    0.0416892003992645,
+    0.0416350409226989,
+    0.041581091616,
+    0.0415273511255028,
+    0.0414738181096999,
+    0.0414204912391014,
+    0.0413673691960969,
+    0.0413144506748198,
+    0.0412617343810132,
+    0.0412092190318976,
+    0.0411569033560404,
+    0.0411047860932278,
+    0.0410528659943376,
+    0.0410011418212142,
+    0.0409496123465455,
+    0.040898276353741,
+    0.0408471326368122,
+    0.0407961800002536,
+    0.0407454172589268,
+    0.0406948432379447,
+    0.0406444567725581,
+    0.0405942567080438,
+    0.040544241899594,
+    0.0404944112122069,
+    0.0404447635205797,
+    0.0403952977090019,
+    0.0403460126712507,
+    0.0402969073104878,
+    0.0402479805391573,
+    0.040199231278885,
+    0.0401506584603793,
+    0.0401022610233328,
+    0.0400540379163262,
+    0.0400059880967321,
+    0.0399581105306216,
+    0.0399104041926707,
+    0.0398628680660689,
+    0.0398155011424285,
+    0.0397683024216952,
+    0.0397212709120599,
+    0.0396744056298716,
+    0.0396277055995515,
+    0.039581169853508,
+    0.0395347974320531,
+    0.0394885873833192,
+    0.0394425387631782,
+    0.0393966506351601,
+    0.0393509220703742,
+    0.0393053521474297,
+    0.0392599399523587,
+    0.0392146845785392,
+    0.0391695851266197,
+    0.0391246407044446,
+    0.0390798504269797,
+    0.0390352134162404,
+    0.038990728801219,
+    0.0389463957178138,
+    0.0389022133087593,
+    0.0388581807235562,
+    0.0388142971184039,
+    0.0387705616561318,
+    0.0387269735061335,
+    0.0386835318443004,
+    0.0386402358529565,
+    0.0385970847207942,
+    0.0385540776428107,
+    0.0385112138202453,
+    0.0384684924605173,
+    0.0384259127771645,
+    0.038383473989783,
+    0.0383411753239674,
+    0.0382990160112515,
+    0.0382569952890498,
+    0.0382151124006002,
+    0.038173366594907,
+    0.0381317571266841,
+    0.0380902832562998,
+    0.0380489442497219,
+    0.0380077393784629,
+    0.0379666679195267,
+    0.0379257291553555,
+    0.0378849223737772,
+    0.0378442468679537,
+    0.0378037019363299,
+    0.0377632868825826,
+    0.037723001015571,
+    0.0376828436492868,
+    0.0376428141028059,
+    0.0376029117002394,
+    0.0375631357706867,
+    0.0375234856481875,
+    0.0374839606716758,
+    0.0374445601849334,
+    0.0374052835365444,
+    0.0373661300798504,
+    0.0373270991729057,
+    0.0372881901784334,
+    0.0372494024637818,
+    0.0372107354008813,
+    0.0371721883662021,
+    0.0371721883662021
+  };
+
+#define FLARGEX 0.002
+#define FSMALLX 0.00001
+#define FSMALLMULT 250000
+#define FLARGELEN 500
+#define FSMALLLEN 500
+#define FSMALLSTEP 0.000004;
+
+/* FLOOKUP macro. NOTE! 0<=(int x)<=1 
+ * Tested u:OK
+ */
+#define FLOOKUP(x) (((x) >= FLARGEX) ? flarge_table[(int) (1/(x))] : \
+                    ( ((x) >= FSMALLX) ? fsmall_table[(int) ((x)*FSMALLMULT)] : 0))
+
+/* Macro to test if FLOOKUP above can be used 
+ * Tested u:OK
+ */
+#ifdef TFRCDEBUG
+#define FLOOKUPTEST(x) do { if ( (x) < 0.0 || (x) > 1.0 || ((x)>= FLARGEX && (int) (1/(x)) < 0) || ((x) < FLARGEX && (x) >= FSMALLX && (int) ((x)*FSMALLMULT) < 0)) panic("FLOOKUPTEST failed!"); } while (0)
+#else
+#define FLOOKUPTEST(x) 
+#endif
+
+double tfrc_flookup_reverse(double fvalue);
+
+/*
+ * Inverse of the FLOOKUP above
+ * args: fvalue - function value to match
+ * returns:  p  closest to that value
+ * Tested u:OK
+ */
+double tfrc_flookup_reverse(double fvalue){
+  int ctr;
+  if(fvalue >= flarge_table[1])
+    return 1.0;
+  else if (fvalue >= flarge_table[FLARGELEN]){
+    ctr = FLARGELEN;
+    while(ctr > 1 && fvalue >= flarge_table[ctr])
+      ctr--;
+
+    /* round to smallest */
+    ctr = ctr + 1;
+    
+    /* round to nearest */
+    /*    if (flarge_table[ctr] - fvalue > fvalue - flarge_table[ctr+1])
+          ctr = ctr+1;*/
+    return ((double)(1.0/((double) ctr)));
+  } else if ( fvalue >= fsmall_table[0]){
+    ctr = 0;
+    while(ctr < FSMALLLEN+1 && fvalue > fsmall_table[ctr])
+      ctr++;
+    return ((double)(ctr))*FSMALLSTEP;
+  } 
+  return TFRC_SMALLEST_P;
+}
+
+#endif
+++ sys/netinet/dccp_tfrc_print.h	Fri Aug 25 04:02:22 2006
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2003  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: dccp_tfrc_print.h,v 1.10 2003/05/28 17:36:43 nilmat-8 Exp $
+ */
+
+/* Prints debug information for TFRC */
+
+#ifndef _NETINET_DCCP_TFRC_PRINT_H_
+#define _NETINET_DCCP_TFRC_PRINT_H_
+
+#define PRINTFLOAT(num) \
+        do{ \
+        if((num) > 2000000000)  \
+           TFRC_DEBUG((LOG_INFO,"Large")); \
+        else if ((num) < 0.0)   \
+           TFRC_DEBUG((LOG_INFO,"Negative")); \
+        else { \
+           TFRC_DEBUG((LOG_INFO,"%u+%u*10^-6",(u_int32_t) (num),(u_int32_t) ((num - (double) ((u_int32_t) (num)))*1000000) )); \
+	} \
+        }while(0)
+
+#define PRINTTIMEVALu(tvp)    \
+        do{  TFRC_DEBUG((LOG_INFO,"%u s, %u us",(u_int32_t) (tvp)->tv_sec,(u_int32_t) (tvp)->tv_usec)); \
+        } while(0)
+#define PRINTTIMEVALi(tvp)    \
+        do{  TFRC_DEBUG((LOG_INFO,"%i s, %i us",(int) (tvp)->tv_sec,(int) (tvp)->tv_usec)); \
+        } while(0)
+
+#define PRINTSHISTENTRY(shp) \
+        do {  TFRC_DEBUG((LOG_INFO,"Entry: seq=%u, win_count=%u t_sent=(",(shp)->seq,(shp)->win_count)); \
+              PRINTTIMEVALu(&((shp)->t_sent)); \
+              TFRC_DEBUG((LOG_INFO,")\n")); \
+        }while(0)
+
+#define PRINTSENDHIST(ccbp,elmp) \
+        do {    \
+            if(STAILQ_EMPTY(&((ccbp)->hist))) \
+               TFRC_DEBUG((LOG_INFO, "Send history is empty\n")); \
+            else {   \
+                TFRC_DEBUG((LOG_INFO, "Send history:\n")); \
+	      (elmp)= STAILQ_FIRST(&((ccbp)->hist)); \
+	      while((elmp) != NULL){  \
+		 PRINTSHISTENTRY((elmp)); \
+                 (elmp) = STAILQ_NEXT((elmp),linfo); \
+	      }\
+	    }\
+         }while(0)
+
+
+#define PRINTRHISTENTRY(rhp) \
+        do {  TFRC_DEBUG((LOG_INFO,"Entry: type=%u, seq=%u, win_count=%u, ndp=%u, t_recv=(",(rhp)->type,(rhp)->seq,(rhp)->win_count,(rhp)->ndp)); \
+              PRINTTIMEVALu(&((rhp)->t_recv)); \
+              TFRC_DEBUG((LOG_INFO,")\n")); \
+        }while(0)
+
+#define PRINTRECVHIST(ccbp,elmp) \
+        do {    \
+            if(STAILQ_EMPTY(&((ccbp)->hist))) \
+               TFRC_DEBUG((LOG_INFO, "Recv history is empty\n")); \
+            else {   \
+                TFRC_DEBUG((LOG_INFO, "Recv history:\n")); \
+	      (elmp)= STAILQ_FIRST(&((ccbp)->hist)); \
+	      while((elmp) != NULL){  \
+		 PRINTRHISTENTRY((elmp)); \
+                 (elmp) = STAILQ_NEXT((elmp),linfo); \
+	      }\
+	    }\
+         }while(0)
+
+#define PRINTLIHISTENTRY(lihp) \
+        do {  TFRC_DEBUG((LOG_INFO,"Entry: seqstart=%u, win_count=%u, interval=%u\n",(lihp)->seq,(lihp)->win_count,(lihp)->interval)); \
+        }while(0)
+
+#define PRINTLIHIST(ccbp,elmp) \
+        do {    \
+            if(TAILQ_EMPTY(&((ccbp)->li_hist))) \
+               TFRC_DEBUG((LOG_INFO, "Loss interval history is empty\n")); \
+            else {   \
+                TFRC_DEBUG((LOG_INFO, "Loss interval history:\n")); \
+	      (elmp)= TAILQ_FIRST(&((ccbp)->li_hist)); \
+	      while((elmp) != NULL){  \
+		 PRINTLIHISTENTRY((elmp)); \
+                 (elmp) = TAILQ_NEXT((elmp),linfo); \
+	      }\
+	    }\
+         }while(0)
+
+
+#define PRINTSCCB(ccbp,elmp)\
+        do{   \
+           TFRC_DEBUG((LOG_INFO,"Sender CCB state=%u\nx=",(ccbp)->state));  \
+           PRINTFLOAT((ccbp)->x);\
+	   TFRC_DEBUG((LOG_INFO,",x_recv="));  \
+           PRINTFLOAT((ccbp)->x_recv);\
+	   TFRC_DEBUG((LOG_INFO,",x_calc=")); \
+	   PRINTFLOAT((ccbp)->x_calc);  \
+           TFRC_DEBUG((LOG_INFO, "\ns=%u, rtt= %u, p=",(ccbp)->s,(ccbp)->rtt)); \
+           PRINTFLOAT((ccbp)->p);  \
+           TFRC_DEBUG((LOG_INFO, "\nlast_win_count=%u, t_last_win_count=(",(ccbp)->last_win_count)); \
+           PRINTTIMEVALu(&((ccbp)->t_last_win_count)); \
+           TFRC_DEBUG((LOG_INFO, "\nidle=%u, t_rto=%u, t_ld=(",(ccbp)->idle,(ccbp)->t_rto)); \
+           PRINTTIMEVALi(&((ccbp)->t_ld)); \
+           TFRC_DEBUG((LOG_INFO, ")\nt_nom=(")); \
+           PRINTTIMEVALu(&((ccbp)->t_nom)); \
+           TFRC_DEBUG((LOG_INFO, ") t_ipi=("));   \
+           PRINTTIMEVALu(&((ccbp)->t_ipi)); \
+           TFRC_DEBUG((LOG_INFO, ") delta=("));   \
+           PRINTTIMEVALu(&((ccbp)->delta)); \
+           TFRC_DEBUG((LOG_INFO, ")\n"));   \
+           PRINTSENDHIST(ccbp,elmp); \
+           TFRC_DEBUG((LOG_INFO, "\n")); \
+        }while(0)
+
+#define PRINTRCCB(ccbp,relmp,lielmp)\
+        do{   \
+           TFRC_DEBUG((LOG_INFO,"Receiver CCB state=%u, s=%u, p=",(ccbp)->state,(ccbp)->s));  \
+           PRINTFLOAT((ccbp)->p); \
+           TFRC_DEBUG((LOG_INFO, "\nlast_counter=%u, seq_last_counter=%u\n",(ccbp)->last_counter,(ccbp)->seq_last_counter)); \
+           TFRC_DEBUG((LOG_INFO, "bytes_recv=%u, t_last_feedback=(",(ccbp)->bytes_recv)); \
+           PRINTTIMEVALi(&((ccbp)->t_last_feedback)); \
+           TFRC_DEBUG((LOG_INFO, ")\n")); \
+           PRINTRECVHIST(ccbp,relmp); \
+           PRINTLIHIST(ccbp,lielmp); \
+           TFRC_DEBUG((LOG_INFO, "\n")); \
+        }while(0)
+
+
+#endif
+++ sys/netinet/dccp_usrreq.c	Fri Aug 25 04:02:22 2006
@@ -0,0 +1,3101 @@
+/*
+ * Copyright (c) 2003 Joacim Häggmark, Magnus Erixzon, 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: dccp_usrreq.c,v 1.47 2003/07/31 11:23:08 joahag-9 Exp $
+ */
+
+/*
+ * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1995
+ *	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.
+ *
+ *	@(#)udp_usrreq.c	8.6 (Berkeley) 5/23/95
+ */
+
+#include "opt_inet6.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/domain.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/proc.h>
+#include <sys/protosw.h>
+#include <sys/signalvar.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/sx.h>
+#include <sys/sysctl.h>
+#include <sys/syslog.h>
+#include <sys/queue.h>
+
+#include <vm/uma.h>
+
+#include <net/if.h>
+#include <net/route.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_pcb.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#ifdef INET6
+#include <netinet/ip6.h>
+#endif
+#include <netinet/ip_icmp.h>
+#include <netinet/icmp_var.h>
+#include <netinet/ip_var.h>
+#ifdef INET6
+#include <netinet6/ip6protosw.h>
+#include <netinet6/in6_pcb.h>
+#include <netinet6/ip6_var.h>
+#include <netinet6/nd6.h>
+/*#include <netinet6/ip6_var.h>
+#include <netinet6/in6_pcb.h>
+#include <netinet6/udp6_var.h>
+#include <netinet6/scope6_var.h>*/
+/* */
+#endif
+#include <netinet/dccp.h>
+#include <netinet/dccp_var.h>
+#include <netinet/dccp6_var.h>
+#include <netinet/dccp_cc_sw.h>
+
+#include <machine/in_cksum.h>
+
+#undef DEBUG
+#undef ACKDEBUG
+
+#if defined(DEBUG)
+#define DCCP_DEBUG(args) log args
+#else
+#define DCCP_DEBUG(args)
+#endif
+
+#ifdef ACKDEBUG
+#define ACK_DEBUG(args) log args
+#else
+#define ACK_DEBUG(args)
+#endif
+
+#define DEFAULT_CCID 3
+
+/* Congestion control switch table */
+extern struct dccp_cc_sw cc_sw[];
+
+int	dccp_log_in_vain = 1;
+SYSCTL_INT(_net_inet_dccp, OID_AUTO, dccp_log_in_vain, CTLFLAG_RW, 
+    &dccp_log_in_vain, 0, "Log all incoming DCCP packets");
+
+struct	inpcbhead dccpb;		/* from dccp_var.h */
+struct	inpcbinfo dccpbinfo;
+
+#ifndef UDBHASHSIZE
+#define UDBHASHSIZE 16
+#endif
+
+u_long	dccp_sendspace = 32768;
+u_long	dccp_recvspace = 65536;
+
+struct	dccpstat dccpstat;	/* from dccp_var.h */
+SYSCTL_STRUCT(_net_inet_dccp, DCCPCTL_STATS, stats, CTLFLAG_RW,
+    &dccpstat, dccpstat, "DCCP statistics (struct dccpstat, netinet/dccp_var.h)");
+
+static struct	sockaddr_in dccp_in = { sizeof(dccp_in), AF_INET };
+
+static int dccp_attach2(struct socket *);
+static int dccp_detach(struct socket *so);
+static int dccp_doconnect(struct dccpcb *, struct sockaddr *, struct thread *, int);
+static struct dccpcb * dccp_close(struct dccpcb *);
+static int dccp_disconnect2(struct dccpcb *);
+int dccp_get_option(char *, int, int, char *,int);
+void dccp_parse_options(struct dccpcb *, char *, int);
+int dccp_add_feature(struct dccpcb *, u_int8_t, u_int8_t,  char *, u_int8_t);
+int dccp_remove_feature(struct dccpcb *, u_int8_t, u_int8_t);
+int dccp_add_feature_option(struct dccpcb *, u_int8_t, u_int8_t, char *, u_int8_t);
+void dccp_feature_neg(struct dccpcb *, u_int8_t, u_int8_t, u_int8_t, char *);
+void dccp_retrans_t(void *);
+void dccp_close_t(void *);
+void dccp_timewait_t(void *);
+void dccp_connect_t(void *);
+
+/* Ack Vector functions */
+#define DCCP_VECTORSIZE 512 /* initial ack and cwnd-vector size. Multiple of 8 ! */
+void dccp_use_ackvector(struct dccpcb *dp);
+void dccp_update_ackvector(struct dccpcb *dp, u_int32_t seqno);
+void dccp_increment_ackvector(struct dccpcb *dp, u_int32_t seqno);
+u_int16_t dccp_generate_ackvector(struct dccpcb *dp, u_char *);
+u_char dccp_ackvector_state(struct dccpcb *dp, u_int32_t seqnr);
+
+
+/*
+ * DCCP initialization
+ *
+*/
+void
+dccp_init()
+{
+	INP_INFO_LOCK_INIT(&dccpbinfo, "dccp");
+	DCCP_DEBUG((LOG_INFO, "Initializing DCCP!\n"));
+	LIST_INIT(&dccpb);
+	dccpbinfo.listhead = &dccpb;
+	dccpbinfo.hashbase = hashinit(UDBHASHSIZE, M_PCB, &dccpbinfo.hashmask);
+	dccpbinfo.porthashbase = hashinit(UDBHASHSIZE, M_PCB,
+					&dccpbinfo.porthashmask);
+	dccpbinfo.ipi_zone = uma_zcreate("dccpcb", sizeof(struct inp_dp), NULL,
+	    NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
+	uma_zone_set_max(dccpbinfo.ipi_zone, maxsockets);
+}
+
+#ifdef INET6
+int
+dccp6_input(struct mbuf **mp, int *offp, int proto)
+{
+	register struct mbuf *m = *mp;
+	struct ip6_hdr *ip6 = NULL;
+	DCCP_DEBUG((LOG_INFO, "In dccp6_input!\n"));
+
+        ip6 = mtod(m, struct ip6_hdr *);
+
+        if (faithprefix_p != NULL && (*faithprefix_p)(&ip6->ip6_dst)) {
+                /* XXX send icmp6 host/port unreach? */
+                m_freem(m);
+                return IPPROTO_DONE;
+        }
+#ifndef PULLDOWN_TEST
+	IP6_EXTHDR_CHECK(m, *offp, sizeof(struct dccphdr), IPPROTO_DONE);
+#endif
+	dccp_input(m, *offp);
+	return IPPROTO_DONE;
+}
+#endif
+
+void
+dccp_input(register struct mbuf *m, int off)
+{
+	int iphlen = off;
+	register struct ip *ip = NULL;
+	register struct dccphdr *dh;
+	register struct inpcb *inp, *oinp;
+	register struct dccpcb *dp;
+	register struct ipovly *ipov = NULL;
+	struct dccp_requesthdr *drqh;
+	struct dccp_ackhdr *dah = NULL;
+	struct dccp_resethdr *drth;
+	struct socket *so;
+	u_char *optp = NULL;
+	struct mbuf *opts = 0;
+	int len, data_off, extrah_len, optlen;
+	struct ip save_ip;
+	char options[DCCP_MAX_OPTIONS];
+	char test[2];
+	u_int32_t cslen, seqnr, low_seqnr, high_seqnr;
+	int isipv6 = 0;
+#ifdef INET6
+	struct ip6_hdr *ip6 = NULL;
+#endif
+
+	dccpstat.dccps_ipackets++;
+	dccpstat.dccps_ibytes += m->m_pkthdr.len;
+
+#ifdef INET6
+	isipv6 = (mtod(m, struct ip *)->ip_v == 6) ? 1 : 0;
+#endif
+
+
+#ifdef INET6
+	if ( isipv6 ) {
+		DCCP_DEBUG((LOG_INFO, "Got DCCP IPv6 packet, iphlen = %u!\n", iphlen));
+#ifndef PULLDOWN_TEST
+	        ip6 = mtod(m, struct ip6_hdr *);
+	        dh = (struct dccphdr *)((caddr_t)ip6 + off);
+#else
+	        IP6_EXTHDR_GET(dh, struct dccphdr *, m, off, sizeof(*dh));
+	        if (!dh)
+	                return IPPROTO_DONE;
+#endif
+		ip6 = mtod(m, struct ip6_hdr *);
+		dh = (struct dccphdr *)((caddr_t)ip6 + iphlen );
+	} else
+#endif
+	{
+	 
+	 DCCP_DEBUG((LOG_INFO, "Got DCCP packet!\n"));
+	 
+	/*
+	 * Strip IP options, if any; should skip this,
+	 * make available to user, and use on returned packets,
+	 * but we don't yet have a way to check the checksum
+	 * with options still present.
+	 */
+	if (iphlen > sizeof (struct ip)) {
+		ip_stripoptions(m, (struct mbuf *)0);
+		iphlen = sizeof(struct ip);
+	}
+
+	/*
+	 * Get IP and DCCP header together in first mbuf.
+	 */
+	ip = mtod(m, struct ip *);
+	if (m->m_len < iphlen + sizeof(struct dccphdr)) {
+		if ((m = m_pullup(m, iphlen + sizeof(struct dccphdr))) == 0) {
+			DCCP_DEBUG((LOG_INFO, "Dropping packet, to short?\n"));
+			dccpstat.dccps_drops++;
+			return;
+		}
+		ip = mtod(m, struct ip *);
+	}
+	dh = (struct dccphdr *)((caddr_t)ip + iphlen);
+
+	/*
+	 * Construct sockaddr format source address.
+	 * Stuff source address and datagram in user buffer.
+	 */
+	dccp_in.sin_port = dh->dh_sport;
+	dccp_in.sin_addr = ip->ip_src;
+
+	}
+
+	DCCP_DEBUG((LOG_INFO, "Header info: cslen = %u ndp = %u, off = %u, type = %u, reserved = %u, seq = %u\n", dh->dh_cslen, dh->dh_ndp, dh->dh_off, dh->dh_type, dh->dh_res, ntohl(dh->dh_seq << 8)));
+
+
+	/*
+	 * Make mbuf data length reflect DCCP length.
+	 * If not enough data to reflect DCCP length, drop.
+	 */
+
+#ifdef INET6
+	if (isipv6)
+		len = ntohs(ip6->ip6_plen) -off + sizeof(*ip6);
+	else
+#endif
+		len = ip->ip_len;
+
+	if ( len < sizeof(struct dccphdr)) {
+			DCCP_DEBUG((LOG_INFO, "Dropping DCCP packet!\n"));
+			dccpstat.dccps_badlen++;
+			goto badunlocked;
+	}
+	/*
+	 * Save a copy of the IP header in case we want restore it
+	 * for sending a DCCP reset packet in response.
+	 */
+	if ( !isipv6 ) {
+		save_ip = *ip;
+		ipov = (struct ipovly *)ip;
+	}
+
+	if ( dh->dh_cslen == 15 ) {
+		cslen = len;
+	} else {
+		cslen = dh->dh_off * 4 + dh->dh_cslen * 4;
+		if ( cslen > len )
+			cslen = len;
+	}
+	
+
+	DCCP_DEBUG((LOG_INFO, "Checksum extend header and data! dh->dh_cslen = %u, cslen = %u, len = %u, dh->dh_sum = 0x%04x\n", dh->dh_cslen, cslen, len, dh->dh_sum));
+
+	/*
+	 * Checksum extended DCCP header and data.
+	 */
+	
+#ifdef INET6
+	if (isipv6) {
+		if (in6_cksum(m, IPPROTO_DCCP, off, cslen) != 0) {
+			DCCP_DEBUG((LOG_INFO, "Bad checksum, not dropping packet!, dh->dh_sum = 0x%04x\n", dh->dh_sum));
+			dccpstat.dccps_badsum++;
+		} else {
+			DCCP_DEBUG((LOG_INFO, "Correct checksum, dh->dh_sum = 0x%04x off = %u, cslen = %u\n", dh->dh_sum, off, cslen));
+		}
+	} else
+#endif
+	{
+	bzero(ipov->ih_x1, sizeof(ipov->ih_x1));
+	((struct ipovly *)ip)->ih_len = htons(len);
+	dh->dh_sum = in_cksum(m, cslen + sizeof (struct ip));
+
+	if (dh->dh_sum) {
+	/*	DCCP_DEBUG((LOG_INFO, "Bad checksum, not dropping packet!, dh->dh_sum = 0x%04x\n", dh->dh_sum)); */
+		DCCP_DEBUG((LOG_INFO, "Bad checksum, dropping packet!, dh->dh_sum = 0x%04x\n", dh->dh_sum));
+		dccpstat.dccps_badsum++;
+		m_freem(m);
+		return;
+	}
+	}
+
+	INP_INFO_WLOCK(&dccpbinfo);
+
+	/*
+	 * Locate pcb for datagram.
+	 */
+#ifdef INET6
+	if ( isipv6 ) {
+		inp = in6_pcblookup_hash(&dccpbinfo, &ip6->ip6_src, dh->dh_sport,
+		    &ip6->ip6_dst, dh->dh_dport, 1, m->m_pkthdr.rcvif);
+
+	} else
+#endif
+	{
+	inp = in_pcblookup_hash(&dccpbinfo, ip->ip_src, dh->dh_sport,
+	    ip->ip_dst, dh->dh_dport, 1, m->m_pkthdr.rcvif);
+	}
+
+	if (inp == NULL) {
+		if (dccp_log_in_vain) {
+#ifdef INET6
+			char dbuf[INET6_ADDRSTRLEN+2], sbuf[INET6_ADDRSTRLEN+2];
+#else
+			char dbuf[4*sizeof "123"], sbuf[4*sizeof "123"];
+#endif
+
+#ifdef INET6
+			if (isipv6 ) {
+				strcpy(dbuf, "[");
+				strcpy(sbuf, "[");
+				strcat(dbuf, ip6_sprintf(&ip6->ip6_dst));
+				strcat(sbuf, ip6_sprintf(&ip6->ip6_src));
+				strcat(dbuf, "]");
+				strcat(sbuf, "]");
+			} else
+#endif
+			{
+				strcpy(dbuf, inet_ntoa(ip->ip_dst));
+				strcpy(sbuf, inet_ntoa(ip->ip_src));
+			}
+			log(LOG_INFO,
+			    "Connection attempt to DCCP %s:%d from %s:%d\n",
+			    dbuf, ntohs(dh->dh_dport), sbuf,
+			    ntohs(dh->dh_sport));
+		}
+		dccpstat.dccps_noport++;
+
+	/*
+	* We should send DCCP reset here but we can't call dccp_output since we
+	* have no dccpcb. A icmp unreachable works great but the specs says DCCP reset :(
+	*
+	* if ( !isipv6) {
+	*	*ip = save_ip;
+	*	ip->ip_len += iphlen;
+	*	icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT, 0, 0); 
+	*} 
+	*/
+
+		INP_INFO_WUNLOCK(&dccpbinfo);
+		return;
+	}
+	INP_LOCK(inp);
+
+	dp = (struct dccpcb *)inp->inp_ppcb;
+
+	if ( dp == 0 ) {
+		INP_UNLOCK(inp);
+		INP_INFO_WUNLOCK(&dccpbinfo);
+		goto badunlocked;
+	}
+
+	if ( dp->state == DCCPS_CLOSED ) {
+		DCCP_DEBUG((LOG_INFO, "We are in closed state, dropping packet and sending reset!\n"));
+		if ( dh->dh_type != DCCP_TYPE_RESET )
+			dccp_output(dp, DCCP_TYPE_RESET + 2);
+		INP_UNLOCK(inp);
+		INP_INFO_WUNLOCK(&dccpbinfo);
+		goto badunlocked;
+	}
+
+	so = inp->inp_socket;
+
+	if (so->so_options & SO_ACCEPTCONN) {
+		DCCP_DEBUG((LOG_INFO, "so->options & SO_ACCEPTCONN! dp->state = %i\n", dp->state));
+		so = sonewconn(so, SS_ISCONNECTED);
+		if (so == 0) {
+			DCCP_DEBUG((LOG_INFO, "Error, sonewconn failed!\n"));
+			INP_UNLOCK(inp);
+			INP_INFO_WUNLOCK(&dccpbinfo);
+			goto badunlocked;
+		}
+
+		oinp = inp;
+		inp = sotoinpcb(so);
+		INP_LOCK(inp);
+
+#ifdef INET6
+		if (isipv6) {
+			inp->in6p_laddr = ip6->ip6_dst;
+			inp->in6p_faddr = ip6->ip6_src;
+		} else 
+#endif
+		{
+			inp->inp_laddr = ip->ip_dst;
+			inp->inp_faddr = ip->ip_src;
+		}
+		inp->inp_lport = dh->dh_dport;
+		inp->inp_fport = dh->dh_sport;
+
+		if (in_pcbinshash(inp) != 0) {
+			DCCP_DEBUG((LOG_INFO, "Error, in_pcbinshash failed!\n"));
+			INP_UNLOCK(inp);
+			INP_INFO_WUNLOCK(&dccpbinfo);
+			goto badunlocked;
+		}
+
+		dp = (struct dccpcb *)inp->inp_ppcb;
+		dp->state = DCCPS_LISTEN;
+		dp->who = DCCP_SERVER;
+		dp->cslen = ((struct dccpcb *)oinp->inp_ppcb)->cslen;
+		dp->avgpsize = ((struct dccpcb *)oinp->inp_ppcb)->avgpsize;
+		dp->seq_snd = arc4random() % 16777216;
+		INP_UNLOCK(oinp);
+		DCCP_DEBUG((LOG_INFO, "New dp = %u, dp->state = %u!\n", (int)dp, dp->state));
+	}
+
+	INP_INFO_WUNLOCK(&dccpbinfo);
+
+	/*
+	* Check if sequence number is inside the loss window 
+	*/
+
+	seqnr = ntohl(dh->dh_seq << 8);
+	
+	if ( dp->gsn_rcv == 1073741824 )  {
+		dp->gsn_rcv = seqnr;
+	}
+
+	low_seqnr = (dp->gsn_rcv - (dp->loss_window / 3)) % 16777216;
+	high_seqnr = (dp->gsn_rcv + (dp->loss_window / 3 * 2)) % 16777216;
+
+	if (! (SEQ_GT(seqnr, low_seqnr) && SEQ_LT(seqnr, high_seqnr)) ) {
+		dccpstat.dccps_badseq++;
+		DCCP_DEBUG((LOG_INFO, "Recieved DCCP packet with bad sequence number = %u (low_seqnr = %u, high_seqnr = %u)\n", seqnr, low_seqnr, high_seqnr));
+		INP_UNLOCK(inp);
+		goto badunlocked;
+	}
+
+	/* dp->gsn_rcv should always be the highest received valid sequence number */
+	if (SEQ_GT(seqnr, dp->gsn_rcv))
+		dp->gsn_rcv = seqnr;
+
+	/* Just ignore DCCP-Move for now */
+	if ( dh->dh_type == DCCP_TYPE_DATA ) {
+		extrah_len = 0;
+		optp = (u_char *)(dh + 1);
+	} else if ( dh->dh_type == DCCP_TYPE_REQUEST ) {
+		drqh = (struct dccp_requesthdr *)(dh + 1);
+		optp = (u_char *)(drqh + 1);
+		extrah_len = 4;
+	} else if ( dh->dh_type == DCCP_TYPE_RESET ) {
+		extrah_len = 8 ;
+		drth = (struct dccp_resethdr *)(dh + 1);
+		optp = (u_char *)(drth + 1);
+	} else {
+		extrah_len = 4;
+		dah = (struct dccp_ackhdr *)(dh + 1);
+		optp = (u_char *)(dah + 1);
+
+	}
+
+	data_off = (dh->dh_off * 4);
+
+	dp->seq_rcv = seqnr;
+	dp->ack_rcv = 0; /* Clear it for now */
+	dp->type_rcv = dh->dh_type;
+	dp->len_rcv = m->m_len - data_off - iphlen; /* Correct length ? */
+	dp->ndp_rcv = dh->dh_ndp;
+	
+	optlen = data_off - (sizeof(struct dccphdr) + extrah_len);
+
+	if ( optlen < 0 ) {
+		DCCP_DEBUG((LOG_INFO, "Data offset is smaller then it could be, optlen = %i data_off = %i, m_len = %i, iphlen = %i extrah_len = %i !\n", optlen, data_off, m->m_len, iphlen, extrah_len));
+		INP_UNLOCK(inp);
+		goto badunlocked;
+	}
+
+	if ( optlen > 0 ) {
+		if ( optlen > DCCP_MAX_OPTIONS ) {
+			DCCP_DEBUG((LOG_INFO, "Error, more options (%i) then DCCP_MAX_OPTIONS options!\n", optlen));
+			INP_UNLOCK(inp);
+			goto badunlocked;
+		}
+
+		DCCP_DEBUG((LOG_INFO, "Parsing DCCP options, optlen = %i\n", optlen));
+		bcopy(optp, options, optlen);
+		dccp_parse_options(dp, options, optlen);
+	}
+
+	DCCP_DEBUG((LOG_INFO, "BEFORE state check, Got a %u packet while in %u state, who = %u!\n", dh->dh_type, dp->state, dp->who));
+
+	if ( dp->state == DCCPS_LISTEN ) {
+		switch(dh->dh_type) {
+
+		case DCCP_TYPE_REQUEST:
+			DCCP_DEBUG((LOG_INFO, "Got DCCP REQUEST\n"));
+			dp->state = DCCPS_REQUEST;
+			if ( dp->cc_in_use[1] < 0 ) {
+				/* To be compatible with Linux implementation */
+				test[0] = DEFAULT_CCID;
+				if ( test[0] == 2 ) {
+					test[1] = 3;
+				} else {
+					test[1] = 2;
+				}	
+				dccp_add_feature(dp, DCCP_OPT_CHANGE, DCCP_FEATURE_CC, test, 2);
+			}
+			if ( len > data_off ) {
+				dccp_add_option(dp, DCCP_OPT_DATA_DISCARD, test, 0);
+			}
+			dp->connect_timer = timeout(dccp_connect_t, dp, DCCP_CONNECT_TIMER);
+			dccp_output(dp, 0);
+			break;
+
+
+		/* These are ok if the sender has a valid init Cookie */
+		case DCCP_TYPE_ACK:
+		case DCCP_TYPE_DATAACK:
+		case DCCP_TYPE_DATA:
+			DCCP_DEBUG((LOG_INFO, "Got DCCP ACK/DATAACK/DATA, should check init cookie...\n"));
+			dccp_output(dp, DCCP_TYPE_RESET + 2);
+			break;
+
+		case DCCP_TYPE_RESET:
+			DCCP_DEBUG((LOG_INFO, "Got DCCP RESET\n"));
+			dp->state = DCCPS_TIME_WAIT;
+			dp = dccp_close(dp);
+			return;
+
+		default:
+			DCCP_DEBUG((LOG_INFO, "Got a %u packet while in listen stage!\n", dh->dh_type));
+			/* Force send reset. */
+			dccp_output(dp, DCCP_TYPE_RESET + 2);
+		}
+
+
+	} else if ( dp->state == DCCPS_REQUEST  ) {
+		switch(dh->dh_type) {
+		case DCCP_TYPE_RESPONSE:
+			DCCP_DEBUG((LOG_INFO, "Got DCCP REPSONSE\n"));
+			dp->ack_rcv = ntohl(dah->dah_ack << 8); /* Ack num */
+			dp->ack_snd = dp->seq_rcv;
+
+			untimeout(dccp_retrans_t, dp, dp->retrans_timer);
+			untimeout(dccp_connect_t, dp, dp->connect_timer);
+
+			/* First check if we have negotiated a cc */
+			if ( dp->cc_in_use[0] > 0 && dp->cc_in_use[1] > 0 ) {
+				DCCP_DEBUG((LOG_INFO, "Setting DCCPS_ESTAB & soisconnected\n"));
+				dp->state = DCCPS_ESTAB;
+				dccpstat.dccps_connects++;
+				soisconnected(inp->inp_socket);
+			} else {
+				dp->state = DCCPS_RESPOND;
+				DCCP_DEBUG((LOG_INFO, "CC negotiation is not finished, cc_in_use[0] = %u, cc_in_use[1] = %u\n",dp->cc_in_use[0], dp->cc_in_use[1]));
+
+			}
+			dccp_output(dp, 0);
+			break;
+
+		case DCCP_TYPE_RESET:
+			DCCP_DEBUG((LOG_INFO, "Got DCCP RESET\n"));
+			dp->state = DCCPS_TIME_WAIT;
+			dp = dccp_close(dp);
+			return;
+
+		default:
+			DCCP_DEBUG((LOG_INFO, "Got a %u packet while in REQUEST stage!\n", dh->dh_type));
+			/* Force send reset. */
+			dccp_output(dp, DCCP_TYPE_RESET + 2);
+			if ( dh->dh_type == DCCP_TYPE_CLOSE ) {
+				dp = dccp_close(dp);
+				return;
+			} else {
+				untimeout(dccp_retrans_t, dp, dp->retrans_timer);
+				dp->state = DCCPS_TIME_WAIT;
+			}
+		}
+
+	} else if ( dp->state == DCCPS_RESPOND ) {
+		switch(dh->dh_type) {
+
+		case DCCP_TYPE_REQUEST:
+			break;
+		case DCCP_TYPE_ACK:
+		case DCCP_TYPE_DATAACK:
+			DCCP_DEBUG((LOG_INFO, "Got DCCP ACK/DATAACK\n"));
+
+			untimeout(dccp_connect_t, dp, dp->connect_timer);
+
+			dp->ack_rcv = ntohl(dah->dah_ack << 8); /* Ack num */
+
+			if ( dp->cc_in_use[0] > 0 && dp->cc_in_use[1] > 0 ) {
+				DCCP_DEBUG((LOG_INFO, "Setting DCCPS_ESTAB & soisconnected\n"));
+				dp->state = DCCPS_ESTAB;
+				dccpstat.dccps_connects++;
+				soisconnected(inp->inp_socket);
+			} else {
+				DCCP_DEBUG((LOG_INFO, "CC negotiation is not finished, cc_in_use[0] = %u, cc_in_use[1] = %u\n",dp->cc_in_use[0], dp->cc_in_use[1]));
+				/* Force an output!!! */
+				dp->ack_snd = dp->seq_rcv;
+				dccp_output(dp, 0);
+			}
+
+			if ( dh->dh_type == DCCP_TYPE_DATAACK && dp->cc_in_use[1] > 0 ) {
+				DCCP_DEBUG((LOG_INFO, "Calling *cc_sw[%u].cc_recv_packet_recv!\n", dp->cc_in_use[1]));
+				(*cc_sw[dp->cc_in_use[1]].cc_recv_packet_recv)(dp->cc_state[1], options, optlen); 
+			}
+			break;
+		case DCCP_TYPE_CLOSE:
+			dccp_output(dp, DCCP_TYPE_CLOSE + 1);
+			dp = dccp_close(dp);
+			return;
+		case DCCP_TYPE_RESET:
+			dp->state = DCCPS_TIME_WAIT;
+			untimeout(dccp_retrans_t, dp, dp->retrans_timer);
+			break;
+
+		default:
+			DCCP_DEBUG((LOG_INFO, "Got a %u packet while in response stage!\n", dh->dh_type));
+			/* Force send reset. */
+			dccp_output(dp, DCCP_TYPE_RESET + 2);
+		}
+
+	} else if ( dp->state == DCCPS_ESTAB ) {
+		switch(dh->dh_type) {
+
+		case DCCP_TYPE_DATA:
+			DCCP_DEBUG((LOG_INFO, "Got DCCP DATA, state = %i, cc_in_use[1] = %u\n", dp->state, dp->cc_in_use[1]));
+			
+			if ( dp->cc_in_use[1] > 0 ) {
+				DCCP_DEBUG((LOG_INFO, "Calling *cc_sw[%u].cc_recv_packet_recv!\n", dp->cc_in_use[1]));
+				(*cc_sw[dp->cc_in_use[1]].cc_recv_packet_recv)(dp->cc_state[1], options, optlen);
+			}
+			break;
+	
+		case DCCP_TYPE_ACK:
+			DCCP_DEBUG((LOG_INFO, "Got DCCP ACK\n"));
+			dp->ack_rcv = ntohl(dah->dah_ack << 8); /* Ack num */
+			if ( dp->cc_in_use[1] > 0 ) {
+				/* This is called so Acks on Acks can be handled */
+				DCCP_DEBUG((LOG_INFO, "Calling *cc_sw[%u].cc_recv_packet_recv!\n", dp->cc_in_use[1]));
+				(*cc_sw[dp->cc_in_use[1]].cc_recv_packet_recv)(dp->cc_state[1], options, optlen); 
+			}
+			break;
+	
+		case DCCP_TYPE_DATAACK:
+			DCCP_DEBUG((LOG_INFO, "Got DCCP DATAACK\n"));
+			dp->ack_rcv = ntohl(dah->dah_ack << 8); /* Ack num */
+			if ( dp->cc_in_use[1] > 0 ) {
+				DCCP_DEBUG((LOG_INFO, "Calling *cc_sw[%u].cc_recv_packet_recv!\n", dp->cc_in_use[1]));
+				(*cc_sw[dp->cc_in_use[1]].cc_recv_packet_recv)(dp->cc_state[1], options, optlen); 
+			}
+			break;
+	
+		case DCCP_TYPE_CLOSEREQ:
+			DCCP_DEBUG((LOG_INFO, "Got DCCP CLOSEREQ, state = estab\n"));
+			if ( dp->who == DCCP_CLIENT ) {
+				dccp_disconnect2(dp);
+			} else {
+				dccp_output(dp, DCCP_TYPE_RESET + 2);
+			}
+			break;
+	
+		case DCCP_TYPE_CLOSE:
+			DCCP_DEBUG((LOG_INFO, "Got DCCP CLOSE, state = estab\n"));
+			dp->state = DCCPS_SERVER_CLOSE; /* So disconnect2 doesn't send CLOSEREQ */
+			dccp_disconnect2(dp);
+			dccp_output(dp, DCCP_TYPE_RESET + 2);
+			dccp_close(dp);
+			goto badunlocked;
+			break;
+	
+		case DCCP_TYPE_RESET:
+			DCCP_DEBUG((LOG_INFO, "Got DCCP RESET\n"));
+			dp->state = DCCPS_TIME_WAIT;
+			untimeout(dccp_retrans_t, dp, dp->retrans_timer);
+			dp->timewait_timer = timeout(dccp_timewait_t, dp, DCCP_TIMEWAIT_TIMER);
+			break;
+	
+		case DCCP_TYPE_MOVE:
+			DCCP_DEBUG((LOG_INFO, "Got DCCP MOVE\n"));
+			break;
+
+		default:
+			DCCP_DEBUG((LOG_INFO, "Got a %u packet while in established stage!\n", dh->dh_type));
+		}
+
+	} else if ( dp->state == DCCPS_SERVER_CLOSE ) {
+		/* Server */
+		switch(dh->dh_type) {
+		case DCCP_TYPE_CLOSE:
+			DCCP_DEBUG((LOG_INFO, "Got DCCP CLOSE (State DCCPS_SERVER_CLOSE)\n"));
+			untimeout(dccp_retrans_t, dp, dp->retrans_timer);
+			dccp_output(dp, DCCP_TYPE_RESET + 2);
+			dp = dccp_close(dp);
+			return;
+		case DCCP_TYPE_RESET:
+			DCCP_DEBUG((LOG_INFO, "Got DCCP RESET\n"));
+			untimeout(dccp_retrans_t, dp, dp->retrans_timer);
+			dccp_output(dp, DCCP_TYPE_RESET + 2);
+			dp->state = DCCPS_TIME_WAIT;
+			break;
+		default:
+			DCCP_DEBUG((LOG_INFO, "Got a %u packet while in server_close stage!\n", dh->dh_type));
+		}
+
+	} else if ( dp->state == DCCPS_CLIENT_CLOSE ) {
+		/* Client */
+		switch(dh->dh_type) {
+		case DCCP_TYPE_CLOSE:
+			/* Ignore */
+			break;
+		case DCCP_TYPE_CLOSEREQ:
+			DCCP_DEBUG((LOG_INFO, "Got DCCP CLOSEREQ, state = DCCPS_CLIENT_CLOSE\n"));
+			/* Just resend close */
+			dccp_output(dp, 0);
+			break;
+		case DCCP_TYPE_RESET:
+			DCCP_DEBUG((LOG_INFO, "Got DCCP RESET\n"));
+			untimeout(dccp_retrans_t, dp, dp->retrans_timer);
+			dp->state = DCCPS_TIME_WAIT;
+			dp->timewait_timer = timeout(dccp_timewait_t, dp, DCCP_TIMEWAIT_TIMER);
+			break;
+		default:
+			DCCP_DEBUG((LOG_INFO, "Got a %u packet while in client_close stage!\n", dh->dh_type));
+
+		}
+	} else {
+		DCCP_DEBUG((LOG_INFO, "Got a %u packet while in %u state!\n", dh->dh_type, dp->state));
+		if ( dh->dh_type != DCCP_TYPE_RESET ) {
+			/* Force send reset. */
+			DCCP_DEBUG((LOG_INFO, "Force sending a request!\n"));
+			dccp_output(dp, DCCP_TYPE_RESET + 2);
+		}
+	}
+
+	if ( dh->dh_type == DCCP_TYPE_DATA ||
+	     dh->dh_type == DCCP_TYPE_ACK  ||
+	     dh->dh_type == DCCP_TYPE_DATAACK) {
+		DCCP_DEBUG((LOG_INFO, "ACK = %u\n", dp->ack_rcv));
+		if ( dp->cc_in_use[0] > 0 ) {
+			(*cc_sw[dp->cc_in_use[0]].cc_send_packet_recv)(dp->cc_state[0],options, optlen);
+		}
+		
+	}
+
+	if ( dh->dh_type == DCCP_TYPE_DATA || dh->dh_type == DCCP_TYPE_DATAACK ) {
+		if (so->so_state & SBS_CANTRCVMORE) {
+			DCCP_DEBUG((LOG_INFO, "state & SBS_CANTRCVMORE...!\n"));
+			m_freem(m);
+			if (opts)
+				m_freem(opts);
+		} else {
+			m_adj(m, (iphlen + data_off));
+			DCCP_DEBUG((LOG_INFO, "Calling sbappend!\n"));
+			sbappend(&so->so_rcv, m);
+		}
+		DCCP_DEBUG((LOG_INFO, "Calling sorwakeup...!\n"));
+		sorwakeup(so);
+	} else {
+		m_freem(m);
+		if (opts)
+			m_freem(opts);
+	}
+	if (dp)
+		INP_UNLOCK(inp);
+
+	return;
+
+badunlocked:
+	m_freem(m);
+	if (opts)
+		m_freem(opts);
+	return;
+}
+
+/*
+ * Notify a dccp user of an asynchronous error;
+ * just wake up so that he can collect error status.
+ */
+struct inpcb *
+dccp_notify(register struct inpcb *inp, int errno)
+{
+	inp->inp_socket->so_error = errno;
+	sorwakeup(inp->inp_socket);
+	sowwakeup(inp->inp_socket);
+	return inp;
+}
+
+/*
+ * Called when we get ICMP errors (destination unrechable,
+ * parameter problem, source quench, time exceeded and redirects)
+*/
+void
+dccp_ctlinput(int cmd, struct sockaddr *sa, void *vip)
+{
+	struct ip *ip = vip;
+	struct dccphdr *dh;
+	struct inpcb *(*notify)(struct inpcb *, int) = dccp_notify;
+        struct in_addr faddr;
+	struct inpcb *inp;
+
+	faddr = ((struct sockaddr_in *)sa)->sin_addr;
+	if (sa->sa_family != AF_INET || faddr.s_addr == INADDR_ANY)
+        	return;
+
+	if (PRC_IS_REDIRECT(cmd)) {
+		return;
+	} else if (cmd == PRC_HOSTDEAD)
+		ip = 0;
+	else if ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0)
+		return;
+	if (ip) {
+		dh = (struct dccphdr *)((caddr_t)ip + (ip->ip_hl << 2));
+		INP_INFO_RLOCK(&dccpbinfo);
+		inp = in_pcblookup_hash(&dccpbinfo, faddr, dh->dh_dport,
+                    ip->ip_src, dh->dh_sport, 0, NULL);
+		if (inp != NULL) {
+			INP_LOCK(inp);
+			if(inp->inp_socket != NULL) {
+				(*notify)(inp, inetctlerrmap[cmd]);
+			}
+			INP_UNLOCK(inp);
+		}
+		INP_INFO_RUNLOCK(&dccpbinfo);
+	} else
+		in_pcbnotifyall(&dccpbinfo, faddr, inetctlerrmap[cmd], notify);
+}
+
+#ifdef INET6
+void
+dccp6_ctlinput(int cmd, struct sockaddr *sa, void *d)
+{
+
+        struct dccphdr dh;
+        struct ip6_hdr *ip6;
+        struct mbuf *m;
+        int off = 0;
+        struct ip6ctlparam *ip6cp = NULL;
+        const struct sockaddr_in6 *sa6_src = NULL;
+        void *cmdarg;
+        struct inpcb *(*notify) __P((struct inpcb *, int)) = dccp_notify;
+        struct dccp_portonly {
+                u_int16_t dh_sport;
+                u_int16_t dh_dport;
+        } *dhp;
+
+        if (sa->sa_family != AF_INET6 ||
+            sa->sa_len != sizeof(struct sockaddr_in6))
+                return;
+
+        if ((unsigned)cmd >= PRC_NCMDS)
+                return;
+        if (PRC_IS_REDIRECT(cmd))
+		notify = in6_rtchange, d = NULL;
+        else if (cmd == PRC_HOSTDEAD)
+                d = NULL;
+        else if (inet6ctlerrmap[cmd] == 0)
+                return;
+
+        /* if the parameter is from icmp6, decode it. */
+        if (d != NULL) {
+                ip6cp = (struct ip6ctlparam *)d;
+                m = ip6cp->ip6c_m;
+                ip6 = ip6cp->ip6c_ip6;
+                off = ip6cp->ip6c_off;
+                cmdarg = ip6cp->ip6c_cmdarg;
+                sa6_src = ip6cp->ip6c_src;
+        } else {
+                m = NULL;
+                ip6 = NULL;
+                cmdarg = NULL;
+                sa6_src = &sa6_any;
+        }
+
+        if (ip6) {
+                /*
+                 * XXX: We assume that when IPV6 is non NULL,
+                 * M and OFF are valid.
+                 */
+
+                /* check if we can safely examine src and dst ports */
+                if (m->m_pkthdr.len < off + sizeof(*dhp))
+                        return;
+
+                bzero(&dh, sizeof(dh));
+                m_copydata(m, off, sizeof(*dhp), (caddr_t)&dh);
+
+                (void) in6_pcbnotify(&dccpbinfo, sa, dh.dh_dport,
+                                     (struct sockaddr *)ip6cp->ip6c_src,
+                                     dh.dh_sport, cmd, cmdarg, notify);
+        } else
+                (void) in6_pcbnotify(&dccpbinfo, sa, 0,
+                                     (const struct sockaddr *)sa6_src,
+                                     0, cmd, cmdarg, notify);
+}
+#endif
+
+/* 
+ * Called by getsockopt and setsockopt.
+ *
+*/
+int
+dccp_ctloutput(struct socket *so, struct sockopt *sopt)
+{
+	int optval, error = 0;
+	struct inpcb	*inp;
+	struct dccpcb	*dp;
+
+
+	INP_INFO_RLOCK(&dccpbinfo);
+	inp = sotoinpcb(so);
+	if ( inp == NULL ) {
+		INP_INFO_RUNLOCK(&dccpbinfo);
+		return (ECONNRESET);
+	}
+	INP_LOCK(inp);
+	INP_INFO_RUNLOCK(&dccpbinfo);
+	
+	if (sopt->sopt_level != IPPROTO_DCCP) {
+		/* Let ip have it. */
+#ifdef INET6
+		if (INP_CHECK_SOCKAF(so, AF_INET6))
+			error = ip6_ctloutput(so, sopt);
+		else 
+#endif
+			error = ip_ctloutput(so, sopt);
+		INP_UNLOCK(inp);
+		return(error);
+	}
+
+	dp = (struct dccpcb *)inp->inp_ppcb;
+	switch (sopt->sopt_dir) {
+	case SOPT_SET:
+	      switch (sopt->sopt_name) {
+		case DCCP_CCID:
+		case DCCP_CSLEN:
+		case DCCP_TFRC_AVGPSIZE:
+		case DCCP_MAXSEG:
+			error = sooptcopyin(sopt, &optval, sizeof optval, sizeof optval);
+
+			if (error)
+				break;
+
+			switch (sopt->sopt_name) {
+			case DCCP_CCID:
+				/* Add check that optval is a CCID we support!!! */
+				if ( optval == 2 || optval == 3 || optval == 0 ) {
+					dp->pref_cc = optval;
+				} else {
+					error = EINVAL;
+				}
+				break;
+			case DCCP_CSLEN:
+				if ( optval > 15 || optval < 0 ) {
+					error = EINVAL;
+				} else {
+					dp->cslen = optval;
+				}
+				break;
+			case DCCP_TFRC_AVGPSIZE:
+				if ( optval > 65536 || optval < 0 ) {
+					error = EINVAL;
+				} else {
+					dp->avgpsize = optval;
+				}
+				break;
+			case DCCP_MAXSEG:
+				if ( optval > 0 && optval <= dp->d_maxseg ) {
+					dp->d_maxseg = optval;
+				} else {
+					error = EINVAL;
+				}
+				break;
+			}
+
+			break;
+
+		default:
+			error = ENOPROTOOPT;
+		}
+
+	      break;
+
+	case SOPT_GET:
+		switch (sopt->sopt_name) {
+		case DCCP_CCID:
+			optval = dp->pref_cc;
+			break;
+		case DCCP_CSLEN:
+			optval = dp->cslen;
+			break;
+		case DCCP_TFRC_AVGPSIZE:
+			optval = dp->avgpsize;
+			break;
+		case DCCP_MAXSEG:
+			optval = dp->d_maxseg;
+			break;
+		default:
+			error = ENOPROTOOPT;
+		}
+
+		if ( error == 0 ) {
+			error = sooptcopyout(sopt, &optval, sizeof optval);
+		}
+		break;
+	}
+
+	INP_UNLOCK(inp);
+	return error;
+}
+
+int
+dccp_output(register struct dccpcb *dp, u_int8_t extra )
+{
+	struct inpcb *inp = dp->d_inpcb;
+	struct socket *so = inp->inp_socket;
+	struct mbuf *m;
+
+	register struct dccpiphdr *di = NULL;
+	register struct dccphdr *dh;
+	struct dccp_requesthdr *drqh;
+	struct dccp_ackhdr *dah;
+	struct dccp_resethdr *drth;
+	u_char *optp = NULL;
+	int error = 0;
+	int off, sendalot, t, i;
+	u_int32_t hdrlen, optlen, extrah_len, cslen;
+	u_int8_t type;
+	char options[DCCP_MAX_OPTIONS *2];
+	long len;
+#ifdef INET6
+	register struct dccpip6hdr *di6 = NULL;
+	int isipv6;
+
+	isipv6 = (dp->d_inpcb->inp_vflag & INP_IPV6) != 0;
+#endif
+
+	DCCP_DEBUG((LOG_INFO, "Going to send a DCCP packet!\n"));
+	mtx_assert(&dp->d_inpcb->inp_mtx, MA_OWNED);
+
+	if ( dp->state != DCCPS_ESTAB && extra == 1 ) {
+		/* Only let cc decide when to resend if we are in establised state */
+		return 0;
+	}
+
+again:
+	sendalot = 0;
+
+
+	off = 0; /* off not needed for dccp because we do not need to wait for ACK
+		    before removing the packet   */
+	len = (long)so->so_snd.sb_cc;
+	optlen = 0;
+
+	/* Check with CC if we can send... */
+	if ( dp->cc_in_use[0] > 0 && dp->state == DCCPS_ESTAB ) {
+		DCCP_DEBUG((LOG_INFO, "Calling *cc_sw[%u].cc_send_packet!\n", dp->cc_in_use[0]));
+		if(!(*cc_sw[dp->cc_in_use[0]].cc_send_packet)(dp->cc_state[0], len)) {
+			DCCP_DEBUG((LOG_INFO, "Not allowed to send right now\n"));
+			return 0;
+		}
+	}
+
+	if (len > dp->d_maxseg ) {
+		len = dp->d_maxseg;
+		sendalot = 1;
+	}
+
+	if ( extra == DCCP_TYPE_RESET + 2 ) {
+		DCCP_DEBUG((LOG_INFO, "Force sending of DCCP TYPE_RESET!\n"));
+		type = DCCP_TYPE_RESET;
+		extrah_len = 8;
+	} else if ( dp->state <= DCCPS_REQUEST && dp->who == DCCP_CLIENT ) {
+		DCCP_DEBUG((LOG_INFO, "Sending DCCP TYPE_REQUEST!\n"));
+		type = DCCP_TYPE_REQUEST;
+		dp->state = DCCPS_REQUEST;
+		extrah_len = 4;
+	} else if ( dp->state == DCCPS_REQUEST && dp->who == DCCP_SERVER ) {
+		DCCP_DEBUG((LOG_INFO, "Sending DCCP TYPE_RESPONSE!\n"));
+		type = DCCP_TYPE_RESPONSE;
+		dp->state = DCCPS_RESPOND;
+		extrah_len = 4;
+	} else if ( dp->state == DCCPS_RESPOND ) {
+		DCCP_DEBUG((LOG_INFO, "Still in feature neg, sending DCCP TYPE_ACK!\n"));
+		type = DCCP_TYPE_ACK;
+		extrah_len = 4;
+	} else if ( dp->state == DCCPS_ESTAB ) {
+		if ( dp->ack_snd && len ) {
+			DCCP_DEBUG((LOG_INFO, "Sending DCCP TYPE_DATAACK!\n"));
+			type = DCCP_TYPE_DATAACK;
+			/*(u_int32_t *)&extrah = dp->seq_rcv; */
+			extrah_len = 4;
+		} else if ( dp->ack_snd ) {
+			DCCP_DEBUG((LOG_INFO, "Sending DCCP TYPE_ACK!\n"));
+			type = DCCP_TYPE_ACK;
+			extrah_len = 4;
+		} else if (len) {
+			DCCP_DEBUG((LOG_INFO, "Sending DCCP TYPE_DATA!\n"));
+			type = DCCP_TYPE_DATA;
+			extrah_len = 0;
+		} else {
+		  DCCP_DEBUG((LOG_INFO, "No ack or data to send!\n"));
+		  return 0;
+		}
+	} else if ( dp->state == DCCPS_CLIENT_CLOSE ) {
+		DCCP_DEBUG((LOG_INFO, "Sending DCCP TYPE_CLOSE!\n"));
+		type = DCCP_TYPE_CLOSE;
+		extrah_len = 4;
+	} else if ( dp->state == DCCPS_SERVER_CLOSE ) {
+		DCCP_DEBUG((LOG_INFO, "Sending DCCP TYPE_CLOSEREQ!\n"));
+		type = DCCP_TYPE_CLOSEREQ;
+		extrah_len = 4;
+	} else {
+		DCCP_DEBUG((LOG_INFO, "Hey, we should never get here, state = %u\n", dp->state));
+		return 1;
+	}
+
+	/* Adding options. */
+	if ( dp->optlen ) {
+		DCCP_DEBUG((LOG_INFO, "Copying options from dp->options!\n"));
+		bcopy(dp->options, options , dp->optlen);
+		optlen = dp->optlen;
+		dp->optlen = 0;
+	}
+
+	if ( dp->featlen && (optlen + dp->featlen < DCCP_MAX_OPTIONS )) {
+		DCCP_DEBUG((LOG_INFO, "Copying options from dp->features!\n"));
+		bcopy(dp->features, options + optlen, dp->featlen);
+		optlen += dp->featlen;
+	}
+
+	t = optlen %4;
+
+	if ( t ) {
+		t = 4 - t;
+		for(i = 0 ; i<t; i++ ) {
+			options[optlen] = 0;
+			optlen++;
+		}
+	}
+
+#ifdef INET6
+	if ( isipv6 ) {
+		DCCP_DEBUG((LOG_INFO, "Sending ipv6 packet...\n"));
+		hdrlen = sizeof(struct dccpip6hdr) + extrah_len + optlen;
+	} else
+#endif
+		hdrlen = sizeof(struct dccpiphdr) + extrah_len + optlen;
+
+	if ( len > (dp->d_maxseg - extrah_len - optlen) ) {
+		len = dp->d_maxseg - extrah_len - optlen;
+		sendalot = 1;
+	}
+	
+	MGETHDR(m, M_DONTWAIT, MT_HEADER);
+	if (m == NULL) {
+		error = ENOBUFS;
+		goto release;
+	}
+	
+	m->m_data += max_linkhdr;
+	m->m_len = hdrlen;
+
+#ifdef INET6
+	if (MHLEN < hdrlen + max_linkhdr) {
+		MCLGET(m, M_DONTWAIT);
+		if ((m->m_flags & M_EXT) == 0) {
+			m_freem(m);
+			error = ENOBUFS;
+			goto release;
+		}
+	}
+#endif
+
+	if (len) { /* We have data to send */
+		if (len <= MHLEN - hdrlen - max_linkhdr) {
+			m_copydata(so->so_snd.sb_mb, off, (int) len,
+			mtod(m, caddr_t) + hdrlen);
+			m->m_len += len;
+		} else {
+			m->m_next = m_copy(so->so_snd.sb_mb, off, (int) len);
+			if (m->m_next == 0) {
+				error = ENOBUFS;
+				goto release;
+			}
+		}
+	} else {
+		dp->ndp++;
+	}
+
+	m->m_pkthdr.rcvif = (struct ifnet *)0;
+
+	if ((len + hdrlen) > IP_MAXPACKET) {
+		error = EMSGSIZE;
+		goto release;
+	}
+
+	/*
+	 * Fill in mbuf with extended DCCP header
+	 * and addresses and length put into network format.
+	 */
+#ifdef INET6
+	if ( isipv6) {
+		di6 = mtod(m, struct dccpip6hdr *);
+		di6->di6_flow = (di6->di6_flow & ~IPV6_FLOWINFO_MASK) |
+			(inp->in6p_flowinfo & IPV6_FLOWINFO_MASK);
+		di6->di6_vfc = ( di6->di6_vfc & ~IPV6_VERSION_MASK) |
+			 (IPV6_VERSION & IPV6_VERSION_MASK);
+		di6->di6_nxt = IPPROTO_DCCP;
+		di6->di6_src = inp->in6p_laddr;
+		di6->di6_dst = inp->in6p_faddr;
+		dh = &di6->di_d;
+	} else 
+#endif
+	{
+		di = mtod(m, struct dccpiphdr *);
+		bzero(di->di_x1, sizeof(di->di_x1));
+		di->di_pr = IPPROTO_DCCP;
+		di->di_src = inp->inp_laddr;
+		di->di_dst = inp->inp_faddr;
+		dh = &di->di_d;
+	}
+
+	dh->dh_sport = inp->inp_lport;
+	dh->dh_dport = inp->inp_fport;
+	dh->dh_cslen = dp->cslen;
+	dh->dh_ndp = (dp->ndp % 16);
+	dh->dh_type = type;
+	dh->dh_res = 0; /* Reserved field should be zero */
+
+	dh->dh_off = 3 + (extrah_len / 4) + (optlen / 4);
+
+	dp->seq_snd = (dp->seq_snd + 1) % 16777216;
+	dh->dh_seq = htonl(dp->seq_snd) >> 8;
+
+	DCCP_DEBUG((LOG_INFO, "Sending with seq %u, (dp->seq_snd = %u)\n\n", dh->dh_seq, dp->seq_snd));
+
+	if ( dh->dh_type == DCCP_TYPE_REQUEST ) {
+#ifdef INET6
+		if (isipv6)
+			drqh = (struct dccp_requesthdr *)(di6 +1);
+		else
+#endif
+			drqh = (struct dccp_requesthdr *)(di +1);
+		drqh->drqh_sname = 0; /* Service name must be 0 if not used */
+		optp = (u_char *)(drqh +1);
+
+	} else if ( dh->dh_type == DCCP_TYPE_RESET ) {
+#ifdef INET6
+		if (isipv6)
+			drth = (struct dccp_resethdr *)(di6 +1);
+		else
+#endif
+			drth = (struct dccp_resethdr *)(di +1);
+		drth->drth_res = 0; /* Reserved field should be zero */
+		drth->drth_ack = htonl(dp->seq_rcv) >> 8;
+		drth->drth_reason = 0; /* FIX, must be able to specify reason  */
+		drth->drth_data1 = 0;
+		drth->drth_data2 = 0;
+		drth->drth_data3 = 0;
+		optp = (u_char *)(drth +1);
+
+	} else if ( extrah_len ) {
+#ifdef INET6
+		if (isipv6)
+			dah = (struct dccp_ackhdr *)(di6 +1);
+		else
+#endif
+			dah = (struct dccp_ackhdr *)(di +1);
+		dah->dah_res = 0; /* Reserved field should be zero */
+
+		if (dp->state == DCCPS_ESTAB) {
+			dah->dah_ack = htonl(dp->ack_snd) >> 8;
+			dp->ack_snd = 0;
+		} else
+			dah->dah_ack = htonl(dp->seq_rcv) >> 8;
+		
+		optp = (u_char *)(dah +1);
+
+	} else {
+#ifdef INET6
+		if (isipv6)
+			optp = (u_char *)(di6 +1);
+		else
+#endif
+			optp = (u_char *)(di +1);
+
+	}
+
+	if (optlen)
+		bcopy(options, optp , optlen);
+
+	m->m_pkthdr.len = hdrlen + len;
+
+	if ( dh->dh_cslen == 15 ) {
+		cslen = len;
+	} else {
+		cslen = 4 * dh->dh_cslen;
+		if ( cslen > len )
+			cslen = len;
+	}
+
+	/*
+	 * Set up checksum 
+	 */
+	m->m_pkthdr.csum_flags = CSUM_IP; /* Do not allow the network card to calculate the checksum */
+
+#ifdef INET6
+	if ( isipv6) {
+		dh->dh_sum = in6_cksum(m, IPPROTO_DCCP, sizeof(struct ip6_hdr), sizeof(struct dccphdr) + extrah_len + optlen + cslen);
+	} else
+#endif
+	{
+	      	dh->dh_sum = in_pseudo(di->di_src.s_addr, di->di_dst.s_addr,
+		    htons((u_short)len + sizeof(struct dccphdr) + extrah_len + optlen + IPPROTO_DCCP)); 
+		dh->dh_sum = in_cksum_skip(m, hdrlen + cslen, 20 );
+		m->m_pkthdr.csum_data = offsetof(struct dccphdr, dh_sum);
+
+		((struct ip *)di)->ip_len = hdrlen + len;
+		((struct ip *)di)->ip_ttl = inp->inp_ip_ttl;	/* XXX */
+		((struct ip *)di)->ip_tos = inp->inp_ip_tos;	/* XXX */
+	}
+
+	DCCP_DEBUG((LOG_INFO, "Calculated checksum,  dh->dh_cslen = %u, cslen = %u, len = %li hdrlen = %u, dh->dh_sum = 0x%04x\n", dh->dh_cslen, cslen, len, hdrlen, dh->dh_sum));
+
+	dccpstat.dccps_opackets++;
+	dccpstat.dccps_obytes += m->m_pkthdr.len;
+
+#ifdef INET6
+	if ( isipv6) {
+		DCCP_DEBUG((LOG_INFO, "Calling ip_output6, mbuf->m_len = %u, mbuf->m_pkthdr.len = %u\n", m->m_len, m->m_pkthdr.len));
+		error = ip6_output(m, inp->in6p_outputopts, NULL,
+		    (inp->inp_socket->so_options & SO_DONTROUTE), NULL, NULL, inp);
+	} else
+#endif
+	{
+		DCCP_DEBUG((LOG_INFO, "Calling ip_output, mbuf->m_len = %u, mbuf->m_pkthdr.len = %u\n", m->m_len, m->m_pkthdr.len));
+		error = ip_output(m, inp->inp_options, NULL,
+		    (inp->inp_socket->so_options & SO_DONTROUTE), 0, inp);
+	}
+
+	if ( error ) {
+		DCCP_DEBUG((LOG_INFO, "IP output failed!\n"));
+		return(error);
+	}
+
+	sbdrop(&inp->inp_socket->so_snd, len);
+	sowwakeup(inp->inp_socket);
+	if ( dp->cc_in_use[0] > 0  && dp->state == DCCPS_ESTAB ) {
+		DCCP_DEBUG((LOG_INFO, "Calling *cc_sw[%u].cc_send_packet_sent!\n", dp->cc_in_use[0]));
+		if (sendalot) {
+			(*cc_sw[dp->cc_in_use[0]].cc_send_packet_sent)(dp->cc_state[0], 1,len);
+			goto again;
+		} else {
+			(*cc_sw[dp->cc_in_use[0]].cc_send_packet_sent)(dp->cc_state[0], 0,len);
+		}
+	} else {
+		if (sendalot)
+			goto again;
+	}
+
+	return (0);
+
+release:
+	m_freem(m);
+	return (error);
+}
+
+
+static int
+dccp_abort(struct socket *so)
+{
+	struct inpcb *inp;
+	register struct dccpcb *dp;
+
+	DCCP_DEBUG((LOG_INFO, "Entering dccp_abort!\n"));
+	INP_INFO_WLOCK(&dccpbinfo);
+	inp = sotoinpcb(so);
+	if (inp == 0) {
+		INP_INFO_WUNLOCK(&dccpbinfo);
+		return EINVAL;
+	}
+
+	dp = (struct dccpcb *)inp->inp_ppcb;
+	dccp_disconnect2(dp);
+
+	INP_INFO_WUNLOCK(&dccpbinfo);
+	return 0;
+}
+
+static struct dccpcb *
+dccp_close(struct dccpcb *dp)
+{
+	struct inpcb *inp = dp->d_inpcb;
+	struct socket *so = inp->inp_socket;
+
+	DCCP_DEBUG((LOG_INFO, "Entering dccp_close!\n"));
+
+	/* Stop all timers */
+	untimeout(dccp_connect_t, dp, dp->connect_timer);
+	untimeout(dccp_retrans_t, dp, dp->retrans_timer);
+	untimeout(dccp_close_t, dp, dp->close_timer);
+	untimeout(dccp_timewait_t, dp, dp->timewait_timer);
+
+	if ( dp->cc_in_use[0] > 0 )
+		(*cc_sw[dp->cc_in_use[0]].cc_send_free)(dp->cc_state[0]);
+	if ( dp->cc_in_use[1] > 0 )
+		(*cc_sw[dp->cc_in_use[1]].cc_recv_free)(dp->cc_state[1]);
+
+	inp->inp_ppcb = NULL;
+	dp->d_inpcb = NULL;
+	soisdisconnected(so);
+	in_pcbdetach(inp);
+	return ((struct dccpcb *)0);
+}
+
+/*
+ * Runs when a new socket is created with the
+ * socket system call or sonewconn.
+*/
+static int
+dccp_attach(struct socket *so, int proto, struct thread *td)
+{
+        int error;
+        struct inpcb *inp;
+        struct dccpcb *dp = 0;
+
+        DCCP_DEBUG((LOG_INFO, "Entering dccp_attach!\n"));
+        INP_INFO_WLOCK(&dccpbinfo);
+        inp = sotoinpcb(so);
+        if (inp) {
+                error = EISCONN;
+                goto out;
+        }
+        error = dccp_attach2(so);
+        if (error)
+                goto out;
+
+        /*MANU if ((so->so_options & SO_LINGER) && so->so_linger == 0)
+	 *                 so->so_linger = TCP_LINGERTIME;*/
+
+        inp = sotoinpcb(so);
+       /* dp = intodccpcb(inp); */
+	dp = (struct dccpcb *)inp->inp_ppcb;            
+out:
+        DCCP_DEBUG((LOG_INFO, "Error pru_attach!\n"));
+        INP_INFO_WUNLOCK(&dccpbinfo);
+        return error;
+}
+
+static int
+dccp_attach2(so)
+        struct socket *so;
+{
+        register struct dccpcb *dp;
+        struct inpcb *inp;
+        int error;
+#ifdef INET6
+        int isipv6 = INP_CHECK_SOCKAF(so, AF_INET6) != 0;
+#endif
+
+        INP_INFO_WLOCK_ASSERT(&dccpbinfo);
+
+        if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
+                error = soreserve(so, dccp_sendspace, dccp_recvspace);
+                if (error)
+                        return (error);
+        }
+        error = in_pcballoc(so, &dccpbinfo, "dccpinp");
+        if (error)
+                return (error);
+	        inp = sotoinpcb(so);
+
+#ifdef INET6
+        if (isipv6) {
+                inp->inp_vflag |= INP_IPV6;
+                inp->in6p_hops = -1;    /* use kernel default */
+        }
+        else
+#endif
+                inp->inp_vflag |= INP_IPV4;
+	
+	inp->inp_ip_ttl = ip_defttl;
+
+        dp = dccp_newdccpcb(inp);
+        if (dp == 0) {
+	       int nofd = so->so_state & SS_NOFDREF;   /* XXX */
+	       so->so_state &= ~SS_NOFDREF;    /* don't free the socket yet */
+               INP_LOCK(inp);
+#ifdef INET6
+                if (isipv6)
+                       in6_pcbdetach(inp);
+                else
+#endif
+                in_pcbdetach(inp);
+                so->so_state |= nofd;
+                return (ENOBUFS);
+        }
+        dp->state = DCCPS_CLOSED;
+        return (0);
+}
+
+#define INI_NOLOCK      0
+#define INI_READ        1
+#define INI_WRITE       2
+
+#define COMMON_START()                                          \
+        do {                                                    \
+                if (inirw == INI_READ)                          \
+                        INP_INFO_RLOCK(&dccpbinfo);             \
+                else if (inirw == INI_WRITE)                    \
+                        INP_INFO_WLOCK(&dccpbinfo);             \
+                inp = sotoinpcb(so);                            \
+                if (inp == 0) {                                 \
+                        if (inirw == INI_READ)                  \
+                                INP_INFO_RUNLOCK(&dccpbinfo);   \
+                        else if (inirw == INI_WRITE)            \
+                                INP_INFO_WUNLOCK(&dccpbinfo);   \
+                        return EINVAL;                          \
+                }                                               \
+                INP_LOCK(inp);                                  \
+                if (inirw == INI_READ)                          \
+                        INP_INFO_RUNLOCK(&dccpbinfo);           \
+                /*dp = intodccpcb(inp); */                      \
+		dp = (struct dccpcb *)inp->inp_ppcb;            \
+	} while(0)
+
+#define COMMON_END(req)                                         \
+out:                                                            \
+        do {                                                    \
+                if (dp)                                         \
+                        INP_UNLOCK(inp);                        \
+                if (inirw == INI_WRITE)                         \
+                        INP_INFO_WUNLOCK(&dccpbinfo);           \
+                return error;                                   \
+                goto out;                                       \
+} while(0)
+
+static int
+dccp_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
+{
+        int error = 0;
+        struct inpcb *inp;
+        struct dccpcb *dp;
+        struct sockaddr_in *sinp;
+        const int inirw = INI_WRITE;
+
+	DCCP_DEBUG((LOG_INFO, "Entering dccp_bind!\n"));
+        sinp = (struct sockaddr_in *)nam;
+        if (nam->sa_len != sizeof (*sinp))
+                return (EINVAL);
+        /*
+         * Must check for multicast addresses and disallow binding
+         * to them.
+         */
+        if (sinp->sin_family == AF_INET && IN_MULTICAST(ntohl(sinp->sin_addr.s_addr)))
+               return (EAFNOSUPPORT);
+
+        COMMON_START();
+        error = in_pcbbind(inp, nam, td->td_ucred);
+        if (error)
+               goto out;
+        COMMON_END(PRU_BIND);
+}
+
+#ifdef INET6
+static int
+dccp6_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
+{
+	struct inpcb *inp;
+	int error;
+	struct sockaddr_in6 *sin6p;
+        struct dccpcb *dp;
+        const int inirw = INI_WRITE;
+
+	DCCP_DEBUG((LOG_INFO, "Entering dccp6_bind!\n"));
+	
+        sin6p = (struct sockaddr_in6 *)nam;
+        
+	if (nam->sa_len != sizeof (*sin6p))
+                return (EINVAL);
+	
+	/* Do not bind to multicast addresses! */
+        if (sin6p->sin6_family == AF_INET6 && IN6_IS_ADDR_MULTICAST(&sin6p->sin6_addr))
+               return (EAFNOSUPPORT);
+
+	
+	COMMON_START();
+
+	inp->inp_vflag &= ~INP_IPV4;
+	inp->inp_vflag |= INP_IPV6;
+	
+	error = in6_pcbbind(inp, nam, td->td_ucred);
+        if (error)
+               goto out;
+        COMMON_END(PRU_BIND6);
+}
+#endif
+
+
+/*
+ * Initiates a connection to a server
+ * Called by the connect system call.
+*/
+static int
+dccp_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
+{
+	struct inpcb *inp;
+	struct dccpcb *dp;
+	int error;
+	struct sockaddr_in *sin;
+	char test[2];
+
+	DCCP_DEBUG((LOG_INFO, "Entering dccp_connect!\n"));
+
+	INP_INFO_WLOCK(&dccpbinfo);
+	inp = sotoinpcb(so);
+	if (inp == 0) {
+		INP_INFO_WUNLOCK(&dccpbinfo);
+		return EINVAL;
+	}
+	INP_LOCK(inp);
+	if (inp->inp_faddr.s_addr != INADDR_ANY) {
+		INP_UNLOCK(inp);
+		INP_INFO_WUNLOCK(&dccpbinfo);
+		return EISCONN;
+	}
+
+	dp = (struct dccpcb *)inp->inp_ppcb;
+
+	if ( dp->state == DCCPS_ESTAB ) {
+		DCCP_DEBUG((LOG_INFO, "Why are we in connect when we already have a established connection?\n"));
+	}
+
+	dp->who = DCCP_CLIENT;
+	dp->seq_snd = (((u_int64_t)arc4random() << 32) | arc4random()) % 281474976710656LL;
+	
+
+	dccpstat.dccps_connattempt++;
+
+	sin = (struct sockaddr_in *)nam;
+	if (sin->sin_family == AF_INET
+	    && IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) {
+		error = EAFNOSUPPORT;
+		goto bad;
+	}
+
+	error = dccp_doconnect(dp, nam, td, 0);
+
+	if (error != 0)
+		goto bad;
+
+	dp->retrans_timer = timeout(dccp_retrans_t, dp, dp->retrans);
+	dp->connect_timer = timeout(dccp_connect_t, dp, DCCP_CONNECT_TIMER);
+
+	test[0] = dp->pref_cc;
+	/* FIX THIS LATER */
+	if ( dp->pref_cc == 2 ) {
+		test[1] = 3;
+	} else {
+		test[1] = 2;
+	}
+	dccp_add_feature(dp, DCCP_OPT_CHANGE, DCCP_FEATURE_CC, test, 2);
+	dccp_add_feature(dp, DCCP_OPT_PREFER, DCCP_FEATURE_CC, test, 2);
+
+	error = dccp_output(dp, 0);
+
+bad:
+	INP_UNLOCK(inp);
+	INP_INFO_WUNLOCK(&dccpbinfo);
+	return error;
+}
+
+#ifdef INET6
+static int
+dccp6_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
+{
+	struct inpcb *inp;
+	struct dccpcb *dp;
+	int error;
+	struct sockaddr_in6 *sin6;
+	char test[2];
+
+	DCCP_DEBUG((LOG_INFO, "Entering dccp6_connect!\n"));
+
+	INP_INFO_WLOCK(&dccpbinfo);
+	inp = sotoinpcb(so);
+	if (inp == 0) {
+		INP_INFO_WUNLOCK(&dccpbinfo);
+		return EINVAL;
+	}
+	INP_LOCK(inp);
+	if (inp->inp_faddr.s_addr != INADDR_ANY) {
+		INP_UNLOCK(inp);
+		INP_INFO_WUNLOCK(&dccpbinfo);
+		return EISCONN;
+	}
+
+	dp = (struct dccpcb *)inp->inp_ppcb;
+
+	if ( dp->state == DCCPS_ESTAB ) {
+		DCCP_DEBUG((LOG_INFO, "Why are we in connect when we already have a established connection?\n"));
+	}
+
+	dp->who = DCCP_CLIENT;
+	dp->seq_snd = (((u_int64_t)arc4random() << 32) | arc4random()) % 281474976710656LL;
+
+	sin6 = (struct sockaddr_in6 *)nam;
+	if (sin6->sin6_family == AF_INET6
+	    && IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
+		error = EAFNOSUPPORT;
+		goto bad;
+	}
+
+	inp->inp_vflag &= ~INP_IPV4;
+	inp->inp_vflag |= INP_IPV6;
+	inp->inp_inc.inc_isipv6 = 1;
+
+	error = dccp_doconnect(dp, nam, td, 1);
+
+	if (error != 0)
+		goto bad;
+
+	dp->retrans_timer = timeout(dccp_retrans_t, dp, dp->retrans);
+	dp->connect_timer = timeout(dccp_connect_t, dp, DCCP_CONNECT_TIMER);
+
+	test[0] = dp->pref_cc;
+	/* FIX THIS LATER */
+	if ( dp->pref_cc == 2 ) {
+		test[1] = 3;
+	} else {
+		test[1] = 2;
+	}
+	dccp_add_feature(dp, DCCP_OPT_CHANGE, DCCP_FEATURE_CC, test, 2);
+	dccp_add_feature(dp, DCCP_OPT_PREFER, DCCP_FEATURE_CC, test, 2);
+
+	error = dccp_output(dp, 0);
+
+bad:
+	INP_UNLOCK(inp);
+	INP_INFO_WUNLOCK(&dccpbinfo);
+	return error;
+}
+#endif
+
+/*
+ *
+ *
+*/
+static int
+dccp_doconnect(struct dccpcb *dp, struct sockaddr *nam, struct thread *td, int isipv6) { 
+	struct inpcb *inp = dp->d_inpcb;
+	struct socket *so = inp->inp_socket;
+#ifdef INET6
+	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)nam;
+	struct in6_addr *addr6;
+#endif
+	struct in_addr laddr;
+	u_short	lport;
+	int error = 0;
+
+	DCCP_DEBUG((LOG_INFO, "Entering dccp_doconnect!\n"));
+
+
+	if (inp->inp_lport == 0) {
+#ifdef INET6
+		if ( isipv6 ) {
+			DCCP_DEBUG((LOG_INFO, "Running in6_pcbbind!\n"));
+			error = in6_pcbbind(inp, (struct sockaddr *)0, td->td_ucred);
+		} else
+#endif
+			error = in_pcbbind(inp, (struct sockaddr *)0, td->td_ucred);
+		if (error)
+			return error;
+	}
+
+	laddr = inp->inp_laddr;
+        lport = inp->inp_lport;
+
+#ifdef INET6
+	if ( isipv6 )
+		error = in6_pcbladdr(inp, nam, &addr6);
+	else
+#endif
+		error = in_pcbconnect_setup(inp, nam, &laddr.s_addr, &lport,
+			&inp->inp_faddr.s_addr, &inp->inp_fport, NULL, td->td_ucred);
+
+	if (error)
+		return error;
+
+#ifdef INET6
+	if ( isipv6 ) {
+		if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr))
+			inp->in6p_laddr = *addr6;
+		inp->in6p_faddr = sin6->sin6_addr;
+		inp->inp_fport = sin6->sin6_port;
+		if ((sin6->sin6_flowinfo & IPV6_FLOWINFO_MASK) != 0)
+			inp->in6p_flowinfo = sin6->sin6_flowinfo;
+	} else
+#endif
+	inp->inp_laddr = laddr;
+
+
+	in_pcbrehash(inp);
+	
+	soisconnecting(so);
+	return error;
+}
+
+/*
+ * Detaches the DCCP protocol from the socket.
+ *
+*/
+static int
+dccp_detach(struct socket *so)
+{
+	struct inpcb *inp;
+	struct dccpcb *dp;
+
+	DCCP_DEBUG((LOG_INFO, "Entering dccp_detach!\n"));
+	INP_INFO_WLOCK(&dccpbinfo);
+	inp = sotoinpcb(so);
+	if (inp == 0) {
+		INP_INFO_WUNLOCK(&dccpbinfo);
+		return EINVAL;
+	}
+	INP_LOCK(inp);
+	dp = (struct dccpcb *)inp->inp_ppcb;
+	if (! dccp_disconnect2(dp))
+		INP_UNLOCK(inp);
+	INP_INFO_WUNLOCK(&dccpbinfo);
+	return 0;
+}
+
+/*
+ * 
+ *
+*/
+static int
+dccp_disconnect(struct socket *so)
+{
+	struct inpcb *inp;
+	struct dccpcb *dp;
+
+	DCCP_DEBUG((LOG_INFO, "Entering dccp_disconnect!\n"));
+	INP_INFO_WLOCK(&dccpbinfo);
+	inp = sotoinpcb(so);
+	if (inp == 0) {
+		INP_INFO_WUNLOCK(&dccpbinfo);
+		return EINVAL;
+	}
+	INP_LOCK(inp);
+	if (inp->inp_faddr.s_addr == INADDR_ANY) {
+		INP_INFO_WUNLOCK(&dccpbinfo);
+		INP_UNLOCK(inp);
+		return ENOTCONN;
+	}
+
+	dp = (struct dccpcb *)inp->inp_ppcb;
+
+	if ( ! dccp_disconnect2(dp))
+		INP_UNLOCK(inp);
+	INP_INFO_WUNLOCK(&dccpbinfo);
+	return 0;
+}
+
+/*
+ * If we have don't have a established connection
+ * we can call dccp_close, otherwise we can just
+ * set SS_ISDISCONNECTED and flush the receive queue.
+*/
+static int
+dccp_disconnect2(struct dccpcb *dp)
+{
+	DCCP_DEBUG((LOG_INFO, "Entering dccp_disconnect2!\n"));
+	struct socket *so = dp->d_inpcb->inp_socket;
+
+	if (dp->state < DCCPS_ESTAB ) {
+		dccp_close(dp);
+		return 1;
+	} else {
+		soisdisconnecting(so);
+		sbflush(&so->so_rcv);
+		if ( dp->state == DCCPS_ESTAB ) {
+			dp->retrans = 100;
+			dp->retrans_timer = timeout(dccp_retrans_t, dp, dp->retrans);
+			dp->close_timer = timeout(dccp_close_t, dp, DCCP_CLOSE_TIMER);
+			if ( dp->who == DCCP_CLIENT ) {
+				dp->state = DCCPS_CLIENT_CLOSE;
+			} else {
+				dp->state = DCCPS_SERVER_CLOSE;
+			}
+			dccp_output(dp, 0);
+		}
+	}
+	return 0;
+}
+
+static int
+dccp_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
+	    struct mbuf *control, struct thread *td)
+{
+	struct inpcb	*inp;
+	struct dccpcb	*dp;
+	int		error = 0;
+	int		isipv6 = 0;
+
+	DCCP_DEBUG((LOG_INFO, "Entering dccp_send!\n"));
+
+	INP_INFO_WLOCK(&dccpbinfo);
+	inp = sotoinpcb(so);
+	if (inp == 0) {
+		INP_INFO_WUNLOCK(&dccpbinfo);
+		m_freem(m);
+		return EINVAL;
+	}
+	INP_LOCK(inp);
+
+#ifdef INET6
+	isipv6 = addr && addr->sa_family == AF_INET6;
+#endif
+
+	dp = (struct dccpcb *)inp->inp_ppcb;
+	if ( dp->state != DCCPS_ESTAB ) {
+		DCCP_DEBUG((LOG_INFO, "We have no established connection!\n"));
+	}
+
+	if (control != NULL) {
+		DCCP_DEBUG((LOG_INFO, "We got a control message!\n"));
+		/* Are we going to use control messages??? */
+		if (control->m_len) {
+			m_freem(control);
+		}
+	}
+
+
+	if (sbspace(&so->so_snd) < -512) {
+		m_freem(m);
+		error = ENOBUFS;
+		goto out;
+	}
+
+	sbappend(&so->so_snd, m);
+
+	if ( addr && dp->state == DCCPS_CLOSED ) {
+		error = dccp_doconnect(dp, addr, td, isipv6);
+		if (error)
+			goto out;
+	}
+
+	error = dccp_output(dp, 0);
+
+out:
+	INP_UNLOCK(inp);
+	INP_INFO_WUNLOCK(&dccpbinfo);
+	return error; 
+}
+
+/*
+ * Sets socket to SS_CANTSENDMORE 
+*/
+int
+dccp_shutdown(struct socket *so)
+{
+	struct inpcb *inp;
+
+	DCCP_DEBUG((LOG_INFO, "Entering dccp_shutdown!\n"));
+	INP_INFO_RLOCK(&dccpbinfo);
+	inp = sotoinpcb(so);
+	if (inp == 0) {
+		INP_INFO_RUNLOCK(&dccpbinfo);
+		return EINVAL;
+	}
+	INP_LOCK(inp);
+	INP_INFO_RUNLOCK(&dccpbinfo);
+	socantsendmore(so);
+	INP_UNLOCK(inp);
+	return 0;
+}
+
+static int
+dccp_listen(struct socket *so, struct thread *td)
+{
+        int error = 0;
+        struct inpcb *inp;
+        struct dccpcb *dp;
+        const int inirw = INI_READ;
+
+	DCCP_DEBUG((LOG_INFO, "Entering dccp_listen!\n"));
+        COMMON_START();
+        SOCK_LOCK(so);
+	/*dp = (struct dccpcb *)inp->inp_ppcb;*/
+        error = solisten_proto_check(so);
+        if (error == 0 && inp->inp_lport == 0)
+                error = in_pcbbind(inp, (struct sockaddr *)0, td->td_ucred);
+        if (error == 0) {
+                dp->state = DCCPS_LISTEN;
+                dp->who = DCCP_LISTENER;
+                solisten_proto(so);
+        }
+        SOCK_UNLOCK(so);
+        COMMON_END(PRU_LISTEN);
+}
+
+#ifdef INET6
+static int
+dccp6_listen(struct socket *so, struct thread *td)
+{
+	int error = 0;
+	struct inpcb *inp;
+	struct dccpcb *dp;
+	const int inirw = INI_READ;
+	
+	DCCP_DEBUG((LOG_INFO, "Entering dccp6_listen!\n"));
+	COMMON_START();
+        SOCK_LOCK(so);
+	DCCP_DEBUG((LOG_INFO, "Checking inp->inp_lport!\n"));
+	if (inp->inp_lport == 0 ) {
+		inp->inp_vflag &= ~INP_IPV4;
+		if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0)
+			inp->inp_vflag |= INP_IPV4;
+		error = in6_pcbbind(inp, (struct sockaddr *)0, td->td_ucred);
+	}
+	if (error == 0) {
+		dp->state = DCCPS_LISTEN;
+		dp->who = DCCP_LISTENER;
+		dp->seq_snd = 512;
+	}
+        SOCK_UNLOCK(so);
+        COMMON_END(PRU_LISTEN);
+}
+#endif
+
+/*
+ * Accepts a connection (accept system call)
+*/
+static int
+dccp_accept(struct socket *so, struct sockaddr **nam)
+{
+        int error = 0;
+        struct dccpcb *dp = NULL;
+ 	struct inpcb *inp = NULL;
+        struct in_addr addr;
+        in_port_t port = 0;
+
+	if (so->so_state & SS_ISDISCONNECTED) {
+                error = ECONNABORTED;
+                goto out;
+        }
+
+        INP_INFO_RLOCK(&dccpbinfo);
+	inp = sotoinpcb(so);
+
+	if (!inp) {
+                INP_INFO_RUNLOCK(&dccpbinfo);
+                return (EINVAL);
+        }
+        INP_LOCK(inp);
+        INP_INFO_RUNLOCK(&dccpbinfo);
+	dp = (struct dccpcb *)inp->inp_ppcb;
+
+        /*
+	 *  We inline in_setpeeraddr and COMMON_END here, so that we can
+	 *  copy the data of interest and defer the malloc until after we
+	 *  release the lock.
+         */
+	port = inp->inp_fport;
+	addr = inp->inp_faddr;
+
+out: 
+        if (dp)
+	      INP_UNLOCK(inp);
+	if (error == 0)
+	      *nam = in_sockaddr(port, &addr);
+	return error;
+}
+
+
+static int
+dccp6_accept(struct socket *so, struct sockaddr **nam)
+{
+	struct inpcb *inp = NULL;
+	struct dccpcb *dp = NULL;
+	struct in_addr	addr;
+	struct in6_addr	addr6;
+	int error = 0;
+	in_port_t port = 0;
+	int v4 = 0;
+
+	DCCP_DEBUG((LOG_INFO, "Entering dccp6_accept!\n"));
+
+	if (so->so_state & SS_ISDISCONNECTED) {
+		DCCP_DEBUG((LOG_INFO, "so_state && SS_ISDISCONNECTED!, so->state = %i\n", so->so_state));
+		return ECONNABORTED;
+	}
+
+	INP_INFO_RLOCK(&dccpbinfo);
+	inp = sotoinpcb(so);
+	if ( inp == 0 ) {
+		INP_INFO_RUNLOCK(&dccpbinfo);
+		return EINVAL;
+	}
+	INP_LOCK(inp);
+	INP_INFO_RUNLOCK(&dccpbinfo);
+	dp = (struct dccpcb *)inp->inp_ppcb;
+
+	port = inp->inp_fport;
+
+	if (inp->inp_vflag & INP_IPV4) {
+		v4 = 1;
+		addr = inp->inp_faddr;
+	} else {
+		addr6 = inp->in6p_faddr;
+	}
+
+	INP_UNLOCK(inp);
+	if ( error == 0) {
+		if (v4)
+			*nam = in6_v4mapsin6_sockaddr(port, &addr);
+		else
+			*nam = in6_sockaddr(port, &addr6);
+	}
+
+	return error;
+}
+
+/*
+ * Initializes a new DCCP control block
+ * (in_pcballoc in attach has already allocated memory for it)
+*/
+struct dccpcb *
+dccp_newdccpcb(struct inpcb *inp)
+{
+	struct inp_dp		*id;
+	register struct dccpcb	*dp;
+
+	DCCP_DEBUG((LOG_INFO, "Creating a new dccpcb!\n"));
+
+	id = (struct inp_dp *)inp;
+	dp = &id->dp;
+	bzero((char *) dp, sizeof(struct dccpcb));
+
+	callout_handle_init(&dp->connect_timer);
+	callout_handle_init(&dp->retrans_timer);
+	callout_handle_init(&dp->close_timer);
+	callout_handle_init(&dp->timewait_timer);
+
+	dp->d_inpcb = inp;
+	dp->ndp = 0;
+	dp->loss_window = 1000;
+	dp->cslen = 15;
+	dp->pref_cc = DEFAULT_CCID;
+	dp->who = DCCP_UNDEF;
+	dp->seq_snd = 0;
+	dp->seq_rcv = 0;
+	dp->gsn_rcv = 1073741824;
+	dp->optlen = 0;
+	dp->cc_in_use[0] = -1;
+	dp->cc_in_use[1] = -1;
+	dp->av_size = 0; /* no ack vector initially */
+	dp->remote_ackvector = 0; /* no ack vector on remote side initially */
+	dp->retrans = 200;
+	dp->avgpsize = 0;
+	dp->d_maxseg = 1400;
+	
+	inp->inp_ppcb = (caddr_t)dp;
+	return dp;
+}
+
+int
+dccp_add_option(struct dccpcb *dp, u_int8_t opt, char *val, u_int8_t val_len) {
+	return dccp_add_feature_option(dp, opt, 0, val, val_len);
+}
+
+int
+dccp_add_feature_option(struct dccpcb *dp, u_int8_t opt, u_int8_t feature, char *val, u_int8_t val_len)
+{
+	int i;
+	DCCP_DEBUG((LOG_INFO, "Entering dccp_add_option, opt = %u, val_len = %u\n", opt, val_len));
+
+	if ( DCCP_MAX_OPTIONS > (dp->optlen + val_len + 2) ) {
+		dp->options[dp->optlen] = opt;
+		if ( opt < 32 ) {
+			dp->optlen++;
+		} else {
+			if ( opt == DCCP_OPT_CONFIRM ) {
+				dp->options[dp->optlen +1] = val_len + 3;
+				dp->options[dp->optlen +2] = feature;
+				dp->optlen += 3;
+			} else {
+				dp->options[dp->optlen +1] = val_len + 2;
+				dp->optlen += 2;
+			}
+	
+			for(i = 0; i<val_len; i++) {
+				dp->options[dp->optlen] = val[i];
+				dp->optlen++;
+			}
+		}
+	} else {
+		DCCP_DEBUG((LOG_INFO, "No room for more options, optlen = %u\n", dp->optlen));
+		return -1;
+	}
+
+	return 0;
+}
+
+/**
+ * Searches "options" for given option type. if found, the data is copied to buffer
+ * and returns the data length.
+ * Returns 0 if option type not found
+ **/
+int
+dccp_get_option(char *options, int optlen, int type, char *buffer, int buflen)
+{
+	int i, j, size;
+	u_int8_t t;
+	
+	for (i=0; i < optlen; ) {
+		t = options[i++];
+		if(t >= 32){		  
+		  size = options[i++] - 2;
+		  if (t == type) {
+		    if(size > buflen)
+		      return 0;
+		    for (j=0; j<size; j++)
+		      buffer[j] = options[i++];
+		    return size;
+		  }
+		  i += size;
+		}
+	}
+	/* If we get here the options was not found */
+	return 0;
+}
+
+void
+dccp_parse_options(struct dccpcb *dp, char *options, int optlen)
+{
+	u_int8_t opt, size, i, j;
+	char val[8];
+
+	for(i = 0; i < optlen; i++) {
+		opt = options[i];
+
+		DCCP_DEBUG((LOG_INFO, "Parsing opt: 0x%02x\n", opt));
+
+		if ( opt < 32 ) {
+			switch(opt) {
+			    case DCCP_OPT_PADDING:
+				DCCP_DEBUG((LOG_INFO, "Got DCCP_OPT_PADDING!\n"));
+				break;
+			    case DCCP_OPT_DATA_DISCARD:
+				DCCP_DEBUG((LOG_INFO, "Got DCCP_OPT_DATA_DISCARD!\n"));
+				break;
+			    case DCCP_OPT_SLOW_RECV:
+				DCCP_DEBUG((LOG_INFO, "Got DCCP_OPT_SLOW_RECV!\n"));
+				break;
+			    case DCCP_OPT_BUF_CLOSED:
+				DCCP_DEBUG((LOG_INFO, "Got DCCP_OPT_BUF_CLOSED!\n"));
+				break;
+			    default:
+				DCCP_DEBUG((LOG_INFO, "Got an unknown option, option = %u!\n", opt));
+			}
+		} else if ( opt > 32 && opt < 36 ) {
+			size = options[i+1];
+			if ( size < 3 || size > 10 ) {
+				DCCP_DEBUG((LOG_INFO, "Error, option size = %u\n", size));
+				return;
+			}
+			/* Feature negotiations are options 33 to 35 */ 
+			DCCP_DEBUG((LOG_INFO, "Got option %u, size = %u, feature = %u\n", opt, size, options[i+2]));
+			bcopy(options + i + 3, val, size -3);
+			DCCP_DEBUG((LOG_INFO, "Calling dccp_feature neg(%u, %u, options[%u + 1], %u)!\n", (u_int)dp, opt, i+1, (size - 3)));
+			dccp_feature_neg(dp, opt, options[i+2], (size -3) , val);
+			i += size - 1;
+
+		} else if ( opt < 128 ) {
+			size = options[i+1];
+			if ( size < 3 || size > 10 ) {
+				DCCP_DEBUG((LOG_INFO, "Error, option size = %u\n", size));
+				return;
+			}
+
+			switch(opt) {
+			    case DCCP_OPT_IGNORED:
+				DCCP_DEBUG((LOG_INFO, "Got DCCP_OPT_IGNORED!\n"));
+				if ( size != 4 ) {
+					DCCP_DEBUG((LOG_INFO, "Error, got a DCCP_OPT_IGNORED but size = %u (should be 4)\n", size));
+					return;
+				}
+				if ( options[2] > 32 && options[2] < 36 ) {
+					/* Feature negotiations */
+					DCCP_DEBUG((LOG_INFO, "Remote DCCP did not understand feature %u, running dccp_remove_feature(dp, %u, %u)\n", options[3], options[2], options[3]));
+					dccp_remove_feature(dp, options[2], options[3]);
+				}
+				break;
+
+			    case DCCP_OPT_RECV_BUF_DROPS:
+				DCCP_DEBUG((LOG_INFO, "Got DCCP_OPT_RECV_BUF_DROPS, size = %u!\n", size));
+				for(j=2; j < size; j++) {
+					DCCP_DEBUG((LOG_INFO, "val[%u] = %u ", j-1, options[i+j]));
+				}
+				DCCP_DEBUG((LOG_INFO, "\n"));
+				break;
+
+			    case DCCP_OPT_TIMESTAMP:
+				DCCP_DEBUG((LOG_INFO, "Got DCCP_OPT_TIMESTAMP, size = %u\n", size));
+
+				/* Adding TimestampEcho to next outgoing */
+				bcopy(options + i + 2, val, 4);
+				bzero(val + 4, 4);
+				dccp_add_option(dp, DCCP_OPT_TIMESTAMP_ECHO, val, 8);
+				break;
+				
+			    case DCCP_OPT_TIMESTAMP_ECHO:
+				DCCP_DEBUG((LOG_INFO, "Got DCCP_OPT_TIMESTAMP_ECHO, size = %u\n",size));
+				for(j=2; j < size; j++) {
+					DCCP_DEBUG((LOG_INFO, "val[%u] = %u ", j-1, options[i+j]));
+				}
+				DCCP_DEBUG((LOG_INFO, "\n"));
+
+				/*
+				bcopy(options + i + 2, &(dp->timestamp_echo), 4);
+				bcopy(options + i + 6, &(dp->timestamp_elapsed), 4);
+				ACK_DEBUG((LOG_INFO, "DATA; echo = %u , elapsed = %u\n",
+					   dp->timestamp_echo, dp->timestamp_elapsed));
+				*/
+				
+				break;
+
+			case DCCP_OPT_ACK_VECTOR0:
+			case DCCP_OPT_ACK_VECTOR1:
+				/* Dont do nothing here. Let the CC deal with it */
+				break;
+				
+			default:
+				DCCP_DEBUG((LOG_INFO, "Got an unknown option, option = %u, size = %u!\n", opt, size));
+				break;
+
+			}
+			i += size - 1;
+
+		} else {
+			DCCP_DEBUG((LOG_INFO, "Got a CCID option, do nothing!"));
+			size = options[i+1];
+			if ( size < 3 || size > 10 ) {
+				DCCP_DEBUG((LOG_INFO, "Error, option size = %u\n", size));
+				return;
+			}
+			i += size - 1;
+		}
+	}
+
+}
+
+int
+dccp_add_feature(struct dccpcb *dp, u_int8_t opt, u_int8_t feature, char *val, u_int8_t val_len)
+{
+	int i;
+	DCCP_DEBUG((LOG_INFO, "Entering dccp_add_feature, opt = %u, feature = %u, val_len = %u\n", opt, feature, val_len));
+
+	if ( DCCP_MAX_OPTIONS > (dp->featlen + val_len + 3) ) {
+		dp->features[dp->featlen] = opt;
+		dp->features[dp->featlen +1] = val_len + 3;
+		dp->features[dp->featlen +2] = feature;
+		dp->featlen += 3;
+		for(i = 0; i<val_len; i++) {
+			dp->features[dp->featlen] = val[i];
+			dp->featlen++;
+		}
+	} else {
+		DCCP_DEBUG((LOG_INFO, "No room for more features, featlen = %u\n", dp->featlen));
+		return -1;
+	}
+
+	return 0;
+}
+
+int
+dccp_remove_feature(struct dccpcb *dp, u_int8_t opt, u_int8_t feature)
+{
+	int i = 0, j = 0, k;
+	u_int8_t t_opt, t_feature, len;
+	DCCP_DEBUG((LOG_INFO, "Entering dccp_remove_feature, featlen = %u, opt = %u, feature = %u\n", dp->featlen, opt, feature));
+
+	while( i < dp->featlen ) {
+		t_opt = dp->features[i];
+		len = dp->features[i+1];
+
+		if ( i + len > dp->featlen ) {
+			DCCP_DEBUG((LOG_INFO, "Error, len = %u and i(%u) + len > dp->featlen (%u)\n", len, i, dp->featlen));
+			return 1;
+		}
+		t_feature = dp->features[i+2];
+
+		if ( t_opt == opt && t_feature == feature ) {
+			i += len;
+		} else {
+			if ( i != j ) {
+				for(k = 0; k < len; k++) {
+					dp->features[j+k] = dp->features[i+k];
+				}
+			}
+			i += len;
+			j += len;
+		}
+	}
+	dp->featlen = j;
+	DCCP_DEBUG((LOG_INFO, "Exiting dccp_remove_feature, featlen = %u\n", dp->featlen));
+	return 0;
+}
+
+void
+dccp_feature_neg(struct dccpcb *dp, u_int8_t opt, u_int8_t feature, u_int8_t val_len, char *val)
+{
+	char ignored[2];
+	DCCP_DEBUG((LOG_INFO, "Running dccp_feature_neg, opt = %u, feature = %u len = %u ", opt, feature, val_len));
+
+	switch(feature) {
+		case DCCP_FEATURE_CC:
+			DCCP_DEBUG((LOG_INFO, "Got CCID negotiation, opt = %u, val[0] = %u\n", opt, val[0]));
+			if ( opt == DCCP_OPT_CHANGE ) {
+				if ( val[0] == 2 || val[0] == 3 || val[0] == 0 ) {
+					DCCP_DEBUG((LOG_INFO, "Sending DCCP_OPT_CONFIRM on CCID %u\n", val[0]));
+					dccp_remove_feature(dp, DCCP_OPT_PREFER, DCCP_FEATURE_CC);
+					dccp_remove_feature(dp, DCCP_OPT_CONFIRM, DCCP_FEATURE_CC);
+					dccp_add_feature_option(dp, DCCP_OPT_CONFIRM, DCCP_FEATURE_CC , val, 1);
+					if ( dp->cc_in_use[0] < 1 ) {
+						dp->cc_state[0] = (*cc_sw[val[0] + 1].cc_send_init)(dp);
+						dp->cc_in_use[0] = val[0] + 1;
+					} else {
+						DCCP_DEBUG((LOG_INFO, "We already have negotiated a CC!!!\n"));
+					}
+				}
+			} else if ( opt == DCCP_OPT_PREFER ) {
+				if ( val[0] == 2 || val[0] == 3 || val[0] == 0 ) {
+					DCCP_DEBUG((LOG_INFO, "Sending DCCP_OPT_CHANGE on CCID %u\n", val[0]));
+					dccp_remove_feature(dp, DCCP_OPT_CHANGE, DCCP_FEATURE_CC);
+					dccp_add_feature(dp, DCCP_OPT_CHANGE, DCCP_FEATURE_CC, val, 1);
+					if ( dp->cc_in_use[1] < 1 ) {
+						dp->cc_in_use[1] = 0;
+					} else {
+						DCCP_DEBUG((LOG_INFO, "We already have negotiated a CC!!!\n"));
+					}
+				}
+			} else if ( opt == DCCP_OPT_CONFIRM ) {
+				DCCP_DEBUG((LOG_INFO, "Got DCCP_OPT_CONFIRM on CCID %u\n", val[0]));
+				dccp_remove_feature(dp, DCCP_OPT_CHANGE, DCCP_FEATURE_CC);
+				if ( dp->cc_in_use[1] < 1 ) {
+					dp->cc_state[1] = (*cc_sw[val[0] +1].cc_recv_init)(dp);
+					dp->cc_in_use[1] = val[0] +1;
+				} else {
+					DCCP_DEBUG((LOG_INFO, "We already have negotiated a CC!!!\n"));
+				}
+			}
+		
+		break;
+
+		case DCCP_FEATURE_ACKVECTOR:
+			ACK_DEBUG((LOG_INFO, "Got _Use Ack Vector_\n"));
+			if (opt == DCCP_OPT_CHANGE) {
+				if (val[0] == 1) {
+					dccp_use_ackvector(dp);
+					dccp_remove_feature(dp, DCCP_OPT_CONFIRM, DCCP_FEATURE_ACKVECTOR);
+					dccp_add_feature_option(dp, DCCP_OPT_CONFIRM, DCCP_FEATURE_ACKVECTOR , val, 1);
+				} else {
+					ACK_DEBUG((LOG_INFO, "ERROR. Strange val %u\n", val[0]));
+				}
+			} else if (opt == DCCP_OPT_CONFIRM) {
+					dccp_remove_feature(dp, DCCP_OPT_CONFIRM, DCCP_FEATURE_ACKVECTOR);
+			if (val[0] == 1) {
+					dp->remote_ackvector = 1;
+					ACK_DEBUG((LOG_INFO,"Remote side confirmed AckVector usage\n"));
+				} else {
+					ACK_DEBUG((LOG_INFO, "ERROR. Strange val %u\n", val[0]));
+				}
+			} else if (opt == DCCP_OPT_PREFER) {
+				ACK_DEBUG((LOG_INFO, "Prefer Ack Vector? MENTAL!!!!\n"));
+			}
+			break;
+			
+        	case DCCP_FEATURE_ACKRATIO:
+                        if (opt == DCCP_OPT_CHANGE) {
+				bcopy(val , &(dp->ack_ratio), 1);
+                                ACK_DEBUG((LOG_INFO, "Feature: Change Ack Ratio to %u\n", dp->ack_ratio));
+                        }
+                        break;
+			
+		case DCCP_FEATURE_ECN:
+		case DCCP_FEATURE_MOBILITY:
+		default:
+			ignored[0] = opt;
+			ignored[1] = feature;
+			dccp_add_option(dp, DCCP_OPT_IGNORED, ignored, 2);
+		break;
+
+	}
+}
+
+static int
+dccp_pcblist(SYSCTL_HANDLER_ARGS)
+{
+
+	int error, i, n;
+	struct inpcb *inp, **inp_list;
+	inp_gen_t gencnt;
+	struct xinpgen xig;
+
+	/*
+	 * The process of preparing the TCB list is too time-consuming and
+	 * resource-intensive to repeat twice on every request.
+	 */
+	if (req->oldptr == 0) {
+		n = dccpbinfo.ipi_count;
+		req->oldidx = 2 * (sizeof xig)
+		        + (n + n/8) * sizeof(struct xdccpcb);
+		return 0;
+        }
+
+
+	if (req->newptr != 0)
+		return EPERM;
+
+
+	/*
+	 * OK, now we're committed to doing something.
+	 */
+	INP_INFO_RLOCK(&dccpbinfo);
+	gencnt = dccpbinfo.ipi_gencnt;
+	n = dccpbinfo.ipi_count;
+	INP_INFO_RUNLOCK(&dccpbinfo);
+
+	sysctl_wire_old_buffer(req, 2 * (sizeof xig)
+	        + n * sizeof(struct xdccpcb));
+
+	xig.xig_len = sizeof xig;
+	xig.xig_count = n;
+	xig.xig_gen = gencnt;
+	xig.xig_sogen = so_gencnt;
+	error = SYSCTL_OUT(req, &xig, sizeof xig);
+	if (error)
+		return error;
+
+	inp_list = malloc(n * sizeof *inp_list, M_TEMP, M_WAITOK);
+	if (inp_list == 0)
+		return ENOMEM;
+        
+	INP_INFO_RLOCK(&dccpbinfo);
+
+	for (inp = LIST_FIRST(dccpbinfo.listhead), i = 0; inp && i < n;
+	     inp = LIST_NEXT(inp, inp_list)) {
+INP_LOCK(inp);
+		if (inp->inp_gencnt <= gencnt &&
+		    cr_canseesocket(req->td->td_ucred, inp->inp_socket) == 0)
+			inp_list[i++] = inp;
+		INP_UNLOCK(inp);
+	}
+	INP_INFO_RUNLOCK(&dccpbinfo);
+	n = i;
+
+	error = 0;
+	for (i = 0; i < n; i++) {
+		inp = inp_list[i];
+		INP_LOCK(inp);
+
+		if (inp->inp_gencnt <= gencnt) {
+			struct xdccpcb xd;
+			caddr_t	inp_ppcb;
+			xd.xd_len = sizeof xd;
+			/* XXX should avoid extra copy */
+			bcopy(inp, &xd.xd_inp, sizeof *inp);
+			inp_ppcb = inp->inp_ppcb;
+			if ( inp_ppcb != NULL )
+				bcopy(inp_ppcb, &xd.xd_dp, sizeof xd.xd_dp);
+			else
+				bzero((char *) &xd.xd_dp, sizeof xd.xd_dp);
+			if (inp->inp_socket)
+       				 sotoxsocket(inp->inp_socket, &xd.xd_socket);
+			error = SYSCTL_OUT(req, &xd, sizeof xd);
+		}
+                INP_UNLOCK(inp);
+	}
+	if (!error) {
+		/*
+		 * Give the user an updated idea of our state.
+		 * If the generation differs from what we told
+		 * her before, she knows that something happened
+		 * while we were processing this request, and it
+		 * might be necessary to retry.
+		 */
+		INP_INFO_RLOCK(&dccpbinfo);
+		xig.xig_gen = dccpbinfo.ipi_gencnt;
+		xig.xig_sogen = so_gencnt;
+		xig.xig_count = dccpbinfo.ipi_count;
+
+
+		INP_INFO_RUNLOCK(&dccpbinfo);
+		error = SYSCTL_OUT(req, &xig, sizeof xig);
+	}
+	free(inp_list, M_TEMP);
+	return error;
+}
+
+SYSCTL_PROC(_net_inet_dccp, DCCPCTL_PCBLIST, pcblist, CTLFLAG_RD, 0, 0,
+            dccp_pcblist, "S,xdccpcb", "List of active DCCP sockets");
+
+
+void dccp_timewait_t(void *dcb)
+{
+	struct dccpcb *dp = dcb;
+
+	DCCP_DEBUG((LOG_INFO, "Entering dccp_timewait_t!\n"));
+	INP_INFO_WLOCK(&dccpbinfo);
+	INP_LOCK(dp->d_inpcb);
+	dccp_close(dp);
+	INP_INFO_WUNLOCK(&dccpbinfo);
+}
+
+void dccp_connect_t(void *dcb)
+{
+	struct dccpcb *dp = dcb;
+
+	DCCP_DEBUG((LOG_INFO, "Entering dccp_connect_t!\n"));
+	INP_INFO_WLOCK(&dccpbinfo);
+	INP_LOCK(dp->d_inpcb);
+	dccp_close(dp);
+	INP_INFO_WUNLOCK(&dccpbinfo);
+}
+
+void dccp_close_t(void *dcb)
+{
+	struct dccpcb *dp = dcb;
+
+	DCCP_DEBUG((LOG_INFO, "Entering dccp_close_t!\n"));
+	INP_INFO_WLOCK(&dccpbinfo);
+	dp->state = DCCPS_TIME_WAIT; /* HMM */
+	if ( dp->who == DCCP_SERVER ) {
+		INP_LOCK(dp->d_inpcb);
+		dccp_output(dp, DCCP_TYPE_RESET + 2);
+		dccp_close(dp);
+	} else {
+		INP_LOCK(dp->d_inpcb);
+		dccp_output(dp, DCCP_TYPE_RESET + 2);
+		/*dp->state = DCCPS_TIME_WAIT; */
+		dp->timewait_timer = timeout(dccp_timewait_t, dp, DCCP_TIMEWAIT_TIMER);
+		INP_UNLOCK(dp->d_inpcb);
+	}
+	INP_INFO_WUNLOCK(&dccpbinfo);
+}
+
+void dccp_retrans_t(void *dcb)
+{
+	struct dccpcb *dp = dcb;
+	struct inpcb *inp;
+
+	DCCP_DEBUG((LOG_INFO, "Entering dccp_retrans_t!\n"));
+	INP_INFO_RLOCK(&dccpbinfo);
+	inp = dp->d_inpcb;
+	INP_LOCK(inp);
+	INP_INFO_RUNLOCK(&dccpbinfo);
+	untimeout(dccp_retrans_t, dp, dp->retrans_timer);
+	dccp_output(dp, 0);
+	dp->retrans = dp->retrans * 2;
+	timeout(dccp_retrans_t, dp, dp->retrans);
+	INP_UNLOCK(inp);
+}
+
+
+/*
+ * This is the wrapper function for in_setsockaddr.  We just pass down 
+ * the pcbinfo for in_setsockaddr to lock.  We don't want to do the locking 
+ * here because in_setsockaddr will call malloc and might block.
+ */
+static int
+dccp_sockaddr(struct socket *so, struct sockaddr **nam)
+{
+	return (in_setsockaddr(so, nam, &dccpbinfo));
+}
+
+/*
+ * This is the wrapper function for in_setpeeraddr.  We just pass down
+ * the pcbinfo for in_setpeeraddr to lock.
+ */
+static int
+dccp_peeraddr(struct socket *so, struct sockaddr **nam)
+{
+	return (in_setpeeraddr(so, nam, &dccpbinfo));
+}
+
+struct pr_usrreqs dccp_usrreqs = {
+        .pru_abort =            dccp_abort,
+        .pru_accept =           dccp_accept,
+        .pru_attach =           dccp_attach,
+        .pru_bind =             dccp_bind,
+        .pru_connect =          dccp_connect,
+        .pru_control =          in_control,
+        .pru_detach =           dccp_detach,
+        .pru_disconnect =       dccp_disconnect,
+        .pru_listen =           dccp_listen,
+        .pru_peeraddr =         dccp_peeraddr,
+        .pru_send =             dccp_send,
+        .pru_shutdown =         dccp_shutdown,
+        .pru_sockaddr =         dccp_sockaddr,
+        .pru_sosetlabel =       in_pcbsosetlabel
+};
+
+#ifdef INET6
+
+struct pr_usrreqs dccp6_usrreqs = {
+        .pru_abort =            dccp_abort,
+        .pru_accept =           dccp6_accept,
+        .pru_attach =           dccp_attach,
+        .pru_bind =             dccp6_bind,
+        .pru_connect =          dccp6_connect,
+        .pru_control =          in6_control,
+        .pru_detach =           dccp_detach,
+        .pru_disconnect =       dccp_disconnect,
+        .pru_listen =           dccp6_listen,
+	.pru_peeraddr =         in6_mapped_peeraddr,
+        .pru_send =             dccp_send,
+        .pru_shutdown =         dccp_shutdown,
+	.pru_sockaddr =         in6_mapped_sockaddr,
+        .pru_sosetlabel =       in_pcbsosetlabel
+};
+
+#endif
+
+/****** Ack Vector functions *********/
+
+/**
+ * Initialize and allocate mem for Ack Vector
+ **/
+void dccp_use_ackvector(struct dccpcb *dp)
+{
+	ACK_DEBUG((LOG_INFO,"Initializing AckVector\n"));
+	if (dp->ackvector > 0) {
+		ACK_DEBUG((LOG_INFO, "It was already initialized!!!\n"));
+		return;
+	}
+	dp->av_size = DCCP_VECTORSIZE;
+	/* need 2 bits per entry */
+	dp->ackvector = malloc(dp->av_size/4, M_PCB, M_DONTWAIT | M_ZERO);
+	if (dp->ackvector == 0) {
+		DCCP_DEBUG((LOG_INFO, "Unable to allocate memory for ackvector\n"));
+		/* What to do now? */
+		dp->av_size = 0;
+		return;
+	}
+	memset(dp->ackvector, 0xff, dp->av_size/4);
+	dp->av_hs = dp->av_ts = 0;
+	dp->av_hp = dp->ackvector;
+}
+
+/**
+ * Set 'seqnr' as the new head in ackvector
+ **/
+void dccp_update_ackvector(struct dccpcb *dp, u_int32_t seqnr)
+{
+	int32_t gap;
+	u_char *t;
+
+	/* Ignore wrapping for now */
+	
+	ACK_DEBUG((LOG_INFO,"New head in ackvector: %u\n", seqnr));
+	
+	if (dp->av_size == 0) {
+		ACK_DEBUG((LOG_INFO, "Update: AckVector NOT YET INITIALIZED!!!\n"));
+		dccp_use_ackvector(dp);
+	}
+	
+	if (seqnr > dp->av_hs) {
+		gap = seqnr - dp->av_hs;
+	} else {
+		/* We received obsolete information */
+		return;
+	}
+	
+	t = dp->av_hp + (gap/4);
+	if (t >= (dp->ackvector + (dp->av_size/4)))
+		t -= (dp->av_size / 4); /* ackvector wrapped */
+	dp->av_hp = t;
+	dp->av_hs = seqnr;
+}
+
+/**
+ * We've received a packet. store in local av so it's included in
+ * next Ack Vector sent
+ **/
+void dccp_increment_ackvector(struct dccpcb *dp, u_int32_t seqnr)
+{
+	u_int32_t offset, dc;
+	int32_t gap;
+	u_char *t, *n;
+	
+	DCCP_DEBUG((LOG_INFO, "Entering dccp_increment_ackvecktor\n"));
+	if (dp->av_size == 0) {
+		ACK_DEBUG((LOG_INFO, "Increment: AckVector NOT YET INITIALIZED!!!\n"));
+		dccp_use_ackvector(dp);
+	}
+	
+	if (dp->av_hs == dp->av_ts) {
+		/* Empty ack vector */
+		dp->av_hs = dp->av_ts = seqnr;
+	}
+
+	/* Check for wrapping */
+	if (seqnr >= dp->av_hs) {
+		/* Not wrapped */
+		gap = seqnr - dp->av_hs;
+	} else {
+		/* Wrapped */
+		gap = seqnr + 0x1000000 - dp->av_hs; /* seq nr = 24 bits */
+	}
+
+	if (gap >= dp->av_size) {
+		/* gap is bigger than ackvector size? baaad */
+		/* maybe we should increase the ackvector here */
+		DCCP_DEBUG((LOG_INFO, "increment_ackvector error. gap: %d, av_size: %d, seqnr: %d\n",
+                            gap, dp->av_size, seqnr));
+		return;
+	}
+	
+	offset = gap % 4; /* hi or low 2 bits to mark */
+	t = dp->av_hp + (gap/4);
+	if (t >= (dp->ackvector + (dp->av_size/4)))
+		t -= (dp->av_size / 4); /* ackvector wrapped */
+	
+	*t = *t & (~(0x03 << (offset *2))); /* turn off bits, 00 is rcvd, 11 is missing */
+
+	dp->av_ts = seqnr+1;
+	if (dp->av_ts == 0x1000000)
+		dp->av_ts = 0;
+
+	if (gap > (dp->av_size - 128)) {
+		n = malloc(dp->av_size/2, M_PCB, M_DONTWAIT | M_ZERO); /* old size * 2 */
+		memset (n+dp->av_size/4,0xff,dp->av_size/4); /* new half all missing */
+		dc = (dp->ackvector + (dp->av_size/4)) - dp->av_hp;
+		memcpy (n,dp->av_hp, dc); /* tail to end */
+		memcpy (n+dc,dp->ackvector,dp->av_hp - dp->ackvector); /* start to tail */
+		dp->av_size = dp->av_size * 2; /* counted in items, so it';s a doubling */
+		free (dp->ackvector, M_PCB);
+		dp->av_hp = dp->ackvector = n;
+	}
+}
+
+/**
+ * Generates the ack vector to send in outgoing packet.
+ * These are backwards (first packet in ack vector is packet indicated by Ack Number,
+ * subsequent are older packets).
+ **/
+
+u_int16_t dccp_generate_ackvector(struct dccpcb *dp, u_char *buf)
+{
+	int32_t j;
+	u_int32_t i;
+	u_int16_t cnt, oldlen, bufsize;
+	u_char oldstate, st;
+
+	bufsize = 16;
+	cnt = 0;
+
+	oldstate = 0x04; /* bad value */
+	oldlen = 0;
+	
+	if (dp->av_size == 0) {
+		ACK_DEBUG((LOG_INFO, "Generate: AckVector NOT YET INITIALIZED!!!\n"));
+		return 0;
+	}
+
+	if (dp->seq_rcv > dp->av_ts) {
+		/* AckNum is beyond our av-list , so we'll start with some
+		 * 0x3 (Packet not yet received) */
+		j = dp->seq_rcv - dp->av_ts -1;
+		do {
+			/* state | length */
+			oldstate = 0x03;
+			if (j > 63)
+				oldlen = 63;
+			else
+				oldlen = j;
+			
+			buf[cnt] = (0x03 << 6) | oldlen;
+			cnt++;
+			if (cnt == bufsize) {
+				/* I've skipped the realloc bshit */
+				/* PANIC */
+			}
+			j-=63;
+		} while (j > 0);
+	}
+	
+	/* Ok now we're at dp->av_ts (unless AckNum is lower) */
+	i = (dp->seq_rcv < dp->av_ts) ? dp->seq_rcv : dp->av_ts;
+	st = dccp_ackvector_state(dp, i);
+
+	if (st == oldstate) {
+		cnt--;
+		oldlen++;
+	} else {
+		oldlen = 0;
+		oldstate = st;
+	}
+
+	if (dp->av_ts > dp->av_hs) {
+		do {
+			i--;
+			st = dccp_ackvector_state(dp, i);
+			if (st == oldstate && oldlen < 64) {
+				oldlen++;
+			} else {
+				buf[cnt] = (oldstate << 6) | (oldlen & 0x3f);
+				cnt++;
+				oldlen = 0;
+				oldstate = st;
+				if (cnt == bufsize) {
+					/* PANIC */
+				}
+			}
+			
+		} while (i > dp->av_hs);
+	} else {
+		/* It's wrapped */
+		do {
+			i--;
+			st = dccp_ackvector_state(dp, i);
+			if (st == oldstate && oldlen < 64) {
+				oldlen++;
+			} else {
+				buf[cnt] = (oldstate << 6) | (oldlen & 0x3f);
+				cnt++;
+				oldlen = 0;
+				oldstate = st;
+				if (cnt == bufsize) {
+					/* PANIC */
+				}
+			}
+			
+		} while (i > 0);
+		i = 0x1000000;
+		do {
+			i--;
+			st = dccp_ackvector_state(dp, i);
+			if (st == oldstate && oldlen < 64) {
+				oldlen++;
+			} else {
+				buf[cnt] = (oldstate << 6) | (oldlen & 0x3f);
+				cnt++;
+				oldlen = 0;
+				oldstate = st;
+				if (cnt == bufsize) {
+					/* PANIC */
+				}
+			}
+		} while (i > dp->av_hs);
+	}
+	
+	/* add the last one */
+	buf[cnt] = (oldstate << 6) | (oldlen & 0x3f);
+	cnt++;
+
+	return cnt;
+}
+
+u_char dccp_ackvector_state(struct dccpcb *dp, u_int32_t seqnr)
+{
+	u_int32_t gap, offset;
+	u_char *t;
+
+	/* Check for wrapping */
+	if (seqnr >= dp->av_hs) {
+		/* Not wrapped */
+		gap = seqnr - dp->av_hs;
+	} else {
+		/* Wrapped */
+		gap = seqnr + 0x1000000 - dp->av_hs; /* seq nr = 24 bits */
+	}
+
+	if (gap >= dp->av_size) {
+		/* gap is bigger than ackvector size? baaad */
+		return 0x03;
+	}
+
+	offset = gap % 4 *2;
+	t = dp->av_hp + (gap/4);
+	if (t >= (dp->ackvector + (dp->av_size/4)))
+		t -= (dp->av_size / 4); /* wrapped */
+	
+	return ((*t & (0x03 << offset)) >> offset);
+}
+
+/****** End of Ack Vector functions *********/
+
+/* No cc functions */
+void* dccp_nocc_init(struct dccpcb *pcb){
+  return (void*) 1;
+}
+
+void  dccp_nocc_free(void *ccb){
+}
+
+int   dccp_nocc_send_packet(void *ccb, long size){
+  return 1;
+}
+
+void  dccp_nocc_send_packet_sent(void *ccb, int moreToSend, long size){
+}
+
+void  dccp_nocc_packet_recv(void *ccb, char* options ,int optlen){
+}
+
+++ sys/netinet/dccp_var.h	Fri Aug 25 04:02:23 2006
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2003 Joacim Häggmark, Magnus Erixzon, 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: dccp_var.h,v 1.25 2003/07/31 11:17:15 joahag-9 Exp $
+ */
+
+#ifndef _NETINET_DCCP_VAR_H_
+#define _NETINET_DCCP_VAR_H_
+
+struct dccpcb {
+	u_int8_t	state; /* initial, listening, connecting, established,
+				  closing, closed etc */
+	u_int8_t	who;	/* undef, server, client, listener */
+
+	struct callout_handle	connect_timer;	/* Connection timer */
+	struct callout_handle	retrans_timer;	/* Retransmit timer */
+	struct callout_handle	close_timer;	/* Closing timer */
+	struct callout_handle	timewait_timer;	/* Time wait timer */
+
+	u_int32_t	retrans;
+
+	u_int32_t	seq_snd;
+	u_int32_t       ack_snd; /* ack num to send in Ack or DataAck packet */
+	u_int32_t	gsn_rcv; /* Greatest received sequence number */
+
+	/* values representing last incoming packet. are set in dccp_input */
+	u_int32_t	seq_rcv;        /* Seq num of received packet */
+	u_int32_t       ack_rcv;        /* Ack num received in Ack or DataAck packet */
+	u_int8_t        type_rcv;       /* Type of packet received */
+	u_int32_t       len_rcv;        /* Length of data received */
+        u_int8_t        ndp_rcv;        /* ndp value of received packet */
+
+	u_int8_t	cslen;		/* How much of outgoing packets
+					   are covered by the checksum */
+	u_int8_t	pref_cc;	/* Client prefered CC */
+	u_int8_t	ndp;		/* Number of non data packets */
+	u_int32_t	loss_window;	/* Loss window (defaults to 1000)  */
+	u_int16_t	ack_ratio;	/* Ack Ratio Feature */
+	int8_t		cc_in_use[2];	/* Current CC in use
+					   (in each direction) */
+	void 		*cc_state[2];
+	struct inpcb	*d_inpcb;	/* Pointer back to Internet PCB  */
+	u_int32_t	d_maxseg;	/* Maximum segment size */
+        char	        options[DCCP_MAX_OPTIONS];
+	u_int8_t	optlen;
+        char	        features[DCCP_MAX_OPTIONS];
+	u_int8_t	featlen;
+
+	u_int32_t	avgpsize;	/* Average packet size */
+
+	/* variables for the local (receiver-side) ack vector */
+	u_char *ackvector;  /* For acks, 2 bits per packet */
+	u_char *av_hp;  /* head ptr for ackvector */
+	u_int16_t av_size;
+	u_int32_t av_hs, av_ts; /* highest/lowest seq no in ackvector */
+	
+	u_int8_t remote_ackvector; /* Is recv side using AckVector? */
+};
+
+struct	dccpiphdr {
+	struct 	ipovly	di_i;		/* overlaid ip structure */
+	struct	dccphdr di_d;		/* dccp header */
+};
+
+struct inp_dp {
+	struct inpcb inp;
+	struct dccpcb dp;
+};
+
+#if defined(_NETINET_IN_PCB_H_) && defined(_SYS_SOCKETVAR_H_)
+struct xdccpcb {
+	size_t		xd_len;
+	struct	inpcb	xd_inp;
+	struct	dccpcb	xd_dp;
+	struct	xsocket	xd_socket;
+};
+#endif
+
+#define di_x1           di_i.ih_x1
+#define di_pr           di_i.ih_pr
+#define di_len          di_i.ih_len
+#define di_src          di_i.ih_src
+#define di_dst          di_i.ih_dst
+
+struct	dccpstat {
+	u_long	dccps_connattempt;	/* Initiated connections */
+	u_long	dccps_connects;		/* Established connections */
+	u_long	dccps_ipackets;		/* Total input packets */
+	u_long	dccps_ibytes;		/* Total input bytes */
+	u_long	dccps_drops;		/* Dropped packets  */
+	u_long	dccps_badsum;		/* Checksum error */
+	u_long	dccps_badlen;		/* Bad length */
+	u_long	dccps_badseq;		/* Sequence number not inside loss_window  */
+	u_long	dccps_noport;		/* No socket on port */
+
+        /* TFRC Sender */
+        u_long  tfrcs_send_conn;        /* Number of conn used TFRC sender */
+        u_long  tfrcs_send_noopt;       /* No options on feedback packet */
+        u_long  tfrcs_send_nomem;       /* Send refused: No mem for history */
+        u_long  tfrcs_send_fbacks;      /* Correct feedback packets received */
+        u_long  tfrcs_send_erropt;      /* Err add option on data */
+  
+        /* TFRC Receiver */
+        u_long  tfrcs_recv_conn;        /* Number of conn used TFRC receiver */
+        u_long  tfrcs_recv_noopt;       /* Packet lost: No options on packet */
+        u_long  tfrcs_recv_nomem;       /* Packet lost: No mem for history */
+        u_long  tfrcs_recv_losts;       /* Detected lost packets */
+        u_long  tfrcs_recv_fbacks;      /* Feedback packets sent */
+        u_long  tfrcs_recv_erropt;      /* Err add option on feedback */      
+
+	/* TCPlike Sender */
+	u_long  tcplikes_send_conn;     /* Connections established */
+	u_long  tcplikes_send_reploss;  /* Data packets reported lost */
+	u_long  tcplikes_send_assloss;  /* Data packets assumed lost */
+	u_long  tcplikes_send_ackrecv;  /* Acknowledgement (w/ Ack Vector) packets received */
+	u_long  tcplikes_send_missack;  /* Ack packets assumed lost */
+	u_long  tcplikes_send_badseq;   /* Bad sequence number on outgoing packet */
+	u_long  tcplikes_send_memerr;   /* Memory allocation errors */
+	
+	/* TCPlike Receiver */
+	u_long  tcplikes_recv_conn;     /* Connections established */
+	u_long  tcplikes_recv_datarecv; /* Number of data packets received */
+	u_long  tcplikes_recv_ackack;   /* Ack-on-acks received */
+	u_long  tcplikes_recv_acksent;  /* Acknowledgement (w/ Ack Vector) packets sent */
+	u_long  tcplikes_recv_memerr;   /* Memory allocation errors */
+	
+	/*	Some CCID statistic should also be here */
+
+	u_long	dccps_opackets;		/* Total output packets */
+	u_long	dccps_obytes;		/* Total output bytes */
+};
+
+/*
+ *	DCCP States
+ */
+
+#define DCCPS_CLOSED	0
+#define DCCPS_LISTEN	1
+#define DCCPS_REQUEST	2
+#define DCCPS_RESPOND	3
+#define DCCPS_ESTAB	4
+#define DCCPS_SERVER_CLOSE	5
+#define DCCPS_CLIENT_CLOSE	6
+#define DCCPS_TIME_WAIT 7
+
+#ifdef DCCPSTATES
+const char *dccpstates[] = {
+	"CLOSED",	"LISTEN",	"REQEST",	"RESPOND",
+	"ESTABLISHED",	"SERVER-CLOSE",	"CLIENT-CLOSE", "TIME_WAIT",
+};
+#endif
+
+#define DCCP_UNDEF	0
+#define DCCP_LISTENER	1
+#define DCCP_SERVER	2
+#define DCCP_CLIENT	3
+
+#define SEQ_LT(a,b)     ((int)((a << 8)-(b << 8)) < 0)
+#define SEQ_GT(a,b)     ((int)((a << 8)-(b << 8)) > 0)
+
+/*
+ * Names for DCCP sysctl objects
+ */
+#define	DCCPCTL_DEFCCID		1	/* Default CCID */
+#define DCCPCTL_STATS		2	/* statistics (read-only) */
+#define DCCPCTL_PCBLIST		3
+
+#define DCCPCTL_NAMES { \
+	{ 0, 0 }, \
+	{ "defccid", CTLTYPE_INT }, \
+	{ "stats", CTLTYPE_STRUCT }, \
+}
+
+#ifdef _KERNEL
+SYSCTL_DECL(_net_inet_dccp);
+
+extern struct	pr_usrreqs dccp_usrreqs;
+extern struct	inpcbhead dccpb;
+extern struct	inpcbinfo dccpbinfo;
+extern u_long	dccp_sendspace;
+extern u_long	dccp_recvspace;
+extern struct	dccpstat dccpstat; /* dccp statistics */
+extern int	dccp_log_in_vain; /* if we should log connections to
+				     ports w/o listeners */
+
+/* These four functions are called from inetsw (in_proto.c) */
+void	dccp_ctlinput(int, struct sockaddr *, void *);
+void	dccp_init(void);
+void	dccp_input(struct mbuf *, int);
+int	dccp_ctloutput(struct socket *so, struct sockopt *sopt);
+
+struct inpcb *
+	dccp_notify(struct inpcb *inp, int errno);
+struct dccpcb *
+	dccp_newdccpcb(struct inpcb *inp);
+
+int	dccp_shutdown(struct socket *so);
+
+int     dccp_output(struct dccpcb *, u_int8_t);
+
+int     dccp_add_option(struct dccpcb *, u_int8_t, char *, u_int8_t);
+
+/* No cc functions */
+void* dccp_nocc_init(struct dccpcb *);
+void  dccp_nocc_free(void*);
+int   dccp_nocc_send_packet(void*,long);
+void  dccp_nocc_send_packet_sent(void*,int,long);
+void  dccp_nocc_packet_recv(void*,char*,int);
+
+#endif
+
+#endif
diff -NruF^f sys-orig/netinet/in.h sys/netinet/in.h
--- sys-orig/netinet/in.h	Tue Dec 27 11:52:24 2005
+++ sys/netinet/in.h	Fri Aug 25 04:02:23 2006
@@ -42,6 +42,7 @@
 #define	IPPROTO_ICMP		1		/* control message protocol */
 #define	IPPROTO_TCP		6		/* tcp */
 #define	IPPROTO_UDP		17		/* user datagram protocol */
+#define	IPPROTO_DCCP		33		/* Datagram congestion Control Protocol */
 
 #define	INADDR_ANY		(u_int32_t)0x00000000
 #define	INADDR_BROADCAST	(u_int32_t)0xffffffff	/* must be masked */
diff -NruF^f sys-orig/netinet/in_proto.c sys/netinet/in_proto.c
--- sys-orig/netinet/in_proto.c	Tue Jan  3 19:15:32 2006
+++ sys/netinet/in_proto.c	Fri Aug 25 04:02:24 2006
@@ -63,6 +63,9 @@
 #include <netinet/tcp_var.h>
 #include <netinet/udp.h>
 #include <netinet/udp_var.h>
+#include <netinet/in_pcb.h>
+#include <netinet/dccp.h>
+#include <netinet/dccp_var.h>
 #include <netinet/ip_encap.h>
 
 /*
@@ -139,6 +142,16 @@
 	.pr_drain =		tcp_drain,
 	.pr_usrreqs =		&tcp_usrreqs
 },
+{ 	.pr_type = 		SOCK_DCCP,	
+	.pr_domain =		&inetdomain,	
+	.pr_protocol =		IPPROTO_DCCP,	
+	.pr_flags =		PR_CONNREQUIRED|PR_IMPLOPCL|PR_ATOMIC,
+	.pr_input =		dccp_input,	
+	.pr_ctlinput =		dccp_ctlinput,	
+	.pr_ctloutput =		dccp_ctloutput,
+	.pr_init = 		dccp_init,	
+	.pr_usrreqs =		&dccp_usrreqs
+},
 {
 	.pr_type =		SOCK_RAW,
 	.pr_domain =		&inetdomain,
@@ -374,6 +387,7 @@
 SYSCTL_NODE(_net_inet, IPPROTO_ICMP,	icmp,	CTLFLAG_RW, 0,	"ICMP");
 SYSCTL_NODE(_net_inet, IPPROTO_UDP,	udp,	CTLFLAG_RW, 0,	"UDP");
 SYSCTL_NODE(_net_inet, IPPROTO_TCP,	tcp,	CTLFLAG_RW, 0,	"TCP");
+SYSCTL_NODE(_net_inet, IPPROTO_DCCP,	dccp,	CTLFLAG_RW, 0,	"DCCP");
 SYSCTL_NODE(_net_inet, IPPROTO_IGMP,	igmp,	CTLFLAG_RW, 0,	"IGMP");
 #ifdef FAST_IPSEC
 /* XXX no protocol # to use, pick something "reserved" */
diff -NruF^f sys-orig/netinet6/in6_proto.c sys/netinet6/in6_proto.c
--- sys-orig/netinet6/in6_proto.c	Wed Nov 16 21:31:23 2005
+++ sys/netinet6/in6_proto.c	Thu Aug 24 06:32:15 2006
@@ -101,6 +101,10 @@
 #include <netinet6/udp6_var.h>
 #include <netinet6/pim6_var.h>
 #include <netinet6/nd6.h>
+#include <netinet/in_pcb.h>
+#include <netinet/dccp.h>
+#include <netinet/dccp_var.h>
+#include <netinet/dccp6_var.h>
 
 #ifdef IPSEC
 #include <netinet6/ipsec.h>
@@ -185,6 +189,18 @@
 #endif
 	.pr_drain =		tcp_drain,
 	.pr_usrreqs =		&tcp6_usrreqs,
+},
+{       .pr_type =              SOCK_DCCP,
+        .pr_domain =            &inet6domain,
+        .pr_protocol =          IPPROTO_DCCP,
+        .pr_flags =             PR_CONNREQUIRED|PR_IMPLOPCL|PR_ATOMIC,
+        .pr_input =             dccp6_input,
+        .pr_ctlinput =          dccp6_ctlinput,
+        .pr_ctloutput =         dccp_ctloutput,
+#ifndef INET	/* don't call initialization and timeout routines twice */
+        .pr_init =              dccp_init,
+#endif
+        .pr_usrreqs =           &dccp6_usrreqs
 },
 {
 	.pr_type =		SOCK_RAW,
diff -NruF^f sys-orig/sys/socket.h sys/sys/socket.h
--- sys-orig/sys/socket.h	Wed Sep 28 07:14:10 2005
+++ sys/sys/socket.h	Thu Aug 24 06:32:15 2006
@@ -96,6 +96,7 @@
 #define	SOCK_RDM	4		/* reliably-delivered message */
 #endif
 #define	SOCK_SEQPACKET	5		/* sequenced packet stream */
+#define SOCK_DCCP	6		/* DCCP socket */
 
 /*
  * Option flags per-socket.

