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

📄 ztcp_output.c

📁 uCOSII上实现的tcpip协议实现代码(gcc编译)
💻 C
字号:
#include "include/zeth.h"#include "include/zarp.h"#include "include/ztcp.h"#include "include/ztask.h"#include "include/zstats.h"u8_t tcp_ip_out(znetif_t *pnetif, ipaddr_t *pdest_ip, ipaddr_t *psrc_ip,zbuffer_t * pbuffer){	ip_header_t	*pipheader;	eth_header_t	*pethheader;	ethaddr_t	remote_eth;	u8_t	i;	if ( pnetif != NULL &&	pbuffer!= NULL)	{		pethheader = (eth_header_t *)pbuffer->pdata;		pipheader = (ip_header_t *) ( (u8_t *)pbuffer->pdata + ETH_HEAD_LEN);		IPH_VHLTOS_SET(pipheader, 4, IP_HEAD_LEN / 4, 0);		IPH_LEN_SET(pipheader, pbuffer->tot_len - ETH_HEAD_LEN);		IPH_OFFSET_SET(pipheader, IP_DF);		IPH_ID_SET(pipheader, ++ip_id);		IPH_TTL_SET(pipheader, TCP_TTL);		IPH_PROTO_SET(pipheader, IP_PROTO_TCP);		pipheader->dest_ipaddr = *pdest_ip;		pipheader->src_ipaddr = *psrc_ip;		IPH_CHKSUM_SET(pipheader, 0);		IPH_CHKSUM_SET(pipheader, inet_chksum(pipheader, IP_HEAD_LEN));		if ( arp_lookup( &remote_eth, pdest_ip) != 0 )		{			if ( arp_query(&remote_eth, pdest_ip ) != 0 )			{				return -1;			}		}		/*last eth header*/		for ( i = 0; i < 6 ; i ++)		{			pethheader->dest_hwaddr.addr[i] = remote_eth.addr[i];			pethheader->src_hwaddr.addr[i] = pnetif->hwaddr.addr[i];		}		pethheader->eth_type = ETHTYPE_IP;		pnetif->netif_tx(pnetif, pbuffer);	}	return 0;}u8_t tcp_reset(znetif_t *pnetif, ip_header_t *pipheader, tcp_header_t *ptcpheader){	zbuffer_t	*sbuf;	ip_header_t	*piph;	eth_header_t	*pethh;	tcp_header_t	*ptcph;	s16_t			hoff;	u16_t			offset;	sbuf = zbuffer_new(IP_HEAD_LEN + ETH_HEAD_LEN + TCP_HEAD_LEN );	if ( sbuf == NULL)		return -1;	/*setup information pointer*/	pethh = (eth_header_t *)(sbuf->pdata);	piph = (ip_header_t *)( (u8_t *)sbuf->pdata + ETH_HEAD_LEN);	ptcph = (tcp_header_t *)((u8_t *)sbuf->pdata + IP_HEAD_LEN + ETH_HEAD_LEN);	/*first setup TCP header*/	ptcph->src = ptcpheader->dest;	ptcph->dest = ptcpheader->src;	if ( TCPH_FLAGS(ptcpheader) & TCP_ACK )	{		ptcph->seqno = ptcpheader->ackno;		TCPH_FLAGS_SET(ptcph, TCP_RST);	}	else	{		ptcph->seqno = 0;		TCPH_FLAGS_SET(ptcph, TCP_RST | TCP_ACK);	}	offset = IPH_LEN(pipheader) - IPH_HL(pipheader) * 4 - (TCPH_OFFSET(ptcpheader) >> 2) ;	if ( TCPH_FLAGS(ptcpheader) & TCP_SYN)	{		offset ++;	}	if ( TCPH_FLAGS(ptcpheader) & TCP_FIN)	{		offset ++;	}	ptcph->ackno = ptcpheader->seqno + offset;	TCPH_OFFSET_SET(ptcph, TCP_HEAD_LEN << 2);	ptcph->wnd = ptcph->urgp = 0;	hoff = (s16_t)(0 - (IP_HEAD_LEN + ETH_HEAD_LEN));	if ( zbuffer_head_adjust(sbuf, hoff) != 0)		return -1;	ptcph->chksum = 0;	ptcph->chksum = inet_chksum_pseudo(sbuf , &pipheader->src_ipaddr, &pipheader->dest_ipaddr, IP_PROTO_TCP, TCP_HEAD_LEN);	hoff *= -1;	if ( zbuffer_head_adjust(sbuf,hoff) != 0)		return -1;	/*send it to network at once*/	tcp_ip_out(pnetif, &pipheader->src_ipaddr, &pipheader->dest_ipaddr, sbuf);	zbuffer_delete(sbuf);	return 0;}static void tcp_output_seg(tcp_pcb_t *ptcp, tcp_seg_t *seg){	s16_t	h_off;	/* The TCP header has already been constructed, but the ackno and	   wnd fields remain. */	seg->ptcpheader->ackno = (ptcp->rcv_nxt);	/* silly window avoidance */	if(ptcp->rcv_wnd < ptcp->mss) 	{		seg->ptcpheader->wnd = 0;	} 	else 	{		seg->ptcpheader->wnd = ptcp->rcv_wnd;	}	/* If we don't have a local IP address, we get one by	   calling ip_route(). */	ptcp->rtime = 0;	if(ptcp->rttest == 0) 	{		ptcp->rttest = tcp_ticks;		ptcp->rtseq = seg->ptcpheader->seqno;		/*DEBUGF(TCP_RTO_DEBUG, ("tcp_output_segment: rtseq %lu\n", pcb->rtseq));*/	}	/*DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output_segment: %lu:%lu\n",	  htonl(seg->tcphdr->seqno), htonl(seg->tcphdr->seqno) +	  seg->len));*/	h_off = (s16_t)(0 - (IP_HEAD_LEN + ETH_HEAD_LEN));		zbuffer_head_adjust( seg->_ori_pbuffer, h_off);	seg->ptcpheader->chksum = 0x00;	seg->ptcpheader->chksum = inet_chksum_pseudo( seg->_ori_pbuffer,			&(ptcp->_psocket->_lipaddr),&(ptcp->_psocket->_ripaddr),			IP_PROTO_TCP,			seg->_ori_pbuffer->tot_len);	h_off = 0 - h_off;	zbuffer_head_adjust( seg->_ori_pbuffer, h_off);		tcp_ip_out(ptcp->_psocket->_pnetif,			&ptcp->_psocket->_ripaddr, &ptcp->_psocket->_lipaddr,			seg->_ori_pbuffer);	}void tcp_rexmit_seg(tcp_pcb_t *ptcp, tcp_seg_t *seg){	u32_t wnd;	s16_t	h_off;/*	DEBUGF(TCP_REXMIT_DEBUG, ("tcp_rexmit_seg: skickar %ld:%ld\n",				ntohl(seg->tcphdr->seqno),				ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg)));*/	wnd = MIN(ptcp->snd_wnd, ptcp->cwnd);	if((seg->ptcpheader->seqno) - ptcp->lastack + seg->len <= wnd) 	{		/* Count the number of retranmissions. */		++ptcp->nrtx;				seg->ptcpheader->ackno = (ptcp->rcv_nxt);		seg->ptcpheader->wnd = (ptcp->rcv_wnd);		/* Recalculate checksum. */		/* Recalculate checksum. */		seg->ptcpheader->chksum = 0;		h_off = (s16_t)(0 - (IP_HEAD_LEN + ETH_HEAD_LEN));		zbuffer_head_adjust( seg->_ori_pbuffer, h_off);		seg->ptcpheader->chksum = inet_chksum_pseudo( seg->_ori_pbuffer,				&(ptcp->_psocket->_lipaddr),&(ptcp->_psocket->_ripaddr),				IP_PROTO_TCP,				seg->_ori_pbuffer->tot_len);		h_off = 0 - h_off;		zbuffer_head_adjust( seg->_ori_pbuffer, h_off);		ptcp->rtime = 0;		/* Don't take any rtt measurements after retransmitting. */    		ptcp->rttest = 0;		tcp_ip_out(ptcp->_psocket->_pnetif,				&ptcp->_psocket->_ripaddr, &ptcp->_psocket->_lipaddr,				seg->_ori_pbuffer);		} 	else 	{		/*DEBUGF(TCP_REXMIT_DEBUG, ("tcp_rexmit_seg: no room in window %lu to send %lu (ack %lu)\n",					wnd, ntohl(seg->tcphdr->seqno), pcb->lastack));*/	}}s8_t tcp_insert_queue( tcp_pcb_t *ptcp, void *pdata, u16_t data_len,		u8_t flags, u8_t *optdata, u8_t opt_len){	tcp_seg_t *seg, *useg, *queue;	u32_t left, seqno;	u16_t seglen, tmp_len;	void *ptr;	u8_t queuelen, i;	s16_t	offset;	left = data_len;	ptr = pdata;	if(data_len > ptcp->snd_buf) 	{		/*DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue: too much data %d\n", len));*/		return ERR_MEM;	}	seqno = ptcp->snd_lbb;	queue = NULL;	/*DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: %d\n", pcb->snd_queuelen));*/	queuelen = ptcp->snd_queuelen;	if(queuelen >= TCP_SND_QUEUELEN) 	{		/*DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue: too long queue %d (max %d)\n", queuelen, TCP_SND_QUEUELEN));*/		goto memerr;	}   	if(ptcp->snd_queuelen != 0) 	{		/*	ASSERT("tcp_enqueue: valid queue length", pcb->unacked != NULL ||			pcb->unsent != NULL);      */	}	seg = NULL;	seglen = 0;	while(queue == NULL || left > 0)	{		seglen = left > ptcp->mss? ptcp->mss: left;		/* allocate memory for tcp_seg, and fill in fields */		seg = tcp_seg_new();		if(seg == NULL) 		{			/*DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue: could not allocate memory for tcp_seg\n"));*/			goto memerr;		}		if(queue == NULL) {			queue = seg;		} else {			for(useg = queue; useg->next != NULL; useg = useg->next);			useg->next = seg;		}		/* If copy is set, memory should be allocated		   and data copied into pbuf, otherwise data comes from		   ROM or other static memory, and need not be copied. If		   optdata is != NULL, we have options instead of data. */		if(optdata != NULL) 		{			seg->_ori_pbuffer = zbuffer_new(TCP_HEAD_LEN + IP_HEAD_LEN + ETH_HEAD_LEN + opt_len);			if (seg->_ori_pbuffer == NULL)			{				goto memerr;			}			++queuelen;			seg->pdata = (void *)((u8_t *)seg->_ori_pbuffer->pdata + 					TCP_HEAD_LEN + IP_HEAD_LEN + ETH_HEAD_LEN + opt_len);			seg->pbuffer = seg->_ori_pbuffer;			seg->ptcpheader = (void *)((u8_t *)seg->_ori_pbuffer->pdata + 					IP_HEAD_LEN + ETH_HEAD_LEN);		}		else  /*there is no optdata*/		{			seg->_ori_pbuffer = zbuffer_new(TCP_HEAD_LEN + IP_HEAD_LEN + ETH_HEAD_LEN + seglen);			if (seg->_ori_pbuffer == NULL)			{				goto memerr;			}			offset = 0 - (TCP_HEAD_LEN + IP_HEAD_LEN + ETH_HEAD_LEN );			if ( zbuffer_head_adjust( seg->_ori_pbuffer, offset) != 0)			{				goto memerr;			}			tmp_len = seglen;			zbuffer_write( seg->_ori_pbuffer, ptr , &tmp_len);	/*write data to segment from call*/			if ( tmp_len != seglen)			{				goto memerr;			}			offset *= -1;			if ( zbuffer_head_adjust(seg->_ori_pbuffer, offset) != 0)			{				goto memerr;			}			++queuelen;			seg->pdata = (void *)((u8_t *)seg->_ori_pbuffer->pdata + 					TCP_HEAD_LEN + IP_HEAD_LEN + ETH_HEAD_LEN);			seg->pbuffer = seg->_ori_pbuffer;			seg->ptcpheader = (void *)((u8_t *)seg->_ori_pbuffer->pdata + 					IP_HEAD_LEN + ETH_HEAD_LEN);		}		if(queuelen > TCP_SND_QUEUELEN) 		{			/*	DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue: queue too long %d (%d)\n", queuelen, TCP_SND_QUEUELEN)); */				goto memerr;		}		seg->len = seglen;		seg->ptcpheader->src = ptcp->_psocket->_lport;		seg->ptcpheader->dest = ptcp->_psocket->_rport;				seg->ptcpheader->seqno = (seqno);		seg->ptcpheader->urgp = 0;		TCPH_FLAGS_SET(seg->ptcpheader, flags);		/* don't fill in tcphdr->ackno and tcphdr->wnd until later */		if(optdata == NULL) 		{			TCPH_OFFSET_SET(seg->ptcpheader, 5 << 4);		} else 		{			TCPH_OFFSET_SET(seg->ptcpheader, (5 + opt_len / 4) << 4);			/* Copy options into data portion of segment.			   Options can thus only be sent in non data carrying			   segments such as SYN|ACK. */			for ( i = 0;  i < opt_len; i++)				*((u8_t *)seg->ptcpheader + TCP_HEAD_LEN + i) = optdata[i];		}		/*		   DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue: queueing %lu:%lu (0x%x)\n",		   ntohl(seg->tcphdr->seqno),		   ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg),		   flags));*/		left -= seglen;		seqno += seglen;		ptr = (void *)((char *)ptr + seglen);	}	/* Go to the last segment on the ->unsent queue. */    	if(ptcp->unsent == NULL) 	{		useg = NULL;	}	else 	{		for(useg = ptcp->unsent; useg->next != NULL; useg = useg->next);	}	/* If there is room in the last pbuf on the unsent queue,	   chain the first pbuf on the queue together with that. */	if(useg != NULL &&			TCP_TCPLEN(useg) != 0 &&			!(TCPH_FLAGS(useg->ptcpheader) & (TCP_SYN | TCP_FIN)) &&			!(flags & (TCP_SYN | TCP_FIN)) &&			useg->len + queue->len <= ptcp->mss) 	{		/* Remove TCP header from first segment. */		offset = 0 - (TCP_HEAD_LEN + IP_HEAD_LEN + ETH_HEAD_LEN );		queue->_ori_pbuffer = zbuffer_adjust( queue->_ori_pbuffer, offset, 0);		zbuffer_add( useg->_ori_pbuffer, queue->_ori_pbuffer);		useg->len += queue->len;			/*TCP's data update*/		useg->next = queue->next;		if(seg == queue) 		{			seg = NULL;		}		queue->_ori_pbuffer = NULL;			/*we will delete queue so we must set it to NULL*/		queue->next = NULL;		tcp_seg_delete(queue);			/*remove this segment*/		queuelen --;						} 	else 	{      		if(useg == NULL) 		{			ptcp->unsent = queue;		} 		else 		{			useg->next = queue;		}	}	if((flags & TCP_SYN) || (flags & TCP_FIN)) 	{		++data_len;	}	ptcp->snd_lbb += data_len;	ptcp->snd_buf -= data_len;	ptcp->snd_queuelen = queuelen;	/*DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: %d (after enqueued)\n", pcb->snd_queuelen));*/	if(ptcp->snd_queuelen != 0) 	{		/*	ASSERT("tcp_enqueue: valid queue length", pcb->unacked != NULL ||			pcb->unsent != NULL);			*/	}	/* Set the PSH flag in the last segment that we enqueued, but only	   if the segment has data (indicated by seglen > 0). */	if(seg != NULL && seglen > 0 && seg->ptcpheader != NULL) 	{		TCPH_FLAGS_SET(seg->ptcpheader, TCPH_FLAGS(seg->ptcpheader) | TCP_PSH);	}	return ERR_OK;memerr:	if(queue != NULL) 	{		tcp_seg_delete(queue);	}	if(ptcp->snd_queuelen != 0) 	{		/*						ASSERT("tcp_enqueue: valid queue length", pcb->unacked != NULL ||				pcb->unsent != NULL);				*/	}	/*	DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: %d (with mem err)\n", pcb->snd_queuelen));*/	return ERR_MEM;}void tcp_abort(tcp_pcb_t *ptcp, zbuffer_t *pbuffer){	ip_header_t	*pipheader;	tcp_header_t *ptcpheader;	/* Figure out on which TCP PCB list we are, and remove us. If we	   are in an active state, call the receive function associated with	   the PCB with a NULL argument, and send an RST to the remote end. */	if(ptcp->state == TIME_WAIT) 	{		tcp_pcb_remove(&ptcp_tw_chain, ptcp);		tcp_pcb_delete(ptcp);	} 	else if(ptcp->state == LISTEN) 	{		tcp_pcb_remove(&ptcp_listen_chain, ptcp);		tcp_pcb_delete(ptcp);	} 	else 	{		if ( pbuffer != NULL)		{			pipheader = (ip_header_t *)( (u8_t *)pbuffer->pdata + ETH_HEAD_LEN);			ptcpheader = (tcp_header_t *)((u8_t *)pbuffer->pdata + IP_HEAD_LEN + ETH_HEAD_LEN);			tcp_reset(ptcp->_psocket->_pnetif, pipheader, ptcpheader);		}		tcp_pcb_remove(&ptcp_active_chain, ptcp);		tcp_pcb_delete(ptcp);	}}/* find out what we can send and send it */s8_t tcp_output(tcp_pcb_t *ptcp){	zbuffer_t *pbuffer;	tcp_header_t *ptcpheader;	tcp_seg_t *seg, *useg;	u32_t wnd;	wnd = MIN(ptcp->snd_wnd, ptcp->cwnd);	seg = ptcp->unsent;	if(ptcp->flags & TF_ACK_NOW) 	{		/* If no segments are enqueued but we should send an ACK, we		   construct the ACK and send it. */		ptcp->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);		pbuffer = zbuffer_new(IP_HEAD_LEN + ETH_HEAD_LEN + TCP_HEAD_LEN );		ptcpheader = (tcp_header_t *)( (u8_t *)pbuffer->pdata + ETH_HEAD_LEN + IP_HEAD_LEN);		/*setup ptcpheader's information*/		ptcpheader->src = ptcp->_psocket->_lport;		ptcpheader->dest = ptcp->_psocket->_rport;		ptcpheader->seqno = ptcp->snd_nxt;		ptcpheader->ackno = ptcp->rcv_nxt;		TCPH_FLAGS_SET(ptcpheader, TCP_ACK);		ptcpheader->wnd = ptcp->rcv_wnd;		ptcpheader->urgp = 0;		TCPH_OFFSET_SET(ptcpheader, 5 << 4);		ptcpheader->chksum = 0;		zbuffer_head_adjust(pbuffer, 0 - IP_HEAD_LEN - ETH_HEAD_LEN);		ptcpheader->chksum = inet_chksum_pseudo(pbuffer, &(ptcp->_psocket->_lipaddr),				&(ptcp->_psocket->_ripaddr), IP_PROTO_TCP, TCP_HEAD_LEN);		zbuffer_head_adjust(pbuffer, IP_HEAD_LEN + ETH_HEAD_LEN);				tcp_ip_out(ptcp->_psocket->_pnetif,				&ptcp->_psocket->_ripaddr, &ptcp->_psocket->_lipaddr, pbuffer);				zbuffer_delete(pbuffer);				return ERR_OK;	} 	while(seg != NULL &&			(seg->ptcpheader->seqno) - ptcp->lastack + seg->len <= wnd) 	{		ptcp->rtime = 0;				ptcp->unsent = seg->next;		seg->next = NULL;		if(ptcp->state != SYN_SENT) 		{			TCPH_FLAGS_SET(seg->ptcpheader, TCPH_FLAGS(seg->ptcpheader) | TCP_ACK);			ptcp->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);		}		tcp_output_seg(ptcp, seg);		ptcp->snd_nxt = (seg->ptcpheader->seqno) + TCP_TCPLEN(seg);				if(TCP_SEQ_LT(ptcp->snd_max, ptcp->snd_nxt)) 		{			ptcp->snd_max = ptcp->snd_nxt;		}		/* put segment on unacknowledged list if length > 0 */		if(TCP_TCPLEN(seg) > 0) 		{			seg->next = NULL;			if(ptcp->unacked == NULL) 			{				ptcp->unacked = seg;			} 			else 			{				for(useg = ptcp->unacked; useg->next != NULL; useg = useg->next);				useg->next = seg;			}		} 		else		{			tcp_seg_delete(seg);			}				seg = ptcp->unsent;	}  	return ERR_OK;}

⌨️ 快捷键说明

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