|
@@ -23,12 +23,18 @@
|
23
|
23
|
*/
|
24
|
24
|
|
25
|
25
|
#include <stdint.h>
|
|
26
|
+#include <stdio.h>
|
26
|
27
|
#include <string.h>
|
|
28
|
+#include <byteswap.h>
|
|
29
|
+#include <basemem_packet.h>
|
27
|
30
|
#include <gpxe/netdevice.h>
|
|
31
|
+#include <gpxe/iobuf.h>
|
28
|
32
|
#include <gpxe/device.h>
|
29
|
33
|
#include <gpxe/pci.h>
|
30
|
|
-#include <gpxe/isapnp.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
|
|
@@ -200,30 +221,30 @@ pxenv_undi_set_mcast_address ( struct s_PXENV_UNDI_SET_MCAST_ADDRESS
|
200
|
221
|
|
201
|
222
|
/* PXENV_UNDI_SET_STATION_ADDRESS
|
202
|
223
|
*
|
203
|
|
- * Status: working (deliberately incomplete)
|
|
224
|
+ * Status: working
|
204
|
225
|
*/
|
205
|
226
|
PXENV_EXIT_t
|
206
|
227
|
pxenv_undi_set_station_address ( struct s_PXENV_UNDI_SET_STATION_ADDRESS
|
207
|
228
|
*undi_set_station_address ) {
|
|
229
|
+
|
208
|
230
|
DBG ( "PXENV_UNDI_SET_STATION_ADDRESS" );
|
209
|
231
|
|
210
|
|
-#if 0
|
211
|
|
- /* We don't offer a facility to set the MAC address; this
|
212
|
|
- * would require adding extra code to all the Etherboot
|
213
|
|
- * drivers, for very little benefit. If we're setting it to
|
214
|
|
- * the current value anyway then return success, otherwise
|
215
|
|
- * return UNSUPPORTED.
|
|
232
|
+ /* If adapter is open, the change will have no effect; return
|
|
233
|
+ * an error
|
216
|
234
|
*/
|
217
|
|
- if ( memcmp ( nic.node_addr,
|
218
|
|
- &undi_set_station_address->StationAddress,
|
219
|
|
- ETH_ALEN ) == 0 ) {
|
220
|
|
- undi_set_station_address->Status = PXENV_STATUS_SUCCESS;
|
221
|
|
- return PXENV_EXIT_SUCCESS;
|
|
235
|
+ if ( pxe_netdev->state & NETDEV_OPEN ) {
|
|
236
|
+ undi_set_station_address->Status =
|
|
237
|
+ PXENV_STATUS_UNDI_INVALID_STATE;
|
|
238
|
+ return PXENV_EXIT_FAILURE;
|
222
|
239
|
}
|
223
|
|
-#endif
|
224
|
240
|
|
225
|
|
- undi_set_station_address->Status = PXENV_STATUS_UNSUPPORTED;
|
226
|
|
- return PXENV_EXIT_FAILURE;
|
|
241
|
+ /* Update MAC address */
|
|
242
|
+ memcpy ( pxe_netdev->ll_addr,
|
|
243
|
+ &undi_set_station_address->StationAddress,
|
|
244
|
+ pxe_netdev->ll_protocol->ll_addr_len );
|
|
245
|
+
|
|
246
|
+ undi_set_station_address = PXENV_STATUS_SUCCESS;
|
|
247
|
+ return PXENV_EXIT_SUCCESS;
|
227
|
248
|
}
|
228
|
249
|
|
229
|
250
|
/* PXENV_UNDI_SET_PACKET_FILTER
|
|
@@ -248,33 +269,11 @@ PXENV_EXIT_t pxenv_undi_get_information ( struct s_PXENV_UNDI_GET_INFORMATION
|
248
|
269
|
*undi_get_information ) {
|
249
|
270
|
struct device *dev = pxe_netdev->dev;
|
250
|
271
|
struct ll_protocol *ll_protocol = pxe_netdev->ll_protocol;
|
251
|
|
- unsigned int ioaddr;
|
252
|
|
- unsigned int irqno;
|
253
|
272
|
|
254
|
273
|
DBG ( "PXENV_UNDI_GET_INFORMATION" );
|
255
|
274
|
|
256
|
|
- switch ( dev->desc.bus_type ) {
|
257
|
|
- case BUS_TYPE_PCI: {
|
258
|
|
- struct pci_device *pci =
|
259
|
|
- container_of ( dev, struct pci_device, dev );
|
260
|
|
-
|
261
|
|
- ioaddr = pci->ioaddr;
|
262
|
|
- irqno = pci->irq;
|
263
|
|
- break; }
|
264
|
|
- case BUS_TYPE_ISAPNP: {
|
265
|
|
- struct isapnp_device *isapnp =
|
266
|
|
- container_of ( dev, struct isapnp_device, dev );
|
267
|
|
-
|
268
|
|
- ioaddr = isapnp->ioaddr;
|
269
|
|
- irqno = isapnp->irqno;
|
270
|
|
- break; }
|
271
|
|
- default:
|
272
|
|
- undi_get_information->Status = PXENV_STATUS_FAILURE;
|
273
|
|
- return PXENV_EXIT_FAILURE;
|
274
|
|
- }
|
275
|
|
-
|
276
|
|
- undi_get_information->BaseIo = ioaddr;
|
277
|
|
- undi_get_information->IntNumber = irqno;
|
|
275
|
+ undi_get_information->BaseIo = dev->desc.ioaddr;
|
|
276
|
+ undi_get_information->IntNumber = dev->desc.irq;
|
278
|
277
|
/* Cheat: assume all cards can cope with this */
|
279
|
278
|
undi_get_information->MaxTranUnit = ETH_MAX_MTU;
|
280
|
279
|
undi_get_information->HwType = ntohs ( ll_protocol->ll_proto );
|
|
@@ -384,17 +383,15 @@ PXENV_EXIT_t pxenv_undi_get_nic_type ( struct s_PXENV_UNDI_GET_NIC_TYPE
|
384
|
383
|
|
385
|
384
|
switch ( dev->desc.bus_type ) {
|
386
|
385
|
case BUS_TYPE_PCI: {
|
387
|
|
- struct pci_device *pci =
|
388
|
|
- container_of ( dev, struct pci_device, dev );
|
389
|
386
|
struct pci_nic_info *info = &undi_get_nic_type->info.pci;
|
390
|
387
|
|
391
|
388
|
undi_get_nic_type->NicType = PCI_NIC;
|
392
|
|
- info->Vendor_ID = pci->vendor;
|
393
|
|
- info->Dev_ID = pci->device;
|
394
|
|
- info->Base_Class = PCI_BASE_CLASS ( pci->class );
|
395
|
|
- info->Sub_Class = PCI_SUB_CLASS ( pci->class );
|
396
|
|
- info->Prog_Intf = PCI_PROG_INTF ( pci->class );
|
397
|
|
- info->BusDevFunc = PCI_BUSDEVFN ( pci->bus, pci->devfn );
|
|
389
|
+ info->Vendor_ID = dev->desc.vendor;
|
|
390
|
+ info->Dev_ID = dev->desc.device;
|
|
391
|
+ info->Base_Class = PCI_BASE_CLASS ( dev->desc.class );
|
|
392
|
+ info->Sub_Class = PCI_SUB_CLASS ( dev->desc.class );
|
|
393
|
+ info->Prog_Intf = PCI_PROG_INTF ( dev->desc.class );
|
|
394
|
+ info->BusDevFunc = dev->desc.location;
|
398
|
395
|
/* Cheat: remaining fields are probably unnecessary,
|
399
|
396
|
* and would require adding extra code to pci.c.
|
400
|
397
|
*/
|
|
@@ -402,14 +399,12 @@ PXENV_EXIT_t pxenv_undi_get_nic_type ( struct s_PXENV_UNDI_GET_NIC_TYPE
|
402
|
399
|
undi_get_nic_type->info.pci.SubDevice_ID = 0xffff;
|
403
|
400
|
break; }
|
404
|
401
|
case BUS_TYPE_ISAPNP: {
|
405
|
|
- struct isapnp_device *isapnp =
|
406
|
|
- container_of ( dev, struct isapnp_device, dev );
|
407
|
402
|
struct pnp_nic_info *info = &undi_get_nic_type->info.pnp;
|
408
|
403
|
|
409
|
404
|
undi_get_nic_type->NicType = PnP_NIC;
|
410
|
|
- info->EISA_Dev_ID = ( ( isapnp->vendor_id << 16 ) |
|
411
|
|
- isapnp->prod_id );
|
412
|
|
- info->CardSelNum = isapnp->csn;
|
|
405
|
+ info->EISA_Dev_ID = ( ( dev->desc.vendor << 16 ) |
|
|
406
|
+ dev->desc.device );
|
|
407
|
+ info->CardSelNum = dev->desc.location;
|
413
|
408
|
/* Cheat: remaining fields are probably unnecessary,
|
414
|
409
|
* and would require adding extra code to isapnp.c.
|
415
|
410
|
*/
|
|
@@ -431,16 +426,15 @@ PXENV_EXIT_t pxenv_undi_get_iface_info ( struct s_PXENV_UNDI_GET_IFACE_INFO
|
431
|
426
|
*undi_get_iface_info ) {
|
432
|
427
|
DBG ( "PXENV_UNDI_GET_IFACE_INFO" );
|
433
|
428
|
|
434
|
|
-#if 0
|
435
|
429
|
/* Just hand back some info, doesn't really matter what it is.
|
436
|
430
|
* Most PXE stacks seem to take this approach.
|
437
|
431
|
*/
|
438
|
|
- sprintf ( undi_get_iface_info->IfaceType, "Etherboot" );
|
|
432
|
+ snprintf ( ( char * ) undi_get_iface_info->IfaceType,
|
|
433
|
+ sizeof ( undi_get_iface_info->IfaceType ), "Etherboot" );
|
439
|
434
|
undi_get_iface_info->LinkSpeed = 10000000; /* 10 Mbps */
|
440
|
435
|
undi_get_iface_info->ServiceFlags = 0;
|
441
|
436
|
memset ( undi_get_iface_info->Reserved, 0,
|
442
|
437
|
sizeof(undi_get_iface_info->Reserved) );
|
443
|
|
-#endif
|
444
|
438
|
|
445
|
439
|
undi_get_iface_info->Status = PXENV_STATUS_SUCCESS;
|
446
|
440
|
return PXENV_EXIT_SUCCESS;
|
|
@@ -463,18 +457,11 @@ PXENV_EXIT_t pxenv_undi_get_state ( struct s_PXENV_UNDI_GET_STATE
|
463
|
457
|
* Status: working
|
464
|
458
|
*/
|
465
|
459
|
PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) {
|
|
460
|
+ struct io_buffer *iobuf;
|
|
461
|
+ size_t len;
|
|
462
|
+
|
466
|
463
|
DBG ( "PXENV_UNDI_ISR" );
|
467
|
464
|
|
468
|
|
-#if 0
|
469
|
|
- /* We can't call ENSURE_READY, because this could be being
|
470
|
|
- * called as part of an interrupt service routine. Instead,
|
471
|
|
- * we should simply die if we're not READY.
|
472
|
|
- */
|
473
|
|
- if ( ( pxe_stack == NULL ) || ( pxe_stack->state < READY ) ) {
|
474
|
|
- undi_isr->Status = PXENV_STATUS_UNDI_INVALID_STATE;
|
475
|
|
- return PXENV_EXIT_FAILURE;
|
476
|
|
- }
|
477
|
|
-
|
478
|
465
|
/* Just in case some idiot actually looks at these fields when
|
479
|
466
|
* we weren't meant to fill them in...
|
480
|
467
|
*/
|
|
@@ -486,18 +473,14 @@ PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) {
|
486
|
473
|
|
487
|
474
|
switch ( undi_isr->FuncFlag ) {
|
488
|
475
|
case PXENV_UNDI_ISR_IN_START :
|
489
|
|
- /* Is there a packet waiting? If so, disable
|
490
|
|
- * interrupts on the NIC and return "it's ours". Do
|
491
|
|
- * *not* necessarily acknowledge the interrupt; this
|
492
|
|
- * can happen later when eth_poll(1) is called. As
|
493
|
|
- * long as the interrupt is masked off so that it
|
494
|
|
- * doesn't immediately retrigger the 8259A then all
|
495
|
|
- * should be well.
|
496
|
|
- */
|
497
|
476
|
DBG ( " START" );
|
498
|
|
- 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 */
|
499
|
483
|
DBG ( " OURS" );
|
500
|
|
- eth_irq ( DISABLE );
|
501
|
484
|
undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_OURS;
|
502
|
485
|
} else {
|
503
|
486
|
DBG ( " NOT_OURS" );
|
|
@@ -505,62 +488,48 @@ PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) {
|
505
|
488
|
}
|
506
|
489
|
break;
|
507
|
490
|
case PXENV_UNDI_ISR_IN_PROCESS :
|
508
|
|
- /* Call poll(), return packet. If no packet, return "done".
|
509
|
|
- */
|
510
|
|
- DBG ( " PROCESS" );
|
511
|
|
- if ( eth_poll ( 1 ) ) {
|
512
|
|
- DBG ( " RECEIVE %d", nic.packetlen );
|
513
|
|
- if ( nic.packetlen > sizeof(pxe_stack->packet) ) {
|
514
|
|
- /* Should never happen */
|
515
|
|
- undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE;
|
516
|
|
- undi_isr->Status =
|
517
|
|
- PXENV_STATUS_OUT_OF_RESOURCES;
|
518
|
|
- return PXENV_EXIT_FAILURE;
|
519
|
|
- }
|
520
|
|
- undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_RECEIVE;
|
521
|
|
- undi_isr->BufferLength = nic.packetlen;
|
522
|
|
- undi_isr->FrameLength = nic.packetlen;
|
523
|
|
- undi_isr->FrameHeaderLength = ETH_HLEN;
|
524
|
|
- memcpy ( pxe_stack->packet, nic.packet, nic.packetlen);
|
525
|
|
- PTR_TO_SEGOFF16 ( pxe_stack->packet, undi_isr->Frame );
|
526
|
|
- switch ( ntohs(media_header->nstype) ) {
|
527
|
|
- case ETH_P_IP: undi_isr->ProtType = P_IP; break;
|
528
|
|
- case ETH_P_ARP: undi_isr->ProtType = P_ARP; break;
|
529
|
|
- case ETH_P_RARP: undi_isr->ProtType = P_RARP; break;
|
530
|
|
- default : undi_isr->ProtType = P_UNKNOWN;
|
531
|
|
- }
|
532
|
|
- if ( memcmp ( media_header->dest, broadcast_mac,
|
533
|
|
- sizeof(broadcast_mac) ) ) {
|
534
|
|
- undi_isr->PktType = XMT_BROADCAST;
|
535
|
|
- } else {
|
536
|
|
- undi_isr->PktType = XMT_DESTADDR;
|
537
|
|
- }
|
|
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;
|
538
|
499
|
break;
|
539
|
|
- } else {
|
540
|
|
- /* No break - fall through to IN_GET_NEXT */
|
541
|
500
|
}
|
542
|
|
- case PXENV_UNDI_ISR_IN_GET_NEXT :
|
543
|
|
- /* We only ever return one frame at a time */
|
544
|
|
- DBG ( " GET_NEXT DONE" );
|
545
|
|
- /* Re-enable interrupts */
|
546
|
|
- eth_irq ( ENABLE );
|
547
|
|
- /* Force an interrupt if there's a packet still
|
548
|
|
- * waiting, since we only handle one packet per
|
549
|
|
- * interrupt.
|
550
|
|
- */
|
551
|
|
- if ( eth_poll ( 0 ) ) {
|
552
|
|
- DBG ( " (RETRIGGER)" );
|
553
|
|
- 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;
|
554
|
510
|
}
|
555
|
|
- 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;
|
556
|
524
|
break;
|
557
|
525
|
default :
|
|
526
|
+ DBG ( " INVALID(%04x)", undi_isr->FuncFlag );
|
|
527
|
+
|
558
|
528
|
/* Should never happen */
|
559
|
529
|
undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE;
|
560
|
530
|
undi_isr->Status = PXENV_STATUS_UNDI_INVALID_PARAMETER;
|
561
|
531
|
return PXENV_EXIT_FAILURE;
|
562
|
532
|
}
|
563
|
|
-#endif
|
564
|
533
|
|
565
|
534
|
undi_isr->Status = PXENV_STATUS_SUCCESS;
|
566
|
535
|
return PXENV_EXIT_SUCCESS;
|