diff -NruF^f sys-orig/conf/files sys/conf/files
--- sys-orig/conf/files	Thu Apr 13 04:09:27 2006
+++ sys/conf/files	Wed Aug 16 07:12:27 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 17 08:34:52 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	Wed Aug 16 07:12:27 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 18 04:58:10 2006
@@ -0,0 +1,153 @@
+/*
+ * 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_ELAPSEDTIME     43
+#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	Wed Aug 16 07:10:43 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	Wed Aug 16 07:10:43 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	Wed Aug 16 07:10:43 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	Thu Aug 24 05:56:07 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	Thu Aug 24 05:56:14 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	Thu Aug 24 06:02:21 2006
@@ -0,0 +1,2007 @@
+/*	$KAME: dccp_tfrc.c,v 1.16 2006/03/01 17:34:08 nishida Exp $	*/
+
+/*
+ * 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/ip.h>
+
+#include <netinet/in_pcb.h>
+#include <netinet/in_var.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_tfrc_lookup.h>
+
+#define TFRCDEBUG
+#if 0
+#define TFRCDEBUGTIMERS
+#define NOTFRCSENDER
+#define NOTFRCRECV
+#endif
+
+#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
+
+/* Timeval operations */
+const struct timeval delta_half = {0, TFRC_OPSYS_TIME_GRAN / 2};
+
+#define	timercmp(tvp, uvp, cmp)							\
+	(((tvp)->tv_sec == (uvp)->tv_sec) ?					\
+	    ((tvp)->tv_usec cmp (uvp)->tv_usec) :				\
+	    ((tvp)->tv_sec cmp (uvp)->tv_sec))					
+#define	timeradd(tvp, uvp, vvp)							\
+	do {									\
+		(vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec;			\
+		(vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec;		\
+		if ((vvp)->tv_usec >= 1000000) {				\
+			(vvp)->tv_sec++;					\
+			(vvp)->tv_usec -= 1000000;				\
+		}								\
+	} while (/* CONSTCOND */ 0)
+
+#define	timersub(tvp, uvp, vvp)							\
+	do {									\
+		(vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec;			\
+		(vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec;		\
+		if ((vvp)->tv_usec < 0) {					\
+			(vvp)->tv_sec--;					\
+			(vvp)->tv_usec += 1000000;				\
+		}								\
+	} while (/* CONSTCOND */ 0)
+/*
+ * 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 { 									\
+			struct fixpoint x, y;					\
+			x.num = ccbp->s;					\
+			x.denom = 1;						\
+			fixpoint_div(&x, &x, &(ccbp)->x);			\
+			y.num = (ccbp)->t_ipi.tv_sec = fixpoint_getlong(&x);	\
+			y.denom = 1;						\
+			fixpoint_sub(&x, &x, &y);				\
+			y.num = 1000000;					\
+			y.denom = 1;						\
+			fixpoint_mul(&x, &x, &y);				\
+			(ccbp)->t_ipi.tv_usec = fixpoint_getlong(&x);		\
+        } 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)
+
+#ifdef TFRCDEBUG
+#define PRINTFLOAT(x) TFRC_DEBUG((LOG_INFO, "%lld/%lld", (x)->num, (x)->denom)); 
+#endif
+
+const struct fixpoint tfrc_smallest_p = { 4LL, 1000000LL };
+
+/* External declarations */
+extern int dccp_get_option(char *, int, int, char *, int);
+
+/* Forward declarations */
+void tfrc_time_no_feedback(void *);
+void tfrc_time_send(void *);
+void tfrc_set_send_timer(struct tfrc_send_ccb *, struct timeval);
+void tfrc_updateX(struct tfrc_send_ccb *, struct timeval);
+const struct fixpoint *tfrc_calcX(u_int16_t, u_int32_t,
+	const struct fixpoint *);
+void tfrc_send_term(void *);
+
+static void normalize(long long *, long long *);
+struct fixpoint *fixpoint_add(struct fixpoint *, const struct fixpoint *,
+	const struct fixpoint *);
+struct fixpoint *fixpoint_sub(struct fixpoint *, const struct fixpoint *,
+	const struct fixpoint *);
+int fixpoint_cmp(const struct fixpoint *, const struct fixpoint *);
+struct fixpoint *fixpoint_mul(struct fixpoint *, const struct fixpoint *,
+	const struct fixpoint *);
+struct fixpoint *fixpoint_div(struct fixpoint *, const struct fixpoint *,
+	const struct fixpoint *);
+long fixpoint_getlong(const struct fixpoint *);
+
+const struct fixpoint *flookup(const struct fixpoint *);
+const struct fixpoint *tfrc_flookup_reverse(const struct fixpoint *);
+
+/*
+ * 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 const struct fixpoint *
+tfrc_calcX(u_int16_t s, u_int32_t r, const struct fixpoint *p)
+{
+	static struct fixpoint x;
+
+	x.num = 1000000 * s;
+	x.denom = 1 * r;
+	fixpoint_div(&x, &x, p);
+	return &x;
+}
+
+/*
+ * 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 (callout_pending(&cb->ch_stimer)) {
+		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);
+
+	callout_stop(&cb->ch_stimer);
+
+	dccp_output(cb->pcb, 1);
+	/* make sure we schedule next send time */
+	tfrc_send_packet_sent(cb, 0, -1);
+
+	/* 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;
+	timersub(&t_temp, &t_now, &t_temp);
+
+#ifdef TFRCDEBUG
+	if (t_temp.tv_sec < 0 || t_temp.tv_usec < 0)
+		panic("TFRC - scheduled a negative time! (tfrc_set_send_timer)");
+#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 %ld ticks (hz=%lu)\n", t_ticks, (unsigned long)hz));
+
+	callout_reset(&cb->ch_stimer, t_ticks, tfrc_time_send, cb);
+}
+
+/*
+ * 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)
+{
+	struct fixpoint temp, temp2;
+	struct timeval t_temp, t_rtt = {0, 0};
+
+	/* to avoid large error in calcX */
+	if (fixpoint_cmp(&cb->p, &tfrc_smallest_p) >= 0) {
+		cb->x_calc = *tfrc_calcX(cb->s, cb->rtt, &cb->p);
+		temp = cb->x_recv;
+		temp.num *= 2;
+		if (fixpoint_cmp(&cb->x_calc, &temp) < 0)
+			temp = cb->x_calc;
+		cb->x = temp;
+		temp2.num = cb->s;
+		temp2.denom = TFRC_MAX_BACK_OFF_TIME;
+		if (fixpoint_cmp(&temp, &temp2) < 0)
+			cb->x = temp2;
+		normalize(&cb->x.num, &cb->x.denom);
+		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;
+		timersub(&t_temp, &cb->t_ld, &t_temp);
+		if (timercmp(&t_temp, &t_rtt, >=)) {
+			temp = cb->x_recv;
+			temp.num *= 2;
+			temp2 = cb->x;
+			temp2.num *= 2;
+			if (fixpoint_cmp(&temp2, &temp) < 0)
+				temp = temp2;
+			cb->x.num = cb->s;
+			cb->x.denom = 1;
+			cb->x.num *= 1000000;
+			cb->x.denom *= cb->rtt;
+			if (fixpoint_cmp(&temp, &cb->x) > 0)
+				cb->x = temp;
+			normalize(&cb->x.num, &cb->x.denom);
+			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)
+{
+	struct fixpoint v, w;
+	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 (callout_pending(&(cb)->ch_nftimer)) {
+		TFRC_DEBUG((LOG_INFO, "TFRC - Callout pending, exiting...(tfrc_time_no_feedback)\n"));
+		goto nf_release;
+	}
+	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.denom *= 2;
+		v.num = cb->s;
+		v.denom *= TFRC_MAX_BACK_OFF_TIME;
+		if (fixpoint_cmp(&cb->x, &v) < 0)
+			cb->x = v;
+
+		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 */
+
+		v.num = 2;
+		v.denom = 1;
+		w.num = cb->s;
+		w.denom = 1;
+		fixpoint_mul(&v, &v, &w);
+		fixpoint_div(&v, &v, &(cb->x));
+		v.num *= 1000000;
+		normalize(&v.num, &v.denom);
+		next_time_out = v.num / v.denom;
+		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
+		 */
+
+		v.num = cb->s;
+		v.num *= 4;
+		v.denom *= cb->rtt;
+		v.num *= 1000000;
+		normalize(&v.num, &v.denom);
+		if (!cb->idle || fixpoint_cmp(&cb->x_recv, &v) >= 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;
+			 */
+			v.num = TFRC_SMALLEST_P;
+			v.denom = 1;
+			if (fixpoint_cmp(&cb->p, &v) < 0 && cb->x_calc.num == 0)
+				panic("TFRC - X_calc is zero! (tfrc_time_no_feedback)\n");
+
+			/* check also if p i zero -> x_calc is infinity ?? */
+			w = cb->x_recv;
+			w.num *= 2;
+			if (fixpoint_cmp(&cb->p, &v) || fixpoint_cmp(&cb->x_calc, &w) > 0) {
+				cb->x_recv.denom *= 2;
+				w.num = cb->s;
+				w.denom *= (2 * TFRC_MAX_BACK_OFF_TIME);
+				if (fixpoint_cmp(&cb->x_recv, &w) < 0)
+					cb->x_recv = w;
+			} else
+				cb->x_recv.denom *= 4;
+			normalize(&cb->x_recv.num, &cb->x_recv.denom);
+
+			/* Update sending rate */
+			microtime(&t_now);
+			tfrc_updateX(cb, t_now);
+		}
+		/* Schedule no feedback timer to expire in max(4*R, 2*s/X) */
+		v.num = cb->s;
+		v.num *= 2;
+		fixpoint_div(&v, &v, &cb->x);
+		v.num *= 1000000;
+		next_time_out = v.num / v.denom;
+		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));
+
+	callout_reset(&cb->ch_nftimer, next_time_out, tfrc_time_no_feedback, cb);
+
+	/* 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_NOWAIT | 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.num = ccb->s;	/* set transmissionrate to 1 packet per second */
+	ccb->x.denom = 1;
+					 
+	ccb->t_ld.tv_sec = -1;
+	ccb->t_ld.tv_usec = 0;
+
+#ifdef TFRCDEBUG
+	ccb->t_last_win_count.tv_sec = -1;
+#endif
+	callout_init(&ccb->ch_stimer, 0);
+	callout_init(&ccb->ch_nftimer, 0);
+
+	/* init packet history */
+	TAILQ_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)
+		return;	
+
+	/* uninit sender */
+
+	/* get mutex */
+	mtx_lock(&(cb->mutex));
+
+	cb->state = TFRC_SSTATE_TERM;
+	/* unschedule timers */
+	callout_stop(&cb->ch_stimer);
+
+	callout_stop(&cb->ch_nftimer);
+
+	/* Empty packet history */
+	elm = TAILQ_FIRST(&(cb->hist));
+	while (elm != NULL) {
+		elm2 = TAILQ_NEXT(elm, linfo);
+		free(elm, M_TEMP);	/* M_TEMP ?? */
+		elm = elm2;
+	}
+	TAILQ_INIT(&(cb->hist));
+
+	mtx_unlock(&(cb->mutex));
+
+	/* schedule the removal of ccb */
+	callout_reset(&cb->ch_stimer, TFRC_SEND_WAIT_TERM * hz, tfrc_send_term, cb);
+}
+
+/*
+ * Ask TFRC whether 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)
+{
+	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 = TAILQ_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_NOWAIT);	/* 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 */
+		TAILQ_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 */
+
+		callout_reset(&cb->ch_nftimer, TFRC_INITIAL_TIMEOUT * hz, tfrc_time_no_feedback, cb);
+		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);
+		timeradd(&cb->t_nom, &cb->t_ipi, &cb->t_nom);
+		/* 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 (!callout_pending(&cb->ch_stimer)) {
+			microtime(&t_now);
+
+			t_temp = t_now;
+			timeradd(&t_temp, &cb->delta, &t_temp);
+
+			if ((timercmp(&(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;
+				timersub(&t_temp, &(cb->t_last_win_count), &t_temp);
+
+				/* XXX calculate window counter */
+				if (cb->state == TFRC_SSTATE_NO_FBACK) {
+					/* Assume RTT = t_rto(initial)/4 */
+					uw_win_count = (t_temp.tv_sec + (t_temp.tv_usec / 1000000)) 
+							/ TFRC_INITIAL_TIMEOUT / (4 * TFRC_WIN_COUNT_PER_RTT);
+				} else {
+					if (cb->rtt)
+						uw_win_count = (t_temp.tv_sec * 1000000 + t_temp.tv_usec) 
+								/ cb->rtt / TFRC_WIN_COUNT_PER_RTT;
+					else 
+						uw_win_count = 0; 
+				}
+				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;
+	}
+
+	if (answer) {
+		/* MANU cb->pcb->ccval = win_count; */
+		new_packet->win_count = win_count;
+	}
+
+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 = TAILQ_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 (%llu, %u, (%lu.%lu)", 
+			packet->seq, packet->win_count, packet->t_sent.tv_sec, packet->t_sent.tv_usec));
+		cb->idle = 0;
+	}
+
+	/* if timer is running, do nothing */
+	if (callout_pending(&cb->ch_stimer)) {
+		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);
+			timeradd(&cb->t_nom, &cb->t_ipi, &cb->t_nom);
+			/* Calculate new delta */
+			CALCNEWDELTA(cb);
+		}
+
+		if (!moreToSend) {
+			/* loop until we find a send time in the future */
+			microtime(&t_now);
+			t_temp = t_now;
+			timeradd(&t_temp, &cb->delta, &t_temp);
+			while ((timercmp(&(t_temp), &(cb->t_nom), >))) {
+				/* Calculate new t_ipi */
+				CALCNEWTIPI(cb);
+				timeradd(&cb->t_nom, &cb->t_ipi, &cb->t_nom);
+
+				/* Calculate new delta */
+				CALCNEWDELTA(cb);
+
+				microtime(&t_now);
+				t_temp = t_now;
+				timeradd(&t_temp, &cb->delta, &t_temp);
+			}
+			tfrc_set_send_timer(cb, t_now);
+		} else {
+			microtime(&t_now);
+			t_temp = t_now;
+			timeradd(&t_temp, &cb->delta, &t_temp);
+
+			/* Check if next packet can not be sent immediately */
+			if (!(timercmp(&(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;
+	struct fixpoint x,y;
+	int res;
+	u_int16_t t_elapsed = 0;
+	u_int32_t t_elapsed_l = 0;
+	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, 6);
+	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, DCCP_OPT_ELAPSEDTIME, (char *) &t_elapsed_l, 6);
+	if (res == 0) {
+		/* try 2 bytes elapsed time */
+		res = dccp_get_option(options, optlen, DCCP_OPT_ELAPSEDTIME, (char *) &t_elapsed, 4);
+		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 */
+	if (t_elapsed)
+		t_elapsed = ntohs(t_elapsed);
+	else
+		t_elapsed_l = ntohl(t_elapsed_l);
+	x_recv = ntohl(x_recv);
+	pinv = ntohl(pinv);
+	if (pinv == 0xFFFFFFFF) pinv = 0; 
+
+	if (t_elapsed)
+  		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));
+	else
+  		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 = TAILQ_FIRST(&(cb->hist));
+		while (elm != NULL) {
+			if (elm->seq == cb->pcb->ack_rcv)
+				break;
+			elm = TAILQ_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);
+		timersub(&t_now, &(elm->t_sent), &t_now);
+		r_sample = t_now.tv_sec * 1000000 + t_now.tv_usec;
+		if (t_elapsed)
+			r_sample = r_sample - ((u_int32_t) t_elapsed * 10); /* t_elapsed in us */	
+		else
+			r_sample = r_sample - (t_elapsed_l * 10);	/* t_elapsed in us */
+
+		/* 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 * cb->rtt +
+			    (1 - TFRC_RTT_FILTER_CONST) * 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 */
+		x.num = x_recv;
+		y.num = 8;
+		x.denom = y.denom = 1;
+		fixpoint_div(&(cb)->x_recv, &x, &y);
+
+		/* Update loss event rate */
+		if (pinv == 0) {
+			cb->p.num = cb->p.denom = 0;
+		} else {
+			cb->p.num  = 1.0;
+			cb->p.denom = pinv;				
+			if (fixpoint_cmp(&cb->p, &tfrc_smallest_p) <= 0) {
+				cb->p.num  = tfrc_smallest_p.num;
+				cb->p.denom  = tfrc_smallest_p.denom;
+				TFRC_DEBUG((LOG_INFO, "TFRC - Smallest p used!\n"));
+			}
+		}
+
+		/* unschedule no feedback timer */
+		if (!callout_pending(&cb->ch_nftimer)) {
+			callout_stop(&cb->ch_nftimer);
+		}
+		/* Update sending rate */
+		microtime(&t_now);
+		tfrc_updateX(cb, t_now);
+
+		/* Update next send time */
+		timersub(&cb->t_nom, &cb->t_ipi, &cb->t_nom);
+
+		/* Calculate new t_ipi */
+		CALCNEWTIPI(cb);
+		timeradd(&cb->t_nom, &cb->t_ipi, &cb->t_nom);
+		/* Calculate new delta */
+		CALCNEWDELTA(cb);
+
+		if (callout_pending(&cb->ch_stimer)) {
+			callout_stop(&cb->ch_stimer);
+		}
+
+#if 0 /* XXX do not send ack of ack so far */ 
+		dccp_output(cb->pcb, 1);
+		tfrc_send_packet_sent(cb, 0, -1);	/* make sure we schedule next send time */
+#endif
+
+		/* remove all packets older than the one acked from history */
+		/* elm points to acked package! */
+
+		elm2 = TAILQ_NEXT(elm, linfo);
+
+		while (elm2 != NULL) {
+			TAILQ_REMOVE(&(cb->hist), elm2, linfo);
+			free(elm2, M_TEMP);
+			elm2 = TAILQ_NEXT(elm, linfo);
+		}
+
+		/* Schedule no feedback timer to expire in max(4*R, 2*s/X) */
+		/* next_time_out = (u_int32_t) (2 * cb->s * 1000000 / cb->x); */
+
+		x.num = 2;
+		x.denom = 1;
+		y.num = cb->s;
+		y.denom = 1;
+		fixpoint_mul(&x, &x, &y);
+		fixpoint_div(&x, &x, &(cb->x));
+		x.num *= 1000000;
+		normalize(&x.num, &x.denom);
+		next_time_out = x.num / x.denom;
+
+		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;
+
+		callout_reset(&cb->ch_nftimer, next_time_out, tfrc_time_no_feedback, cb);
+
+		/* 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 */
+long tfrc_calclmean(struct tfrc_recv_ccb *);
+void tfrc_recv_send_feedback(struct tfrc_recv_ccb *);
+int tfrc_recv_add_hist(struct tfrc_recv_ccb *, struct r_hist_entry *);
+void tfrc_recv_detectLoss(struct tfrc_recv_ccb *);
+u_int32_t tfrc_recv_calcFirstLI(struct tfrc_recv_ccb *);
+void tfrc_recv_updateLI(struct tfrc_recv_ccb *, long, u_int8_t);
+
+/* Weights used to calculate loss event rate */
+/* const double tfrc_recv_w[] = { 1,  1,   1,   1,  0.8,  0.6, 0.4, 0.2}; */
+const struct fixpoint tfrc_recv_w[] = {{1,1},  {1,1},  {1,1},  {1,1},  {4,5},  {3,5}, {2,5}, {1,5}};
+
+/* 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 = TAILQ_FIRST(&((cb)->hist)); \
+      while ((elm) != NULL) { \
+        if ((elm)->type == DCCP_TYPE_DATA || (elm)->type == DCCP_TYPE_DATAACK) \
+          (num)--; \
+        if (num == 0) \
+          break; \
+        elm = TAILQ_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 = TAILQ_NEXT(elm, linfo); \
+      while ((elm) != NULL && (elm)->type != DCCP_TYPE_DATA && (elm)->type != DCCP_TYPE_DATAACK) { \
+        elm = TAILQ_NEXT((elm), linfo); \
+      } \
+    } \
+  } while (0)
+
+/*
+ * Calculate avarage loss Interval I_mean
+ * args: cb - ccb of receiver
+ * returns: avarage loss interval
+ * Tested u:OK
+ */
+long 
+tfrc_calclmean(struct tfrc_recv_ccb * cb)
+{
+	struct li_hist_entry *elm;
+	struct fixpoint l_tot;
+	struct fixpoint l_tot0 = {0,0};
+	struct fixpoint l_tot1 = {0,0};
+	struct fixpoint W_tot = {0, 0};
+	struct fixpoint tmp;
+	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];
+*/
+		tmp.num = elm->interval; 
+		tmp.denom = 1;
+		fixpoint_mul(&tmp, &tmp, &tfrc_recv_w[i]);
+		fixpoint_add(&l_tot0, &l_tot0, &tmp);
+		fixpoint_add(&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]);
+*/
+		tmp.num = elm->interval; 
+		tmp.denom = 1;
+		fixpoint_mul(&tmp, &tmp, &tfrc_recv_w[i-1]);
+		fixpoint_add(&l_tot1, &l_tot1, &tmp);
+
+		elm = TAILQ_NEXT(elm, linfo);
+	}
+
+	/* I_tot = max(I_tot0, I_tot1) */
+	/*
+	I_tot = I_tot0;		
+	if (I_tot0 < I_tot1)
+		I_tot = I_tot1;
+
+	if (I_tot < W_tot)
+		I_tot = W_tot;
+	return (I_tot / W_tot);
+	*/
+
+	l_tot.num = l_tot0.num;
+	l_tot.denom = l_tot0.denom;
+	if (fixpoint_cmp(&l_tot0, &l_tot1) < 0){
+		l_tot.num = l_tot1.num;
+		l_tot.denom = l_tot1.denom;
+	}
+
+	if (fixpoint_cmp(&l_tot, &W_tot) < 0){
+		l_tot.num = W_tot.num;
+		l_tot.denom = W_tot.denom;
+	}
+	fixpoint_div(&tmp, &l_tot, &W_tot);
+	return(fixpoint_getlong(&tmp));
+
+#ifdef TFRCDEBUG
+I_panic:
+	panic("TFRC - Missing entry in interval history! (tfrc_calclmean)");
+#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_int32_t t_elapsed;
+	struct r_hist_entry *elm;
+	struct fixpoint x;
+	struct timeval t_now, t_temp;
+	int num;
+
+	x.num = 1;
+	x.denom = 4000000000LL;		/* -> 1/p > 4 000 000 000 */
+	if (fixpoint_cmp(&cb->p, &x) < 0) 	
+		/*  if (cb->p < 0.00000000025)	-> 1/p > 4 000 000 000 */
+		pinv = 0xFFFFFFFF;
+	else {
+		/*	pinv = (u_int32_t) (1.0 / cb->p); */
+		x.num = 1;
+		x.denom = 1;
+		fixpoint_div(&x, &x, &(cb)->p);
+		pinv = fixpoint_getlong(&x);
+	}			
+
+	switch (cb->state) {
+	case TFRC_RSTATE_NO_DATA:
+		x_recv = 0;
+		break;
+	case TFRC_RSTATE_DATA:
+		/* Calculate x_recv */
+		microtime(&t_temp);
+		timersub(&t_temp, &cb->t_last_feedback, &t_temp);
+
+		x_recv = (u_int32_t) (cb->bytes_recv * 8 * 1000000) / (t_temp.tv_sec * 1000000 + t_temp.tv_usec);
+
+		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);
+	timersub(&t_now, &elm->t_recv, &t_now);
+	t_elapsed = (u_int32_t) (t_now.tv_sec * 100000 + t_now.tv_usec / 10);
+
+	/* change byte order */
+	t_elapsed = htonl(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, DCCP_OPT_ELAPSEDTIME, (char *) &t_elapsed, 4)
+	    || 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_TIME((LOG_INFO, "TFRC - Sending a feedback packet with (t_elapsed %u, pinv %x, x_recv %u, ack=%llu) (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 timeval t_temp;
+	int temp;
+	struct fixpoint x_recv, fval, t_rtt, x;
+	const struct fixpoint *fval2;
+	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;
+		}
+	}
+	timersub(&t_temp, &elm2->t_recv, &t_temp);
+	t_rtt.num = t_temp.tv_sec * 1000000 + t_temp.tv_usec; 
+	t_rtt.denom = 1000000;
+
+	if (t_rtt.num < 0 && t_rtt.denom < 0) {
+		TFRC_DEBUG((LOG_INFO, "TFRC - Approximation of RTT is negative!\n"));
+		t_rtt.num = -t_rtt.num;
+		t_rtt.denom = -t_rtt.denom;
+	}
+
+	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);
+	timersub(&t_temp, &cb->t_last_feedback, &t_temp);
+	/*
+		x_recv = (((double) (cb->bytes_recv)) /
+	    (((double) t_temp.tv_sec) + ((double) t_temp.tv_usec) / 1000000.0));
+	*/
+	x_recv.num = cb->bytes_recv * 1000000; 
+	x_recv.denom = t_temp.tv_sec * 1000000 + t_temp.tv_usec;
+
+	TFRC_DEBUG((LOG_INFO, "TFRC - Receive rate XXX"));
+	PRINTFLOAT(&x_recv);
+	TFRC_DEBUG((LOG_INFO, " bytes/s (tfrc_recv_calcFirstLI)\n"));
+
+	/*	fval = ((double) (cb->s)) / (x_recv * t_rtt); */
+	fval.num = cb->s;
+	fval.denom = 1;
+	fixpoint_div(&fval, &fval, &x_recv);
+	fixpoint_div(&fval, &fval, &t_rtt);
+
+	TFRC_DEBUG((LOG_INFO, "TFRC - Fvalue to locate XXX"));
+	PRINTFLOAT(&fval);
+	TFRC_DEBUG((LOG_INFO, " (tfrc_recv_calcFirstLI)\n"));
+	fval2 = tfrc_flookup_reverse(&fval);
+	TFRC_DEBUG((LOG_INFO, "TFRC - Lookup gives p= XXX"));
+	PRINTFLOAT(&fval);
+	TFRC_DEBUG((LOG_INFO, " (tfrc_recv_calcFirstLI)\n"));
+	if (fval2->num == 0 && fval2->denom == 0)
+		return (u_int32_t) 0xFFFFFFFF;
+	x.num = x.denom = 1;
+	fixpoint_div(&x, &x, fval2);
+	return (u_int32_t) (fixpoint_getlong(&x));
+}
+/* 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=%llu,win_count=%u,type=%u,ndp=%u) to history! (tfrc_recv_add_hist)\n", packet->seq, packet->win_count, packet->type, packet->ndp));
+
+	if (TAILQ_EMPTY(&(cb->hist))) {
+		TAILQ_INSERT_HEAD(&(cb->hist), packet, linfo);
+	} else {
+		elm = TAILQ_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)) {
+			TAILQ_INSERT_HEAD(&(cb->hist), packet, linfo);
+		} else {
+			if (elm->type == DCCP_TYPE_DATA || elm->type == DCCP_TYPE_DATAACK)
+				num_later = 1;
+
+			elm2 = TAILQ_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)) {
+					TAILQ_INSERT_AFTER(&(cb->hist), elm, packet, linfo);
+					break;
+				}
+				elm = elm2;
+				elm2 = TAILQ_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) {
+				TAILQ_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 = TAILQ_NEXT(elm, linfo);
+			while (elm2 != NULL) {
+				TAILQ_REMOVE(&(cb->hist), elm2, linfo);
+				free(elm2, M_TEMP);
+				elm2 = TAILQ_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 = TAILQ_NEXT(elm2, linfo);
+
+					while (elm != NULL) {
+						TAILQ_REMOVE(&(cb->hist), elm, linfo);
+						free(elm, M_TEMP);
+						elm = TAILQ_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 = TAILQ_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 = TAILQ_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;
+	struct li_hist_entry *li_elm, *li_elm2;
+	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_NOWAIT | 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 %llu (tfrc_recv_updateLI)\n", elm->seq));
+		}
+	}
+}
+
+
+/* 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_NOWAIT | 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 */
+	TAILQ_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 */
+
+	cb->state = TFRC_RSTATE_TERM;
+	/* get mutex */
+	mtx_lock(&(cb->mutex));
+
+	/* Empty packet history */
+	elm = TAILQ_FIRST(&(cb->hist));
+	while (elm != NULL) {
+		elm2 = TAILQ_NEXT(elm, linfo);
+		free(elm, M_TEMP);	/* M_TEMP ?? */
+		elm = elm2;
+	}
+	TAILQ_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;
+	struct fixpoint p_prev;
+	int ins = 0;
+	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_NOWAIT);	/* 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;
+
+	/* get window counter */
+	/* MANU win_count = cb->pcb->ccval; */
+	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.num = cb->p.num;
+				p_prev.denom = cb->p.denom;
+
+				/* Calculate loss event rate */
+				if (!TAILQ_EMPTY(&(cb->li_hist))) {
+					cb->p.num = 1; 
+					cb->p.denom = tfrc_calclmean(cb);
+				}
+				/* check send conditions then send */
+
+				if (fixpoint_cmp(&(cb)->p, &p_prev) > 0) {
+					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));
+	;
+}
+
+
+/*
+ * fixpoint routines
+ */
+static void
+normalize(num, denom)
+	long long *num, *denom;
+{
+	static const int prime[] = { 2, 3, 5, 7, 11, 13, 17, 19, 0 };
+	int i;
+
+	if (!*denom) return;
+	if (denom < 0) {
+		*num *= (-1);
+		*denom *= (-1);
+	}
+
+	if (*num % *denom == 0) {
+		*num /= *denom;
+		*denom = 1;
+	}
+	for (i = 0; prime[i]; i++)
+		while (*num % prime[i] == 0 && *denom % prime[i] == 0) {
+			*num /= prime[i];
+			*denom /= prime[i];
+		}
+}
+
+struct fixpoint *
+fixpoint_add(x, a, b)
+	struct fixpoint *x;
+	const struct fixpoint *a, *b;
+{
+	long long num, denom;
+
+	num = a->num * b->denom + a->denom * b->num;
+	denom = a->denom * b->denom;
+	normalize(&num, &denom);
+
+	x->num = num;
+	x->denom = denom;
+	return (x);
+}
+
+struct fixpoint *
+fixpoint_sub(x, a, b)
+	struct fixpoint *x;
+	const struct fixpoint *a, *b;
+{
+	long long num, denom;
+
+	if (!a->denom) {
+		x->num = -1 * b->num;
+		x->denom = -1 * b->denom;
+		return (x);
+	}		
+	if (!b->denom) {
+		x->num = a->num;
+		x->denom = a->denom;
+		return (x);
+	}		
+	num = a->num * b->denom - a->denom * b->num;
+	denom = a->denom * b->denom;
+	normalize(&num, &denom);
+
+	x->num = num;
+	x->denom = denom;
+	return (x);
+}
+
+int
+fixpoint_cmp(a, b)
+	const struct fixpoint *a, *b;
+{
+	struct fixpoint x;
+
+	fixpoint_sub(&x, a, b);
+	if (x.num > 0)
+		return (1);
+	else if (x.num < 0)
+		return (-1);
+	else
+		return (0);
+}
+
+struct fixpoint *
+fixpoint_mul(x, a, b)
+	struct fixpoint *x;
+	const struct fixpoint *a, *b;
+{
+	long long num, denom;
+
+	num = a->num * b->num;
+	denom = a->denom * b->denom;
+	normalize(&num, &denom);
+
+	x->num = num;
+	x->denom = denom;
+	return (x);
+}
+
+struct fixpoint *
+fixpoint_div(x, a, b)
+	struct fixpoint *x;
+	const struct fixpoint *a, *b;
+{
+	long long num, denom;
+
+	num = a->num * b->denom;
+	denom = a->denom * b->num;
+	normalize(&num, &denom);
+
+	x->num = num;
+	x->denom = denom;
+	return (x);
+}
+
+long
+fixpoint_getlong(x)
+	const struct fixpoint *x;
+{
+
+	if (x->denom == 0)
+		return (0);
+	return (x->num / x->denom);
+}
+
+const struct fixpoint flargex = { 2LL, 1000LL };
+const struct fixpoint fsmallx = { 1LL, 100000LL };
+const struct fixpoint fsmallstep = { 4LL, 1000000LL };
+
+/*
+ * FLOOKUP macro. NOTE! 0<=(int x)<=1 
+ * Tested u:OK
+ */
+const struct fixpoint *
+flookup(x)
+	const struct fixpoint *x;
+{
+	static const struct fixpoint y = { 250000, 1 };
+	struct fixpoint z;
+	int i;
+
+	if (fixpoint_cmp(x, &flargex) >= 0) {
+		if (x->num == 0)
+			return NULL;
+		i = x->denom / x->num;
+#ifdef TFRCDEBUG
+		if (i >= sizeof(flarge_table) / sizeof(flarge_table[0]))
+			panic("flarge_table lookup failed");
+#endif
+
+		return &flarge_table[i];
+	} else {
+		fixpoint_mul(&z, x, &y);
+		if (z.num == 0)
+			return NULL;
+		i = fixpoint_getlong(&z);
+#ifdef TFRCDEBUG
+		if (i >= sizeof(fsmall_table) / sizeof(fsmall_table[0]))
+			panic("fsmall_table lookup failed");
+#endif
+
+		return &fsmall_table[i];
+	}
+}
+
+/*
+ * Inverse of the FLOOKUP above
+ * args: fvalue - function value to match
+ * returns:  p  closest to that value
+ * Tested u:OK
+ */
+const struct fixpoint *
+tfrc_flookup_reverse(const struct fixpoint *fvalue)
+{
+	static struct fixpoint x;
+	int ctr;
+
+	if (fixpoint_cmp(fvalue, &flarge_table[1]) >= 0) {
+		/* 1.0 */
+		x.num = 1;
+		x.denom = 1;
+		return &x;
+	} else if (fixpoint_cmp(fvalue, &flarge_table[sizeof(flarge_table) /
+	    sizeof(flarge_table[0]) - 1]) >= 0) {
+		ctr = sizeof(flarge_table) / sizeof(flarge_table[0]) - 1;
+		while (ctr > 1 && fixpoint_cmp(fvalue, &flarge_table[ctr]) >= 0)
+			ctr--;
+
+		/* round to smallest */
+		ctr = ctr + 1;
+    
+		/* round to nearest */
+		return &flarge_table[ctr];
+	} else if (fixpoint_cmp(fvalue, &fsmall_table[0]) >= 0) {
+		ctr = 0;
+		while (ctr < sizeof(fsmall_table) / sizeof(fsmall_table[0]) &&
+		    fixpoint_cmp(fvalue, &fsmall_table[ctr]) > 0)
+			ctr++;
+		x = fsmallstep;
+		x.num *= ctr;
+		return &x;
+	}
+	return &fsmallstep;
+}
+++ sys/netinet/dccp_tfrc.h	Thu Aug 24 05:28:54 2006
@@ -0,0 +1,245 @@
+/*	$KAME: dccp_tfrc.h,v 1.10 2005/10/26 11:36:49 nishida Exp $	*/
+
+/*
+ * 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    16
+#define TFRC_WIN_COUNT_PER_RTT  4
+#define TFRC_SMALLEST_P         0.00004
+/* 
+ * TFRC sender 
+ */
+
+/* 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 */
+TAILQ_HEAD(s_hist_head,s_hist_entry); 
+
+struct fixpoint {
+	long long num;
+	long long denom;
+};
+ 
+struct s_hist_entry {
+	TAILQ_ENTRY(s_hist_entry) linfo;	/* Tail queue. */
+	u_int64_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 */
+
+	struct fixpoint x;		/* Current sending rate */
+	struct fixpoint x_recv;	/* Receive rate */
+	struct fixpoint x_calc;	/* Calculated send (?) rate */ 
+
+	u_int16_t s;		/* Packet size */
+
+	u_int32_t rtt;		/* Estimate of current round trip time */
+	struct fixpoint p;	/* Current loss event rate */  
+	u_int8_t last_win_count;	/* Last window counter sent */
+	/* Timestamp of earliest packet with last_win_count value sent */
+	struct timeval t_last_win_count;
+	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 */
+	struct timeval t_ipi;	/* Interpacket (send) interval */
+	struct timeval delta;	/* Send timer delta */    
+
+	struct callout ch_stimer;	/* Handle to scheduled send timer */ 
+	struct callout ch_nftimer;	/* Handle to no feedback 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 *); 
+
+/*
+ * Free the sender side
+ * args: ccb - ccb of sender
+ */
+void tfrc_send_free(void *);
+
+/*
+ * 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 *, long);
+
+/*
+ * 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 *, int, long);
+
+/*
+ * 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 *, char *, int);
+
+#endif
+
+/* 
+ * TFRC Receiver 
+ */
+
+/* TFRC specific dccp options */
+#define TFRC_OPT_LOSS_RATE	192
+#define TFRC_OPT_LOSS_INTERVAL	193
+//#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 */
+/*
+ * seq_num x,y; if y-x is smaller than this number (note, wrap around) then
+ * y is newer than x
+ */
+#define TFRC_RECV_NEW_SEQ_RANGE 10000000
+/* number of later packets received before one is considered lost */
+#define TFRC_RECV_NUM_LATE_LOSS 3
+/* length(w[]) */
+#define TFRC_RECV_IVAL_F_LENGTH  8
+
+/* Packet history */
+TAILQ_HEAD(r_hist_head,r_hist_entry); 
+ 
+struct r_hist_entry {
+	TAILQ_ENTRY(r_hist_entry) linfo;	/* Tail queue. */
+	u_int64_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_int64_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 */
+
+	struct fixpoint p;	/* Loss event rate */
+
+	struct li_hist_head li_hist;	/* Loss interval history */
+
+	/*
+	 * Highest value of the window counter received when last feedback
+	 * was sent
+	 */
+	u_int8_t	last_counter;
+	/* Sequence number of the packet above */
+	u_int64_t	seq_last_counter;
+
+	/* Timestamp of when last feedback was sent */
+	struct timeval t_last_feedback;
+	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 *); 
+
+/* Free the receiver side
+ * args: ccb - ccb of recevier
+ */
+void tfrc_recv_free(void *);
+
+/*
+ * Tell TFRC that a packet has been received
+ * args: ccb  -  ccb block for current connection 
+ */
+void tfrc_recv_packet_recv(void *, char *, int);
+
+#endif
+
+#endif
+++ sys/netinet/dccp_tfrc_lookup.h	Fri Aug 18 04:58:10 2006
@@ -0,0 +1,1046 @@
+/*	$KAME: dccp_tfrc_lookup.h,v 1.8 2005/10/21 05:33:51 nishida Exp $	*/
+
+/*
+ * 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,
+ * INCIDENTALL, 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 struct fixpoint fsmall_table[] = {
+	{ 0LL, 1LL },					/* 0 */
+	{ 163305194960931LL, 100000000000000000LL },	/* 0.00163305194960931 */
+	{ 230956735363637LL, 100000000000000000LL },	/* 0.00230956735363637 */
+	{ 282873259487707LL, 100000000000000000LL },	/* 0.00282873259487707 */
+	{ 326645662574537LL, 100000000000000000LL },	/* 0.00326645662574537 */
+	{ 365214098377853LL, 100000000000000000LL },	/* 0.00365214098377853 */
+	{ 400086400001593LL, 100000000000000000LL },	/* 0.00400086400001593 */
+	{ 432158256340322LL, 100000000000000000LL },	/* 0.00432158256340322 */
+	{ 462013236858081LL, 100000000000000000LL },	/* 0.00462013236858081 */
+	{ 490056675498551LL, 100000000000000000LL },	/* 0.00490056675498551 */
+	{ 516583682704458LL, 100000000000000000LL },	/* 0.00516583682704458 */
+	{ 541817034936234LL, 100000000000000000LL },	/* 0.00541817034936234 */
+	{ 565929801070833LL, 100000000000000000LL },	/* 0.00565929801070833 */
+	{ 589059608718062LL, 100000000000000000LL },	/* 0.00589059608718062 */
+	{ 611318041778383LL, 100000000000000000LL },	/* 0.00611318041778383 */
+	{ 632797058060318LL, 100000000000000000LL },	/* 0.00632797058060318 */
+	{ 653573506415987LL, 100000000000000000LL },	/* 0.00653573506415987 */
+	{ 673712389086595LL, 100000000000000000LL },	/* 0.00673712389086595 */
+	{ 693269270671348LL, 100000000000000000LL },	/* 0.00693269270671348 */
+	{ 71229209166037LL, 10000000000000000LL },	/* 0.0071229209166037 */
+	{ 730822557103113LL, 100000000000000000LL },	/* 0.00730822557103113 */
+	{ 748897216079408LL, 100000000000000000LL },	/* 0.00748897216079408 */
+	{ 766548312170872LL, 100000000000000000LL },	/* 0.00766548312170872 */
+	{ 783804461648552LL, 100000000000000000LL },	/* 0.00783804461648552 */
+	{ 800691200203843LL, 100000000000000000LL },	/* 0.00800691200203843 */
+	{ 817231428085712LL, 100000000000000000LL },	/* 0.00817231428085712 */
+	{ 833445775806404LL, 100000000000000000LL },	/* 0.00833445775806404 */
+	{ 849352907081277LL, 100000000000000000LL },	/* 0.00849352907081277 */
+	{ 864969771687212LL, 100000000000000000LL },	/* 0.00864969771687212 */
+	{ 880311818001545LL, 100000000000000000LL },	/* 0.00880311818001545 */
+	{ 89539317281132LL, 10000000000000000LL },	/* 0.0089539317281132 */
+	{ 910226794349901LL, 100000000000000000LL },	/* 0.00910226794349901 */
+	{ 924824603277504LL, 100000000000000000LL },	/* 0.00924824603277504 */
+	{ 939197595370597LL, 100000000000000000LL },	/* 0.00939197595370597 */
+	{ 9533559389484LL, 1000000000000000LL },	/* 0.009533559389484 */
+	{ 967309059489451LL, 100000000000000000LL },	/* 0.00967309059489451 */
+	{ 981065713438519LL, 100000000000000000LL },	/* 0.00981065713438519 */
+	{ 994634052845154LL, 100000000000000000LL },	/* 0.00994634052845154 */
+	{ 100802168218855LL, 10000000000000000LL },	/* 0.0100802168218855 */
+	{ 102123570851299LL, 10000000000000000LL },	/* 0.0102123570851299 */
+	{ 103428278581192LL, 10000000000000000LL },	/* 0.0103428278581192 */
+	{ 10471691544469LL, 1000000000000000LL },	/* 0.010471691544469 */
+	{ 105990067626397LL, 10000000000000000LL },	/* 0.0105990067626397 */
+	{ 107248286596785LL, 10000000000000000LL },	/* 0.0107248286596785 */
+	{ 108492091922994LL, 10000000000000000LL },	/* 0.0108492091922994 */
+	{ 109721973793658LL, 10000000000000000LL },	/* 0.0109721973793658 */
+	{ 110938395292506LL, 10000000000000000LL },	/* 0.0110938395292506 */
+	{ 112141794450653LL, 10000000000000000LL },	/* 0.0112141794450653 */
+	{ 113332586103332LL, 10000000000000000LL },	/* 0.0113332586103332 */
+	{ 114511163573388LL, 10000000000000000LL },	/* 0.0114511163573388 */
+	{ 115677900200876LL, 10000000000000000LL },	/* 0.0115677900200876 */
+	{ 116833150735621LL, 10000000000000000LL },	/* 0.0116833150735621 */
+	{ 11797725260745LL, 1000000000000000LL },	/* 0.011797725260745 */
+	{ 119110527086984LL, 10000000000000000LL },	/* 0.0119110527086984 */
+	{ 120233280348285LL, 10000000000000000LL },	/* 0.0120233280348285 */
+	{ 121345804443331LL, 10000000000000000LL },	/* 0.0121345804443331 */
+	{ 122448378197079LL, 10000000000000000LL },	/* 0.0122448378197079 */
+	{ 123541268030903LL, 10000000000000000LL },	/* 0.0123541268030903 */
+	{ 124624728721277LL, 10000000000000000LL },	/* 0.0124624728721277 */
+	{ 125699004099823LL, 10000000000000000LL },	/* 0.0125699004099823 */
+	{ 126764327700174LL, 10000000000000000LL },	/* 0.0126764327700174 */
+	{ 127820923356504LL, 10000000000000000LL },	/* 0.0127820923356504 */
+	{ 128869005758063LL, 10000000000000000LL },	/* 0.0128869005758063 */
+	{ 129908780963614LL, 10000000000000000LL },	/* 0.0129908780963614 */
+	{ 130940446879258LL, 10000000000000000LL },	/* 0.0130940446879258 */
+	{ 131964193702772LL, 10000000000000000LL },	/* 0.0131964193702772 */
+	{ 1329802043373LL, 100000000000000LL },	/* 0.01329802043373 */
+	{ 133988654776928LL, 10000000000000000LL },	/* 0.0133988654776928 */
+	{ 134989714466453LL, 10000000000000000LL },	/* 0.0134989714466453 */
+	{ 135983546637418LL, 10000000000000000LL },	/* 0.0135983546637418 */
+	{ 136970308622305LL, 10000000000000000LL },	/* 0.0136970308622305 */
+	{ 137950152148595LL, 10000000000000000LL },	/* 0.0137950152148595 */
+	{ 138923223614248LL, 10000000000000000LL },	/* 0.0138923223614248 */
+	{ 139889664346018LL, 10000000000000000LL },	/* 0.0139889664346018 */
+	{ 140849610841894LL, 10000000000000000LL },	/* 0.0140849610841894 */
+	{ 141803194998843LL, 10000000000000000LL },	/* 0.0141803194998843 */
+	{ 142750544326924LL, 10000000000000000LL },	/* 0.0142750544326924 */
+	{ 143691782150771LL, 10000000000000000LL },	/* 0.0143691782150771 */
+	{ 144627027799322LL, 10000000000000000LL },	/* 0.0144627027799322 */
+	{ 145556396784645LL, 10000000000000000LL },	/* 0.0145556396784645 */
+	{ 146480000970597LL, 10000000000000000LL },	/* 0.0146480000970597 */
+	{ 14739794873203LL, 1000000000000000LL },	/* 0.014739794873203 */
+	{ 148310345105165LL, 10000000000000000LL },	/* 0.0148310345105165 */
+	{ 149217291929752LL, 10000000000000000LL },	/* 0.0149217291929752 */
+	{ 150118887983524LL, 10000000000000000LL },	/* 0.0150118887983524 */
+	{ 151015229109484LL, 10000000000000000LL },	/* 0.0151015229109484 */
+	{ 151906408336458LL, 10000000000000000LL },	/* 0.0151906408336458 */
+	{ 152792515993363LL, 10000000000000000LL },	/* 0.0152792515993363 */
+	{ 153673639817576LL, 10000000000000000LL },	/* 0.0153673639817576 */
+	{ 154549865057777LL, 10000000000000000LL },	/* 0.0154549865057777 */
+	{ 155421274571605LL, 10000000000000000LL },	/* 0.0155421274571605 */
+	{ 156287948918437LL, 10000000000000000LL },	/* 0.0156287948918437 */
+	{ 157149966447599LL, 10000000000000000LL },	/* 0.0157149966447599 */
+	{ 158007403382266LL, 10000000000000000LL },	/* 0.0158007403382266 */
+	{ 158860333899315LL, 10000000000000000LL },	/* 0.0158860333899315 */
+	{ 159708830205358LL, 10000000000000000LL },	/* 0.0159708830205358 */
+	{ 160552962609193LL, 10000000000000000LL },	/* 0.0160552962609193 */
+	{ 161392799590851LL, 10000000000000000LL },	/* 0.0161392799590851 */
+	{ 162228407867464LL, 10000000000000000LL },	/* 0.0162228407867464 */
+	{ 163059852456097LL, 10000000000000000LL },	/* 0.0163059852456097 */
+	{ 163887196733746LL, 10000000000000000LL },	/* 0.0163887196733746 */
+	{ 164710502494631LL, 10000000000000000LL },	/* 0.0164710502494631 */
+	{ 165529830004946LL, 10000000000000000LL },	/* 0.0165529830004946 */
+	{ 166345238055199LL, 10000000000000000LL },	/* 0.0166345238055199 */
+	{ 167156784010267LL, 10000000000000000LL },	/* 0.0167156784010267 */
+	{ 167964523857295LL, 10000000000000000LL },	/* 0.0167964523857295 */
+	{ 168768512251538LL, 10000000000000000LL },	/* 0.0168768512251538 */
+	{ 169568802560266LL, 10000000000000000LL },	/* 0.0169568802560266 */
+	{ 170365446904829LL, 10000000000000000LL },	/* 0.0170365446904829 */
+	{ 171158496200964LL, 10000000000000000LL },	/* 0.0171158496200964 */
+	{ 171948000197448LL, 10000000000000000LL },	/* 0.0171948000197448 */
+	{ 172734007513173LL, 10000000000000000LL },	/* 0.0172734007513173 */
+	{ 173516565672713LL, 10000000000000000LL },	/* 0.0173516565672713 */
+	{ 174295721140473LL, 10000000000000000LL },	/* 0.0174295721140473 */
+	{ 17507151935348LL, 1000000000000000LL },	/* 0.017507151935348 */
+	{ 175844004752871LL, 10000000000000000LL },	/* 0.0175844004752871 */
+	{ 17661322081417LL, 1000000000000000LL },	/* 0.017661322081417 */
+	{ 177379210076372LL, 10000000000000000LL },	/* 0.0177379210076372 */
+	{ 178142014169926LL, 10000000000000000LL },	/* 0.0178142014169926 */
+	{ 178901673843644LL, 10000000000000000LL },	/* 0.0178901673843644 */
+	{ 179658228990597LL, 10000000000000000LL },	/* 0.0179658228990597 */
+	{ 180411718673042LL, 10000000000000000LL },	/* 0.0180411718673042 */
+	{ 181162181146423LL, 10000000000000000LL },	/* 0.0181162181146423 */
+	{ 181909653882486LL, 10000000000000000LL },	/* 0.0181909653882486 */
+	{ 182654173591552LL, 10000000000000000LL },	/* 0.0182654173591552 */
+	{ 183395776243984LL, 10000000000000000LL },	/* 0.0183395776243984 */
+	{ 18413449709088LL, 1000000000000000LL },	/* 0.018413449709088 */
+	{ 184870370684027LL, 10000000000000000LL },	/* 0.0184870370684027 */
+	{ 185603430895154LL, 10000000000000000LL },	/* 0.0185603430895154 */
+	{ 186333710934504LL, 10000000000000000LL },	/* 0.0186333710934504 */
+	{ 187061243368762LL, 10000000000000000LL },	/* 0.0187061243368762 */
+	{ 187786060138361LL, 10000000000000000LL },	/* 0.0187786060138361 */
+	{ 188508192574198LL, 10000000000000000LL },	/* 0.0188508192574198 */
+	{ 189227671413778LL, 10000000000000000LL },	/* 0.0189227671413778 */
+	{ 189944526816812LL, 10000000000000000LL },	/* 0.0189944526816812 */
+	{ 190658788380296LL, 10000000000000000LL },	/* 0.0190658788380296 */
+	{ 19137048515308LL, 1000000000000000LL },	/* 0.019137048515308 */
+	{ 192079645649969LL, 10000000000000000LL },	/* 0.0192079645649969 */
+	{ 192786297865344LL, 10000000000000000LL },	/* 0.0192786297865344 */
+	{ 193490469286358LL, 10000000000000000LL },	/* 0.0193490469286358 */
+	{ 194192186905687LL, 10000000000000000LL },	/* 0.0194192186905687 */
+	{ 194891477233888LL, 10000000000000000LL },	/* 0.0194891477233888 */
+	{ 195588366311352LL, 10000000000000000LL },	/* 0.0195588366311352 */
+	{ 196282879719884LL, 10000000000000000LL },	/* 0.0196282879719884 */
+	{ 196975042593915LL, 10000000000000000LL },	/* 0.0196975042593915 */
+	{ 197664879631372LL, 10000000000000000LL },	/* 0.0197664879631372 */
+	{ 1983524151042LL, 100000000000000LL },	/* 0.01983524151042 */
+	{ 199037672868568LL, 10000000000000000LL },	/* 0.0199037672868568 */
+	{ 199720676374761LL, 10000000000000000LL },	/* 0.0199720676374761 */
+	{ 200401448676771LL, 10000000000000000LL },	/* 0.0200401448676771 */
+	{ 2010800124416LL, 100000000000000LL },	/* 0.02010800124416 */
+	{ 20175638995828LL, 1000000000000000LL },	/* 0.020175638995828 */
+	{ 202430603146631LL, 10000000000000000LL },	/* 0.0202430603146631 */
+	{ 203102673565755LL, 10000000000000000LL },	/* 0.0203102673565755 */
+	{ 203772622422282LL, 10000000000000000LL },	/* 0.0203772622422282 */
+	{ 204440470578377LL, 10000000000000000LL },	/* 0.0204440470578377 */
+	{ 205106238559511LL, 10000000000000000LL },	/* 0.0205106238559511 */
+	{ 205769946562011LL, 10000000000000000LL },	/* 0.0205769946562011 */
+	{ 206431614460395LL, 10000000000000000LL },	/* 0.0206431614460395 */
+	{ 207091261814494LL, 10000000000000000LL },	/* 0.0207091261814494 */
+	{ 207748907876375LL, 10000000000000000LL },	/* 0.0207748907876375 */
+	{ 20840457159707LL, 1000000000000000LL },	/* 0.020840457159707 */
+	{ 20905827163312LL, 1000000000000000LL },	/* 0.020905827163312 */
+	{ 209710026352927LL, 10000000000000000LL },	/* 0.0209710026352927 */
+	{ 210359853842945LL, 10000000000000000LL },	/* 0.0210359853842945 */
+	{ 211007771913689LL, 10000000000000000LL },	/* 0.0211007771913689 */
+	{ 211653798105588LL, 10000000000000000LL },	/* 0.0211653798105588 */
+	{ 212297949694677LL, 10000000000000000LL },	/* 0.0212297949694677 */
+	{ 212940243698132LL, 10000000000000000LL },	/* 0.0212940243698132 */
+	{ 213580696879667LL, 10000000000000000LL },	/* 0.0213580696879667 */
+	{ 214219325754774LL, 10000000000000000LL },	/* 0.0214219325754774 */
+	{ 214856146595837LL, 10000000000000000LL },	/* 0.0214856146595837 */
+	{ 215491175437103LL, 10000000000000000LL },	/* 0.0215491175437103 */
+	{ 216124428079525LL, 10000000000000000LL },	/* 0.0216124428079525 */
+	{ 216755920095483LL, 10000000000000000LL },	/* 0.0216755920095483 */
+	{ 217385666833377LL, 10000000000000000LL },	/* 0.0217385666833377 */
+	{ 218013683422109LL, 10000000000000000LL },	/* 0.0218013683422109 */
+	{ 218639984775441LL, 10000000000000000LL },	/* 0.0218639984775441 */
+	{ 219264585596254LL, 10000000000000000LL },	/* 0.0219264585596254 */
+	{ 219887500380688LL, 10000000000000000LL },	/* 0.0219887500380688 */
+	{ 220508743422187LL, 10000000000000000LL },	/* 0.0220508743422187 */
+	{ 221128328815438LL, 10000000000000000LL },	/* 0.0221128328815438 */
+	{ 22174627046021LL, 1000000000000000LL },	/* 0.022174627046021 */
+	{ 22236258206511LL, 1000000000000000LL },	/* 0.022236258206511 */
+	{ 222977277151227LL, 10000000000000000LL },	/* 0.0222977277151227 */
+	{ 223590369055709LL, 10000000000000000LL },	/* 0.0223590369055709 */
+	{ 224201870935234LL, 10000000000000000LL },	/* 0.0224201870935234 */
+	{ 224811795769409LL, 10000000000000000LL },	/* 0.0224811795769409 */
+	{ 225420156364085LL, 10000000000000000LL },	/* 0.0225420156364085 */
+	{ 226026965354587LL, 10000000000000000LL },	/* 0.0226026965354587 */
+	{ 226632235208875LL, 10000000000000000LL },	/* 0.0226632235208875 */
+	{ 227235978230625LL, 10000000000000000LL },	/* 0.0227235978230625 */
+	{ 22783820656224LL, 1000000000000000LL },	/* 0.022783820656224 */
+	{ 228438932187787LL, 10000000000000000LL },	/* 0.0228438932187787 */
+	{ 229038166935873LL, 10000000000000000LL },	/* 0.0229038166935873 */
+	{ 229635922482444LL, 10000000000000000LL },	/* 0.0229635922482444 */
+	{ 230232210353529LL, 10000000000000000LL },	/* 0.0230232210353529 */
+	{ 230827041927913LL, 10000000000000000LL },	/* 0.0230827041927913 */
+	{ 231420428439758LL, 10000000000000000LL },	/* 0.0231420428439758 */
+	{ 232012380981154LL, 10000000000000000LL },	/* 0.0232012380981154 */
+	{ 232602910504621LL, 10000000000000000LL },	/* 0.0232602910504621 */
+	{ 233192027825551LL, 10000000000000000LL },	/* 0.0233192027825551 */
+	{ 233779743624595LL, 10000000000000000LL },	/* 0.0233779743624595 */
+	{ 234366068449998LL, 10000000000000000LL },	/* 0.0234366068449998 */
+	{ 234951012719883LL, 10000000000000000LL },	/* 0.0234951012719883 */
+	{ 235534586724479LL, 10000000000000000LL },	/* 0.0235534586724479 */
+	{ 236116800628313LL, 10000000000000000LL },	/* 0.0236116800628313 */
+	{ 236697664472338LL, 10000000000000000LL },	/* 0.0236697664472338 */
+	{ 237277188176025LL, 10000000000000000LL },	/* 0.0237277188176025 */
+	{ 23785538153941LL, 1000000000000000LL },	/* 0.023785538153941 */
+	{ 238432254245091LL, 10000000000000000LL },	/* 0.0238432254245091 */
+	{ 239007815860187LL, 10000000000000000LL },	/* 0.0239007815860187 */
+	{ 239582075838253LL, 10000000000000000LL },	/* 0.0239582075838253 */
+	{ 240155043521156LL, 10000000000000000LL },	/* 0.0240155043521156 */
+	{ 240726728140909LL, 10000000000000000LL },	/* 0.0240726728140909 */
+	{ 241297138821471LL, 10000000000000000LL },	/* 0.0241297138821471 */
+	{ 241866284580502LL, 10000000000000000LL },	/* 0.0241866284580502 */
+	{ 24243417433109LL, 1000000000000000LL },	/* 0.024243417433109 */
+	{ 243000816883436LL, 10000000000000000LL },	/* 0.0243000816883436 */
+	{ 243566220946503LL, 10000000000000000LL },	/* 0.0243566220946503 */
+	{ 244130395129642LL, 10000000000000000LL },	/* 0.0244130395129642 */
+	{ 244693347944169LL, 10000000000000000LL },	/* 0.0244693347944169 */
+	{ 245255087804923LL, 10000000000000000LL },	/* 0.0245255087804923 */
+	{ 245815623031787LL, 10000000000000000LL },	/* 0.0245815623031787 */
+	{ 246374961851176LL, 10000000000000000LL },	/* 0.0246374961851176 */
+	{ 246933112397499LL, 10000000000000000LL },	/* 0.0246933112397499 */
+	{ 247490082714593LL, 10000000000000000LL },	/* 0.0247490082714593 */
+	{ 248045880757123LL, 10000000000000000LL },	/* 0.0248045880757123 */
+	{ 248600514391958LL, 10000000000000000LL },	/* 0.0248600514391958 */
+	{ 249153991399521LL, 10000000000000000LL },	/* 0.0249153991399521 */
+	{ 249706319475108LL, 10000000000000000LL },	/* 0.0249706319475108 */
+	{ 250257506230185LL, 10000000000000000LL },	/* 0.0250257506230185 */
+	{ 25080755919366LL, 1000000000000000LL },	/* 0.025080755919366 */
+	{ 251356485813126LL, 10000000000000000LL },	/* 0.0251356485813126 */
+	{ 251904293456085LL, 10000000000000000LL },	/* 0.0251904293456085 */
+	{ 252450989411148LL, 10000000000000000LL },	/* 0.0252450989411148 */
+	{ 252996580889205LL, 10000000000000000LL },	/* 0.0252996580889205 */
+	{ 253541075024583LL, 10000000000000000LL },	/* 0.0253541075024583 */
+	{ 254084478876176LL, 10000000000000000LL },	/* 0.0254084478876176 */
+	{ 254626799428553LL, 10000000000000000LL },	/* 0.0254626799428553 */
+	{ 25516804359305LL, 1000000000000000LL },	/* 0.025516804359305 */
+	{ 255708218208836LL, 10000000000000000LL },	/* 0.0255708218208836 */
+	{ 256247330043961LL, 10000000000000000LL },	/* 0.0256247330043961 */
+	{ 256785385796388LL, 10000000000000000LL },	/* 0.0256785385796388 */
+	{ 257322392095LL, 10000000000000LL },	/* 0.0257322392095 */
+	{ 257858355500594LL, 10000000000000000LL },	/* 0.0257858355500594 */
+	{ 25839328250685LL, 1000000000000000LL },	/* 0.025839328250685 */
+	{ 258927179541294LL, 10000000000000000LL },	/* 0.0258927179541294 */
+	{ 259460052966225LL, 10000000000000000LL },	/* 0.0259460052966225 */
+	{ 259991909079647LL, 10000000000000000LL },	/* 0.0259991909079647 */
+	{ 260522754116166LL, 10000000000000000LL },	/* 0.0260522754116166 */
+	{ 26105259424788LL, 1000000000000000LL },	/* 0.026105259424788 */
+	{ 261581435585253LL, 10000000000000000LL },	/* 0.0261581435585253 */
+	{ 262109284177969LL, 10000000000000000LL },	/* 0.0262109284177969 */
+	{ 262636146015774LL, 10000000000000000LL },	/* 0.0262636146015774 */
+	{ 263162027029303LL, 10000000000000000LL },	/* 0.0263162027029303 */
+	{ 263686933090892LL, 10000000000000000LL },	/* 0.0263686933090892 */
+	{ 264210870015373LL, 10000000000000000LL },	/* 0.0264210870015373 */
+	{ 264733843560862LL, 10000000000000000LL },	/* 0.0264733843560862 */
+	{ 265255859429526LL, 10000000000000000LL },	/* 0.0265255859429526 */
+	{ 265776923268339LL, 10000000000000000LL },	/* 0.0265776923268339 */
+	{ 266297040669827LL, 10000000000000000LL },	/* 0.0266297040669827 */
+	{ 266816217172798LL, 10000000000000000LL },	/* 0.0266816217172798 */
+	{ 26733445826306LL, 1000000000000000LL },	/* 0.026733445826306 */
+	{ 267851769374128LL, 10000000000000000LL },	/* 0.0267851769374128 */
+	{ 268368155887916LL, 10000000000000000LL },	/* 0.0268368155887916 */
+	{ 26888362313542LL, 1000000000000000LL },	/* 0.026888362313542 */
+	{ 269398176397387LL, 10000000000000000LL },	/* 0.0269398176397387 */
+	{ 269911820904977LL, 10000000000000000LL },	/* 0.0269911820904977 */
+	{ 270424561840408LL, 10000000000000000LL },	/* 0.0270424561840408 */
+	{ 270936404337596LL, 10000000000000000LL },	/* 0.0270936404337596 */
+	{ 271447353482779LL, 10000000000000000LL },	/* 0.0271447353482779 */
+	{ 271957414315136LL, 10000000000000000LL },	/* 0.0271957414315136 */
+	{ 272466591827389LL, 10000000000000000LL },	/* 0.0272466591827389 */
+	{ 272974890966405LL, 10000000000000000LL },	/* 0.0272974890966405 */
+	{ 273482316633775LL, 10000000000000000LL },	/* 0.0273482316633775 */
+	{ 273988873686397LL, 10000000000000000LL },	/* 0.0273988873686397 */
+	{ 27449456693704LL, 1000000000000000LL },	/* 0.027449456693704 */
+	{ 274999401154902LL, 10000000000000000LL },	/* 0.0274999401154902 */
+	{ 27550338106616LL, 1000000000000000LL },	/* 0.027550338106616 */
+	{ 276006511354511LL, 10000000000000000LL },	/* 0.0276006511354511 */
+	{ 2765087966617LL, 100000000000000LL },	/* 0.02765087966617 */
+	{ 277010241588047LL, 10000000000000000LL },	/* 0.0277010241588047 */
+	{ 27751085069296LL, 1000000000000000LL },	/* 0.027751085069296 */
+	{ 278010628495439LL, 10000000000000000LL },	/* 0.0278010628495439 */
+	{ 27850957947458LL, 1000000000000000LL },	/* 0.027850957947458 */
+	{ 279007708070058LL, 10000000000000000LL },	/* 0.0279007708070058 */
+	{ 279505018682618LL, 10000000000000000LL },	/* 0.0279505018682618 */
+	{ 280001515674544LL, 10000000000000000LL },	/* 0.0280001515674544 */
+	{ 280497203370128LL, 10000000000000000LL },	/* 0.0280497203370128 */
+	{ 280992086056135LL, 10000000000000000LL },	/* 0.0280992086056135 */
+	{ 28148616798225LL, 1000000000000000LL },	/* 0.028148616798225 */
+	{ 281979453361527LL, 10000000000000000LL },	/* 0.0281979453361527 */
+	{ 28247194637083LL, 1000000000000000LL },	/* 0.028247194637083 */
+	{ 282963651151265LL, 10000000000000000LL },	/* 0.0282963651151265 */
+	{ 283454571808605LL, 10000000000000000LL },	/* 0.0283454571808605 */
+	{ 283944712413708LL, 10000000000000000LL },	/* 0.0283944712413708 */
+	{ 284434077002936LL, 10000000000000000LL },	/* 0.0284434077002936 */
+	{ 284922669578557LL, 10000000000000000LL },	/* 0.0284922669578557 */
+	{ 285410494109145LL, 10000000000000000LL },	/* 0.0285410494109145 */
+	{ 285897554529981LL, 10000000000000000LL },	/* 0.0285897554529981 */
+	{ 286383854743433LL, 10000000000000000LL },	/* 0.0286383854743433 */
+	{ 286869398619349LL, 10000000000000000LL },	/* 0.0286869398619349 */
+	{ 287354189995426LL, 10000000000000000LL },	/* 0.0287354189995426 */
+	{ 287838232677585LL, 10000000000000000LL },	/* 0.0287838232677585 */
+	{ 288321530440338LL, 10000000000000000LL },	/* 0.0288321530440338 */
+	{ 288804087027148LL, 10000000000000000LL },	/* 0.0288804087027148 */
+	{ 289285906150784LL, 10000000000000000LL },	/* 0.0289285906150784 */
+	{ 289766991493673LL, 10000000000000000LL },	/* 0.0289766991493673 */
+	{ 290247346708242LL, 10000000000000000LL },	/* 0.0290247346708242 */
+	{ 290726975417263LL, 10000000000000000LL },	/* 0.0290726975417263 */
+	{ 291205881214181LL, 10000000000000000LL },	/* 0.0291205881214181 */
+	{ 291684067663454LL, 10000000000000000LL },	/* 0.0291684067663454 */
+	{ 292161538300869LL, 10000000000000000LL },	/* 0.0292161538300869 */
+	{ 29263829663387LL, 1000000000000000LL },	/* 0.029263829663387 */
+	{ 293114346141869LL, 10000000000000000LL },	/* 0.0293114346141869 */
+	{ 293589690276564LL, 10000000000000000LL },	/* 0.0293589690276564 */
+	{ 29406433246224LL, 1000000000000000LL },	/* 0.029406433246224 */
+	{ 294538276096075LL, 10000000000000000LL },	/* 0.0294538276096075 */
+	{ 295011524548438LL, 10000000000000000LL },	/* 0.0295011524548438 */
+	{ 295484081163186LL, 10000000000000000LL },	/* 0.0295484081163186 */
+	{ 29595594925795LL, 1000000000000000LL },	/* 0.029595594925795 */
+	{ 296427132124425LL, 10000000000000000LL },	/* 0.0296427132124425 */
+	{ 29689763302865LL, 1000000000000000LL },	/* 0.029689763302865 */
+	{ 297367455211288LL, 10000000000000000LL },	/* 0.0297367455211288 */
+	{ 297836601887898LL, 10000000000000000LL },	/* 0.0297836601887898 */
+	{ 298305076249208LL, 10000000000000000LL },	/* 0.0298305076249208 */
+	{ 298772881461383LL, 10000000000000000LL },	/* 0.0298772881461383 */
+	{ 299240020666283LL, 10000000000000000LL },	/* 0.0299240020666283 */
+	{ 299706496981729LL, 10000000000000000LL },	/* 0.0299706496981729 */
+	{ 300172313501756LL, 10000000000000000LL },	/* 0.0300172313501756 */
+	{ 300637473296863LL, 10000000000000000LL },	/* 0.0300637473296863 */
+	{ 301101979414268LL, 10000000000000000LL },	/* 0.0301101979414268 */
+	{ 30156583487815LL, 1000000000000000LL },	/* 0.030156583487815 */
+	{ 302029042689891LL, 10000000000000000LL },	/* 0.0302029042689891 */
+	{ 302491605828317LL, 10000000000000000LL },	/* 0.0302491605828317 */
+	{ 302953527249935LL, 10000000000000000LL },	/* 0.0302953527249935 */
+	{ 303414809889161LL, 10000000000000000LL },	/* 0.0303414809889161 */
+	{ 303875456658556LL, 10000000000000000LL },	/* 0.0303875456658556 */
+	{ 304335470449047LL, 10000000000000000LL },	/* 0.0304335470449047 */
+	{ 304794854130155LL, 10000000000000000LL },	/* 0.0304794854130155 */
+	{ 305253610550213LL, 10000000000000000LL },	/* 0.0305253610550213 */
+	{ 305711742536585LL, 10000000000000000LL },	/* 0.0305711742536585 */
+	{ 30616925289588LL, 1000000000000000LL },	/* 0.030616925289588 */
+	{ 306626144414165LL, 10000000000000000LL },	/* 0.0306626144414165 */
+	{ 307082419857174LL, 10000000000000000LL },	/* 0.0307082419857174 */
+	{ 307538081970513LL, 10000000000000000LL },	/* 0.0307538081970513 */
+	{ 307993133479868LL, 10000000000000000LL },	/* 0.0307993133479868 */
+	{ 308447577091201LL, 10000000000000000LL },	/* 0.0308447577091201 */
+	{ 308901415490953LL, 10000000000000000LL },	/* 0.0308901415490953 */
+	{ 309354651346236LL, 10000000000000000LL },	/* 0.0309354651346236 */
+	{ 309807287305032LL, 10000000000000000LL },	/* 0.0309807287305032 */
+	{ 310259325996379LL, 10000000000000000LL },	/* 0.0310259325996379 */
+	{ 310710770030561LL, 10000000000000000LL },	/* 0.0310710770030561 */
+	{ 311161621999296LL, 10000000000000000LL },	/* 0.0311161621999296 */
+	{ 311611884475917LL, 10000000000000000LL },	/* 0.0311611884475917 */
+	{ 312061560015558LL, 10000000000000000LL },	/* 0.0312061560015558 */
+	{ 312510651155326LL, 10000000000000000LL },	/* 0.0312510651155326 */
+	{ 312959160414486LL, 10000000000000000LL },	/* 0.0312959160414486 */
+	{ 31340709029463LL, 1000000000000000LL },	/* 0.031340709029463 */
+	{ 313854443279853LL, 10000000000000000LL },	/* 0.0313854443279853 */
+	{ 31430122183692LL, 1000000000000000LL },	/* 0.031430122183692 */
+	{ 314747428415438LL, 10000000000000000LL },	/* 0.0314747428415438 */
+	{ 315193065448019LL, 10000000000000000LL },	/* 0.0315193065448019 */
+	{ 315638135350446LL, 10000000000000000LL },	/* 0.0315638135350446 */
+	{ 316082640521835LL, 10000000000000000LL },	/* 0.0316082640521835 */
+	{ 316526583344794LL, 10000000000000000LL },	/* 0.0316526583344794 */
+	{ 316969966185581LL, 10000000000000000LL },	/* 0.0316969966185581 */
+	{ 317412791394264LL, 10000000000000000LL },	/* 0.0317412791394264 */
+	{ 317855061304867LL, 10000000000000000LL },	/* 0.0317855061304867 */
+	{ 318296778235532LL, 10000000000000000LL },	/* 0.0318296778235532 */
+	{ 318737944488663LL, 10000000000000000LL },	/* 0.0318737944488663 */
+	{ 319178562351077LL, 10000000000000000LL },	/* 0.0319178562351077 */
+	{ 319618634094152LL, 10000000000000000LL },	/* 0.0319618634094152 */
+	{ 320058161973967LL, 10000000000000000LL },	/* 0.0320058161973967 */
+	{ 320497148231454LL, 10000000000000000LL },	/* 0.0320497148231454 */
+	{ 320935595092531LL, 10000000000000000LL },	/* 0.0320935595092531 */
+	{ 321373504768247LL, 10000000000000000LL },	/* 0.0321373504768247 */
+	{ 32181087945492LL, 1000000000000000LL },	/* 0.032181087945492 */
+	{ 32224772133427LL, 1000000000000000LL },	/* 0.032224772133427 */
+	{ 32268403257356LL, 1000000000000000LL },	/* 0.032268403257356 */
+	{ 323119815325724LL, 10000000000000000LL },	/* 0.0323119815325724 */
+	{ 323555071729501LL, 10000000000000000LL },	/* 0.0323555071729501 */
+	{ 323989803909566LL, 10000000000000000LL },	/* 0.0323989803909566 */
+	{ 324424013976657LL, 10000000000000000LL },	/* 0.0324424013976657 */
+	{ 324857704027703LL, 10000000000000000LL },	/* 0.0324857704027703 */
+	{ 325290876145952LL, 10000000000000000LL },	/* 0.0325290876145952 */
+	{ 32572353240109LL, 1000000000000000LL },	/* 0.032572353240109 */
+	{ 32615567484937LL, 1000000000000000LL },	/* 0.032615567484937 */
+	{ 326587305533729LL, 10000000000000000LL },	/* 0.0326587305533729 */
+	{ 32701842648391LL, 1000000000000000LL },	/* 0.032701842648391 */
+	{ 327449039716579LL, 10000000000000000LL },	/* 0.0327449039716579 */
+	{ 327879147235444LL, 10000000000000000LL },	/* 0.0327879147235444 */
+	{ 328308751031372LL, 10000000000000000LL },	/* 0.0328308751031372 */
+	{ 328737853082498LL, 10000000000000000LL },	/* 0.0328737853082498 */
+	{ 329166455354347LL, 10000000000000000LL },	/* 0.0329166455354347 */
+	{ 329594559799936LL, 10000000000000000LL },	/* 0.0329594559799936 */
+	{ 330022168359894LL, 10000000000000000LL },	/* 0.0330022168359894 */
+	{ 330449282962565LL, 10000000000000000LL },	/* 0.0330449282962565 */
+	{ 330875905524119LL, 10000000000000000LL },	/* 0.0330875905524119 */
+	{ 331302037948658LL, 10000000000000000LL },	/* 0.0331302037948658 */
+	{ 331727682128323LL, 10000000000000000LL },	/* 0.0331727682128323 */
+	{ 332152839943397LL, 10000000000000000LL },	/* 0.0332152839943397 */
+	{ 332577513262411LL, 10000000000000000LL },	/* 0.0332577513262411 */
+	{ 333001703942243LL, 10000000000000000LL },	/* 0.0333001703942243 */
+	{ 333425413828221LL, 10000000000000000LL },	/* 0.0333425413828221 */
+	{ 333848644754222LL, 10000000000000000LL },	/* 0.0333848644754222 */
+	{ 334271398542773LL, 10000000000000000LL },	/* 0.0334271398542773 */
+	{ 334693677005146LL, 10000000000000000LL },	/* 0.0334693677005146 */
+	{ 335115481941457LL, 10000000000000000LL },	/* 0.0335115481941457 */
+	{ 335536815140761LL, 10000000000000000LL },	/* 0.0335536815140761 */
+	{ 335957678381145LL, 10000000000000000LL },	/* 0.0335957678381145 */
+	{ 336378073429825LL, 10000000000000000LL },	/* 0.0336378073429825 */
+	{ 336798002043235LL, 10000000000000000LL },	/* 0.0336798002043235 */
+	{ 337217465967119LL, 10000000000000000LL },	/* 0.0337217465967119 */
+	{ 337636466936625LL, 10000000000000000LL },	/* 0.0337636466936625 */
+	{ 338055006676391LL, 10000000000000000LL },	/* 0.0338055006676391 */
+	{ 338473086900635LL, 10000000000000000LL },	/* 0.0338473086900635 */
+	{ 338890709313242LL, 10000000000000000LL },	/* 0.0338890709313242 */
+	{ 33930787560785LL, 1000000000000000LL },	/* 0.033930787560785 */
+	{ 33972458746794LL, 1000000000000000LL },	/* 0.033972458746794 */
+	{ 340140846566914LL, 10000000000000000LL },	/* 0.0340140846566914 */
+	{ 340556654568185LL, 10000000000000000LL },	/* 0.0340556654568185 */
+	{ 340972013125256LL, 10000000000000000LL },	/* 0.0340972013125256 */
+	{ 341386923881805LL, 10000000000000000LL },	/* 0.0341386923881805 */
+	{ 341801388471764LL, 10000000000000000LL },	/* 0.0341801388471764 */
+	{ 342215408519403LL, 10000000000000000LL },	/* 0.0342215408519403 */
+	{ 342628985639403LL, 10000000000000000LL },	/* 0.0342628985639403 */
+	{ 343042121436941LL, 10000000000000000LL },	/* 0.0343042121436941 */
+	{ 343454817507766LL, 10000000000000000LL },	/* 0.0343454817507766 */
+	{ 343867075438276LL, 10000000000000000LL },	/* 0.0343867075438276 */
+	{ 344278896805592LL, 10000000000000000LL },	/* 0.0344278896805592 */
+	{ 344690283177636LL, 10000000000000000LL },	/* 0.0344690283177636 */
+	{ 345101236113208LL, 10000000000000000LL },	/* 0.0345101236113208 */
+	{ 345511757162053LL, 10000000000000000LL },	/* 0.0345511757162053 */
+	{ 345921847864941LL, 10000000000000000LL },	/* 0.0345921847864941 */
+	{ 346331509753735LL, 10000000000000000LL },	/* 0.0346331509753735 */
+	{ 346740744351467LL, 10000000000000000LL },	/* 0.0346740744351467 */
+	{ 347149553172402LL, 10000000000000000LL },	/* 0.0347149553172402 */
+	{ 347557937722115LL, 10000000000000000LL },	/* 0.0347557937722115 */
+	{ 347965899497558LL, 10000000000000000LL },	/* 0.0347965899497558 */
+	{ 348373439987127LL, 10000000000000000LL },	/* 0.0348373439987127 */
+	{ 348780560670734LL, 10000000000000000LL },	/* 0.0348780560670734 */
+	{ 349187263019868LL, 10000000000000000LL },	/* 0.0349187263019868 */
+	{ 34959354849767LL, 1000000000000000LL },	/* 0.034959354849767 */
+	{ 349999418558991LL, 10000000000000000LL },	/* 0.0349999418558991 */
+	{ 350404874650462LL, 10000000000000000LL },	/* 0.0350404874650462 */
+	{ 35080991821056LL, 1000000000000000LL },	/* 0.035080991821056 */
+	{ 351214550669666LL, 10000000000000000LL },	/* 0.0351214550669666 */
+	{ 351618773450133LL, 10000000000000000LL },	/* 0.0351618773450133 */
+	{ 352022587966348LL, 10000000000000000LL },	/* 0.0352022587966348 */
+	{ 352425995624795LL, 10000000000000000LL },	/* 0.0352425995624795 */
+	{ 352828997824113LL, 10000000000000000LL },	/* 0.0352828997824113 */
+	{ 35323159595516LL, 1000000000000000LL },	/* 0.035323159595516 */
+	{ 353633791401072LL, 10000000000000000LL },	/* 0.0353633791401072 */
+	{ 354035585537324LL, 10000000000000000LL },	/* 0.0354035585537324 */
+	{ 354436979731787LL, 10000000000000000LL },	/* 0.0354436979731787 */
+	{ 354837975344788LL, 10000000000000000LL },	/* 0.0354837975344788 */
+	{ 355238573729168LL, 10000000000000000LL },	/* 0.0355238573729168 */
+	{ 355638776230337LL, 10000000000000000LL },	/* 0.0355638776230337 */
+	{ 356038584186336LL, 10000000000000000LL },	/* 0.0356038584186336 */
+	{ 356437998927886LL, 10000000000000000LL },	/* 0.0356437998927886 */
+	{ 356837021778449LL, 10000000000000000LL },	/* 0.0356837021778449 */
+	{ 357235654054283LL, 10000000000000000LL },	/* 0.0357235654054283 */
+	{ 357633897064494LL, 10000000000000000LL },	/* 0.0357633897064494 */
+	{ 358031752111091LL, 10000000000000000LL },	/* 0.0358031752111091 */
+	{ 35842922048904LL, 1000000000000000LL },	/* 0.035842922048904 */
+	{ 358826303486317LL, 10000000000000000LL },	/* 0.0358826303486317 */
+	{ 359223002383961LL, 10000000000000000LL },	/* 0.0359223002383961 */
+	{ 359619318456125LL, 10000000000000000LL },	/* 0.0359619318456125 */
+	{ 360015252970127LL, 10000000000000000LL },	/* 0.0360015252970127 */
+	{ 360410807186503LL, 10000000000000000LL },	/* 0.0360410807186503 */
+	{ 360805982359056LL, 10000000000000000LL },	/* 0.0360805982359056 */
+	{ 361200779734907LL, 10000000000000000LL },	/* 0.0361200779734907 */
+	{ 361595200554543LL, 10000000000000000LL },	/* 0.0361595200554543 */
+	{ 361989246051867LL, 10000000000000000LL },	/* 0.0361989246051867 */
+	{ 362382917454249LL, 10000000000000000LL },	/* 0.0362382917454249 */
+	{ 362776215982569LL, 10000000000000000LL },	/* 0.0362776215982569 */
+	{ 36316914285127LL, 1000000000000000LL },	/* 0.036316914285127 */
+	{ 363561699268402LL, 10000000000000000LL },	/* 0.0363561699268402 */
+	{ 363953886435669LL, 10000000000000000LL },	/* 0.0363953886435669 */
+	{ 364345705548478LL, 10000000000000000LL },	/* 0.0364345705548478 */
+	{ 36473715779598LL, 1000000000000000LL },	/* 0.036473715779598 */
+	{ 365128244361123LL, 10000000000000000LL },	/* 0.0365128244361123 */
+	{ 365518966420688LL, 10000000000000000LL },	/* 0.0365518966420688 */
+	{ 365909325145341LL, 10000000000000000LL },	/* 0.0365909325145341 */
+	{ 366299321699675LL, 10000000000000000LL },	/* 0.0366299321699675 */
+	{ 366688957242252LL, 10000000000000000LL },	/* 0.0366688957242252 */
+	{ 367078232925648LL, 10000000000000000LL },	/* 0.0367078232925648 */
+	{ 367467149896497LL, 10000000000000000LL },	/* 0.0367467149896497 */
+	{ 367855709295533LL, 10000000000000000LL },	/* 0.0367855709295533 */
+	{ 368243912257629LL, 10000000000000000LL },	/* 0.0368243912257629 */
+	{ 368631759911844LL, 10000000000000000LL },	/* 0.0368631759911844 */
+	{ 369019253381463LL, 10000000000000000LL },	/* 0.0369019253381463 */
+	{ 369406393784034LL, 10000000000000000LL },	/* 0.0369406393784034 */
+	{ 369793182231416LL, 10000000000000000LL },	/* 0.0369793182231416 */
+	{ 370179619829813LL, 10000000000000000LL },	/* 0.0370179619829813 */
+	{ 370565707679816LL, 10000000000000000LL },	/* 0.0370565707679816 */
+	{ 370951446876444LL, 10000000000000000LL },	/* 0.0370951446876444 */
+	{ 371336838509182LL, 10000000000000000LL },	/* 0.0371336838509182 */
+	{ 371721883662021LL, 10000000000000000LL },	/* 0.0371721883662021 */
+	{ 371721883662021LL, 10000000000000000LL }	/* 0.0371721883662021 */
+};
+
+const struct fixpoint flarge_table[] = {
+	{ 243315981116462LL, 1000000000000LL },	/* 243.315981116462 */
+	{ 243315981116462LL, 1000000000000LL },	/* 243.315981116462 */
+	{ 239600361713695LL, 10000000000000LL },	/* 23.9600361713695 */
+	{ 69139329716018LL, 10000000000000LL },	/* 6.9139329716018 */
+	{ 316392425109494LL, 100000000000000LL },	/* 3.16392425109494 */
+	{ 186371728900425LL, 100000000000000LL },	/* 1.86371728900425 */
+	{ 127777777777778LL, 100000000000000LL },	/* 1.27777777777778 */
+	{ 964508403261589LL, 1000000000000000LL },	/* 0.964508403261589 */
+	{ 77581442422356LL, 100000000000000LL },	/* 0.77581442422356 */
+	{ 651853237448473LL, 1000000000000000LL },	/* 0.651853237448473 */
+	{ 564939170766789LL, 1000000000000000LL },	/* 0.564939170766789 */
+	{ 50087416614881LL, 100000000000000LL },	/* 0.50087416614881 */
+	{ 451762665758072LL, 1000000000000000LL },	/* 0.451762665758072 */
+	{ 412917778678493LL, 1000000000000000LL },	/* 0.412917778678493 */
+	{ 381404155091771LL, 1000000000000000LL },	/* 0.381404155091771 */
+	{ 355299463329141LL, 1000000000000000LL },	/* 0.355299463329141 */
+	{ 333296455886513LL, 1000000000000000LL },	/* 0.333296455886513 */
+	{ 314477147580053LL, 1000000000000000LL },	/* 0.314477147580053 */
+	{ 298178842729622LL, 1000000000000000LL },	/* 0.298178842729622 */
+	{ 283911535127666LL, 1000000000000000LL },	/* 0.283911535127666 */
+	{ 271305240150892LL, 1000000000000000LL },	/* 0.271305240150892 */
+	{ 260075403532531LL, 1000000000000000LL },	/* 0.260075403532531 */
+	{ 249999578782356LL, 1000000000000000LL },	/* 0.249999578782356 */
+	{ 24090133037795LL, 100000000000000LL },	/* 0.24090133037795 */
+	{ 232638888888889LL, 1000000000000000LL },	/* 0.232638888888889 */
+	{ 225097003008273LL, 1000000000000000LL },	/* 0.225097003008273 */
+	{ 218180986989316LL, 1000000000000000LL },	/* 0.218180986989316 */
+	{ 211812304114001LL, 1000000000000000LL },	/* 0.211812304114001 */
+	{ 205925243280314LL, 1000000000000000LL },	/* 0.205925243280314 */
+	{ 200464385692282LL, 1000000000000000LL },	/* 0.200464385692282 */
+	{ 195382650833982LL, 1000000000000000LL },	/* 0.195382650833982 */
+	{ 19063977276852LL, 100000000000000LL },	/* 0.19063977276852 */
+	{ 186201099999877LL, 1000000000000000LL },	/* 0.186201099999877 */
+	{ 182036641362817LL, 1000000000000000LL },	/* 0.182036641362817 */
+	{ 178120300939LL, 1000000000000LL },	/* 0.178120300939 */
+	{ 174429259613497LL, 1000000000000000LL },	/* 0.174429259613497 */
+	{ 170943471418511LL, 1000000000000000LL },	/* 0.170943471418511 */
+	{ 16764525048842LL, 100000000000000LL },	/* 0.16764525048842 */
+	{ 164518930106658LL, 1000000000000000LL },	/* 0.164518930106658 */
+	{ 161550579534251LL, 1000000000000000LL },	/* 0.161550579534251 */
+	{ 158727767472067LL, 1000000000000000LL },	/* 0.158727767472067 */
+	{ 156039363405452LL, 1000000000000000LL },	/* 0.156039363405452 */
+	{ 153475369911586LL, 1000000000000000LL },	/* 0.153475369911586 */
+	{ 151026780420806LL, 1000000000000000LL },	/* 0.151026780420806 */
+	{ 148685458018048LL, 1000000000000000LL },	/* 0.148685458018048 */
+	{ 146444031726265LL, 1000000000000000LL },	/* 0.146444031726265 */
+	{ 144295807386892LL, 1000000000000000LL },	/* 0.144295807386892 */
+	{ 142234690785429LL, 1000000000000000LL },	/* 0.142234690785429 */
+	{ 140255121094728LL, 1000000000000000LL },	/* 0.140255121094728 */
+	{ 13835201304867LL, 100000000000000LL },	/* 0.13835201304867 */
+	{ 136520706532794LL, 1000000000000000LL },	/* 0.136520706532794 */
+	{ 1347569225002LL, 10000000000000LL },	/* 0.1347569225002 */
+	{ 133056724301448LL, 1000000000000000LL },	/* 0.133056724301448 */
+	{ 131416483664691LL, 1000000000000000LL },	/* 0.131416483664691 */
+	{ 129832850683331LL, 1000000000000000LL },	/* 0.129832850683331 */
+	{ 128302727268412LL, 1000000000000000LL },	/* 0.128302727268412 */
+	{ 12682324360563LL, 100000000000000LL },	/* 0.12682324360563 */
+	{ 125391737225632LL, 1000000000000000LL },	/* 0.125391737225632 */
+	{ 12400573435363LL, 100000000000000LL },	/* 0.12400573435363 */
+	{ 122662933252459LL, 1000000000000000LL },	/* 0.122662933252459 */
+	{ 121361189313573LL, 1000000000000000LL },	/* 0.121361189313573 */
+	{ 12009850168457LL, 100000000000000LL },	/* 0.12009850168457 */
+	{ 118873001250667LL, 1000000000000000LL },	/* 0.118873001250667 */
+	{ 117682939811998LL, 1000000000000000LL },	/* 0.117682939811998 */
+	{ 116526680319474LL, 1000000000000000LL },	/* 0.116526680319474 */
+	{ 115402688049678LL, 1000000000000000LL },	/* 0.115402688049678 */
+	{ 114309522614568LL, 1000000000000000LL },	/* 0.114309522614568 */
+	{ 113245830714757LL, 1000000000000000LL },	/* 0.113245830714757 */
+	{ 11221033955645LL, 100000000000000LL },	/* 0.11221033955645 */
+	{ 111201850861809LL, 1000000000000000LL },	/* 0.111201850861809 */
+	{ 1102192354109LL, 10000000000000LL },	/* 0.1102192354109 */
+	{ 109261428060689LL, 1000000000000000LL },	/* 0.109261428060689 */
+	{ 108327423192858LL, 1000000000000000LL },	/* 0.108327423192858 */
+	{ 107416270547744LL, 1000000000000000LL },	/* 0.107416270547744 */
+	{ 106527071406495LL, 1000000000000000LL },	/* 0.106527071406495 */
+	{ 105658975087763LL, 1000000000000000LL },	/* 0.105658975087763 */
+	{ 104811175728943LL, 1000000000000000LL },	/* 0.104811175728943 */
+	{ 103982909325178LL, 1000000000000000LL },	/* 0.103982909325178 */
+	{ 103173451002242LL, 1000000000000000LL },	/* 0.103173451002242 */
+	{ 102382112501895LL, 1000000000000000LL },	/* 0.102382112501895 */
+	{ 101608239860516LL, 1000000000000000LL },	/* 0.101608239860516 */
+	{ 100851211263824LL, 1000000000000000LL },	/* 0.100851211263824 */
+	{ 100110435062178LL, 1000000000000000LL },	/* 0.100110435062178 */
+	{ 993853479325371LL, 10000000000000000LL },	/* 0.0993853479325371 */
+	{ 986754131745014LL, 10000000000000000LL },	/* 0.0986754131745014 */
+	{ 97980119129101LL, 1000000000000000LL },	/* 0.097980119129101 */
+	{ 972989777100651LL, 10000000000000000LL },	/* 0.0972989777100651 */
+	{ 96631523038292LL, 1000000000000000LL },	/* 0.096631523038292 */
+	{ 959773101711038LL, 10000000000000000LL },	/* 0.0959773101711038 */
+	{ 953359139186481LL, 10000000000000000LL },	/* 0.0953359139186481 */
+	{ 947069277405102LL, 10000000000000000LL },	/* 0.0947069277405102 */
+	{ 940899627162219LL, 10000000000000000LL },	/* 0.0940899627162219 */
+	{ 934846465839213LL, 10000000000000000LL },	/* 0.0934846465839213 */
+	{ 928906228419223LL, 10000000000000000LL },	/* 0.0928906228419223 */
+	{ 923075499084108LL, 10000000000000000LL },	/* 0.0923075499084108 */
+	{ 917351003348998LL, 10000000000000000LL },	/* 0.0917351003348998 */
+	{ 911729600694444LL, 10000000000000000LL },	/* 0.0911729600694444 */
+	{ 906208277659599LL, 10000000000000000LL },	/* 0.0906208277659599 */
+	{ 900784141362873LL, 10000000000000000LL },	/* 0.0900784141362873 */
+	{ 895454413419325LL, 10000000000000000LL },	/* 0.0895454413419325 */
+	{ 890216424226529LL, 10000000000000000LL },	/* 0.0890216424226529 */
+	{ 885067607592958LL, 10000000000000000LL },	/* 0.0885067607592958 */
+	{ 88000549568501LL, 1000000000000000LL },	/* 0.088000549568501 */
+	{ 875027714270677LL, 10000000000000000LL },	/* 0.0875027714270677 */
+	{ 870131978239609LL, 10000000000000000LL },	/* 0.0870131978239609 */
+	{ 865316087380871LL, 10000000000000000LL },	/* 0.0865316087380871 */
+	{ 860577922401151LL, 10000000000000000LL },	/* 0.0860577922401151 */
+	{ 855915441167475LL, 10000000000000000LL },	/* 0.0855915441167475 */
+	{ 851326675159692LL, 10000000000000000LL },	/* 0.0851326675159692 */
+	{ 846809726119106LL, 10000000000000000LL },	/* 0.0846809726119106 */
+	{ 842362762880613LL, 10000000000000000LL },	/* 0.0842362762880613 */
+	{ 837984018376643LL, 10000000000000000LL },	/* 0.0837984018376643 */
+	{ 833671786802068LL, 10000000000000000LL },	/* 0.0833671786802068 */
+	{ 829424420929991LL, 10000000000000000LL },	/* 0.0829424420929991 */
+	{ 825240329569059LL, 10000000000000000LL },	/* 0.0825240329569059 */
+	{ 821117975153618LL, 10000000000000000LL },	/* 0.0821117975153618 */
+	{ 817055871458615LL, 10000000000000000LL },	/* 0.0817055871458615 */
+	{ 813052581431724LL, 10000000000000000LL },	/* 0.0813052581431724 */
+	{ 809106715135683LL, 10000000000000000LL },	/* 0.0809106715135683 */
+	{ 805216927794322LL, 10000000000000000LL },	/* 0.0805216927794322 */
+	{ 801381917936175LL, 10000000000000000LL },	/* 0.0801381917936175 */
+	{ 797600425630009LL, 10000000000000000LL },	/* 0.0797600425630009 */
+	{ 793871230806953LL, 10000000000000000LL },	/* 0.0793871230806953 */
+	{ 790193151664281LL, 10000000000000000LL },	/* 0.0790193151664281 */
+	{ 786565043146194LL, 10000000000000000LL },	/* 0.0786565043146194 */
+	{ 782985795497303LL, 10000000000000000LL },	/* 0.0782985795497303 */
+	{ 779454332884719LL, 10000000000000000LL },	/* 0.0779454332884719 */
+	{ 775969612084976LL, 10000000000000000LL },	/* 0.0775969612084976 */
+	{ 77253062123222LL, 1000000000000000LL },	/* 0.077253062123222 */
+	{ 769136378624335LL, 10000000000000000LL },	/* 0.0769136378624335 */
+	{ 765785931583867LL, 10000000000000000LL },	/* 0.0765785931583867 */
+	{ 762478355370815LL, 10000000000000000LL },	/* 0.0762478355370815 */
+	{ 759212752144541LL, 10000000000000000LL },	/* 0.0759212752144541 */
+	{ 755988249972193LL, 10000000000000000LL },	/* 0.0755988249972193 */
+	{ 752804001881223LL, 10000000000000000LL },	/* 0.0752804001881223 */
+	{ 749659184953696LL, 10000000000000000LL },	/* 0.0749659184953696 */
+	{ 746552999460257LL, 10000000000000000LL },	/* 0.0746552999460257 */
+	{ 743484668031706LL, 10000000000000000LL },	/* 0.0743484668031706 */
+	{ 740453434866294LL, 10000000000000000LL },	/* 0.0740453434866294 */
+	{ 737458564970926LL, 10000000000000000LL },	/* 0.0737458564970926 */
+	{ 734499343434585LL, 10000000000000000LL },	/* 0.0734499343434585 */
+	{ 731575074732384LL, 10000000000000000LL },	/* 0.0731575074732384 */
+	{ 728685082058719LL, 10000000000000000LL },	/* 0.0728685082058719 */
+	{ 725828706688121LL, 10000000000000000LL },	/* 0.0725828706688121 */
+	{ 723005307362458LL, 10000000000000000LL },	/* 0.0723005307362458 */
+	{ 720214259703205LL, 10000000000000000LL },	/* 0.0720214259703205 */
+	{ 717454955647604LL, 10000000000000000LL },	/* 0.0717454955647604 */
+	{ 714726802907563LL, 10000000000000000LL },	/* 0.0714726802907563 */
+	{ 712029224450229LL, 10000000000000000LL },	/* 0.0712029224450229 */
+	{ 70936165799922LL, 1000000000000000LL },	/* 0.070936165799922 */
+	{ 706723555555556LL, 10000000000000000LL },	/* 0.0706723555555556 */
+	{ 704114382937376LL, 10000000000000000LL },	/* 0.0704114382937376 */
+	{ 701533619337587LL, 10000000000000000LL },	/* 0.0701533619337587 */
+	{ 698980756898617LL, 10000000000000000LL },	/* 0.0698980756898617 */
+	{ 696455300303507LL, 10000000000000000LL },	/* 0.0696455300303507 */
+	{ 693956766382614LL, 10000000000000000LL },	/* 0.0693956766382614 */
+	{ 691484683735212LL, 10000000000000000LL },	/* 0.0691484683735212 */
+	{ 689038592365337LL, 10000000000000000LL },	/* 0.0689038592365337 */
+	{ 686618043331262LL, 10000000000000000LL },	/* 0.0686618043331262 */
+	{ 684222598407987LL, 10000000000000000LL },	/* 0.0684222598407987 */
+	{ 681851829762186LL, 10000000000000000LL },	/* 0.0681851829762186 */
+	{ 679505319639075LL, 10000000000000000LL },	/* 0.0679505319639075 */
+	{ 677182660060694LL, 10000000000000000LL },	/* 0.0677182660060694 */
+	{ 674883452535098LL, 10000000000000000LL },	/* 0.0674883452535098 */
+	{ 672607307776018LL, 10000000000000000LL },	/* 0.0672607307776018 */
+	{ 670353845432538LL, 10000000000000000LL },	/* 0.0670353845432538 */
+	{ 668122693828371LL, 10000000000000000LL },	/* 0.0668122693828371 */
+	{ 665913489710335LL, 10000000000000000LL },	/* 0.0665913489710335 */
+	{ 663725878005655LL, 10000000000000000LL },	/* 0.0663725878005655 */
+	{ 66155951158772LL, 1000000000000000LL },	/* 0.066155951158772 */
+	{ 659414051049953LL, 10000000000000000LL },	/* 0.0659414051049953 */
+	{ 657289164487471LL, 10000000000000000LL },	/* 0.0657289164487471 */
+	{ 655184527286211LL, 10000000000000000LL },	/* 0.0655184527286211 */
+	{ 653099821919232LL, 10000000000000000LL },	/* 0.0653099821919232 */
+	{ 651034737749902LL, 10000000000000000LL },	/* 0.0651034737749902 */
+	{ 648988970841695LL, 10000000000000000LL },	/* 0.0648988970841695 */
+	{ 646962223774351LL, 10000000000000000LL },	/* 0.0646962223774351 */
+	{ 644954205466131LL, 10000000000000000LL },	/* 0.0644954205466131 */
+	{ 642964631001948LL, 10000000000000000LL },	/* 0.0642964631001948 */
+	{ 64099322146713LL, 1000000000000000LL },	/* 0.064099322146713 */
+	{ 639039703786617LL, 10000000000000000LL },	/* 0.0639039703786617 */
+	{ 63710381056937LL, 1000000000000000LL },	/* 0.063710381056937 */
+	{ 635185279957794LL, 10000000000000000LL },	/* 0.0635185279957794 */
+	{ 633283855482LL, 10000000000000LL },	/* 0.0633283855482 */
+	{ 631399285918708LL, 10000000000000000LL },	/* 0.0631399285918708 */
+	{ 629531325154621LL, 10000000000000000LL },	/* 0.0629531325154621 */
+	{ 62767973205412LL, 1000000000000000LL },	/* 0.062767973205412 */
+	{ 625844270331088LL, 10000000000000000LL },	/* 0.0625844270331088 */
+	{ 624024708424753LL, 10000000000000000LL },	/* 0.0624024708424753 */
+	{ 622220819379358LL, 10000000000000000LL },	/* 0.0622220819379358 */
+	{ 620432380727561LL, 10000000000000000LL },	/* 0.0620432380727561 */
+	{ 618659174377399LL, 10000000000000000LL },	/* 0.0618659174377399 */
+	{ 616900986502709LL, 10000000000000000LL },	/* 0.0616900986502709 */
+	{ 61515760743686LL, 1000000000000000LL },	/* 0.061515760743686 */
+	{ 61342883156971LL, 1000000000000000LL },	/* 0.061342883156971 */
+	{ 611714457247638LL, 10000000000000000LL },	/* 0.0611714457247638 */
+	{ 610014286676573LL, 10000000000000000LL },	/* 0.0610014286676573 */
+	{ 608328125827897LL, 10000000000000000LL },	/* 0.0608328125827897 */
+	{ 606655784347128LL, 10000000000000000LL },	/* 0.0606655784347128 */
+	{ 604997075465285LL, 10000000000000000LL },	/* 0.0604997075465285 */
+	{ 60335181591285LL, 1000000000000000LL },	/* 0.060335181591285 */
+	{ 601719825836224LL, 10000000000000000LL },	/* 0.0601719825836224 */
+	{ 600100928716606LL, 10000000000000000LL },	/* 0.0600100928716606 */
+	{ 598494951291204LL, 10000000000000000LL },	/* 0.0598494951291204 */
+	{ 5969017234767LL, 100000000000000LL },	/* 0.05969017234767 */
+	{ 595321078294903LL, 10000000000000000LL },	/* 0.0595321078294903 */
+	{ 593752851800498LL, 10000000000000000LL },	/* 0.0593752851800498 */
+	{ 592196883010845LL, 10000000000000000LL },	/* 0.0592196883010845 */
+	{ 590653013837736LL, 10000000000000000LL },	/* 0.0590653013837736 */
+	{ 589121089021067LL, 10000000000000000LL },	/* 0.0589121089021067 */
+	{ 587600956064349LL, 10000000000000000LL },	/* 0.0587600956064349 */
+	{ 586092465171998LL, 10000000000000000LL },	/* 0.0586092465171998 */
+	{ 584595469188356LL, 10000000000000000LL },	/* 0.0584595469188356 */
+	{ 583109823538382LL, 10000000000000000LL },	/* 0.0583109823538382 */
+	{ 58163538616995LL, 1000000000000000LL },	/* 0.058163538616995 */
+	{ 580172017497721LL, 10000000000000000LL },	/* 0.0580172017497721 */
+	{ 578719580348524LL, 10000000000000000LL },	/* 0.0578719580348524 */
+	{ 577277939908204LL, 10000000000000000LL },	/* 0.0577277939908204 */
+	{ 575846963669894LL, 10000000000000000LL },	/* 0.0575846963669894 */
+	{ 574426521383656LL, 10000000000000000LL },	/* 0.0574426521383656 */
+	{ 573016485007461LL, 10000000000000000LL },	/* 0.0573016485007461 */
+	{ 571616728659458LL, 10000000000000000LL },	/* 0.0571616728659458 */
+	{ 570227128571493LL, 10000000000000000LL },	/* 0.0570227128571493 */
+	{ 568847563043846LL, 10000000000000000LL },	/* 0.0568847563043846 */
+	{ 567477912401137LL, 10000000000000000LL },	/* 0.0567477912401137 */
+	{ 566118058949378LL, 10000000000000000LL },	/* 0.0566118058949378 */
+	{ 564767886934124LL, 10000000000000000LL },	/* 0.0564767886934124 */
+	{ 563427282499708LL, 10000000000000000LL },	/* 0.0563427282499708 */
+	{ 5620961336495LL, 100000000000000LL },	/* 0.05620961336495 */
+	{ 560774330207186LL, 10000000000000000LL },	/* 0.0560774330207186 */
+	{ 559461763779024LL, 10000000000000000LL },	/* 0.0559461763779024 */
+	{ 558158327717044LL, 10000000000000000LL },	/* 0.0558158327717044 */
+	{ 556863917083178LL, 10000000000000000LL },	/* 0.0556863917083178 */
+	{ 555578428614275LL, 10000000000000000LL },	/* 0.0555578428614275 */
+	{ 554301760687995LL, 10000000000000000LL },	/* 0.0554301760687995 */
+	{ 553033813289536LL, 10000000000000000LL },	/* 0.0553033813289536 */
+	{ 551774487979186LL, 10000000000000000LL },	/* 0.0551774487979186 */
+	{ 550523687860669LL, 10000000000000000LL },	/* 0.0550523687860669 */
+	{ 549281317550259LL, 10000000000000000LL },	/* 0.0549281317550259 */
+	{ 548047283146649LL, 10000000000000000LL },	/* 0.0548047283146649 */
+	{ 546821492201547LL, 10000000000000000LL },	/* 0.0546821492201547 */
+	{ 545603853690978LL, 10000000000000000LL },	/* 0.0545603853690978 */
+	{ 544394277987275LL, 10000000000000000LL },	/* 0.0544394277987275 */
+	{ 543192676831744LL, 10000000000000000LL },	/* 0.0543192676831744 */
+	{ 541998963307965LL, 10000000000000000LL },	/* 0.0541998963307965 */
+	{ 540813051815741LL, 10000000000000000LL },	/* 0.0540813051815741 */
+	{ 539634858045649LL, 10000000000000000LL },	/* 0.0539634858045649 */
+	{ 538464298954196LL, 10000000000000000LL },	/* 0.0538464298954196 */
+	{ 537301292739549LL, 10000000000000000LL },	/* 0.0537301292739549 */
+	{ 536145758817836LL, 10000000000000000LL },	/* 0.0536145758817836 */
+	{ 534997617799989LL, 10000000000000000LL },	/* 0.0534997617799989 */
+	{ 533856791469134LL, 10000000000000000LL },	/* 0.0533856791469134 */
+	{ 532723202758481LL, 10000000000000000LL },	/* 0.0532723202758481 */
+	{ 531596775729743LL, 10000000000000000LL },	/* 0.0531596775729743 */
+	{ 530477435552026LL, 10000000000000000LL },	/* 0.0530477435552026 */
+	{ 529365108481215LL, 10000000000000000LL },	/* 0.0529365108481215 */
+	{ 528259721839814LL, 10000000000000000LL },	/* 0.0528259721839814 */
+	{ 527161203997248LL, 10000000000000000LL },	/* 0.0527161203997248 */
+	{ 526069484350602LL, 10000000000000000LL },	/* 0.0526069484350602 */
+	{ 524984493305793LL, 10000000000000000LL },	/* 0.0524984493305793 */
+	{ 523906162259159LL, 10000000000000000LL },	/* 0.0523906162259159 */
+	{ 522834423579459LL, 10000000000000000LL },	/* 0.0522834423579459 */
+	{ 521769210590265LL, 10000000000000000LL },	/* 0.0521769210590265 */
+	{ 52071045755275LL, 1000000000000000LL },	/* 0.052071045755275 */
+	{ 519658099648841LL, 10000000000000000LL },	/* 0.0519658099648841 */
+	{ 518612072964751LL, 10000000000000000LL },	/* 0.0518612072964751 */
+	{ 517572314474861LL, 10000000000000000LL },	/* 0.0517572314474861 */
+	{ 516538762025956LL, 10000000000000000LL },	/* 0.0516538762025956 */
+	{ 515511354321798LL, 10000000000000000LL },	/* 0.0515511354321798 */
+	{ 514490030908028LL, 10000000000000000LL },	/* 0.0514490030908028 */
+	{ 5134747321574LL, 100000000000000LL },	/* 0.05134747321574 */
+	{ 512465399255321LL, 10000000000000000LL },	/* 0.0512465399255321 */
+	{ 511461974185697LL, 10000000000000000LL },	/* 0.0511461974185697 */
+	{ 510464399717091LL, 10000000000000000LL },	/* 0.0510464399717091 */
+	{ 509472619389156LL, 10000000000000000LL },	/* 0.0509472619389156 */
+	{ 508486577499364LL, 10000000000000000LL },	/* 0.0508486577499364 */
+	{ 507506219090011LL, 10000000000000000LL },	/* 0.0507506219090011 */
+	{ 506531489935488LL, 10000000000000000LL },	/* 0.0506531489935488 */
+	{ 505562336529823LL, 10000000000000000LL },	/* 0.0505562336529823 */
+	{ 504598706074472LL, 10000000000000000LL },	/* 0.0504598706074472 */
+	{ 503640546466374LL, 10000000000000000LL },	/* 0.0503640546466374 */
+	{ 502687806286237LL, 10000000000000000LL },	/* 0.0502687806286237 */
+	{ 501740434787074LL, 10000000000000000LL },	/* 0.0501740434787074 */
+	{ 500798381882968LL, 10000000000000000LL },	/* 0.0500798381882968 */
+	{ 499861598138068LL, 10000000000000000LL },	/* 0.0499861598138068 */
+	{ 498930034755803LL, 10000000000000000LL },	/* 0.0498930034755803 */
+	{ 498003643568319LL, 10000000000000000LL },	/* 0.0498003643568319 */
+	{ 497082377026125LL, 10000000000000000LL },	/* 0.0497082377026125 */
+	{ 496166188187944LL, 10000000000000000LL },	/* 0.0496166188187944 */
+	{ 495255030710775LL, 10000000000000000LL },	/* 0.0495255030710775 */
+	{ 494348858840139LL, 10000000000000000LL },	/* 0.0494348858840139 */
+	{ 493447627400532LL, 10000000000000000LL },	/* 0.0493447627400532 */
+	{ 492551291786056LL, 10000000000000000LL },	/* 0.0492551291786056 */
+	{ 491659807951242LL, 10000000000000000LL },	/* 0.0491659807951242 */
+	{ 490773132402045LL, 10000000000000000LL },	/* 0.0490773132402045 */
+	{ 489891222187022LL, 10000000000000000LL },	/* 0.0489891222187022 */
+	{ 489014034888677LL, 10000000000000000LL },	/* 0.0489014034888677 */
+	{ 488141528614973LL, 10000000000000000LL },	/* 0.0488141528614973 */
+	{ 487273661991017LL, 10000000000000000LL },	/* 0.0487273661991017 */
+	{ 486410394150891LL, 10000000000000000LL },	/* 0.0486410394150891 */
+	{ 485551684729651LL, 10000000000000000LL },	/* 0.0485551684729651 */
+	{ 484697493855474LL, 10000000000000000LL },	/* 0.0484697493855474 */
+	{ 483847782141954LL, 10000000000000000LL },	/* 0.0483847782141954 */
+	{ 48300251068055LL, 1000000000000000LL },	/* 0.048300251068055 */
+	{ 48216164103317LL, 1000000000000000LL },	/* 0.048216164103317 */
+	{ 481325135224896LL, 10000000000000000LL },	/* 0.0481325135224896 */
+	{ 48049295573685LL, 1000000000000000LL },	/* 0.048049295573685 */
+	{ 479665065499194LL, 10000000000000000LL },	/* 0.0479665065499194 */
+	{ 478841427884249LL, 10000000000000000LL },	/* 0.0478841427884249 */
+	{ 478022006699761LL, 10000000000000000LL },	/* 0.0478022006699761 */
+	{ 477206766182274LL, 10000000000000000LL },	/* 0.0477206766182274 */
+	{ 476395670990636LL, 10000000000000000LL },	/* 0.0476395670990636 */
+	{ 475588686199625LL, 10000000000000000LL },	/* 0.0475588686199625 */
+	{ 474785777293681LL, 10000000000000000LL },	/* 0.0474785777293681 */
+	{ 47398691016077LL, 1000000000000000LL },	/* 0.047398691016077 */
+	{ 473192051086343LL, 10000000000000000LL },	/* 0.0473192051086343 */
+	{ 472401166747416LL, 10000000000000000LL },	/* 0.0472401166747416 */
+	{ 471614224206753LL, 10000000000000000LL },	/* 0.0471614224206753 */
+	{ 470831190907155LL, 10000000000000000LL },	/* 0.0470831190907155 */
+	{ 470052034665852LL, 10000000000000000LL },	/* 0.0470052034665852 */
+	{ 469276723668991LL, 10000000000000000LL },	/* 0.0469276723668991 */
+	{ 468505226466234LL, 10000000000000000LL },	/* 0.0468505226466234 */
+	{ 467737511965439LL, 10000000000000000LL },	/* 0.0467737511965439 */
+	{ 466973549427445LL, 10000000000000000LL },	/* 0.0466973549427445 */
+	{ 466213308460944LL, 10000000000000000LL },	/* 0.0466213308460944 */
+	{ 465456759017447LL, 10000000000000000LL },	/* 0.0465456759017447 */
+	{ 464703871386338LL, 10000000000000000LL },	/* 0.0464703871386338 */
+	{ 463954616190012LL, 10000000000000000LL },	/* 0.0463954616190012 */
+	{ 463208964379101LL, 10000000000000000LL },	/* 0.0463208964379101 */
+	{ 462466887227783LL, 10000000000000000LL },	/* 0.0462466887227783 */
+	{ 461728356329171LL, 10000000000000000LL },	/* 0.0461728356329171 */
+	{ 460993343590784LL, 10000000000000000LL },	/* 0.0460993343590784 */
+	{ 460261821230094LL, 10000000000000000LL },	/* 0.0460261821230094 */
+	{ 459533761770151LL, 10000000000000000LL },	/* 0.0459533761770151 */
+	{ 458809138035283LL, 10000000000000000LL },	/* 0.0458809138035283 */
+	{ 45808792314687LL, 1000000000000000LL },	/* 0.045808792314687 */
+	{ 457370090519191LL, 10000000000000000LL },	/* 0.0457370090519191 */
+	{ 456655613855335LL, 10000000000000000LL },	/* 0.0456655613855335 */
+	{ 455944467143193LL, 10000000000000000LL },	/* 0.0455944467143193 */
+	{ 455236624651509LL, 10000000000000000LL },	/* 0.0455236624651509 */
+	{ 454532060925998LL, 10000000000000000LL },	/* 0.0454532060925998 */
+	{ 453830750785534LL, 10000000000000000LL },	/* 0.0453830750785534 */
+	{ 453132669318397LL, 10000000000000000LL },	/* 0.0453132669318397 */
+	{ 452437791878588LL, 10000000000000000LL },	/* 0.0452437791878588 */
+	{ 451746094082199LL, 10000000000000000LL },	/* 0.0451746094082199 */
+	{ 451057551803846LL, 10000000000000000LL },	/* 0.0451057551803846 */
+	{ 450372141173166LL, 10000000000000000LL },	/* 0.0450372141173166 */
+	{ 449689838571361LL, 10000000000000000LL },	/* 0.0449689838571361 */
+	{ 449010620627813LL, 10000000000000000LL },	/* 0.0449010620627813 */
+	{ 448334464216739LL, 10000000000000000LL },	/* 0.0448334464216739 */
+	{ 447661346453912LL, 10000000000000000LL },	/* 0.0447661346453912 */
+	{ 446991244693435LL, 10000000000000000LL },	/* 0.0446991244693435 */
+	{ 446324136524557LL, 10000000000000000LL },	/* 0.0446324136524557 */
+	{ 445659999768557LL, 10000000000000000LL },	/* 0.0445659999768557 */
+	{ 444998812475661LL, 10000000000000000LL },	/* 0.0444998812475661 */
+	{ 444340552922024LL, 10000000000000000LL },	/* 0.0444340552922024 */
+	{ 44368519960675LL, 1000000000000000LL },	/* 0.044368519960675 */
+	{ 443032731248964LL, 10000000000000000LL },	/* 0.0443032731248964 */
+	{ 442383126784931LL, 10000000000000000LL },	/* 0.0442383126784931 */
+	{ 44173636536522LL, 1000000000000000LL },	/* 0.044173636536522 */
+	{ 441092426351912LL, 10000000000000000LL },	/* 0.0441092426351912 */
+	{ 440451289315857LL, 10000000000000000LL },	/* 0.0440451289315857 */
+	{ 439812934033966LL, 10000000000000000LL },	/* 0.0439812934033966 */
+	{ 439177340486556LL, 10000000000000000LL },	/* 0.0439177340486556 */
+	{ 438544488854725LL, 10000000000000000LL },	/* 0.0438544488854725 */
+	{ 43791435951778LL, 1000000000000000LL },	/* 0.043791435951778 */
+	{ 437286933050696LL, 10000000000000000LL },	/* 0.0437286933050696 */
+	{ 436662190221621LL, 10000000000000000LL },	/* 0.0436662190221621 */
+	{ 436040111989415LL, 10000000000000000LL },	/* 0.0436040111989415 */
+	{ 435420679501227LL, 10000000000000000LL },	/* 0.0435420679501227 */
+	{ 434803874090116LL, 10000000000000000LL },	/* 0.0434803874090116 */
+	{ 434189677272704LL, 10000000000000000LL },	/* 0.0434189677272704 */
+	{ 433578070746858LL, 10000000000000000LL },	/* 0.0433578070746858 */
+	{ 432969036389425LL, 10000000000000000LL },	/* 0.0432969036389425 */
+	{ 432362556253984LL, 10000000000000000LL },	/* 0.0432362556253984 */
+	{ 431758612568642LL, 10000000000000000LL },	/* 0.0431758612568642 */
+	{ 431157187733861LL, 10000000000000000LL },	/* 0.0431157187733861 */
+	{ 430558264320317LL, 10000000000000000LL },	/* 0.0430558264320317 */
+	{ 429961825066796LL, 10000000000000000LL },	/* 0.0429961825066796 */
+	{ 429367852878112LL, 10000000000000000LL },	/* 0.0429367852878112 */
+	{ 428776330823068LL, 10000000000000000LL },	/* 0.0428776330823068 */
+	{ 428187242132439LL, 10000000000000000LL },	/* 0.0428187242132439 */
+	{ 427600570196989LL, 10000000000000000LL },	/* 0.0427600570196989 */
+	{ 427016298565515LL, 10000000000000000LL },	/* 0.0427016298565515 */
+	{ 426434410942925LL, 10000000000000000LL },	/* 0.0426434410942925 */
+	{ 425854891188339LL, 10000000000000000LL },	/* 0.0425854891188339 */
+	{ 425277723313219LL, 10000000000000000LL },	/* 0.0425277723313219 */
+	{ 424702891479532LL, 10000000000000000LL },	/* 0.0424702891479532 */
+	{ 424130379997931LL, 10000000000000000LL },	/* 0.0424130379997931 */
+	{ 423560173325973LL, 10000000000000000LL },	/* 0.0423560173325973 */
+	{ 422992256066352LL, 10000000000000000LL },	/* 0.0422992256066352 */
+	{ 422426612965169LL, 10000000000000000LL },	/* 0.0422426612965169 */
+	{ 421863228910218LL, 10000000000000000LL },	/* 0.0421863228910218 */
+	{ 421302088929301LL, 10000000000000000LL },	/* 0.0421302088929301 */
+	{ 420743178188567LL, 10000000000000000LL },	/* 0.0420743178188567 */
+	{ 420186481990879LL, 10000000000000000LL },	/* 0.0420186481990879 */
+	{ 419631985774193LL, 10000000000000000LL },	/* 0.0419631985774193 */
+	{ 419079675109974LL, 10000000000000000LL },	/* 0.0419079675109974 */
+	{ 418529535701626LL, 10000000000000000LL },	/* 0.0418529535701626 */
+	{ 417981553382947LL, 10000000000000000LL },	/* 0.0417981553382947 */
+	{ 417435714116607LL, 10000000000000000LL },	/* 0.0417435714116607 */
+	{ 416892003992645LL, 10000000000000000LL },	/* 0.0416892003992645 */
+	{ 416350409226989LL, 10000000000000000LL },	/* 0.0416350409226989 */
+	{ 41581091616LL, 1000000000000LL },	/* 0.041581091616 */
+	{ 415273511255028LL, 10000000000000000LL },	/* 0.0415273511255028 */
+	{ 414738181096999LL, 10000000000000000LL },	/* 0.0414738181096999 */
+	{ 414204912391014LL, 10000000000000000LL },	/* 0.0414204912391014 */
+	{ 413673691960969LL, 10000000000000000LL },	/* 0.0413673691960969 */
+	{ 413144506748198LL, 10000000000000000LL },	/* 0.0413144506748198 */
+	{ 412617343810132LL, 10000000000000000LL },	/* 0.0412617343810132 */
+	{ 412092190318976LL, 10000000000000000LL },	/* 0.0412092190318976 */
+	{ 411569033560404LL, 10000000000000000LL },	/* 0.0411569033560404 */
+	{ 411047860932278LL, 10000000000000000LL },	/* 0.0411047860932278 */
+	{ 410528659943376LL, 10000000000000000LL },	/* 0.0410528659943376 */
+	{ 410011418212142LL, 10000000000000000LL },	/* 0.0410011418212142 */
+	{ 409496123465455LL, 10000000000000000LL },	/* 0.0409496123465455 */
+	{ 40898276353741LL, 1000000000000000LL },	/* 0.040898276353741 */
+	{ 408471326368122LL, 10000000000000000LL },	/* 0.0408471326368122 */
+	{ 407961800002536LL, 10000000000000000LL },	/* 0.0407961800002536 */
+	{ 407454172589268LL, 10000000000000000LL },	/* 0.0407454172589268 */
+	{ 406948432379447LL, 10000000000000000LL },	/* 0.0406948432379447 */
+	{ 406444567725581LL, 10000000000000000LL },	/* 0.0406444567725581 */
+	{ 405942567080438LL, 10000000000000000LL },	/* 0.0405942567080438 */
+	{ 40544241899594LL, 1000000000000000LL },	/* 0.040544241899594 */
+	{ 404944112122069LL, 10000000000000000LL },	/* 0.0404944112122069 */
+	{ 404447635205797LL, 10000000000000000LL },	/* 0.0404447635205797 */
+	{ 403952977090019LL, 10000000000000000LL },	/* 0.0403952977090019 */
+	{ 403460126712507LL, 10000000000000000LL },	/* 0.0403460126712507 */
+	{ 402969073104878LL, 10000000000000000LL },	/* 0.0402969073104878 */
+	{ 402479805391573LL, 10000000000000000LL },	/* 0.0402479805391573 */
+	{ 40199231278885LL, 1000000000000000LL },	/* 0.040199231278885 */
+	{ 401506584603793LL, 10000000000000000LL },	/* 0.0401506584603793 */
+	{ 401022610233328LL, 10000000000000000LL },	/* 0.0401022610233328 */
+	{ 400540379163262LL, 10000000000000000LL },	/* 0.0400540379163262 */
+	{ 400059880967321LL, 10000000000000000LL },	/* 0.0400059880967321 */
+	{ 399581105306216LL, 10000000000000000LL },	/* 0.0399581105306216 */
+	{ 399104041926707LL, 10000000000000000LL },	/* 0.0399104041926707 */
+	{ 398628680660689LL, 10000000000000000LL },	/* 0.0398628680660689 */
+	{ 398155011424285LL, 10000000000000000LL },	/* 0.0398155011424285 */
+	{ 397683024216952LL, 10000000000000000LL },	/* 0.0397683024216952 */
+	{ 397212709120599LL, 10000000000000000LL },	/* 0.0397212709120599 */
+	{ 396744056298716LL, 10000000000000000LL },	/* 0.0396744056298716 */
+	{ 396277055995515LL, 10000000000000000LL },	/* 0.0396277055995515 */
+	{ 39581169853508LL, 1000000000000000LL },	/* 0.039581169853508 */
+	{ 395347974320531LL, 10000000000000000LL },	/* 0.0395347974320531 */
+	{ 394885873833192LL, 10000000000000000LL },	/* 0.0394885873833192 */
+	{ 394425387631782LL, 10000000000000000LL },	/* 0.0394425387631782 */
+	{ 393966506351601LL, 10000000000000000LL },	/* 0.0393966506351601 */
+	{ 393509220703742LL, 10000000000000000LL },	/* 0.0393509220703742 */
+	{ 393053521474297LL, 10000000000000000LL },	/* 0.0393053521474297 */
+	{ 392599399523587LL, 10000000000000000LL },	/* 0.0392599399523587 */
+	{ 392146845785392LL, 10000000000000000LL },	/* 0.0392146845785392 */
+	{ 391695851266197LL, 10000000000000000LL },	/* 0.0391695851266197 */
+	{ 391246407044446LL, 10000000000000000LL },	/* 0.0391246407044446 */
+	{ 390798504269797LL, 10000000000000000LL },	/* 0.0390798504269797 */
+	{ 390352134162404LL, 10000000000000000LL },	/* 0.0390352134162404 */
+	{ 38990728801219LL, 1000000000000000LL },	/* 0.038990728801219 */
+	{ 389463957178138LL, 10000000000000000LL },	/* 0.0389463957178138 */
+	{ 389022133087593LL, 10000000000000000LL },	/* 0.0389022133087593 */
+	{ 388581807235562LL, 10000000000000000LL },	/* 0.0388581807235562 */
+	{ 388142971184039LL, 10000000000000000LL },	/* 0.0388142971184039 */
+	{ 387705616561318LL, 10000000000000000LL },	/* 0.0387705616561318 */
+	{ 387269735061335LL, 10000000000000000LL },	/* 0.0387269735061335 */
+	{ 386835318443004LL, 10000000000000000LL },	/* 0.0386835318443004 */
+	{ 386402358529565LL, 10000000000000000LL },	/* 0.0386402358529565 */
+	{ 385970847207942LL, 10000000000000000LL },	/* 0.0385970847207942 */
+	{ 385540776428107LL, 10000000000000000LL },	/* 0.0385540776428107 */
+	{ 385112138202453LL, 10000000000000000LL },	/* 0.0385112138202453 */
+	{ 384684924605173LL, 10000000000000000LL },	/* 0.0384684924605173 */
+	{ 384259127771645LL, 10000000000000000LL },	/* 0.0384259127771645 */
+	{ 38383473989783LL, 1000000000000000LL },	/* 0.038383473989783 */
+	{ 383411753239674LL, 10000000000000000LL },	/* 0.0383411753239674 */
+	{ 382990160112515LL, 10000000000000000LL },	/* 0.0382990160112515 */
+	{ 382569952890498LL, 10000000000000000LL },	/* 0.0382569952890498 */
+	{ 382151124006002LL, 10000000000000000LL },	/* 0.0382151124006002 */
+	{ 38173366594907LL, 1000000000000000LL },	/* 0.038173366594907 */
+	{ 381317571266841LL, 10000000000000000LL },	/* 0.0381317571266841 */
+	{ 380902832562998LL, 10000000000000000LL },	/* 0.0380902832562998 */
+	{ 380489442497219LL, 10000000000000000LL },	/* 0.0380489442497219 */
+	{ 380077393784629LL, 10000000000000000LL },	/* 0.0380077393784629 */
+	{ 379666679195267LL, 10000000000000000LL },	/* 0.0379666679195267 */
+	{ 379257291553555LL, 10000000000000000LL },	/* 0.0379257291553555 */
+	{ 378849223737772LL, 10000000000000000LL },	/* 0.0378849223737772 */
+	{ 378442468679537LL, 10000000000000000LL },	/* 0.0378442468679537 */
+	{ 378037019363299LL, 10000000000000000LL },	/* 0.0378037019363299 */
+	{ 377632868825826LL, 10000000000000000LL },	/* 0.0377632868825826 */
+	{ 37723001015571LL, 1000000000000000LL },	/* 0.037723001015571 */
+	{ 376828436492868LL, 10000000000000000LL },	/* 0.0376828436492868 */
+	{ 376428141028059LL, 10000000000000000LL },	/* 0.0376428141028059 */
+	{ 376029117002394LL, 10000000000000000LL },	/* 0.0376029117002394 */
+	{ 375631357706867LL, 10000000000000000LL },	/* 0.0375631357706867 */
+	{ 375234856481875LL, 10000000000000000LL },	/* 0.0375234856481875 */
+	{ 374839606716758LL, 10000000000000000LL },	/* 0.0374839606716758 */
+	{ 374445601849334LL, 10000000000000000LL },	/* 0.0374445601849334 */
+	{ 374052835365444LL, 10000000000000000LL },	/* 0.0374052835365444 */
+	{ 373661300798504LL, 10000000000000000LL },	/* 0.0373661300798504 */
+	{ 373270991729057LL, 10000000000000000LL },	/* 0.0373270991729057 */
+	{ 372881901784334LL, 10000000000000000LL },	/* 0.0372881901784334 */
+	{ 372494024637818LL, 10000000000000000LL },	/* 0.0372494024637818 */
+	{ 372107354008813LL, 10000000000000000LL },	/* 0.0372107354008813 */
+	{ 371721883662021LL, 10000000000000000LL },	/* 0.0371721883662021 */
+	{ 371721883662021LL, 10000000000000000LL }	/* 0.0371721883662021 */
+};
+
+#endif
+++ sys/netinet/dccp_usrreq.c	Thu Aug 24 06:10:09 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	Thu Aug 24 05:55:37 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	Wed Aug 16 07:12:27 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	Wed Aug 16 07:12:27 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	Wed Aug 16 07:12:27 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	Wed Aug 16 07:12:27 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.

