Просмотр исходного кода

lwip: add option to allow accepting TCP connections not destined to a local address

ambrop7 15 лет назад
Родитель
Сommit
f46086d2cc

+ 6 - 0
lwip/src/core/ipv4/ip.c

@@ -414,6 +414,12 @@ ip_input(struct pbuf *p, struct netif *inp)
       return ERR_OK;
     }
   }
+  
+  /* if we're pretending we are everyone for TCP, assume the packet is for source interface if it
+     isn't for a local address */
+  if (netif == NULL && (inp->flags & NETIF_FLAG_PRETEND_TCP) && IPH_PROTO(iphdr) == IP_PROTO_TCP) {
+      netif = inp;
+  }
 
   /* packet not for us? */
   if (netif == NULL) {

+ 16 - 0
lwip/src/core/netif.c

@@ -306,6 +306,13 @@ netif_find(char *name)
   return NULL;
 }
 
+int netif_is_named (struct netif *netif, const char name[3])
+{
+    u8_t num = name[2] - '0';
+    
+    return (!memcmp(netif->name, name, 2) && netif->num == num);
+}
+
 /**
  * Change the IP address of a network interface
  *
@@ -392,6 +399,15 @@ netif_set_gw(struct netif *netif, ip_addr_t *gw)
     ip4_addr4_16(&netif->gw)));
 }
 
+void netif_set_pretend_tcp (struct netif *netif, u8_t pretend)
+{
+    if (pretend) {
+        netif->flags |= NETIF_FLAG_PRETEND_TCP;
+    } else {
+        netif->flags &= ~NETIF_FLAG_PRETEND_TCP;
+    }
+}
+
 /**
  * Change the netmask of a network interface
  *

+ 40 - 4
lwip/src/core/tcp.c

@@ -441,6 +441,7 @@ tcp_bind(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port)
     }
   }
 
+  pcb->bound_to_netif = 0;
   if (!ip_addr_isany(ipaddr)) {
     pcb->local_ip = *ipaddr;
   }
@@ -449,6 +450,30 @@ tcp_bind(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port)
   LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: bind to port %"U16_F"\n", port));
   return ERR_OK;
 }
+
+err_t
+tcp_bind_to_netif(struct tcp_pcb *pcb, const char ifname[3])
+{
+    LWIP_ERROR("tcp_bind_if: can only bind in state CLOSED", pcb->state == CLOSED, return ERR_ISCONN);
+    
+    /* Check if the interface is already in use */
+    for (int i = 0; i < NUM_TCP_PCB_LISTS; i++) {
+        for(struct tcp_pcb *cpcb = *tcp_pcb_lists[i]; cpcb != NULL; cpcb = cpcb->next) {
+            if (cpcb->bound_to_netif && !memcmp(cpcb->local_netif, ifname, sizeof(ifname))) {
+                return ERR_USE;
+            }
+        }
+    }
+    
+    pcb->bound_to_netif = 1;
+    ip_addr_set_any(&pcb->local_ip);
+    pcb->local_port = 0;
+    memcpy(pcb->local_netif, ifname, sizeof(ifname));
+    TCP_REG(&tcp_bound_pcbs, pcb);
+    LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind_if: bind to interface %s", ifname));
+    return ERR_OK;
+}
+
 #if LWIP_CALLBACK_API
 /**
  * Default accept callback if no accept callback is specified by the user.
@@ -491,7 +516,7 @@ tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog)
     return pcb;
   }
 #if SO_REUSE
-  if ((pcb->so_options & SOF_REUSEADDR) != 0) {
+  if ((pcb->so_options & SOF_REUSEADDR) != 0 && !pcb->have_local_netif) {
     /* Since SOF_REUSEADDR allows reusing a local address before the pcb's usage
        is declared (listen-/connection-pcb), we have to make sure now that
        this port is only used once for every local IP. */
@@ -510,7 +535,9 @@ tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog)
     return NULL;
   }
   lpcb->callback_arg = pcb->callback_arg;
+  lpcb->bound_to_netif = pcb->bound_to_netif;
   lpcb->local_port = pcb->local_port;
+  memcpy(lpcb->local_netif, pcb->local_netif, sizeof(pcb->local_netif));
   lpcb->state = LISTEN;
   lpcb->prio = pcb->prio;
   lpcb->so_options = pcb->so_options;
