⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dcp.c

📁 DCCP协议在linux下的C编程实现 linux C
💻 C
📖 第 1 页 / 共 5 页
字号:
#define DCP_DATA_EVENT_OPEN    ((tp->rcvq_h != tp->rcvq_t) || (sk->state != DCP_OPEN) || tp->shake_defer)#define wrapdec_24(i) ((!i) ? i=0xffffff : --i)//#define wrapdec_24(i) ((!i) ? 0xffffff : --i)//#define wrapdec_24(i) if (i >0) i--; else i=0xffffff;  /* code *//* Gets an option from a provided option list and copies it into a buffer. * Designed for use with TFRC as standard DCCP options are dealt with in other functions, i.e. generic_option_parse() * * Parameters:	options - the options list * 		optlen - the length of the options list * 		type - the option id that is being looked for * 		buffer - the buffer to copy the option into * 		buflen - the length of the buffer * */int dccp_get_option(char *options, int optlen, int type, char *buffer, int buflen){	int i, j, size;	u_int8_t t;   #if DCP_DEBUG > 0	printk("TFRC reckons it wants to get an OPTION\n");#endif	for (i=0; i < optlen; ) {		t = options[i++];		// options with codes less than 32 are only one byte		if(t >= 32){		  			size = options[i++] - 2;			if (t == type) {				// buffer would overflow!				if(size > buflen)					return 0;				// copying option code into the buffer				for (j=0; j<size; j++)					buffer[j] = options[i++];				return size;			}			i += size;		}	}	/* If we get here the option was not found */	return 0;}/* Adds an option to the option list. * Used by TFRC to append TFRC-specific options. Standard DCCP options are dealt with in other functions * * Parameters:	tp - the dcp_opt structure describing the current connection * 		type - the type of option to append * 		option - the option data * 		optlen - the length of the option data * */int  dccp_add_option(struct dcp_opt *tp, u_int8_t type, char *option , u_int8_t optlen){	/* NOTE: Just in case you're confused, the +2 used throughout this function is because optlen does	 * not include the option type and size bytes, just the data. */		spin_lock (&tp->rsem);   //lock this for the length feild to avoid race conditions   #if DCP_DEBUG > 0	printk("TFRC reckons it wants to append an OPTION %i\n",type);#endif   	// making sure we've got space to add the option	if (tp->opt_a_sz + optlen +2 > DCP_OPTASZ)	{#if DCP_DEBUG > 2 		printk("DCCP run out of space for %i len(%i) using %d of %d\n",type,optlen, tp->opt_a_sz, DCP_OPTASZ);#endif      //shuldent spinlock be released befor return? I try, BJORN.      spin_unlock(&tp->rsem);		return 1;	}	tp->opt_append[tp->opt_a_sz++] = type;	tp->opt_append[tp->opt_a_sz++] = optlen+2;	memcpy(&tp->opt_append[tp->opt_a_sz],option,optlen);	tp->opt_a_sz+=optlen; //+2 here creates a DOS attack that takes out the other side and ethereal. NICE..	// so is the above line wrong then??? - SHANE	spin_unlock (&tp->rsem);		//This should be easy enough!	return 0;}//ASSUME LOCK HERE MOFO~!/* Schedules an ACK if necessary under TFRC * * Parameters:	tp - the dcp_opt structure describing the connection * 		extra - unused * */int dccp_output(register struct dcp_opt *tp, unsigned char extra ){#if DCP_DEBUG > 0	printk("TFRC reckons it wants to SEND a packet\n");#endif	// if an ack has been scheduled, start arranging for one	if((!(tp->flags & FLAG_ACKSCHED)))	{#if DCP_DEBUG > 0		printk("TFRC did schedule an ack\n");#endif		//	tp->atask.data =sk;		tp->flags |= FLAG_ACKSCHED;		schedule_task(&tp->atask);	}	//Told mcmanaus to schedule that sucker.	//dccp_schedule_ack_locked(tp, sk); //HACKQ! atask hopefully holds the socket descriptor, if it doesn't it was like that when i found it....	//	wake_up (&tp->newdata);  //TODO: what does this actullay achieve, i just copied it from dccp_schedule_ack..	KERNEL_ASSERT(0);	return 0;}/* Converts the packet buffer into a build_t structure - used for packets not involved with the connection handshake *  * Parameters:	b - a previously declared build_t structure * 		h - the packet buffer representing the header of the packet to be transmitted * 		hl - the length of the packet header * 		iov - the data portion of the packet * */inline static int mkbuildt (struct build_t *b, unsigned char *h, u16 hl, struct iovec *iov){	b->h = h;	b->hl = hl;	b->iov = iov;	b->check = 0;	b->kdb= NULL;			/* occasionally (on handshake) we'll have data not from an iovec,							   but from a kernel buffer.. */	b->kdbl =0;	return 0;}/* Converts the packet buffer into a build_t structure - used for connection handshake packets  * * Parameters	b - a previously declared build_t structure * 		h - the packet buffer representing the header of the packet to be transmitted  * 		hl - the length of the packet header * 		kdb - the data portion of the packet * 		kbdl - the length of the data portion of the packet * */inline static int mkbuildt_k (struct build_t *b, unsigned char *h, u16 hl, unsigned char *kdb, int kdbl){	b->h = h;	b->hl = hl;	b->iov = NULL;	b->check = 0;	b->kdb=kdb;	b->kdbl =kdbl;	return 0;}/* A hash function for sockets, based on the remote address, remote port and local port * * Parameters:	ra - the remote address for the connection that uses this socket * 		rp - the remote port for the connection that uses this socket * 		lp - the local port for the connection that uses this socket */static inline u16 skhash (u32 ra, u16 rp, u16 lp){	u32 t;	t = ra * rp *lp + rp + lp +ra;	return t % DCP_SK_HASH_SZ;}/* Finds a socket in the sock hashtable * * Parameters:	locala - the IP address of the local end of the connection, needed for matching * 		remotea - the IP address of the remote end of the connection, needed for hashing and matching * 		svc - the service code for the socket, needed for matching bound sockets * 		lp - the port used at the local end of the connection, needed for hashing and matching * 		rp - the port used at the remote end of the connection, needed for hashing and matching * 		ptype - the type of packet received, used to distinguish between bound and connected sockets * */static struct sock *lookup_dccp_sk ( u32 locala, u32 remotea, u32 svc,		u16 lp, u16 rp, unsigned char ptype){	struct dccp_sk_list_t *p, *el, *dccp_sk_list;	u16 n,nl;	/* bound sockets (not connected) have a zeroed ra and rport */	el = NULL;	// if the packet is a request then we aren't connected yet, use 0 for ra and rp	if (ptype == TYPE_REQUEST)		n = skhash(0,0,lp);	else		n = skhash(remotea,rp,lp);	nl = n & 0xF;	read_lock (dccp_table_lock+nl);		dccp_sk_list = dccp_sk_hash[n];	// cycle through the list of sockets matching the skhash, looking for a socket whose attributes match	// the ones given as parameters	if (ptype == TYPE_REQUEST)	{		/*printk ("looking for request in chain %d - %X %d %d\n",n,locala, ntohs(lp),ntohs(rp)); */				for (p = dccp_sk_list;  (p && (!el)); p = p->n)		{			// ra and rp cannot be set because we aren't connected!			if  ( (!p->remotea) && (!p->rp) && (p->lp == lp) && (p->svc == svc) &&					((!locala) || (locala == p->locala)))				el = p;					/*printk ("%p %X %d %X %d %X, %X %d %X %d %X\n",el,			  remotea, ntohs(rp), locala, ntohs(lp), svc,			  p->remotea, ntohs(p->rp), p->locala, ntohs(p->lp), p->svc); */		}	}	else	{		for (p = dccp_sk_list;  (p && (!el)); p = p->n)			if  ((remotea == p->remotea) && (lp == p->lp) && (rp == p->rp)     /* normal connected case  */					&& ((!locala) || (locala == p->locala))) /* svc isn't considerd here */				el = p;	}	read_unlock (dccp_table_lock+nl);	// return NULL if we didn't find a matching socket	return el ? el->sk : NULL;}/*   inline static void output_stats( struct sock *sk;)   {#if DCP_DEBUG > 2struct dcp_opt *tp;tp = &(sk->tp_pinfo.tp_dcp);printk("ackr:%d\trtt:%d\tcwnd:%d\trcvr:%d\twndcount:%djiffies:%ld\n", tp->ackratio, tp->rtt, tp->cwnd,tp->rcvr_ratio,tp->wndcount,jiffies);#endif}*//* Translates the DCCP header information into local variables   * * Parameters: 	skb - the sk_buff containing the DCCP packet * 		la - the location IP address  * 		ra - the remote IP address  * 		svc - the service code * 		lp - the location port * 		rp - the remote port * 		*/static unsigned char parse_dccp_pkt (struct sk_buff *skb,		u32 *la, u32 *ra, u32 *svc,		u16 *lp, u16 *rp){	u32 t;	u16 rcheck,tc,lcheck;	unsigned char cslen,hl,rv;	if (skb->len < 12)		return TYPE_INVALID;	// saving a copy of the checksum and then zeroing it for computation	memcpy (&rcheck,skb->data+10,2);	memset (skb->data+10,0,2);	/* zero it for computation */	// getting checksum coverage field	cslen = skb->data[9] & 0x0F;	/* OK, I think the processing of cslen here is not up to date with the latest specs	 * IF cslen is 0 then checksum covers the whole packet	 * Otherwise the checksum covers cslen - 1 * 4 bytes of the application data, plus all the headers, options etc	 * IF cslen - 1 * 4 is greater than the length of the application data, then the packet must be ignored.	 * - SHANE	 */	if (cslen==15)		tc = skb->len;	else	{		// hl = header length		hl = skb->data[8];		tc = ((int)cslen+ (int)hl)  *4;		tc = (tc < skb->len) ? tc : skb->len;	}	// checksum is broken1	t = 0;	t = csum_partial (skb->data,tc,t);	lcheck = csum_fold (t);	memcpy (skb->data+10,&rcheck,2); /* put it back */	if (rp) memcpy (rp,skb->data,2);	if (lp) memcpy (lp,skb->data+2,2);	// rv = packet type	rv = skb->data[4] & 0xF0;	if (lcheck != rcheck)	{#if DCP_DEBUG > 0		printk ("dccp check-mismatch (%d: type %d) over %d of %d: sending %X, Rcv %X\n",				ntohs (*lp),rv,				tc,skb->len,rcheck,lcheck);#endif		return TYPE_INVALID; 	}	// svc = service code	if (rv == TYPE_REQUEST)	{		if (skb->len < 16)			return TYPE_INVALID;		if (svc) 			memcpy (svc,skb->data+12,4); 	}	else		if (svc) 			*svc = 0;	if (ra) 		*ra =  skb->nh.iph->saddr;	if (la) 		*la = skb->nh.iph->daddr;	return rv;}/* Asks for the socket to send a CLOSE packet. Called via tp->ctask. * * Parameters:	vsk - the socket which must send the CLOSE packet */static void dccp_safe_close (void *vsk){	struct sock *sk = vsk;	dccp_send_close (sk,TYPE_CLOSE);      /* send close */	return;}/* Asks for the socket to send a RESET packet. Called via tp->rtask. * * Parameters:	sk - the socket which must send the CLOSE packet */static void dccp_safe_reset (void *vsk){				/* we are only invoked by server side when a close or reset comes int */	struct sock *sk = vsk;	dccp_reset (sk,0);	unregister_dccp_sk(sk);	return;}/* Creates an ACK packet and sends it, as long as we've got too many unacked packets. Called via tp->atask. * * Parameters:	vsk - the socket on which the connection is taking place */static void  dccp_schedule_ack (void *vsk){	struct sock *sk = vsk;	struct dcp_opt *tp;	struct build_t b;	unsigned char *pbuf,*ackv,*mt;	struct ipcm_cookie ipc;	struct rtable *rt;	int ackvl,nma;   spin_lock (&tp->rsem);		tp = &(sk->tp_pinfo.tp_dcp);	nma =1;	//spin_lock (&tp->rsem);	#if DCP_DEBUG > 2	printk ("acktimer\n"); #endif	if ((sk->state == DCP_OPEN) && // we're due to send an ACK, according to the ACK vector			(tp->unacked >= tp->ackratio))	{		ipc.oif = sk->bound_dev_if;		ipc.opt = sk->protinfo.af_inet.opt;		ipc.addr = sk->daddr;		pbuf = kmem_cache_alloc (dccp_slab,GFP_ATOMIC);		memcpy (pbuf,&sk->sport,2);		memcpy (pbuf+2,&sk->dport,2);		pbuf[4] = TYPE_ACK;	/* ack pkt, includes the 4 rsvd bits */		pbuf[8] = 0x04;		/* header length - 4 32 bit words */		pbuf[9] = dcp_write_ndp (&tp->ndp,1);	/* ndp=tp->ndp and cslen=15 */		memset (pbuf+10,0,2);		/* checksum - starts at 0 for calc */		pbuf[12] = 0;			/* reserved */		tp->unacked = 0;		/* cause we're locked */		dccp_write_24 (&tp->ackn, pbuf+13,0); 		generic_option_negotiation (tp); /* cleaned out by genackvector */		ackv =dccp_generate_ackvector (sk, &ackvl); /* keep before seqno++ */		dccp_write_24 (&tp->seq, pbuf+5,1); /* incs sn for me */		// if we have an ack vector to append		if (ackvl)		{			pbuf[8] += ackvl /4;			if ((ackvl + 16) > MAX_DCP_REQUEST_SZ) //if the ackvl is too long to fit in pbuf, then make pbuf bigger			{				nma = 0;				//mt = kmalloc(ackvl+16,GFP_ATOMIC);            mt = vmalloc(ackvl+16);				memcpy (mt,pbuf,16);				kmem_cache_free (dccp_slab,pbuf);				pbuf = mt;			}		   memcpy (pbuf+16,ackv,ackvl);		}		// build and send our ACK		ip_route_output(&rt, sk->daddr, sk->saddr,RT_CONN_FLAGS(sk) , ipc.oif);		mkbuildt (&b, pbuf, 16+ackvl,NULL);		ip_build_xmit (sk,dccp_getfrag, &b,16+ackvl,&ipc,rt,MSG_DONTWAIT); 		if (nma)			kmem_cache_free (dccp_slab,pbuf);		else{          vfree(pbuf);			//kfree (pbuf);         }		//kfree (ackv);      vfree(ackv);	}	// an ACK is no longer scheduled so update the flags	tp->flags &= ~FLAG_ACKSCHED;	spin_unlock (&tp->rsem);		wake_up (&tp->newdata);  	return;}/* Closes the connection following the end of the TIMEWAIT state * * Parameters:	s - the socket which is to be closed */static void *dcp_handle_timewait (unsigned long s){

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -