📄 dcp.c
字号:
/* dcp.c - an implemenetation of the DCCP protocol *//* ------------------------------------------------------------------------- *//* Copyright (c) 2005 The University of Waikato, Hamilton, New Zealand. This code has been developed by the University of Waikato WAND research group. For further information please see http://www.wand.net.nz/ This code has been based on the work of other developers: Patrick McManus (mcmanus@ducksong.com) Lulea Univeristy of Technology This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *//* ------------------------------------------------------------------------- */#include <linux/config.h>#include <linux/module.h>#include <linux/types.h>#include <linux/sched.h>#include <linux/kernel.h>#include <linux/skbuff.h>#include <linux/netdevice.h>#include <linux/in.h>#include <linux/if_arp.h>#include <linux/init.h>#include <net/checksum.h>#include <net/sock.h>#include <net/ip.h>#include <net/protocol.h>#include <net/inet_common.h>#include <asm/semaphore.h>#include <linux/spinlock.h>#include <linux/timer.h>#include <linux/delay.h>#include <linux/poll.h>#include <linux/mm.h>#include <linux/vmalloc.h> //vmalloc ;)/* obviously, for kmalloc */ /* for struct file_operations, register_chrdev() */ #include <linux/fs.h>/* this header files wraps some common module-space operations ... here we use mem_map_reserve() macro */ #include <linux/wrapper.h> /* needed for virt_to_phys() */ #include <asm/io.h> // virt_to_phys()#define DCCP_STAT_EXTERN#ifdef MODULE#include "compat.h"#include "queue.h"#include "dccp_tfrc.h"#include "dccp_tfrc_lookup.h"#include "dccp_tfrc_print.h"#else#include "dcp_super.h"#endif /* MODULE *///#define KERNEL_ASSERT_ON#ifdef KERNEL_ASSERT_ON#define KERNEL_ASSERT(expr) if (!(expr)) printk(KERN_DEBUG "KASSERT: %s:%d - Assertion failed! (%s) ", __FILE__, __LINE__, #expr)#else#define KERNEL_ASSERT(expr)#endif#include <linux/config.h>#include <linux/module.h>#include <linux/types.h>#include <linux/sched.h>#include <linux/kernel.h>#include <linux/time.h>#include <linux/timer.h>#include <linux/slab.h>#include <linux/string.h>#include <asm/semaphore.h>#include <net/sock.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 <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>#define LOG_INFO 1#define DCP_DEBUG 10 //outcommented by BJORN//#define TFRCDEBUG//#define TFRCDEBUGTIMERS/*#define NOTFRCSENDER#define NOTFRCRECV*///#define TFRC_DEBUG((LOG_INFO, (printk(#ifdef TFRCDEBUG#define TFRC_DEBUG(args) do_weird_debug 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};/* * Half time value struct (accurate to +- 0.5us) * args: tvp - pointer to timeval structure * Tested u:OK */#define HALFTIMEVAL(tvp) \do { \ if((tvp)->tv_sec & 1) \ (tvp)->tv_usec += 1000000; \ (tvp)->tv_sec = (tvp)->tv_sec >> 1; \ (tvp)->tv_usec = (tvp)->tv_usec >> 1; \}while(0)/* Sender side *//* Calculate new t_ipi (inter packet interval) by * t_ipi = s/X_inst; * args: ccbp - pointer to sender ccb block * Tested u:OK - Note: No check for x=0 -> t_ipi ={0xFFF...,0xFFF} */#define CALCNEWTIPI(ccbp) \do{ \ ccbp->t_ipi.tv_sec = (long) ( ((double) (ccbp->s)) / (ccbp->x) ); \ ccbp->t_ipi.tv_usec = (long) (( ((double)(ccbp->s)) / (ccbp->x) - ccbp->t_ipi.tv_sec)*((double)1000000.0)); \}while (0)/* Calculate new delta by * delta = min(t_ipi/2, t_gran/2); * args: ccbp - pointer to sender ccb block * Tested u:OK */#define CALCNEWDELTA(ccbp) \do { \ ccbp->delta = delta_half; \ if (ccbp->t_ipi.tv_sec == 0 && ccbp->t_ipi.tv_usec < TFRC_OPSYS_TIME_GRAN){ \ ccbp->delta = ccbp->t_ipi; \ HALFTIMEVAL(&(ccbp->delta)); \ } \} while (0)/******************************************************//* things that could be useful in a userspace program */#define SOCK_DCCP 6 /* for api purposes */#define SOL_DCCP 269 #define SO_HANDSHAKE_DATA 1 /* sockopt */#define SO_ALLOW_HANDSHAKE_DATA 2/* the following is an optional struct for connect() or bind().. if a normal sockaddr_in is used instead, a service of 0 is assumed. accept() returns normal sockaddr_in's *//* service names should be supplied in network byte order */struct sockaddr_dcp{ struct sockaddr_in in; unsigned int service;};/******************************************************/#define DCCP_PROTO 33#define DCP_INITIAL_CWND 3#define DCP_TIMEOUT (2*HZ) /* 2 second */#define DCP_MAX_TRIES 6 /* really 6-1 = 5 */#define DCP_TIMEWAIT_LEN (30*HZ) /* 30 seconds */#define DCP_MIN_RTT (HZ >> 3) /* 1/8 of a second, that's 12 jiffies on i386 */#define DCP_RESPOND_TIMEOUT (15*HZ)#define MAX_DCP_REQUEST_SZ 284#define DCP_NUMDUPACKS 3/* states */#define DCP_REQUESTING 1#define DCP_OPEN 2#define DCP_LISTENING 3#define DCP_RESPOND 4#define DCP_HALF_CLOSE 5#define DCP_TIMEWAIT 6#define DCP_CLOSED 7 /* same as TCP_CLOSE, don't change value */#define TYPE_REQUEST 0x00#define TYPE_RESPONSE 0x10#define TYPE_DATA 0x20#define TYPE_ACK 0x30#define TYPE_DATAACK 0x40#define TYPE_CLOSEREQ 0x50#define TYPE_CLOSE 0x60#define TYPE_RESET 0x70#define TYPE_MOVE 0x80#define TYPE_INVALID 0xF0#define DCP_OPT_PAD 00#define DCP_OPT_DISCARD 01#define DCP_OPT_IGNORED 32#define DCP_OPT_ASK 33#define DCP_OPT_CHOOSE 34#define DCP_OPT_ANSWER 35#define DCP_OPT_ICOOKIE 36#define DCP_OPT_ACKV0 37#define DCP_OPT_ACKV1 38#define DCP_OPT_RBDROP 39#define DCP_OPT_TS 40#define DCP_OPT_TS_ECHO 41#define DCP_OPT_MOBILE 42#define DCP_OPT_BCD 43#define DCP_OPT_WINCOUNT 128 /* Used for DCCP CCID 3 */#define DCP_OPT_ELAPTIME 193#define DCP_OPT_LOSSEVENT 192#define DCP_OPT_RECEIVERATE 194 /* END USED FOR DCCP CCID 3 */#define DCP_OPT_LOSSINTER 195 /* included for completeness will not be used */#define DCP_OPT_STATE_KNOWN 1#define DCP_OPT_STATE_ASKING 2#define DCP_OPT_STATE_ANS 3#define DCP_NEG_TYPE_CC 1#define DCP_NEG_TYPE_ECN 2#define DCP_NEG_TYPE_ACKRATIO 3#define DCP_NEG_TYPE_ACKVECTOR 4#define WHOAMI_UNKNOWN 0#define WHOAMI_CLIENT 1#define WHOAMI_SERVER 2#define WHOAMI_BINDER 3#define FLAG_ACKSCHED 0x01#define FLAG_ALLOW_LOADED_HANDSHAKE 0x02#define DCCP_PORT_BASE 1025#define DCCP_PORT_RANGE 16000#define DCCP_PORT_HI (DCCP_PORT_BASE + DCCP_PORT_RANGE)#define DCP_SK_HASH_SZ 863#define INIT_VECTOR_SIZE 512 /* keep as a multiple of 8!! *//* datatypes *//* Used to store an outgoing packet in the right format for ip_build_xmit * * Fields: h - the DCCP header (including headers) of the packet * kdb - the handshake data (for connection handshake packets only), // kdb stands for Kernel Data Block?? - SHANE * hl - the length of the DCCP header * kdbl - the length of the handshake data * iov - the io vector containing the data portion of the packet (except when we're in connection handshake) * check - the checksum for the future IP packet? We set it to zero as checksum calc for IP will come later * */struct build_t{ unsigned char *h,*kdb; u16 hl,kdbl; struct iovec *iov; u32 check;};/* Describes a DCCP socket * * Fields: sk - the actual socket structure itself * locala - the address of the local end of the connection * remotea - the address of the remote end of the connection * svc - the service code * lp - the local port number for the connection * rp - the remote port number for the connection * p - the previous entry in the DCCP socket list * n - the next entry in the DCCP socket list * */struct dccp_sk_list_t{ struct sock *sk; u32 locala, remotea, svc; u16 lp, rp; struct dccp_sk_list_t *p, *n;};/* Used to represent an outgoing ACK that is acknowledging previously received ACKs, rather than incoming data * * Fields: localseq - the sequence number of the outgoing ACK * ackthru - the acknowledgement number of the outgoing ACK * next - the next member of the clist * */struct ack_collapse_t{ u32 localseq, ackthru; struct ack_collapse_t *next;};/* global allocations - mostly counters and locks */static struct dccp_sk_list_t *dccp_sk_hash[DCP_SK_HASH_SZ];static spinlock_t dccp_port_lock;static spinlock_t dccp_reset_lock;static u16 dccp_port;static rwlock_t dccp_table_lock[16];static unsigned char dccp_port_map[DCCP_PORT_RANGE/8+1];static kmem_cache_t *dccp_slab, *dccp_slab_sk, *dccp_slab_ack;/* *sk used for resets when no connection exists */static struct inode reset_inode;static struct socket *reset_socket = &reset_inode.u.socket_i;static struct tq_struct itask;/* prototypes */static void dccp_reset (struct sock *sk, u32 reason);static void dccp_send_close (struct sock *sk, unsigned char close_or_closeR);static int unregister_dccp_sk (struct sock *sk);static void dccp_port_release (u16 i);static int dccp_port_claim (u16 i);static inline void dccp_update_ackn (unsigned int *t, struct sk_buff *skb);static inline void new_rtt_sample (struct dcp_opt *tp, u16 M);static int credit_pkt (struct sock *sk, u32 sn);static inline int increment_ackvector (struct sock *sk, u32 sn);static u32 dccp_whatis_ackn (struct sk_buff *skb);static void dccp_write_24 (u32 *s, char *d, int inc);static inline unsigned char dcp_write_ndp (u16 *ndp, int inc);static unsigned char *dccp_generate_ackvector (struct sock *sk, int *l);static int dccp_getfrag(const void *p, char * to, unsigned int offset, unsigned int fraglen) ;static inline int check_clist (struct dcp_opt *tp, u32 sn);void inet_sock_release(struct sock *sk);static void dccp_half_closed (void *vsk);static u16 dccp_parse_option (struct sk_buff *skb, unsigned char option,u16 *ics);static void generic_option_negotiation (struct dcp_opt *tp);static inline void rcvr_ratio_inbounds (struct dcp_opt *tp);static inline unsigned char value_in_ackvector (struct sock *sk, u32 sn);static void dccp_schedule_ack (void *vsk);/* External declarations */extern int dccp_get_option(char *, int, int, char *,int);/* Forward declarations */void tfrc_time_no_feedback(void *ccb);void tfrc_time_send(void *ccb);void tfrc_set_send_timer(struct tfrc_send_ccb *cb, struct timeval t_now);void tfrc_updateX(struct tfrc_send_ccb *cb, struct timeval t_now);double tfrc_calcX(u_int16_t s, u_int32_t R, double p);void tfrc_send_term(void *ccb);/* Forward declarations */double tfrc_calcImean(struct tfrc_recv_ccb *cb);void tfrc_recv_send_feedback(struct tfrc_recv_ccb *cb);int tfrc_recv_add_hist(struct tfrc_recv_ccb *cb, struct r_hist_entry *packet);void tfrc_recv_detectLoss(struct tfrc_recv_ccb *cb);u_int32_t tfrc_recv_calcFirstLI(struct tfrc_recv_ccb *cb);void tfrc_recv_updateLI(struct tfrc_recv_ccb *cb, long seq_loss, u_int8_t win_loss);void *tfrc_recv_init(struct dccpcb *pcb);void *tfrc_send_init(struct dccpcb* pcb);void tfrc_send_packet_recv(void *ccb, char *options, int optlen);void tfrc_recv_packet_recv(void *ccb, char *options, int optlen);void tfrc_send_free(void *ccb);void tfrc_recv_free(void *ccb);int tfrc_send_packet(void *ccb, long datasize);void tfrc_send_packet_sent(void *ccb, int moreToSend, long datasize);/* Weights used to calculate loss event rate */const double tfrc_recv_w[] = {1, 1, 1, 1, 0.8, 0.6, 0.4, 0.2};/* macros *//* Find a data packet in history * args: cb - ccb of receiver * elm - pointer to element (variable) * num - number in history (variable) * returns: elm points to found packet, otherwise NULL * Tested u:OK */#define TFRC_RECV_FINDDATAPACKET(cb,elm,num) \do{ \ elm = STAILQ_FIRST(&((cb)->hist)); \ while((elm) != NULL){ \ if((elm)->type == DCCP_TYPE_DATA || (elm)->type == DCCP_TYPE_DATAACK) \ (num)--; \ if(num == 0) \ break; \ elm = STAILQ_NEXT((elm), linfo); \ } \} while (0)/* Find next data packet in history * args: cb - ccb of receiver * elm - pointer to element (variable) * returns: elm points to found packet, otherwise NULL * Tested u:OK */#define TFRC_RECV_NEXTDATAPACKET(cb,elm) \do{ \ if(elm != NULL){ \ elm = STAILQ_NEXT(elm, linfo); \ while((elm) != NULL && (elm)->type != DCCP_TYPE_DATA && (elm)->type != DCCP_TYPE_DATAACK){ \ elm = STAILQ_NEXT((elm), linfo); \ } \ } \} while (0)#define DCP_DATA_EVENT (tp->rcvq_h != tp->rcvq_t)#define DCP_DATA_EVENT_TO ((tp->rcvq_h != tp->rcvq_t) || tp->timer_expired)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -