[ipxe-devel] [PATCH] [undi] on transmit, fill in more of the PXENV_UNDI_TRANSMIT fields,; was: undionly.kpxe fails to DHCP on QLogic 8242
Buck Huppmann
buckh at pobox.com
Thu Mar 1 21:58:42 UTC 2012
Well, this works on the QLogic CNA/NIC (but, alas, it is ignoring the
DHCP Offers that it is eliciting. Sigh). Also doesn't break a machine
that was booting fine with unpatched undionly.kpxe (on NVidia MCP55)
Not that this isn't horribly wrong (so please don't flame), but, in
case there's a smidgen of rightness in here anybody can pick up on ...
I got the PXENV_UNDI_TRANSMIT Protocol numbers from
http://svnweb.freebsd.org/base/head/sys/boot/i386/libi386/pxe.h?revision=103870&view=markup
--buck
[undi] on transmit, fill in more of the PXENV_UNDI_TRANSMIT fields,
using what we presume to be the Ethernet header data at the start
of the presumptive Ethernet frame we are supposed to transmit, and
drop the header from the transmitted buffer, since the PXENV/UNDI
will take care of the framing at that point
otherwise, you end up (on some stacks) with the PXENV/UNDI encapsu-
lating the frame in its own spurious garbage framing
---
src/arch/i386/drivers/net/undinet.c | 31 ++++++++++++++++++++++++++-----
1 files changed, 26 insertions(+), 5 deletions(-)
diff --git a/src/arch/i386/drivers/net/undinet.c b/src/arch/i386/drivers/net/undinet.c
index 63b3738..4bd4b02 100644
--- a/src/arch/i386/drivers/net/undinet.c
+++ b/src/arch/i386/drivers/net/undinet.c
@@ -19,6 +19,7 @@
FILE_LICENCE ( GPL2_OR_LATER );
#include <string.h>
+#include <byteswap.h>
#include <unistd.h>
#include <pxe.h>
#include <realmode.h>
@@ -162,6 +163,9 @@ static int undinet_isr_triggered ( void ) {
*****************************************************************************
*/
+/** destination address for transmitted packet */
+static uint8_t __data16_array(undinet_dst_addr, [sizeof(((struct ethhdr *)0)->h_dest)]);
+#define undinet_dst_addr __use_data16 ( undinet_dst_addr )
/** UNDI transmit buffer descriptor */
static struct s_PXENV_UNDI_TBD __data16 ( undinet_tbd );
#define undinet_tbd __use_data16 ( undinet_tbd )
@@ -176,6 +180,7 @@ static struct s_PXENV_UNDI_TBD __data16 ( undinet_tbd );
static int undinet_transmit ( struct net_device *netdev,
struct io_buffer *iobuf ) {
struct s_PXENV_UNDI_TRANSMIT undi_transmit;
+ const void *data = iobuf->data;
size_t len = iob_len ( iobuf );
int rc;
@@ -188,20 +193,36 @@ static int undinet_transmit ( struct net_device *netdev,
* assuming that a TX will be complete by the time we want to
* transmit the next packet.
*/
-
+ /* Create PXENV_UNDI_TRANSMIT data structure */
+ memset ( &undi_transmit, 0, sizeof ( undi_transmit ) );
+ if (len < sizeof(struct ethhdr)) {
+ /* ??? not enough data to copy out for frame header addresses
+ * & proto - hope we can at least copy in destination */
+ memcpy(&undinet_dst_addr, data, sizeof(undinet_dst_addr));
+ }
+ else {
+ const struct ethhdr *e = (const struct ethhdr *)(data);
+ undi_transmit.Protocol =
+ ntohs(e->h_protocol) == ETH_P_IP ? 1 :
+ ntohs(e->h_protocol) == ETH_P_ARP ? 2 :
+ ntohs(e->h_protocol) == ETH_P_RARP ? 3 :
+ 0;
+ memcpy(&undinet_dst_addr, e->h_dest, sizeof(e->h_dest));
+ len -= sizeof(*e);
+ data = (void *)e + sizeof(*e);
+ }
/* Copy packet to UNDI I/O buffer */
if ( len > sizeof ( basemem_packet ) )
len = sizeof ( basemem_packet );
- memcpy ( &basemem_packet, iobuf->data, len );
+ memcpy ( &basemem_packet, data, len );
- /* Create PXENV_UNDI_TRANSMIT data structure */
- memset ( &undi_transmit, 0, sizeof ( undi_transmit ) );
undi_transmit.DestAddr.segment = rm_ds;
- undi_transmit.DestAddr.offset = __from_data16 ( &undinet_tbd );
+ undi_transmit.DestAddr.offset = __from_data16 ( &undinet_dst_addr );
undi_transmit.TBD.segment = rm_ds;
undi_transmit.TBD.offset = __from_data16 ( &undinet_tbd );
/* Create PXENV_UNDI_TBD data structure */
+ memset(&undinet_tbd, 0, sizeof(undinet_tbd));
undinet_tbd.ImmedLength = len;
undinet_tbd.Xmit.segment = rm_ds;
undinet_tbd.Xmit.offset = __from_data16 ( basemem_packet );
--
1.7.2.5
More information about the ipxe-devel
mailing list