Browse Source

Add untested support for UNDI transmit and receive.

tags/v0.9.3
Michael Brown 17 years ago
parent
commit
332614a382
7 changed files with 195 additions and 114 deletions
  1. 2
    0
      src/include/gpxe/arp.h
  2. 2
    0
      src/include/gpxe/netdevice.h
  3. 14
    0
      src/include/gpxe/rarp.h
  4. 107
    112
      src/interface/pxe/pxe_undi.c
  5. 1
    2
      src/net/arp.c
  6. 1
    0
      src/net/ethernet.c
  7. 68
    0
      src/net/rarp.c

+ 2
- 0
src/include/gpxe/arp.h View File

@@ -30,6 +30,8 @@ struct arp_net_protocol {
30 30
 #define __arp_net_protocol \
31 31
 	__table ( struct arp_net_protocol, arp_net_protocols, 01 )
32 32
 
33
+extern struct net_protocol arp_protocol;
34
+
33 35
 extern int arp_resolve ( struct net_device *netdev,
34 36
 			 struct net_protocol *net_protocol,
35 37
 			 const void *dest_net_addr,

+ 2
- 0
src/include/gpxe/netdevice.h View File

@@ -122,6 +122,8 @@ struct ll_protocol {
122 122
 	uint16_t ll_proto;
123 123
 	/** Link-layer address length */
124 124
 	uint8_t ll_addr_len;
125
+	/** Link-layer header length */
126
+	uint8_t ll_header_len;
125 127
 	/** Link-layer broadcast address */
126 128
 	const uint8_t *ll_broadcast;
127 129
 };

+ 14
- 0
src/include/gpxe/rarp.h View File

@@ -0,0 +1,14 @@
1
+#ifndef _GPXE_RARP_H
2
+#define _GPXE_RARP_H
3
+
4
+/** @file
5
+ *
6
+ * Reverse Address Resolution Protocol
7
+ *
8
+ */
9
+
10
+struct net_protocol;
11
+
12
+extern struct net_protocol rarp_protocol;
13
+
14
+#endif /* _GPXE_RARP_H */

+ 107
- 112
src/interface/pxe/pxe_undi.c View File

@@ -23,12 +23,18 @@
23 23
  */
24 24
 
25 25
 #include <stdint.h>
26
+#include <stdio.h>
26 27
 #include <string.h>
27 28
 #include <byteswap.h>
29
+#include <basemem_packet.h>
28 30
 #include <gpxe/netdevice.h>
31
+#include <gpxe/iobuf.h>
29 32
 #include <gpxe/device.h>
30 33
 #include <gpxe/pci.h>
31 34
 #include <gpxe/if_ether.h>
35
+#include <gpxe/ip.h>
36
+#include <gpxe/arp.h>
37
+#include <gpxe/rarp.h>
32 38
 #include <gpxe/shutdown.h>
33 39
 #include "pxe.h"
34 40
 
@@ -128,61 +134,76 @@ PXENV_EXIT_t pxenv_undi_close ( struct s_PXENV_UNDI_CLOSE *undi_close ) {
128 134
  */
129 135
 PXENV_EXIT_t pxenv_undi_transmit ( struct s_PXENV_UNDI_TRANSMIT
130 136
 				   *undi_transmit ) {
131
-	struct s_PXENV_UNDI_TBD *tbd;
132
-	const char *dest;
133
-	unsigned int type;
134
-	unsigned int length;
135
-	const char *data;
137
+	struct s_PXENV_UNDI_TBD tbd;
138
+	struct DataBlk *datablk;
139
+	struct io_buffer *iobuf;
140
+	struct net_protocol *net_protocol;
141
+	char destaddr[MAX_LL_ADDR_LEN];
142
+	const void *ll_dest;
143
+	size_t len;
144
+	unsigned int i;
145
+	int rc;
136 146
 
137 147
 	DBG ( "PXENV_UNDI_TRANSMIT" );
138 148
 
139
-#if 0
140
-	/* We support only the "immediate" portion of the TBD.  Who
141
-	 * knows what Intel's "engineers" were smoking when they came
142
-	 * up with the array of transmit data blocks...
143
-	 */
144
-	tbd = SEGOFF16_TO_PTR ( undi_transmit->TBD );
145
-	if ( tbd->DataBlkCount > 0 ) {
149
+	/* Identify network-layer protocol */
150
+	switch ( undi_transmit->Protocol ) {
151
+	case P_IP:	net_protocol = &ipv4_protocol;	break;
152
+	case P_ARP:	net_protocol = &arp_protocol;	break;
153
+	case P_RARP:	net_protocol = &rarp_protocol;	break;
154
+	case P_UNKNOWN:	net_protocol = NULL;		break;
155
+	default:
146 156
 		undi_transmit->Status = PXENV_STATUS_UNDI_INVALID_PARAMETER;
147 157
 		return PXENV_EXIT_FAILURE;
148 158
 	}
149
-	data = SEGOFF16_TO_PTR ( tbd->Xmit );
150
-	length = tbd->ImmedLength;
151 159
 
152
-	/* If destination is broadcast, we need to supply the MAC address */
153
-	if ( undi_transmit->XmitFlag == XMT_BROADCAST ) {
154
-		dest = broadcast_mac;
155
-	} else {
156
-		dest = SEGOFF16_TO_PTR ( undi_transmit->DestAddr );
160
+	/* Calculate total packet length */
161
+	copy_from_real ( &tbd, undi_transmit->TBD.segment,
162
+			 undi_transmit->TBD.offset, sizeof ( tbd ) );
163
+	len = tbd.ImmedLength;
164
+	for ( i = 0 ; i < tbd.DataBlkCount ; i++ ) {
165
+		datablk = &tbd.DataBlock[i];
166
+		len += datablk->TDDataLen;
157 167
 	}
158 168
 
159
-	/* We can't properly support P_UNKNOWN without rewriting all
160
-	 * the driver transmit() methods, so we cheat: if P_UNKNOWN is
161
-	 * specified we rip the destination address and type out of
162
-	 * the pre-assembled packet, then skip over the header.
163
-	 */
164
-	switch ( undi_transmit->Protocol ) {
165
-	case P_IP:	type = ETH_P_IP;	break;
166
-	case P_ARP:	type = ETH_P_ARP;	break;
167
-	case P_RARP:	type = ETH_P_RARP;	break;
168
-	case P_UNKNOWN:
169
-		media_header = (media_header_t*)data;
170
-		dest = media_header->dest;
171
-		type = ntohs ( media_header->nstype );
172
-		data += ETH_HLEN;
173
-		length -= ETH_HLEN;
174
-		break;
175
-	default:
176
-		undi_transmit->Status = PXENV_STATUS_UNDI_INVALID_PARAMETER;
169
+	/* Allocate and fill I/O buffer */
170
+	iobuf = alloc_iob ( len );
171
+	if ( ! iobuf ) {
172
+		undi_transmit->Status = PXENV_STATUS_OUT_OF_RESOURCES;
177 173
 		return PXENV_EXIT_FAILURE;
178 174
 	}
175
+	copy_from_real ( iob_put ( iobuf, tbd.ImmedLength ), tbd.Xmit.segment,
176
+			 tbd.Xmit.offset, tbd.ImmedLength );
177
+	for ( i = 0 ; i < tbd.DataBlkCount ; i++ ) {
178
+		datablk = &tbd.DataBlock[i];
179
+		copy_from_real ( iob_put ( iobuf, datablk->TDDataLen ),
180
+				 datablk->TDDataPtr.segment,
181
+				 datablk->TDDataPtr.offset,
182
+				 datablk->TDDataLen );
183
+	}
179 184
 
180
-	/* Send the packet */
181
-	eth_transmit ( dest, type, length, data );
182
-#endif
183
-	
184
-	undi_transmit->Status = PXENV_STATUS_SUCCESS;
185
-	return PXENV_EXIT_SUCCESS;
185
+	/* Transmit packet */
186
+	if ( net_protocol == NULL ) {
187
+		/* Link-layer header already present */
188
+		rc = netdev_tx ( pxe_netdev, iobuf );
189
+	} else {
190
+		/* Calculate destination address */
191
+		if ( undi_transmit->XmitFlag == XMT_DESTADDR ) {
192
+			copy_from_real ( destaddr,
193
+					 undi_transmit->DestAddr.segment,
194
+					 undi_transmit->DestAddr.offset,
195
+					 pxe_netdev->ll_protocol->ll_addr_len );
196
+			ll_dest = destaddr;
197
+		} else {
198
+			ll_dest = pxe_netdev->ll_protocol->ll_broadcast;
199
+		}
200
+		rc = net_tx ( iobuf, pxe_netdev, net_protocol, ll_dest );
201
+	}
202
+
203
+#warning "TX completion?"
204
+
205
+	undi_transmit->Status = PXENV_STATUS ( rc );
206
+	return ( ( rc == 0 ) ? PXENV_EXIT_SUCCESS : PXENV_EXIT_FAILURE );
186 207
 }
187 208
 
188 209
 /* PXENV_UNDI_SET_MCAST_ADDRESS
@@ -405,16 +426,15 @@ PXENV_EXIT_t pxenv_undi_get_iface_info ( struct s_PXENV_UNDI_GET_IFACE_INFO
405 426
 					 *undi_get_iface_info ) {
406 427
 	DBG ( "PXENV_UNDI_GET_IFACE_INFO" );
407 428
 
408
-#if 0
409 429
 	/* Just hand back some info, doesn't really matter what it is.
410 430
 	 * Most PXE stacks seem to take this approach.
411 431
 	 */
412
-	sprintf ( undi_get_iface_info->IfaceType, "Etherboot" );
432
+	snprintf ( ( char * ) undi_get_iface_info->IfaceType,
433
+		   sizeof ( undi_get_iface_info->IfaceType ), "Etherboot" );
413 434
 	undi_get_iface_info->LinkSpeed = 10000000; /* 10 Mbps */
414 435
 	undi_get_iface_info->ServiceFlags = 0;
415 436
 	memset ( undi_get_iface_info->Reserved, 0,
416 437
 		 sizeof(undi_get_iface_info->Reserved) );
417
-#endif
418 438
 
419 439
 	undi_get_iface_info->Status = PXENV_STATUS_SUCCESS;
420 440
 	return PXENV_EXIT_SUCCESS;
@@ -437,18 +457,11 @@ PXENV_EXIT_t pxenv_undi_get_state ( struct s_PXENV_UNDI_GET_STATE
437 457
  * Status: working
438 458
  */
439 459
 PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) {
460
+	struct io_buffer *iobuf;
461
+	size_t len;
462
+
440 463
 	DBG ( "PXENV_UNDI_ISR" );
441 464
 
442
-#if 0
443
-	/* We can't call ENSURE_READY, because this could be being
444
-	 * called as part of an interrupt service routine.  Instead,
445
-	 * we should simply die if we're not READY.
446
-	 */
447
-	if ( ( pxe_stack == NULL ) || ( pxe_stack->state < READY ) ) {
448
-		undi_isr->Status = PXENV_STATUS_UNDI_INVALID_STATE;
449
-		return PXENV_EXIT_FAILURE;
450
-	}
451
-	
452 465
 	/* Just in case some idiot actually looks at these fields when
453 466
 	 * we weren't meant to fill them in...
454 467
 	 */
@@ -460,18 +473,14 @@ PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) {
460 473
 
461 474
 	switch ( undi_isr->FuncFlag ) {
462 475
 	case PXENV_UNDI_ISR_IN_START :
463
-		/* Is there a packet waiting?  If so, disable
464
-		 * interrupts on the NIC and return "it's ours".  Do
465
-		 * *not* necessarily acknowledge the interrupt; this
466
-		 * can happen later when eth_poll(1) is called.  As
467
-		 * long as the interrupt is masked off so that it
468
-		 * doesn't immediately retrigger the 8259A then all
469
-		 * should be well.
470
-		 */
471 476
 		DBG ( " START" );
472
-		if ( eth_poll ( 0 ) ) {
477
+
478
+		/* Call poll().  This should acknowledge the device
479
+		 * interrupt and queue up any received packet.
480
+		 */
481
+		if ( netdev_poll ( pxe_netdev, -1U ) ) {
482
+			/* Packet waiting in queue */
473 483
 			DBG ( " OURS" );
474
-			eth_irq ( DISABLE );
475 484
 			undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_OURS;
476 485
 		} else {
477 486
 			DBG ( " NOT_OURS" );
@@ -479,62 +488,48 @@ PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) {
479 488
 		}
480 489
 		break;
481 490
 	case PXENV_UNDI_ISR_IN_PROCESS :
482
-		/* Call poll(), return packet.  If no packet, return "done".
483
-		 */
484
-		DBG ( " PROCESS" );
485
-		if ( eth_poll ( 1 ) ) {
486
-			DBG ( " RECEIVE %d", nic.packetlen );
487
-			if ( nic.packetlen > sizeof(pxe_stack->packet) ) {
488
-				/* Should never happen */
489
-				undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE;
490
-				undi_isr->Status =
491
-					PXENV_STATUS_OUT_OF_RESOURCES;
492
-				return PXENV_EXIT_FAILURE;
493
-			}
494
-			undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_RECEIVE;
495
-			undi_isr->BufferLength = nic.packetlen;
496
-			undi_isr->FrameLength = nic.packetlen;
497
-			undi_isr->FrameHeaderLength = ETH_HLEN;
498
-			memcpy ( pxe_stack->packet, nic.packet, nic.packetlen);
499
-			PTR_TO_SEGOFF16 ( pxe_stack->packet, undi_isr->Frame );
500
-			switch ( ntohs(media_header->nstype) ) {
501
-			case ETH_P_IP:	undi_isr->ProtType = P_IP;	break;
502
-			case ETH_P_ARP:	undi_isr->ProtType = P_ARP;	break;
503
-			case ETH_P_RARP: undi_isr->ProtType = P_RARP;	break;
504
-			default :	undi_isr->ProtType = P_UNKNOWN;
505
-			}
506
-			if ( memcmp ( media_header->dest, broadcast_mac,
507
-				      sizeof(broadcast_mac) ) ) {
508
-				undi_isr->PktType = XMT_BROADCAST;
509
-			} else {
510
-				undi_isr->PktType = XMT_DESTADDR;
511
-			}
491
+	case PXENV_UNDI_ISR_IN_GET_NEXT :
492
+		DBG ( " PROCESS/GET_NEXT" );
493
+		
494
+		/* Remove first packet from netdev RX queue */
495
+		iobuf = netdev_rx_dequeue ( pxe_netdev );
496
+		if ( ! iobuf ) {
497
+			/* No more packets remaining */
498
+			undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE;
512 499
 			break;
513
-		} else {
514
-			/* No break - fall through to IN_GET_NEXT */
515 500
 		}
516
-	case PXENV_UNDI_ISR_IN_GET_NEXT :
517
-		/* We only ever return one frame at a time */
518
-		DBG ( " GET_NEXT DONE" );
519
-		/* Re-enable interrupts */
520
-		eth_irq ( ENABLE );
521
-		/* Force an interrupt if there's a packet still
522
-		 * waiting, since we only handle one packet per
523
-		 * interrupt.
524
-		 */
525
-		if ( eth_poll ( 0 ) ) {
526
-			DBG ( " (RETRIGGER)" );
527
-			eth_irq ( FORCE );
501
+
502
+		/* Copy packet to base memory buffer */
503
+		len = iob_len ( iobuf );
504
+		DBG ( " RECEIVE %zd", len );
505
+		if ( len > sizeof ( basemem_packet ) ) {
506
+			/* Should never happen */
507
+			undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE;
508
+			undi_isr->Status = PXENV_STATUS_OUT_OF_RESOURCES;
509
+			return PXENV_EXIT_FAILURE;
528 510
 		}
529
-		undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE;
511
+		memcpy ( basemem_packet, iobuf->data, len );
512
+
513
+		undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_RECEIVE;
514
+		undi_isr->BufferLength = len;
515
+		undi_isr->FrameLength = len;
516
+		undi_isr->FrameHeaderLength =
517
+			pxe_netdev->ll_protocol->ll_header_len;
518
+		undi_isr->Frame.segment = rm_ds;
519
+		undi_isr->Frame.offset =
520
+			( ( unsigned ) & __from_data16 ( basemem_packet ) );
521
+		/* Probably ought to fill in packet type */
522
+		undi_isr->ProtType = P_UNKNOWN;
523
+		undi_isr->PktType = XMT_DESTADDR;
530 524
 		break;
531 525
 	default :
526
+		DBG ( " INVALID(%04x)", undi_isr->FuncFlag );
527
+
532 528
 		/* Should never happen */
533 529
 		undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE;
534 530
 		undi_isr->Status = PXENV_STATUS_UNDI_INVALID_PARAMETER;
535 531
 		return PXENV_EXIT_FAILURE;
536 532
 	}
537
-#endif
538 533
 
539 534
 	undi_isr->Status = PXENV_STATUS_SUCCESS;
540 535
 	return PXENV_EXIT_SUCCESS;

+ 1
- 2
src/net/arp.c View File

@@ -281,8 +281,7 @@ static int arp_rx ( struct io_buffer *iobuf, struct net_device *netdev,
281 281
  *
282 282
  * This operation is meaningless for the ARP protocol.
283 283
  */
284
-static const char *
285
-arp_ntoa ( const void *net_addr __attribute__ (( unused )) ) {
284
+static const char * arp_ntoa ( const void *net_addr __unused ) {
286 285
 	return "<ARP>";
287 286
 }
288 287
 

+ 1
- 0
src/net/ethernet.c View File

@@ -108,6 +108,7 @@ struct ll_protocol ethernet_protocol __ll_protocol = {
108 108
 	.name		= "Ethernet",
109 109
 	.ll_proto	= htons ( ARPHRD_ETHER ),
110 110
 	.ll_addr_len	= ETH_ALEN,
111
+	.ll_header_len	= ETH_HLEN,
111 112
 	.ll_broadcast	= eth_broadcast,
112 113
 	.tx		= eth_tx,
113 114
 	.rx		= eth_rx,

+ 68
- 0
src/net/rarp.c View File

@@ -0,0 +1,68 @@
1
+/*
2
+ * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
+ */
18
+
19
+#include <stdint.h>
20
+#include <byteswap.h>
21
+#include <gpxe/netdevice.h>
22
+#include <gpxe/iobuf.h>
23
+#include <gpxe/if_ether.h>
24
+#include <gpxe/rarp.h>
25
+
26
+/** @file
27
+ *
28
+ * Reverse Address Resolution Protocol
29
+ *
30
+ */
31
+
32
+/**
33
+ * Process incoming ARP packets
34
+ *
35
+ * @v iobuf		I/O buffer
36
+ * @v netdev		Network device
37
+ * @v ll_source		Link-layer source address
38
+ * @ret rc		Return status code
39
+ *
40
+ * This is a dummy method which simply discards RARP packets.
41
+ */
42
+static int rarp_rx ( struct io_buffer *iobuf,
43
+		     struct net_device *netdev __unused,
44
+		     const void *ll_source __unused ) {
45
+	free_iob ( iobuf );
46
+	return 0;
47
+}
48
+
49
+
50
+/**
51
+ * Transcribe RARP address
52
+ *
53
+ * @v net_addr	RARP address
54
+ * @ret string	"<RARP>"
55
+ *
56
+ * This operation is meaningless for the RARP protocol.
57
+ */
58
+static const char * rarp_ntoa ( const void *net_addr __unused ) {
59
+	return "<RARP>";
60
+}
61
+
62
+/** RARP protocol */
63
+struct net_protocol rarp_protocol __net_protocol = {
64
+	.name = "RARP",
65
+	.net_proto = htons ( ETH_P_RARP ),
66
+	.rx = rarp_rx,
67
+	.ntoa = rarp_ntoa,
68
+};

Loading…
Cancel
Save