📄 ztcp_input.c
字号:
#include "include/zeth.h"#include "include/zarp.h"#include "include/ztcp.h"#include "include/ztask.h"#include "include/zstats.h"/****used in tcp_process and tcp_input reduse paramer's number*****/static tcp_header_t *ptcpheader;static ip_header_t *pipheader;static tcp_seg_t inseg;static void tcp_parseopt(tcp_pcb_t *ptcp, tcp_header_t *ptcpheader){ u8_t c; u8_t *opts, opt; u16_t mss; opts = (u8_t *)ptcpheader + TCP_HEAD_LEN; /* Parse the TCP MSS option, if present. */ if((TCPH_OFFSET(ptcpheader) & 0xf0) > 0x50) { for(c = 0; c < ((TCPH_OFFSET(ptcpheader) >> 4) - 5) << 2 ;) { opt = opts[c]; if(opt == 0x00) { /* End of options. */ break; } else if(opt == 0x01) { ++c; /* NOP option. */ } else if(opt == 0x02 && opts[c + 1] == 0x04) { /* An MSS option with the right option length. */ mss = (opts[c + 2] << 8) | opts[c + 3]; ptcp->mss = mss > TCP_MSS? TCP_MSS: mss; /* And we are done processing options. */ break; } else { if(opts[c + 1] == 0) { /* If the length field is zero, the options are malformed and we don't process them further. */ break; } /* All other options have a length field, so that we easily can skip past them. */ c += opts[c + 1]; } } }}static void tcp_process(znetif_t *pnetif, zbuffer_t *pbuffer, tcp_pcb_t *ptcp);static void tcp_receive(tcp_pcb_t *ptcp, zbuffer_t *pbuffer);void tcp_input(znetif_t *pnetif, zbuffer_t *pbuffer){ eth_header_t *pethheader; u16_t offset; s16_t h_off; tcp_pcb_t *prev, *ptcp; zsocket_t *psocket; /*setup information pointer*/ pethheader = (eth_header_t *)( (u8_t *)pbuffer->pdata); pipheader = (ip_header_t *)( (u8_t *)pbuffer->pdata + ETH_HEAD_LEN); offset = IPH_HL(pipheader) * 4 + ETH_HEAD_LEN; ptcpheader = (tcp_header_t *)((u8_t *)pbuffer->pdata + offset); inseg.next = NULL; inseg.len = IPH_LEN(pipheader) - (TCPH_OFFSET(ptcpheader) >> 2) - (IPH_HL(pipheader) << 2); inseg._ori_pbuffer = pbuffer; inseg.pbuffer = pbuffer; inseg.pdata = (void *)((u8_t *)ptcpheader + (TCPH_OFFSET(ptcpheader) >> 2)); inseg.ptcpheader = ptcpheader; if ( !((pipheader->dest_ipaddr == pnetif->ipaddr) || (ip_addr_isbroadcast(pipheader->dest_ipaddr,pnetif->netmask) && ip_addr_maskcmp(pipheader->dest_ipaddr,pnetif->ipaddr,pnetif->netmask) ))) { zbuffer_delete(pbuffer); return ; } /*we check checksum*/ h_off = (s16_t)(0 -offset); if ( zbuffer_head_adjust(pbuffer, h_off) != 0) return; if ( inet_chksum_pseudo(pbuffer,&pipheader->src_ipaddr, &pipheader->dest_ipaddr,IP_PROTO_TCP,pbuffer->tot_len) != 0) { zbuffer_delete(pbuffer); return; } h_off *= -1; if ( zbuffer_head_adjust(pbuffer, h_off) != 0) return; /*add to arp table*/ add_arp_item( &pipheader->src_ipaddr,&pethheader->src_hwaddr); /* Demultiplex an incoming segment. First, we check if it is destined for an active connection. */ prev = NULL; for(ptcp = ptcp_active_chain; ptcp != NULL; ptcp = ptcp->next) { /* ASSERT("tcp_input: active pcb->state != CLOSED", pcb->state != CLOSED); ASSERT("tcp_input: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT); ASSERT("tcp_input: active pcb->state != LISTEN", pcb->state != LISTEN); */ psocket = ptcp->_psocket; if ( psocket->_lport == ptcpheader->dest && psocket->_rport == ptcpheader->src && psocket->_lipaddr == pipheader->dest_ipaddr && psocket->_ripaddr == pipheader->src_ipaddr) { /* Move this PCB to the front of the list so that subsequent lookups will be faster (we exploit locality in TCP segment arrivals). */ /* ASSERT("tcp_input: pcb->next != pcb (before cache)", pcb->next != pcb); */ if(prev != NULL) { prev->next = ptcp->next; ptcp->next = ptcp_active_chain; ptcp_active_chain = ptcp; } /* ASSERT("tcp_input: pcb->next != pcb (after cache)", pcb->next != pcb); */ break; } prev = ptcp; } /* If it did not go to an active connection, we check the connections in the TIME-WAIT state. */ if(ptcp == NULL) { for(ptcp = ptcp_tw_chain; ptcp != NULL; ptcp = ptcp->next) { /*ASSERT("tcp_input: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT);*/ psocket = ptcp->_psocket; if ( psocket->_lport == ptcpheader->dest && psocket->_rport == ptcpheader->src && psocket->_lipaddr == pipheader->dest_ipaddr && psocket->_ripaddr == pipheader->src_ipaddr) { /* We don't really care enough to move this PCB to the front of the list since we are not very likely to receive that many segments for connections in TIME-WAIT. */ break; } } /* Finally, if we still did not get a match, we check all PCBs that are LISTENing for incomming connections. */ prev = NULL; if(ptcp == NULL) { for(ptcp = ptcp_listen_chain; ptcp != NULL; ptcp = ptcp->next) { /*ASSERT("tcp_input: LISTEN pcb->state == LISTEN", pcb->state == LISTEN);*/ psocket = ptcp->_psocket; if ( psocket->_lport == ptcpheader->dest && psocket->_lipaddr == pipheader->dest_ipaddr) { /* Move this PCB to the front of the list so that subsequent lookups will be faster (we exploit locality in TCP segment arrivals). */ if(prev != NULL) { prev->next = ptcp->next; ptcp->next = ptcp_listen_chain; ptcp_listen_chain = ptcp; } break; } prev = ptcp; } } } if ( ptcp == NULL) { tcp_reset(pnetif, pipheader, ptcpheader); zbuffer_delete(pbuffer); return; } tcp_process(pnetif, pbuffer, ptcp); zbuffer_delete(pbuffer); if (ptcp->flags & TF_CLOSED) { if(ptcp->state == TIME_WAIT) { tcp_pcb_remove(&ptcp_tw_chain, ptcp); } else { tcp_pcb_remove(&ptcp_active_chain, ptcp); } sys_signal_sem(ptcp->user_sem); /*just as a EVENT*/ tcp_pcb_delete(ptcp); return; } if (ptcp->state != LISTEN && ptcp->state != CLOSED) { tcp_output(ptcp); } if (ptcp->flags & TF_GOT_FIN) { tcp_pcb_close(ptcp); }}void tcp_process(znetif_t *pnetif, zbuffer_t *pbuffer, tcp_pcb_t *ptcp){ tcp_pcb_t *nptcp, *tcp_tmp_pcb; u32_t seqno, ackno; u8_t flags; u32_t optdata; tcp_seg_t *rseg; u8_t acceptable = 0; s8_t nsocket, err; flags = TCPH_FLAGS(ptcpheader); seqno = ptcpheader->seqno; ackno = ptcpheader->ackno; /* Process incoming RST segments. */ if(flags & TCP_RST) { /* First, determine if the reset is acceptable. */ if(ptcp->state != LISTEN) { if(ptcp->state == SYN_SENT) { if(ackno == ptcp->snd_nxt) { acceptable = 1; } } else { if(TCP_SEQ_GEQ(seqno, ptcp->rcv_nxt) && TCP_SEQ_LEQ(seqno, ptcp->rcv_nxt + ptcp->rcv_wnd)) { acceptable = 1; } } } if(acceptable) { /* DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: Connection RESET\n")); ASSERT("tcp_input: pcb->state != CLOSED", pcb->state != CLOSED); */ ptcp->flags |= TF_RESET; ptcp->flags &= ~TF_ACK_DELAY; if(ptcp->state == TIME_WAIT) { tcp_pcb_remove(&ptcp_tw_chain, ptcp); } else { tcp_pcb_remove(&ptcp_active_chain, ptcp); } sys_signal_sem(ptcp->user_sem); /*just as a EVENT*/ tcp_pcb_delete(ptcp); } else { /* DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: unacceptable reset seqno %lu rcv_nxt %lu\n", seqno, pcb->rcv_nxt)); DEBUGF(TCP_DEBUG, ("tcp_process: unacceptable reset seqno %lu rcv_nxt %lu\n", seqno, pcb->rcv_nxt)); */ } return; /*XXX return point*/ }/*end of process reset TCP falgs*/ /*Ok,there is no RESET flags set in incoming tcp packet for a PCB*/ /* Update the PCB timer unless we are in the LISTEN state, in which case we don't even have memory allocated for the timer, much less use it. */ ptcp->tmr = tcp_ticks; /*first we update the PCB's timer*/ /* Do different things depending on the TCP state. */ switch(ptcp->state) { case CLOSED: /* Do nothing in the CLOSED state. In fact, this case should never occur since PCBs in the CLOSED state are never found in the list of active PCBs. */ break; case LISTEN: /* In the LISTEN state, we check for incoming SYN segments, creates a new PCB, and responds with a SYN|ACK. */ if(flags & TCP_ACK) { /* For incoming segments with the ACK flag set, respond with a RST. */ /*DEBUGF(TCP_RST_DEBUG, ("tcp_process: ACK in LISTEN, sending reset\n"));*/ tcp_reset(pnetif, pipheader, ptcpheader); return; /*XXX return point*/ } else if(flags & TCP_SYN) { if ( ptcp->accept != 0) /*if there is a connected remote client*/ { tcp_reset(pnetif, pipheader, ptcpheader); return; /*XXX return point*/ } nsocket = zsocket(data_stream); if ( nsocket < 0) /*because there are too many sockets in system*/ { tcp_reset(pnetif, pipheader, ptcpheader); return; /*XXX return point*/ } zbind(nsocket, &ptcp->_psocket->_lipaddr, &ptcp->_psocket->_lport); nptcp = tcp_pcb_query(nsocket); /*identify this is a listen's client, * when ESTABLISH send a EVENT*/ nptcp->server = ptcp; /* Set up the new PCB. */ nptcp->_psocket->_ripaddr = pipheader->src_ipaddr; nptcp->_psocket->_rport = ptcpheader->src; nptcp->state = SYN_RCVD; nptcp->rcv_nxt = seqno + 1; nptcp->snd_wnd = ptcpheader->wnd; nptcp->ssthresh = nptcp->snd_wnd; nptcp->snd_wl1 = ptcpheader->seqno; TCP_REG(&ptcp_active_chain, nptcp); /* Parse any options in the SYN. */ tcp_parseopt(nptcp, ptcpheader); /* Build an MSS option. */ optdata = (((u32_t)2 << 24) | ((u32_t)4 << 16) | (((u32_t)nptcp->mss / 256) << 8) | (nptcp->mss & 255)); /* Send a SYN|ACK together with the MSS option. */ err = tcp_insert_queue(nptcp, NULL, 0, TCP_SYN | TCP_ACK, (u8_t *)&optdata, 4); if ( err != ERR_OK) { tcp_pcb_remove(&ptcp_active_chain, nptcp); tcp_pcb_delete(nptcp); tcp_reset(pnetif, pipheader, ptcpheader); return; /*XXX return point*/ } tcp_output(nptcp); } else { tcp_reset(pnetif, pipheader, ptcpheader); } break; case SYN_SENT: /*DEBUGF(TCP_INPUT_DEBUG, ("SYN-SENT: ackno %lu pcb->snd_nxt %lu unacked %lu\n", ackno, pcb->snd_nxt, ntohl(pcb->unacked->tcphdr->seqno)));*/ if(flags & TCP_ACK && flags & TCP_SYN && ackno == (ptcp->unacked->ptcpheader->seqno) + 1) { ptcp->rcv_nxt = seqno + 1; ptcp->lastack = ackno; ptcp->rcv_wnd = ptcpheader->wnd; ptcp->state = ESTABLISHED; sys_signal_sem(ptcp->user_sem); /*as a EVENT */ ptcp->cwnd = ptcp->mss; --ptcp->snd_queuelen; /* DEBUGF(TCP_QLEN_DEBUG, ("tcp_process: SYN-SENT --queuelen %d\n", pcb->snd_queuelen));*/ rseg = ptcp->unacked; ptcp->unacked = rseg->next; rseg->next = NULL; tcp_seg_delete(rseg); /* Parse any options in the SYNACK. */ tcp_parseopt(ptcp, ptcpheader); tcp_ack(ptcp); /*ack later*/ } break; case SYN_RCVD: if(flags & TCP_ACK && !(flags & TCP_RST)) { if(TCP_SEQ_LT(ptcp->lastack, ackno) && TCP_SEQ_LEQ(ackno, ptcp->snd_nxt)) { ptcp->state = ESTABLISHED; /* DEBUGF(DEMO_DEBUG, ("TCP connection established %d -> %d.\n", inseg.tcphdr->src, inseg.tcphdr->dest)); */ /* Call the accept function. */ if ( ptcp->server != NULL) { ptcp->server->accept = ptcp->_psocket->_id; sys_signal_sem( ptcp->server->user_sem); } else /*FIXME we don't operate SYN_SENT t0 SYN_RECV*/ { tcp_abort(ptcp, pbuffer); return; } /* If there was any data contained within this ACK, we'd better pass it on to the application as well. */ tcp_receive(ptcp, pbuffer); ptcp->cwnd = ptcp->mss; } } break; case CLOSE_WAIT: case ESTABLISHED: tcp_receive(ptcp, pbuffer); if(flags & TCP_FIN) { tcp_ack_now(ptcp); ptcp->state = CLOSE_WAIT; } break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -