[syslinux:elflink] PXELINUX: Use sendto() instead of connect()/ send()/disconnect()

syslinux-bot for Gene Cumm gene.cumm at gmail.com
Mon Sep 30 04:18:09 PDT 2013


Commit-ID:  131b9981b8dbf5fa1c014995f44b10b7b099fe12
Gitweb:     http://www.syslinux.org/commit/131b9981b8dbf5fa1c014995f44b10b7b099fe12
Author:     Gene Cumm <gene.cumm at gmail.com>
AuthorDate: Mon, 23 Sep 2013 17:13:53 -0400
Committer:  Gene Cumm <gene.cumm at gmail.com>
CommitDate: Mon, 23 Sep 2013 17:13:53 -0400

PXELINUX: Use sendto() instead of connect()/send()/disconnect()

This commit prevents a race-condition on systems that have functional
interrupts (observed with iPXE and select other Dell systems).  Without
this, the reply packet could be received by the core prior to the
disconnect() call, see that it doesn't have a matching PCB (protocol
control block, iirc) since the reply has a different far-end UDP port
than the original request, and lwIP will discard the packet before
PXELINUX can see it.

net_core_sendto() instead of
net_core_connect() net_core_send() net_core_disconnect()

Commit message expanded with Matt Fleming's assistance

Signed-off-by: Gene Cumm <gene.cumm at gmail.com>

---
 core/fs/pxe/core.c    | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
 core/fs/pxe/tftp.c    | 14 ++++++--------
 core/include/net.h    |  3 +++
 core/legacynet/core.c | 37 +++++++++++++++++++++++++++++++++++++
 4 files changed, 94 insertions(+), 8 deletions(-)

diff --git a/core/fs/pxe/core.c b/core/fs/pxe/core.c
index e330ba8..c1de895 100644
--- a/core/fs/pxe/core.c
+++ b/core/fs/pxe/core.c
@@ -6,6 +6,8 @@
 #include <net.h>
 #include "pxe.h"
 
+#include <dprintf.h>
+
 const struct url_scheme url_schemes[] = {
     { "tftp", tftp_open, 0 },
     { "http", http_open, O_DIRECTORY },
@@ -81,6 +83,7 @@ void net_core_connect(struct pxe_pvt_inode *socket, uint32_t ip,
     struct net_private_lwip *priv = &socket->net.lwip;
     struct ip_addr addr;
 
+    dprintf2("net_core_connect: %08X %04X\n", ntohl(ip), port);
     addr.addr = ip;
     netconn_connect(priv->conn, &addr, port);
 }
@@ -174,6 +177,51 @@ out:
     netbuf_delete(nbuf);
 }
 
+ /**
+ * Send a UDP packet to a destination
+ *
+ * @param:socket, the open socket
+ * @param:data, data buffer to send
+ * @param:len, size of data bufer
+ * @param:ip, the ip address
+ * @param:port, the port number, host-byte order
+ */
+void net_core_sendto(struct pxe_pvt_inode *socket, const void *data,
+		     size_t len, uint32_t ip, uint16_t port)
+{
+    struct netconn *conn = socket->net.lwip.conn;
+    struct ip_addr addr;
+    struct netbuf *nbuf;
+    void *pbuf;
+    int err;
+
+    nbuf = netbuf_new();
+    if (!nbuf) {
+	printf("netbuf allocation error\n");
+	return;
+    }
+
+    pbuf = netbuf_alloc(nbuf, len);
+    if (!pbuf) {
+	printf("pbuf allocation error\n");
+	goto out;
+    }
+
+    memcpy(pbuf, data, len);
+
+    dprintf("net_core_sendto: %08X %04X\n", ntohl(ip), port);
+    addr.addr = ip;
+
+    err = netconn_sendto(conn, nbuf, &addr, port);
+    if (err) {
+	printf("netconn_sendto error %d\n", err);
+	goto out;
+    }
+
+out:
+    netbuf_delete(nbuf);
+}
+
 /**
  * Network stack-specific initialization
  */
diff --git a/core/fs/pxe/tftp.c b/core/fs/pxe/tftp.c
index 9b755c9..c04e0f5 100644
--- a/core/fs/pxe/tftp.c
+++ b/core/fs/pxe/tftp.c
@@ -255,18 +255,16 @@ void tftp_open(struct url_info *url, int flags, struct inode *inode,
 
     timeout_ptr = TimeoutTable;   /* Reset timeout */
 sendreq:
-    net_core_disconnect(socket);
     timeout = *timeout_ptr++;
     if (!timeout)
 	return;			/* No file available... */
     oldtime = jiffies();
 
-    net_core_connect(socket, url->ip, url->port);
-    net_core_send(socket, rrq_packet_buf, rrq_len);
+    /* net_core_open() calls netconn_bind() */
+    net_core_sendto(socket, rrq_packet_buf, rrq_len, url->ip, url->port);
 
     /* If the WRITE call fails, we let the timeout take care of it... */
 wait_pkt:
-    net_core_disconnect(socket);
     for (;;) {
 	buf_len = sizeof(reply_packet_buf);
 
@@ -277,8 +275,10 @@ wait_pkt:
 	    if (now - oldtime >= timeout)
 		 goto sendreq;
 	} else {
-	    /* Make sure the packet actually came from the server */
-	    if (src_ip == url->ip)
+	    /* Make sure the packet actually came from the server and
+	       is long enough for a TFTP opcode */
+	    dprintf("tftp_open: got packet buflen=%d\n", buf_len);
+	    if ((src_ip == url->ip) && (buf_len >= 2))
 		break;
 	}
     }
@@ -290,8 +290,6 @@ wait_pkt:
     inode->size = -1;
     socket->tftp_blksize = TFTP_BLOCKSIZE;
     buffersize = buf_len - 2;	  /* bytes after opcode */
-    if (buffersize < 0)
-        goto wait_pkt;                     /* Garbled reply */
 
     /*
      * Get the opcode type, and parse it
diff --git a/core/include/net.h b/core/include/net.h
index 4f6819f..f970ab0 100644
--- a/core/include/net.h
+++ b/core/include/net.h
@@ -27,6 +27,9 @@ int net_core_recv(struct pxe_pvt_inode *socket, void *buf, uint16_t *buf_len,
 void net_core_send(struct pxe_pvt_inode *socket,
 		   const void *data, size_t len);
 
+void net_core_sendto(struct pxe_pvt_inode *socket, const void *data, size_t len,
+		     uint32_t ip, uint16_t port);
+
 void probe_undi(void);
 void pxe_init_isr(void);
 
diff --git a/core/legacynet/core.c b/core/legacynet/core.c
index 848410c..94da649 100644
--- a/core/legacynet/core.c
+++ b/core/legacynet/core.c
@@ -153,6 +153,43 @@ void net_core_send(struct pxe_pvt_inode *socket, const void *data, size_t len)
 }
 
 /**
+ * Send a UDP packet to a destination
+ *
+ * @param:socket, the open socket
+ * @param:data, data buffer to send
+ * @param:len, size of data bufer
+ * @param:ip, the ip address
+ * @param:port, the port number, host-byte order
+ */
+void net_core_sendto(struct pxe_pvt_inode *socket, const void *data, size_t len,
+		     uint32_t ip, uint16_t port)
+{
+    static __lowmem struct s_PXENV_UDP_WRITE udp_write;
+    struct net_private_tftp *priv = &socket->net.tftp;
+    void *lbuf;
+    uint16_t tid;
+
+    lbuf = lmalloc(len);
+    if (!lbuf)
+	return;
+
+    memcpy(lbuf, data, len);
+
+    tid = priv->localport;   /* TID(local port No) */
+    udp_write.buffer    = FAR_PTR(lbuf);
+    udp_write.ip        = ip;
+    udp_write.gw        = gateway(udp_write.ip);
+    udp_write.src_port  = tid;
+    udp_write.dst_port  = htons(port);
+    udp_write.buffer_size = len;
+
+    pxe_call(PXENV_UDP_WRITE, &udp_write);
+
+    lfree(lbuf);
+}
+
+
+/**
  * Network stack-specific initialization
  *
  * Initialize UDP stack


More information about the Syslinux-commits mailing list