diff --git a/src/arch/i386/core/dhcp_basemem.c b/src/arch/i386/core/basemem_packet.c similarity index 76% rename from src/arch/i386/core/dhcp_basemem.c rename to src/arch/i386/core/basemem_packet.c index de40c30d..eedfaba4 100644 --- a/src/arch/i386/core/dhcp_basemem.c +++ b/src/arch/i386/core/basemem_packet.c @@ -19,11 +19,12 @@ /** * @file * - * DHCP parameter block provided to external programs in base memory + * Packet buffer in base memory. Used by various components which + * need to pass packets to and from external real-mode code. * */ -#include +#include -#undef dhcp_basemem -char __data16_array ( dhcp_basemem, [DHCP_BASEMEM_LEN] ); +#undef basemem_packet +char __data16_array ( basemem_packet, [BASEMEM_PACKET_LEN] ); diff --git a/src/arch/i386/drivers/net/undinet.c b/src/arch/i386/drivers/net/undinet.c index 865c6e8d..6bc0fc36 100644 --- a/src/arch/i386/drivers/net/undinet.c +++ b/src/arch/i386/drivers/net/undinet.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -314,13 +315,6 @@ static int undinet_isr_triggered ( void ) { ***************************************************************************** */ -/** Maximum length of a packet transmitted via the UNDI API */ -#define UNDI_IOB_LEN 1514 - -/** UNDI I/O buffer */ -static char __data16_array ( undinet_iob, [UNDI_IOB_LEN] ); -#define undinet_iob __use_data16 ( undinet_iob ) - /** UNDI transmit buffer descriptor */ static struct s_PXENV_UNDI_TBD __data16 ( undinet_tbd ); #define undinet_tbd __use_data16 ( undinet_tbd ) @@ -340,9 +334,9 @@ static int undinet_transmit ( struct net_device *netdev, int rc; /* Copy packet to UNDI I/O buffer */ - if ( len > sizeof ( undinet_iob ) ) - len = sizeof ( undinet_iob ); - memcpy ( &undinet_iob, iobuf->data, len ); + if ( len > sizeof ( basemem_packet ) ) + len = sizeof ( basemem_packet ); + memcpy ( &basemem_packet, iobuf->data, len ); /* Create PXENV_UNDI_TRANSMIT data structure */ memset ( &undi_transmit, 0, sizeof ( undi_transmit ) ); @@ -357,7 +351,7 @@ static int undinet_transmit ( struct net_device *netdev, undinet_tbd.ImmedLength = len; undinet_tbd.Xmit.segment = rm_ds; undinet_tbd.Xmit.offset - = ( ( unsigned ) & __from_data16 ( undinet_iob ) ); + = ( ( unsigned ) & __from_data16 ( basemem_packet ) ); /* Issue PXE API call */ if ( ( rc = undinet_call ( undinic, PXENV_UNDI_TRANSMIT, diff --git a/src/arch/i386/image/nbi.c b/src/arch/i386/image/nbi.c index fe0757cc..6084b21b 100644 --- a/src/arch/i386/image/nbi.c +++ b/src/arch/i386/image/nbi.c @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include #include #include @@ -321,7 +321,7 @@ static int nbi_boot16 ( struct image *image, struct imgheader *imgheader ) { "=b" ( discard_b ) : "D" ( imgheader->execaddr.segoff ), "S" ( imgheader->location ), - "b" ( __from_data16 ( dhcp_basemem ) ) + "b" ( __from_data16 ( basemem_packet ) ) : "ecx", "edx", "ebp" ); gateA20_set(); @@ -356,7 +356,7 @@ static int nbi_boot32 ( struct image *image, struct imgheader *imgheader ) { : "D" ( imgheader->execaddr.linear ), "S" ( ( imgheader->location.segment << 4 ) + imgheader->location.offset ), - "b" ( virt_to_phys ( dhcp_basemem ) ), + "b" ( virt_to_phys ( basemem_packet ) ), "a" ( virt_to_phys ( &loaderinfo ) ) : "ecx", "edx", "ebp", "memory" ); @@ -397,8 +397,8 @@ static int nbi_prepare_dhcp ( struct image *image ) { return -ENODEV; } - if ( ( rc = create_dhcp_packet ( boot_netdev, DHCPACK, - dhcp_basemem, sizeof ( dhcp_basemem ), + if ( ( rc = create_dhcp_packet ( boot_netdev, DHCPACK, basemem_packet, + sizeof ( basemem_packet ), &dhcppkt ) ) != 0 ) { DBGC ( image, "NBI %p failed to build DHCP packet\n", image ); return rc; diff --git a/src/arch/i386/image/pxe_image.c b/src/arch/i386/image/pxe_image.c index 9cf54691..c6469290 100644 --- a/src/arch/i386/image/pxe_image.c +++ b/src/arch/i386/image/pxe_image.c @@ -40,6 +40,7 @@ struct image_type pxe_image_type __image_type ( PROBE_PXE ); */ static int pxe_exec ( struct image *image __unused ) { struct net_device *netdev; + int rc; /* Ensure that PXE stack is ready to use */ pxe_init_structures(); @@ -47,11 +48,18 @@ static int pxe_exec ( struct image *image __unused ) { /* Arbitrarily pick the first open network device to use for PXE */ for_each_netdev ( netdev ) { - pxe_netdev = netdev; + pxe_set_netdev ( netdev ); break; } - return pxe_start_nbp(); + /* Start PXE NBP */ + rc = pxe_start_nbp(); + + /* Deactivate PXE */ + pxe_set_netdev ( NULL ); + pxe_unhook_int1a(); + + return rc; } /** diff --git a/src/arch/i386/include/basemem_packet.h b/src/arch/i386/include/basemem_packet.h new file mode 100644 index 00000000..2f7212dc --- /dev/null +++ b/src/arch/i386/include/basemem_packet.h @@ -0,0 +1,13 @@ +#ifndef BASEMEM_PACKET_H +#define BASEMEM_PACKET_H + +#include + +/** Maximum length of base memory packet buffer */ +#define BASEMEM_PACKET_LEN 1514 + +/** Base memory packet buffer */ +extern char __data16_array ( basemem_packet, [BASEMEM_PACKET_LEN] ); +#define basemem_packet __use_data16 ( basemem_packet ) + +#endif /* BASEMEM_PACKET_H */ diff --git a/src/arch/i386/include/dhcp_basemem.h b/src/arch/i386/include/dhcp_basemem.h deleted file mode 100644 index 82d5ccb9..00000000 --- a/src/arch/i386/include/dhcp_basemem.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef DHCP_BASEMEM_H -#define DHCP_BASEMEM_H - -#include - -/** Maximum length of a DHCP data buffer */ -#define DHCP_BASEMEM_LEN 1514 - -/** DHCP data buffer */ -extern char __data16_array ( dhcp_basemem, [DHCP_BASEMEM_LEN] ); -#define dhcp_basemem __use_data16 ( dhcp_basemem ) - -#endif /* DHCP_BASEMEM_H */ diff --git a/src/drivers/bus/isapnp.c b/src/drivers/bus/isapnp.c index 96bc60ec..79268d44 100644 --- a/src/drivers/bus/isapnp.c +++ b/src/drivers/bus/isapnp.c @@ -705,6 +705,8 @@ static int isapnpbus_probe ( struct root_device *rootdev ) { isapnp->dev.desc.bus_type = BUS_TYPE_ISAPNP; isapnp->dev.desc.vendor = isapnp->vendor_id; isapnp->dev.desc.device = isapnp->prod_id; + isapnp->dev.desc.ioaddr = isapnp->ioaddr; + isapnp->dev.desc.irq = isapnp->irqno; isapnp->dev.parent = &rootdev->dev; list_add ( &isapnp->dev.siblings, &rootdev->dev.children ); diff --git a/src/drivers/bus/pci.c b/src/drivers/bus/pci.c index 577691f5..967441ac 100644 --- a/src/drivers/bus/pci.c +++ b/src/drivers/bus/pci.c @@ -286,6 +286,9 @@ static int pcibus_probe ( struct root_device *rootdev ) { pci->dev.desc.location = PCI_BUSDEVFN (bus, devfn); pci->dev.desc.vendor = pci->vendor; pci->dev.desc.device = pci->device; + pci->dev.desc.class = pci->class; + pci->dev.desc.ioaddr = pci->ioaddr; + pci->dev.desc.irq = pci->irq; pci->dev.parent = &rootdev->dev; list_add ( &pci->dev.siblings, &rootdev->dev.children); INIT_LIST_HEAD ( &pci->dev.children ); diff --git a/src/include/gpxe/arp.h b/src/include/gpxe/arp.h index 1c702b00..6464ce0c 100644 --- a/src/include/gpxe/arp.h +++ b/src/include/gpxe/arp.h @@ -30,6 +30,8 @@ struct arp_net_protocol { #define __arp_net_protocol \ __table ( struct arp_net_protocol, arp_net_protocols, 01 ) +extern struct net_protocol arp_protocol; + extern int arp_resolve ( struct net_device *netdev, struct net_protocol *net_protocol, const void *dest_net_addr, diff --git a/src/include/gpxe/device.h b/src/include/gpxe/device.h index f88a2da5..caabdae5 100644 --- a/src/include/gpxe/device.h +++ b/src/include/gpxe/device.h @@ -27,6 +27,12 @@ struct device_description { unsigned int vendor; /** Device ID */ unsigned int device; + /** Device class */ + unsigned long class; + /** I/O address */ + unsigned long ioaddr; + /** IRQ */ + unsigned int irq; }; /** PCI bus type */ diff --git a/src/include/gpxe/netdevice.h b/src/include/gpxe/netdevice.h index 9800ef56..0060e7d5 100644 --- a/src/include/gpxe/netdevice.h +++ b/src/include/gpxe/netdevice.h @@ -122,6 +122,8 @@ struct ll_protocol { uint16_t ll_proto; /** Link-layer address length */ uint8_t ll_addr_len; + /** Link-layer header length */ + uint8_t ll_header_len; /** Link-layer broadcast address */ const uint8_t *ll_broadcast; }; diff --git a/src/include/gpxe/rarp.h b/src/include/gpxe/rarp.h new file mode 100644 index 00000000..81e03bde --- /dev/null +++ b/src/include/gpxe/rarp.h @@ -0,0 +1,14 @@ +#ifndef _GPXE_RARP_H +#define _GPXE_RARP_H + +/** @file + * + * Reverse Address Resolution Protocol + * + */ + +struct net_protocol; + +extern struct net_protocol rarp_protocol; + +#endif /* _GPXE_RARP_H */ diff --git a/src/include/pxe.h b/src/include/pxe.h index aba774ef..301bb10b 100644 --- a/src/include/pxe.h +++ b/src/include/pxe.h @@ -137,4 +137,6 @@ struct pcir_header { extern struct net_device *pxe_netdev; +extern void pxe_set_netdev ( struct net_device *netdev ); + #endif /* PXE_H */ diff --git a/src/interface/pxe/pxe.c b/src/interface/pxe/pxe.c index 8aa7df0d..5e67758b 100644 --- a/src/interface/pxe/pxe.c +++ b/src/interface/pxe/pxe.c @@ -22,12 +22,24 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "dev.h" +#include #include "pxe.h" -#warning "pxe_netdev should hold a persistent reference to the net device" struct net_device *pxe_netdev = NULL; +/** + * Set network device as current PXE network device + * + * @v netdev Network device, or NULL + */ +void pxe_set_netdev ( struct net_device *netdev ) { + if ( pxe_netdev ) + netdev_put ( pxe_netdev ); + pxe_netdev = NULL; + if ( netdev ) + pxe_netdev = netdev_get ( netdev ); +} + #if 0 /* Global pointer to currently installed PXE stack */ diff --git a/src/interface/pxe/pxe_preboot.c b/src/interface/pxe/pxe_preboot.c index 3cbbf226..15752b23 100644 --- a/src/interface/pxe/pxe_preboot.c +++ b/src/interface/pxe/pxe_preboot.c @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include "pxe.h" #include "pxe_call.h" @@ -99,10 +99,10 @@ PXENV_EXIT_t pxenv_get_cached_info ( struct s_PXENV_GET_CACHED_INFO */ len = get_cached_info->BufferSize; if ( len == 0 ) { - len = sizeof ( dhcp_basemem ); + len = sizeof ( basemem_packet ); get_cached_info->Buffer.segment = rm_ds; get_cached_info->Buffer.offset = - ( unsigned int ) ( & __from_data16 ( dhcp_basemem ) ); + ( unsigned int ) ( & __from_data16 ( basemem_packet ) ); get_cached_info->BufferLimit = len; } diff --git a/src/interface/pxe/pxe_undi.c b/src/interface/pxe/pxe_undi.c index 4a9b3390..9488d9f4 100644 --- a/src/interface/pxe/pxe_undi.c +++ b/src/interface/pxe/pxe_undi.c @@ -23,12 +23,18 @@ */ #include +#include #include +#include +#include #include +#include #include #include -#include #include +#include +#include +#include #include #include "pxe.h" @@ -128,61 +134,76 @@ PXENV_EXIT_t pxenv_undi_close ( struct s_PXENV_UNDI_CLOSE *undi_close ) { */ PXENV_EXIT_t pxenv_undi_transmit ( struct s_PXENV_UNDI_TRANSMIT *undi_transmit ) { - struct s_PXENV_UNDI_TBD *tbd; - const char *dest; - unsigned int type; - unsigned int length; - const char *data; + struct s_PXENV_UNDI_TBD tbd; + struct DataBlk *datablk; + struct io_buffer *iobuf; + struct net_protocol *net_protocol; + char destaddr[MAX_LL_ADDR_LEN]; + const void *ll_dest; + size_t len; + unsigned int i; + int rc; DBG ( "PXENV_UNDI_TRANSMIT" ); -#if 0 - /* We support only the "immediate" portion of the TBD. Who - * knows what Intel's "engineers" were smoking when they came - * up with the array of transmit data blocks... - */ - tbd = SEGOFF16_TO_PTR ( undi_transmit->TBD ); - if ( tbd->DataBlkCount > 0 ) { - undi_transmit->Status = PXENV_STATUS_UNDI_INVALID_PARAMETER; - return PXENV_EXIT_FAILURE; - } - data = SEGOFF16_TO_PTR ( tbd->Xmit ); - length = tbd->ImmedLength; - - /* If destination is broadcast, we need to supply the MAC address */ - if ( undi_transmit->XmitFlag == XMT_BROADCAST ) { - dest = broadcast_mac; - } else { - dest = SEGOFF16_TO_PTR ( undi_transmit->DestAddr ); - } - - /* We can't properly support P_UNKNOWN without rewriting all - * the driver transmit() methods, so we cheat: if P_UNKNOWN is - * specified we rip the destination address and type out of - * the pre-assembled packet, then skip over the header. - */ + /* Identify network-layer protocol */ switch ( undi_transmit->Protocol ) { - case P_IP: type = ETH_P_IP; break; - case P_ARP: type = ETH_P_ARP; break; - case P_RARP: type = ETH_P_RARP; break; - case P_UNKNOWN: - media_header = (media_header_t*)data; - dest = media_header->dest; - type = ntohs ( media_header->nstype ); - data += ETH_HLEN; - length -= ETH_HLEN; - break; + case P_IP: net_protocol = &ipv4_protocol; break; + case P_ARP: net_protocol = &arp_protocol; break; + case P_RARP: net_protocol = &rarp_protocol; break; + case P_UNKNOWN: net_protocol = NULL; break; default: undi_transmit->Status = PXENV_STATUS_UNDI_INVALID_PARAMETER; return PXENV_EXIT_FAILURE; } - /* Send the packet */ - eth_transmit ( dest, type, length, data ); -#endif - - undi_transmit->Status = PXENV_STATUS_SUCCESS; - return PXENV_EXIT_SUCCESS; + /* Calculate total packet length */ + copy_from_real ( &tbd, undi_transmit->TBD.segment, + undi_transmit->TBD.offset, sizeof ( tbd ) ); + len = tbd.ImmedLength; + for ( i = 0 ; i < tbd.DataBlkCount ; i++ ) { + datablk = &tbd.DataBlock[i]; + len += datablk->TDDataLen; + } + + /* Allocate and fill I/O buffer */ + iobuf = alloc_iob ( len ); + if ( ! iobuf ) { + undi_transmit->Status = PXENV_STATUS_OUT_OF_RESOURCES; + return PXENV_EXIT_FAILURE; + } + copy_from_real ( iob_put ( iobuf, tbd.ImmedLength ), tbd.Xmit.segment, + tbd.Xmit.offset, tbd.ImmedLength ); + for ( i = 0 ; i < tbd.DataBlkCount ; i++ ) { + datablk = &tbd.DataBlock[i]; + copy_from_real ( iob_put ( iobuf, datablk->TDDataLen ), + datablk->TDDataPtr.segment, + datablk->TDDataPtr.offset, + datablk->TDDataLen ); + } + + /* Transmit packet */ + if ( net_protocol == NULL ) { + /* Link-layer header already present */ + rc = netdev_tx ( pxe_netdev, iobuf ); + } else { + /* Calculate destination address */ + if ( undi_transmit->XmitFlag == XMT_DESTADDR ) { + copy_from_real ( destaddr, + undi_transmit->DestAddr.segment, + undi_transmit->DestAddr.offset, + pxe_netdev->ll_protocol->ll_addr_len ); + ll_dest = destaddr; + } else { + ll_dest = pxe_netdev->ll_protocol->ll_broadcast; + } + rc = net_tx ( iobuf, pxe_netdev, net_protocol, ll_dest ); + } + +#warning "TX completion?" + + undi_transmit->Status = PXENV_STATUS ( rc ); + return ( ( rc == 0 ) ? PXENV_EXIT_SUCCESS : PXENV_EXIT_FAILURE ); } /* PXENV_UNDI_SET_MCAST_ADDRESS @@ -200,30 +221,30 @@ pxenv_undi_set_mcast_address ( struct s_PXENV_UNDI_SET_MCAST_ADDRESS /* PXENV_UNDI_SET_STATION_ADDRESS * - * Status: working (deliberately incomplete) + * Status: working */ PXENV_EXIT_t pxenv_undi_set_station_address ( struct s_PXENV_UNDI_SET_STATION_ADDRESS *undi_set_station_address ) { + DBG ( "PXENV_UNDI_SET_STATION_ADDRESS" ); -#if 0 - /* We don't offer a facility to set the MAC address; this - * would require adding extra code to all the Etherboot - * drivers, for very little benefit. If we're setting it to - * the current value anyway then return success, otherwise - * return UNSUPPORTED. + /* If adapter is open, the change will have no effect; return + * an error */ - if ( memcmp ( nic.node_addr, - &undi_set_station_address->StationAddress, - ETH_ALEN ) == 0 ) { - undi_set_station_address->Status = PXENV_STATUS_SUCCESS; - return PXENV_EXIT_SUCCESS; + if ( pxe_netdev->state & NETDEV_OPEN ) { + undi_set_station_address->Status = + PXENV_STATUS_UNDI_INVALID_STATE; + return PXENV_EXIT_FAILURE; } -#endif - undi_set_station_address->Status = PXENV_STATUS_UNSUPPORTED; - return PXENV_EXIT_FAILURE; + /* Update MAC address */ + memcpy ( pxe_netdev->ll_addr, + &undi_set_station_address->StationAddress, + pxe_netdev->ll_protocol->ll_addr_len ); + + undi_set_station_address = PXENV_STATUS_SUCCESS; + return PXENV_EXIT_SUCCESS; } /* PXENV_UNDI_SET_PACKET_FILTER @@ -248,33 +269,11 @@ PXENV_EXIT_t pxenv_undi_get_information ( struct s_PXENV_UNDI_GET_INFORMATION *undi_get_information ) { struct device *dev = pxe_netdev->dev; struct ll_protocol *ll_protocol = pxe_netdev->ll_protocol; - unsigned int ioaddr; - unsigned int irqno; DBG ( "PXENV_UNDI_GET_INFORMATION" ); - switch ( dev->desc.bus_type ) { - case BUS_TYPE_PCI: { - struct pci_device *pci = - container_of ( dev, struct pci_device, dev ); - - ioaddr = pci->ioaddr; - irqno = pci->irq; - break; } - case BUS_TYPE_ISAPNP: { - struct isapnp_device *isapnp = - container_of ( dev, struct isapnp_device, dev ); - - ioaddr = isapnp->ioaddr; - irqno = isapnp->irqno; - break; } - default: - undi_get_information->Status = PXENV_STATUS_FAILURE; - return PXENV_EXIT_FAILURE; - } - - undi_get_information->BaseIo = ioaddr; - undi_get_information->IntNumber = irqno; + undi_get_information->BaseIo = dev->desc.ioaddr; + undi_get_information->IntNumber = dev->desc.irq; /* Cheat: assume all cards can cope with this */ undi_get_information->MaxTranUnit = ETH_MAX_MTU; 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 switch ( dev->desc.bus_type ) { case BUS_TYPE_PCI: { - struct pci_device *pci = - container_of ( dev, struct pci_device, dev ); struct pci_nic_info *info = &undi_get_nic_type->info.pci; undi_get_nic_type->NicType = PCI_NIC; - info->Vendor_ID = pci->vendor; - info->Dev_ID = pci->device; - info->Base_Class = PCI_BASE_CLASS ( pci->class ); - info->Sub_Class = PCI_SUB_CLASS ( pci->class ); - info->Prog_Intf = PCI_PROG_INTF ( pci->class ); - info->BusDevFunc = PCI_BUSDEVFN ( pci->bus, pci->devfn ); + info->Vendor_ID = dev->desc.vendor; + info->Dev_ID = dev->desc.device; + info->Base_Class = PCI_BASE_CLASS ( dev->desc.class ); + info->Sub_Class = PCI_SUB_CLASS ( dev->desc.class ); + info->Prog_Intf = PCI_PROG_INTF ( dev->desc.class ); + info->BusDevFunc = dev->desc.location; /* Cheat: remaining fields are probably unnecessary, * and would require adding extra code to pci.c. */ @@ -402,14 +399,12 @@ PXENV_EXIT_t pxenv_undi_get_nic_type ( struct s_PXENV_UNDI_GET_NIC_TYPE undi_get_nic_type->info.pci.SubDevice_ID = 0xffff; break; } case BUS_TYPE_ISAPNP: { - struct isapnp_device *isapnp = - container_of ( dev, struct isapnp_device, dev ); struct pnp_nic_info *info = &undi_get_nic_type->info.pnp; undi_get_nic_type->NicType = PnP_NIC; - info->EISA_Dev_ID = ( ( isapnp->vendor_id << 16 ) | - isapnp->prod_id ); - info->CardSelNum = isapnp->csn; + info->EISA_Dev_ID = ( ( dev->desc.vendor << 16 ) | + dev->desc.device ); + info->CardSelNum = dev->desc.location; /* Cheat: remaining fields are probably unnecessary, * and would require adding extra code to isapnp.c. */ @@ -431,16 +426,15 @@ PXENV_EXIT_t pxenv_undi_get_iface_info ( struct s_PXENV_UNDI_GET_IFACE_INFO *undi_get_iface_info ) { DBG ( "PXENV_UNDI_GET_IFACE_INFO" ); -#if 0 /* Just hand back some info, doesn't really matter what it is. * Most PXE stacks seem to take this approach. */ - sprintf ( undi_get_iface_info->IfaceType, "Etherboot" ); + snprintf ( ( char * ) undi_get_iface_info->IfaceType, + sizeof ( undi_get_iface_info->IfaceType ), "Etherboot" ); undi_get_iface_info->LinkSpeed = 10000000; /* 10 Mbps */ undi_get_iface_info->ServiceFlags = 0; memset ( undi_get_iface_info->Reserved, 0, sizeof(undi_get_iface_info->Reserved) ); -#endif undi_get_iface_info->Status = PXENV_STATUS_SUCCESS; return PXENV_EXIT_SUCCESS; @@ -463,18 +457,11 @@ PXENV_EXIT_t pxenv_undi_get_state ( struct s_PXENV_UNDI_GET_STATE * Status: working */ PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) { + struct io_buffer *iobuf; + size_t len; + DBG ( "PXENV_UNDI_ISR" ); -#if 0 - /* We can't call ENSURE_READY, because this could be being - * called as part of an interrupt service routine. Instead, - * we should simply die if we're not READY. - */ - if ( ( pxe_stack == NULL ) || ( pxe_stack->state < READY ) ) { - undi_isr->Status = PXENV_STATUS_UNDI_INVALID_STATE; - return PXENV_EXIT_FAILURE; - } - /* Just in case some idiot actually looks at these fields when * we weren't meant to fill them in... */ @@ -486,18 +473,14 @@ PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) { switch ( undi_isr->FuncFlag ) { case PXENV_UNDI_ISR_IN_START : - /* Is there a packet waiting? If so, disable - * interrupts on the NIC and return "it's ours". Do - * *not* necessarily acknowledge the interrupt; this - * can happen later when eth_poll(1) is called. As - * long as the interrupt is masked off so that it - * doesn't immediately retrigger the 8259A then all - * should be well. - */ DBG ( " START" ); - if ( eth_poll ( 0 ) ) { + + /* Call poll(). This should acknowledge the device + * interrupt and queue up any received packet. + */ + if ( netdev_poll ( pxe_netdev, -1U ) ) { + /* Packet waiting in queue */ DBG ( " OURS" ); - eth_irq ( DISABLE ); undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_OURS; } else { DBG ( " NOT_OURS" ); @@ -505,62 +488,48 @@ PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) { } break; case PXENV_UNDI_ISR_IN_PROCESS : - /* Call poll(), return packet. If no packet, return "done". - */ - DBG ( " PROCESS" ); - if ( eth_poll ( 1 ) ) { - DBG ( " RECEIVE %d", nic.packetlen ); - if ( nic.packetlen > sizeof(pxe_stack->packet) ) { - /* Should never happen */ - undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE; - undi_isr->Status = - PXENV_STATUS_OUT_OF_RESOURCES; - return PXENV_EXIT_FAILURE; - } - undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_RECEIVE; - undi_isr->BufferLength = nic.packetlen; - undi_isr->FrameLength = nic.packetlen; - undi_isr->FrameHeaderLength = ETH_HLEN; - memcpy ( pxe_stack->packet, nic.packet, nic.packetlen); - PTR_TO_SEGOFF16 ( pxe_stack->packet, undi_isr->Frame ); - switch ( ntohs(media_header->nstype) ) { - case ETH_P_IP: undi_isr->ProtType = P_IP; break; - case ETH_P_ARP: undi_isr->ProtType = P_ARP; break; - case ETH_P_RARP: undi_isr->ProtType = P_RARP; break; - default : undi_isr->ProtType = P_UNKNOWN; - } - if ( memcmp ( media_header->dest, broadcast_mac, - sizeof(broadcast_mac) ) ) { - undi_isr->PktType = XMT_BROADCAST; - } else { - undi_isr->PktType = XMT_DESTADDR; - } - break; - } else { - /* No break - fall through to IN_GET_NEXT */ - } case PXENV_UNDI_ISR_IN_GET_NEXT : - /* We only ever return one frame at a time */ - DBG ( " GET_NEXT DONE" ); - /* Re-enable interrupts */ - eth_irq ( ENABLE ); - /* Force an interrupt if there's a packet still - * waiting, since we only handle one packet per - * interrupt. - */ - if ( eth_poll ( 0 ) ) { - DBG ( " (RETRIGGER)" ); - eth_irq ( FORCE ); + DBG ( " PROCESS/GET_NEXT" ); + + /* Remove first packet from netdev RX queue */ + iobuf = netdev_rx_dequeue ( pxe_netdev ); + if ( ! iobuf ) { + /* No more packets remaining */ + undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE; + break; } - undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE; + + /* Copy packet to base memory buffer */ + len = iob_len ( iobuf ); + DBG ( " RECEIVE %zd", len ); + if ( len > sizeof ( basemem_packet ) ) { + /* Should never happen */ + undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE; + undi_isr->Status = PXENV_STATUS_OUT_OF_RESOURCES; + return PXENV_EXIT_FAILURE; + } + memcpy ( basemem_packet, iobuf->data, len ); + + undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_RECEIVE; + undi_isr->BufferLength = len; + undi_isr->FrameLength = len; + undi_isr->FrameHeaderLength = + pxe_netdev->ll_protocol->ll_header_len; + undi_isr->Frame.segment = rm_ds; + undi_isr->Frame.offset = + ( ( unsigned ) & __from_data16 ( basemem_packet ) ); + /* Probably ought to fill in packet type */ + undi_isr->ProtType = P_UNKNOWN; + undi_isr->PktType = XMT_DESTADDR; break; default : + DBG ( " INVALID(%04x)", undi_isr->FuncFlag ); + /* Should never happen */ undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE; undi_isr->Status = PXENV_STATUS_UNDI_INVALID_PARAMETER; return PXENV_EXIT_FAILURE; } -#endif undi_isr->Status = PXENV_STATUS_SUCCESS; return PXENV_EXIT_SUCCESS; diff --git a/src/net/arp.c b/src/net/arp.c index 383dc842..011d4fef 100644 --- a/src/net/arp.c +++ b/src/net/arp.c @@ -281,8 +281,7 @@ static int arp_rx ( struct io_buffer *iobuf, struct net_device *netdev, * * This operation is meaningless for the ARP protocol. */ -static const char * -arp_ntoa ( const void *net_addr __attribute__ (( unused )) ) { +static const char * arp_ntoa ( const void *net_addr __unused ) { return ""; } diff --git a/src/net/ethernet.c b/src/net/ethernet.c index 7108beff..8f259fb3 100644 --- a/src/net/ethernet.c +++ b/src/net/ethernet.c @@ -108,6 +108,7 @@ struct ll_protocol ethernet_protocol __ll_protocol = { .name = "Ethernet", .ll_proto = htons ( ARPHRD_ETHER ), .ll_addr_len = ETH_ALEN, + .ll_header_len = ETH_HLEN, .ll_broadcast = eth_broadcast, .tx = eth_tx, .rx = eth_rx, diff --git a/src/net/rarp.c b/src/net/rarp.c new file mode 100644 index 00000000..bb5e6ad7 --- /dev/null +++ b/src/net/rarp.c @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2007 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include + +/** @file + * + * Reverse Address Resolution Protocol + * + */ + +/** + * Process incoming ARP packets + * + * @v iobuf I/O buffer + * @v netdev Network device + * @v ll_source Link-layer source address + * @ret rc Return status code + * + * This is a dummy method which simply discards RARP packets. + */ +static int rarp_rx ( struct io_buffer *iobuf, + struct net_device *netdev __unused, + const void *ll_source __unused ) { + free_iob ( iobuf ); + return 0; +} + + +/** + * Transcribe RARP address + * + * @v net_addr RARP address + * @ret string "" + * + * This operation is meaningless for the RARP protocol. + */ +static const char * rarp_ntoa ( const void *net_addr __unused ) { + return ""; +} + +/** RARP protocol */ +struct net_protocol rarp_protocol __net_protocol = { + .name = "RARP", + .net_proto = htons ( ETH_P_RARP ), + .rx = rarp_rx, + .ntoa = rarp_ntoa, +};