@@ -1364,9 +1391,18 @@ tcp_pcb_purge(struct tcp_pcb *pcb)
       LWIP_ASSERT("tcp_pcb_purge: pcb->state == SYN_RCVD but tcp_listen_pcbs is NULL",
         tcp_listen_pcbs.listen_pcbs != NULL);
       for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {
-        if ((lpcb->local_port == pcb->local_port) &&
-            (ip_addr_isany(&lpcb->local_ip) ||
-             ip_addr_cmp(&pcb->local_ip, &lpcb->local_ip))) {
+        if (
+          (
+            !lpcb->bound_to_netif && !pcb->bound_to_netif &&
+            lpcb->local_port == pcb->local_port && (
+              ip_addr_isany(&lpcb->local_ip) ||
+              ip_addr_cmp(&pcb->local_ip, &lpcb->local_ip)
+            )
+          ) || (
+            lpcb->bound_to_netif && pcb->bound_to_netif &&
+            !memcmp(lpcb->local_netif, pcb->local_netif, sizeof(pcb->local_netif))
+          )
+        ) {
             /* port and address of the listen pcb match the timed-out pcb */
             LWIP_ASSERT("tcp_pcb_purge: listen pcb does not have accepts pending",
               lpcb->accepts_pending > 0);

+ 16 - 2
lwip/src/core/tcp_in.c

@@ -225,8 +225,16 @@ tcp_input(struct pbuf *p, struct netif *inp)
     /* Finally, if we still did not get a match, we check all PCBs that
        are LISTENing for incoming connections. */
     prev = NULL;
+    struct tcp_pcb_listen *netif_pcb = NULL;
+    struct tcp_pcb *netif_pcb_prev;
     for(lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {
-      if (lpcb->local_port == tcphdr->dest) {
+      if (lpcb->bound_to_netif) {
+        if (netif_is_named(inp, lpcb->local_netif)) {
+          netif_pcb = lpcb;
+          netif_pcb_prev = prev;
+        }
+      }
+      else if (lpcb->local_port == tcphdr->dest) {
 #if SO_REUSE
         if (ip_addr_cmp(&(lpcb->local_ip), &current_iphdr_dest)) {
           /* found an exact match */
@@ -254,6 +262,10 @@ tcp_input(struct pbuf *p, struct netif *inp)
       prev = lpcb_prev;
     }
 #endif /* SO_REUSE */
+    if (lpcb == NULL && netif_pcb) {
+        lpcb = netif_pcb;
+        prev = netif_pcb_prev;
+    }
     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
@@ -474,7 +486,9 @@ tcp_listen_input(struct tcp_pcb_listen *pcb)
 #endif /* TCP_LISTEN_BACKLOG */
     /* Set up the new PCB. */
     ip_addr_copy(npcb->local_ip, current_iphdr_dest);
-    npcb->local_port = pcb->local_port;
+    npcb->bound_to_netif = pcb->bound_to_netif;
+    npcb->local_port = tcphdr->dest;
+    memcpy(npcb->local_netif, pcb->local_netif, sizeof(pcb->local_netif));
     ip_addr_copy(npcb->remote_ip, current_iphdr_src);
     npcb->remote_port = tcphdr->src;
     npcb->state = SYN_RCVD;

+ 7 - 1
lwip/src/include/lwip/netif.h

@@ -93,6 +93,9 @@ extern "C" {
 /** If set, the netif has IGMP capability.
  * Set by the netif driver in its init function. */
 #define NETIF_FLAG_IGMP         0x80U
+/** Whether to pretend that we are every host for TCP packets.
+ * Set by netif_set_pretend_tcp. */
+#define NETIF_FLAG_PRETEND_TCP  0x100U
 
 /** Function prototype for netif init functions. Set up flags and output/linkoutput
  * callback functions in this function.
@@ -185,7 +188,7 @@ struct netif {
   /** link level hardware address of this interface */
   u8_t hwaddr[NETIF_MAX_HWADDR_LEN];
   /** flags (see NETIF_FLAG_ above) */
-  u8_t flags;
+  u16_t flags;
   /** descriptive abbreviation */
   char name[2];
   /** number of this interface */
@@ -266,11 +269,14 @@ void netif_remove(struct netif * netif);
    structure. */
 struct netif *netif_find(char *name);
 
+int netif_is_named (struct netif *netif, const char name[3]);
+
 void netif_set_default(struct netif *netif);
 
 void netif_set_ipaddr(struct netif *netif, ip_addr_t *ipaddr);
 void netif_set_netmask(struct netif *netif, ip_addr_t *netmask);
 void netif_set_gw(struct netif *netif, ip_addr_t *gw);
+void netif_set_pretend_tcp(struct netif *netif, u8_t pretend);
 
 void netif_set_up(struct netif *netif);
 void netif_set_down(struct netif *netif);

+ 4 - 1
lwip/src/include/lwip/tcp.h

@@ -162,7 +162,9 @@ enum tcp_state {
   /* the accept callback for listen- and normal pcbs, if LWIP_CALLBACK_API */ \
   DEF_ACCEPT_CALLBACK \
   /* ports are in host byte order */ \
-  u16_t local_port
+  int bound_to_netif; \
+  u16_t local_port; \
+  char local_netif[3]
 
 
 /* the TCP protocol control block */
@@ -339,6 +341,7 @@ void             tcp_err     (struct tcp_pcb *pcb, tcp_err_fn err);
 void             tcp_recved  (struct tcp_pcb *pcb, u16_t len);
 err_t            tcp_bind    (struct tcp_pcb *pcb, ip_addr_t *ipaddr,
                               u16_t port);
+err_t            tcp_bind_to_netif (struct tcp_pcb *pcb, const char ifname[3]);
 err_t            tcp_connect (struct tcp_pcb *pcb, ip_addr_t *ipaddr,
                               u16_t port, tcp_connected_fn connected);