📄 ztcp_output.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 + -