From 5800cf51be3caba6b68fbc09f3ff8b524e57ab9b Mon Sep 17 00:00:00 2001 From: Dirk Ziegelmeier Date: Wed, 3 May 2017 08:00:06 +0200 Subject: [PATCH] Work on task #14494: Implement SO_BINDTODEVICE TCP needs additional netif handling --- src/core/tcp.c | 46 +++++++++++++++++--------------- src/core/tcp_in.c | 26 +++++++++++++----- src/core/tcp_out.c | 22 ++++++++++----- src/include/lwip/priv/tcp_priv.h | 2 +- 4 files changed, 62 insertions(+), 34 deletions(-) diff --git a/src/core/tcp.c b/src/core/tcp.c index 2b5da31f..15e2d687 100644 --- a/src/core/tcp.c +++ b/src/core/tcp.c @@ -272,7 +272,7 @@ tcp_close_shutdown(struct tcp_pcb *pcb, u8_t rst_on_unacked_data) /* don't call tcp_abort here: we must not deallocate the pcb since that might not be expected when calling tcp_close */ - tcp_rst(pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip, + tcp_rst(pcb, pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip, pcb->local_port, pcb->remote_port); tcp_pcb_purge(pcb); @@ -513,7 +513,7 @@ tcp_abandon(struct tcp_pcb *pcb, int reset) tcp_backlog_accepted(pcb); if (send_rst) { LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_abandon: sending RST\n")); - tcp_rst(seqno, ackno, &pcb->local_ip, &pcb->remote_ip, local_port, pcb->remote_port); + tcp_rst(pcb, seqno, ackno, &pcb->local_ip, &pcb->remote_ip, local_port, pcb->remote_port); } last_state = pcb->state; memp_free(MEMP_TCP_PCB, pcb); @@ -920,24 +920,28 @@ tcp_connect(struct tcp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port, ip_addr_set(&pcb->remote_ip, ipaddr); pcb->remote_port = port; - /* check if we have a route to the remote host */ - if (ip_addr_isany(&pcb->local_ip)) { - /* no local IP address set, yet. */ - const ip_addr_t *local_ip; - ip_route_get_local_ip(&pcb->local_ip, &pcb->remote_ip, netif, local_ip); - if ((netif == NULL) || (local_ip == NULL)) { - /* Don't even try to send a SYN packet if we have no route - since that will fail. */ - return ERR_RTE; - } - /* Use the address as local address of the pcb. */ - ip_addr_copy(pcb->local_ip, *local_ip); + if (pcb->netif_idx != NETIF_NO_INDEX) { + netif = netif_get_by_index(pcb->netif_idx); } else { - netif = ip_route(&pcb->local_ip, &pcb->remote_ip); - if (netif == NULL) { - /* Don't even try to send a SYN packet if we have no route - since that will fail. */ - return ERR_RTE; + /* check if we have a route to the remote host */ + if (ip_addr_isany(&pcb->local_ip)) { + /* no local IP address set, yet. */ + const ip_addr_t *local_ip; + ip_route_get_local_ip(&pcb->local_ip, &pcb->remote_ip, netif, local_ip); + if ((netif == NULL) || (local_ip == NULL)) { + /* Don't even try to send a SYN packet if we have no route + since that will fail. */ + return ERR_RTE; + } + /* Use the address as local address of the pcb. */ + ip_addr_copy(pcb->local_ip, *local_ip); + } else { + netif = ip_route(&pcb->local_ip, &pcb->remote_ip); + if (netif == NULL) { + /* Don't even try to send a SYN packet if we have no route + since that will fail. */ + return ERR_RTE; + } } } LWIP_ASSERT("netif != NULL", netif != NULL); @@ -1213,8 +1217,8 @@ tcp_slowtmr_start: } if (pcb_reset) { - tcp_rst(pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip, - pcb->local_port, pcb->remote_port); + tcp_rst(pcb, pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip, + pcb->local_port, pcb->remote_port); } err_arg = pcb->callback_arg; diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c index a1beda17..1a33d2fb 100644 --- a/src/core/tcp_in.c +++ b/src/core/tcp_in.c @@ -224,6 +224,13 @@ tcp_input(struct pbuf *p, struct netif *inp) LWIP_ASSERT("tcp_input: active pcb->state != CLOSED", pcb->state != CLOSED); LWIP_ASSERT("tcp_input: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT); LWIP_ASSERT("tcp_input: active pcb->state != LISTEN", pcb->state != LISTEN); + + /* check if PCB is bound to specific netif */ + if ((pcb->netif_idx != NETIF_NO_INDEX) && + (pcb->netif_idx != netif_get_index(ip_data.current_input_netif))) { + continue; + } + if (pcb->remote_port == tcphdr->src && pcb->local_port == tcphdr->dest && ip_addr_cmp(&pcb->remote_ip, ip_current_src_addr()) && @@ -250,6 +257,13 @@ tcp_input(struct pbuf *p, struct netif *inp) in the TIME-WAIT state. */ for (pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { LWIP_ASSERT("tcp_input: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT); + + /* check if PCB is bound to specific netif */ + if ((pcb->netif_idx != NETIF_NO_INDEX) && + (pcb->netif_idx != netif_get_index(ip_data.current_input_netif))) { + continue; + } + if (pcb->remote_port == tcphdr->src && pcb->local_port == tcphdr->dest && ip_addr_cmp(&pcb->remote_ip, ip_current_src_addr()) && @@ -516,14 +530,13 @@ aborted: inseg.p = NULL; } } else { - /* If no matching PCB was found, send a TCP RST (reset) to the sender. */ LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_input: no PCB match found, resetting.\n")); if (!(TCPH_FLAGS(tcphdr) & TCP_RST)) { TCP_STATS_INC(tcp.proterr); TCP_STATS_INC(tcp.drop); - tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), + tcp_rst(NULL, ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(), tcphdr->dest, tcphdr->src); } pbuf_free(p); @@ -565,7 +578,7 @@ tcp_listen_input(struct tcp_pcb_listen *pcb) /* For incoming segments with the ACK flag set, respond with a RST. */ LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_listen_input: ACK in LISTEN, sending reset\n")); - tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), + tcp_rst((const struct tcp_pcb*)pcb, ackno, seqno + tcplen, 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)); @@ -611,6 +624,7 @@ tcp_listen_input(struct tcp_pcb_listen *pcb) #endif /* LWIP_CALLBACK_API || TCP_LISTEN_BACKLOG */ /* inherit socket options */ npcb->so_options = pcb->so_options & SOF_INHERITED; + npcb->netif_idx = pcb->netif_idx; /* Register the new PCB so that we can begin receiving segments for it. */ TCP_REG_ACTIVE(npcb); @@ -663,7 +677,7 @@ tcp_timewait_input(struct tcp_pcb *pcb) 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, ip_current_dest_addr(), + tcp_rst(pcb, ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(), tcphdr->dest, tcphdr->src); return; } @@ -813,7 +827,7 @@ tcp_process(struct tcp_pcb *pcb) /* 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, ip_current_dest_addr(), + tcp_rst(pcb, ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(), tcphdr->dest, tcphdr->src); /* Resend SYN immediately (don't wait for rto timeout) to establish connection faster, but do not send more SYNs than we otherwise would @@ -873,7 +887,7 @@ tcp_process(struct tcp_pcb *pcb) } } else { /* incorrect ACK number, send RST */ - tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), + tcp_rst(pcb, 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)) { diff --git a/src/core/tcp_out.c b/src/core/tcp_out.c index 138a7be0..a53a9d8b 100644 --- a/src/core/tcp_out.c +++ b/src/core/tcp_out.c @@ -94,6 +94,15 @@ /* Forward declarations.*/ static err_t tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb, struct netif *netif); +static struct netif* tcp_route(const struct tcp_pcb *pcb, const ip_addr_t *src, const ip_addr_t *dst) +{ + if ((pcb != NULL) && (pcb->netif_idx != NETIF_NO_INDEX)) { + return netif_get_by_index(pcb->netif_idx); + } else { + return ip_route(src, dst); + } +} + /** Allocate a pbuf and create a tcphdr at p->payload, used for output * functions other than the default tcp_output -> tcp_output_segment * (e.g. tcp_send_empty_ack, etc.) @@ -959,7 +968,7 @@ tcp_send_empty_ack(struct tcp_pcb *pcb) } #endif - netif = ip_route(&pcb->local_ip, &pcb->remote_ip); + netif = tcp_route(pcb, &pcb->local_ip, &pcb->remote_ip); if (netif == NULL) { err = ERR_RTE; } else { @@ -1040,7 +1049,7 @@ tcp_output(struct tcp_pcb *pcb) for (; useg->next != NULL; useg = useg->next); } - netif = ip_route(&pcb->local_ip, &pcb->remote_ip); + netif = tcp_route(pcb, &pcb->local_ip, &pcb->remote_ip); if (netif == NULL) { return ERR_RTE; } @@ -1339,6 +1348,7 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb, struct netif *netif * tcp_rst() has a number of arguments that are taken from a tcp_pcb for * most other segment output functions. * + * @param pcb TCP pcb * @param seqno the sequence number to use for the outgoing segment * @param ackno the acknowledge number to use for the outgoing segment * @param local_ip the local IP address to send the segment from @@ -1347,7 +1357,7 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb, struct netif *netif * @param remote_port the remote TCP port to send the segment to */ void -tcp_rst(u32_t seqno, u32_t ackno, +tcp_rst(const struct tcp_pcb *pcb, u32_t seqno, u32_t ackno, const ip_addr_t *local_ip, const ip_addr_t *remote_ip, u16_t local_port, u16_t remote_port) { @@ -1379,7 +1389,7 @@ tcp_rst(u32_t seqno, u32_t ackno, TCP_STATS_INC(tcp.xmit); MIB2_STATS_INC(mib2.tcpoutrsts); - netif = ip_route(local_ip, remote_ip); + netif = tcp_route(pcb, local_ip, remote_ip); if (netif != NULL) { #if CHECKSUM_GEN_TCP IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_TCP) { @@ -1559,7 +1569,7 @@ tcp_keepalive(struct tcp_pcb *pcb) ("tcp_keepalive: could not allocate memory for pbuf\n")); return ERR_MEM; } - netif = ip_route(&pcb->local_ip, &pcb->remote_ip); + netif = tcp_route(pcb, &pcb->local_ip, &pcb->remote_ip); if (netif == NULL) { err = ERR_RTE; } else { @@ -1653,7 +1663,7 @@ tcp_zero_window_probe(struct tcp_pcb *pcb) pcb->snd_nxt = snd_nxt; } - netif = ip_route(&pcb->local_ip, &pcb->remote_ip); + netif = tcp_route(pcb, &pcb->local_ip, &pcb->remote_ip); if (netif == NULL) { err = ERR_RTE; } else { diff --git a/src/include/lwip/priv/tcp_priv.h b/src/include/lwip/priv/tcp_priv.h index 3e115b23..bbf4305c 100644 --- a/src/include/lwip/priv/tcp_priv.h +++ b/src/include/lwip/priv/tcp_priv.h @@ -451,7 +451,7 @@ err_t tcp_enqueue_flags(struct tcp_pcb *pcb, u8_t flags); void tcp_rexmit_seg(struct tcp_pcb *pcb, struct tcp_seg *seg); -void tcp_rst(u32_t seqno, u32_t ackno, +void tcp_rst(const struct tcp_pcb* pcb, u32_t seqno, u32_t ackno, const ip_addr_t *local_ip, const ip_addr_t *remote_ip, u16_t local_port, u16_t remote_port);