NetServices Stack source
Dependents: HelloWorld ServoInterfaceBoardExample1 4180_Lab4
Diff: lwip/core/tcp_in.c
- Revision:
- 5:dd63a1e02b1b
- Parent:
- 0:632c9925f013
--- a/lwip/core/tcp_in.c Fri Jul 09 14:46:47 2010 +0000 +++ b/lwip/core/tcp_in.c Tue Jul 27 15:59:42 2010 +0000 @@ -93,6 +93,10 @@ { struct tcp_pcb *pcb, *prev; struct tcp_pcb_listen *lpcb; +#if SO_REUSE + struct tcp_pcb *lpcb_prev = NULL; + struct tcp_pcb_listen *lpcb_any = NULL; +#endif /* SO_REUSE */ u8_t hdrlen; err_t err; @@ -120,8 +124,8 @@ } /* Don't even process incoming broadcasts/multicasts. */ - if (ip_addr_isbroadcast(&(iphdr->dest), inp) || - ip_addr_ismulticast(&(iphdr->dest))) { + if (ip_addr_isbroadcast(¤t_iphdr_dest, inp) || + ip_addr_ismulticast(¤t_iphdr_dest)) { TCP_STATS_INC(tcp.proterr); TCP_STATS_INC(tcp.drop); snmp_inc_tcpinerrs(); @@ -131,10 +135,10 @@ #if CHECKSUM_CHECK_TCP /* Verify TCP checksum. */ - if (inet_chksum_pseudo(p, &iphdr->src, &iphdr->dest, + if (inet_chksum_pseudo(p, ip_current_src_addr(), ip_current_dest_addr(), IP_PROTO_TCP, p->tot_len) != 0) { LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packet discarded due to failing checksum 0x%04"X16_F"\n", - inet_chksum_pseudo(p, &iphdr->src, &iphdr->dest, + inet_chksum_pseudo(p, ip_current_src_addr(), ip_current_dest_addr(), IP_PROTO_TCP, p->tot_len))); #if TCP_DEBUG tcp_debug_print(tcphdr); @@ -181,8 +185,8 @@ LWIP_ASSERT("tcp_input: active pcb->state != LISTEN", pcb->state != LISTEN); if (pcb->remote_port == tcphdr->src && pcb->local_port == tcphdr->dest && - ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src)) && - ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest))) { + ip_addr_cmp(&(pcb->remote_ip), ¤t_iphdr_src) && + ip_addr_cmp(&(pcb->local_ip), ¤t_iphdr_dest)) { /* Move this PCB to the front of the list so that subsequent lookups will be faster (we exploit locality in TCP segment @@ -206,8 +210,8 @@ LWIP_ASSERT("tcp_input: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT); if (pcb->remote_port == tcphdr->src && pcb->local_port == tcphdr->dest && - ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src)) && - ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest))) { + ip_addr_cmp(&(pcb->remote_ip), ¤t_iphdr_src) && + ip_addr_cmp(&(pcb->local_ip), ¤t_iphdr_dest)) { /* 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. */ @@ -218,31 +222,55 @@ } } - /* Finally, if we still did not get a match, we check all PCBs that - are LISTENing for incoming connections. */ + /* Finally, if we still did not get a match, we check all PCBs that + are LISTENing for incoming connections. */ prev = NULL; for(lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) { - if ((ip_addr_isany(&(lpcb->local_ip)) || - ip_addr_cmp(&(lpcb->local_ip), &(iphdr->dest))) && - lpcb->local_port == tcphdr->dest) { - /* 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) { - ((struct tcp_pcb_listen *)prev)->next = lpcb->next; - /* our successor is the remainder of the listening list */ - lpcb->next = tcp_listen_pcbs.listen_pcbs; - /* put this listening pcb at the head of the listening list */ - tcp_listen_pcbs.listen_pcbs = lpcb; + if (lpcb->local_port == tcphdr->dest) { +#if SO_REUSE + if (ip_addr_cmp(&(lpcb->local_ip), ¤t_iphdr_dest)) { + /* found an exact match */ + break; + } else if(ip_addr_isany(&(lpcb->local_ip))) { + /* found an ANY-match */ + lpcb_any = lpcb; + lpcb_prev = prev; } - - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for LISTENing connection.\n")); - tcp_listen_input(lpcb); - pbuf_free(p); - return; +#else /* SO_REUSE */ + if (ip_addr_cmp(&(lpcb->local_ip), ¤t_iphdr_dest) || + ip_addr_isany(&(lpcb->local_ip))) { + /* found a match */ + break; + } +#endif /* SO_REUSE */ } prev = (struct tcp_pcb *)lpcb; } +#if SO_REUSE + /* first try specific local IP */ + if (lpcb == NULL) { + /* only pass to ANY if no specific local IP has been found */ + lpcb = lpcb_any; + prev = lpcb_prev; + } +#endif /* SO_REUSE */ + if (lpcb != NULL) { + /* 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) { + ((struct tcp_pcb_listen *)prev)->next = lpcb->next; + /* our successor is the remainder of the listening list */ + lpcb->next = tcp_listen_pcbs.listen_pcbs; + /* put this listening pcb at the head of the listening list */ + tcp_listen_pcbs.listen_pcbs = lpcb; + } + + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for LISTENing connection.\n")); + tcp_listen_input(lpcb); + pbuf_free(p); + return; + } } #if TCP_INPUT_DEBUG @@ -318,7 +346,14 @@ } if (recv_data != NULL) { - if(flags & TCP_PSH) { + if (pcb->flags & TF_RXCLOSED) { + /* received data although already closed -> abort (send RST) to + notify the remote host that not all data has been processed */ + pbuf_free(recv_data); + tcp_abort(pcb); + goto aborted; + } + if (flags & TCP_PSH) { recv_data->flags |= PBUF_FLAG_PUSH; } @@ -343,7 +378,7 @@ if (pcb->rcv_wnd != TCP_WND) { pcb->rcv_wnd++; } - TCP_EVENT_RECV(pcb, NULL, ERR_OK, err); + TCP_EVENT_CLOSED(pcb, err); if (err == ERR_ABRT) { goto aborted; } @@ -363,7 +398,7 @@ Below this line, 'pcb' may not be dereferenced! */ aborted: tcp_input_pcb = NULL; - + recv_data = NULL; /* give up our reference to inseg.p */ if (inseg.p != NULL) @@ -380,7 +415,7 @@ TCP_STATS_INC(tcp.proterr); TCP_STATS_INC(tcp.drop); tcp_rst(ackno, seqno + tcplen, - &(iphdr->dest), &(iphdr->src), + ip_current_dest_addr(), ip_current_src_addr(), tcphdr->dest, tcphdr->src); } pbuf_free(p); @@ -415,7 +450,7 @@ RST. */ LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_listen_input: ACK in LISTEN, sending reset\n")); tcp_rst(ackno + 1, seqno + tcplen, - &(iphdr->dest), &(iphdr->src), + ip_current_dest_addr(), ip_current_src_addr(), tcphdr->dest, tcphdr->src); } else if (flags & TCP_SYN) { LWIP_DEBUGF(TCP_DEBUG, ("TCP connection request %"U16_F" -> %"U16_F".\n", tcphdr->src, tcphdr->dest)); @@ -438,9 +473,9 @@ pcb->accepts_pending++; #endif /* TCP_LISTEN_BACKLOG */ /* Set up the new PCB. */ - ip_addr_copy(npcb->local_ip, iphdr->dest); + ip_addr_copy(npcb->local_ip, current_iphdr_dest); npcb->local_port = pcb->local_port; - ip_addr_copy(npcb->remote_ip, iphdr->src); + ip_addr_copy(npcb->remote_ip, current_iphdr_src); npcb->remote_port = tcphdr->src; npcb->state = SYN_RCVD; npcb->rcv_nxt = seqno + 1; @@ -453,7 +488,7 @@ npcb->accept = pcb->accept; #endif /* LWIP_CALLBACK_API */ /* inherit socket options */ - npcb->so_options = pcb->so_options & (SOF_DEBUG|SOF_DONTROUTE|SOF_KEEPALIVE|SOF_OOBINLINE|SOF_LINGER); + npcb->so_options = pcb->so_options & SOF_INHERITED; /* Register the new PCB so that we can begin receiving segments for it. */ TCP_REG(&tcp_active_pcbs, npcb); @@ -503,7 +538,7 @@ should be sent in reply */ if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt+pcb->rcv_wnd)) { /* If the SYN is in the window it is an error, send a reset */ - tcp_rst(ackno, seqno + tcplen, &(iphdr->dest), &(iphdr->src), + tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(), tcphdr->dest, tcphdr->src); return ERR_OK; } @@ -637,7 +672,7 @@ /* received ACK? possibly a half-open connection */ else if (flags & TCP_ACK) { /* send a RST to bring the other side in a non-synchronized state. */ - tcp_rst(ackno, seqno + tcplen, &(iphdr->dest), &(iphdr->src), + tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(), tcphdr->dest, tcphdr->src); } break; @@ -680,7 +715,7 @@ } } else { /* incorrect ACK number, send RST */ - tcp_rst(ackno, seqno + tcplen, &(iphdr->dest), &(iphdr->src), + tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(), tcphdr->dest, tcphdr->src); } } else if ((flags & TCP_SYN) && (seqno == pcb->rcv_nxt - 1)) { @@ -1402,6 +1437,24 @@ next->len = (u16_t)(seqno - next->tcphdr->seqno); pbuf_realloc(next->p, next->len); } + /* check if the remote side overruns our receive window */ + if ((u32_t)tcplen + seqno > pcb->rcv_nxt + (u32_t)pcb->rcv_wnd) { + LWIP_DEBUGF(TCP_INPUT_DEBUG, + ("tcp_receive: other end overran receive window" + "seqno %"U32_F" len %"U16_F" right edge %"U32_F"\n", + seqno, tcplen, pcb->rcv_nxt + pcb->rcv_wnd)); + if (TCPH_FLAGS(next->next->tcphdr) & TCP_FIN) { + /* Must remove the FIN from the header as we're trimming + * that byte of sequence-space from the packet */ + TCPH_FLAGS_SET(next->next->tcphdr, TCPH_FLAGS(next->next->tcphdr) &~ TCP_FIN); + } + /* Adjust length of segment to fit in the window. */ + next->next->len = pcb->rcv_nxt + pcb->rcv_wnd - seqno; + pbuf_realloc(next->next->p, next->next->len); + tcplen = TCP_TCPLEN(next->next); + LWIP_ASSERT("tcp_receive: segment not trimmed correctly to rcv_wnd\n", + (seqno + tcplen) == (pcb->rcv_nxt + pcb->rcv_wnd)); + } } break; }