iPXE
Functions | Variables
pxe_undi.c File Reference

PXE UNDI API. More...

#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <byteswap.h>
#include <basemem_packet.h>
#include <ipxe/netdevice.h>
#include <ipxe/iobuf.h>
#include <ipxe/device.h>
#include <ipxe/pci.h>
#include <ipxe/if_ether.h>
#include <ipxe/ip.h>
#include <ipxe/arp.h>
#include <ipxe/rarp.h>
#include <ipxe/profile.h>
#include "pxe.h"

Go to the source code of this file.

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
void pxe_set_netdev (struct net_device *netdev)
 Set network device as current PXE network device.
static int pxe_netdev_open (void)
 Open PXE network device.
static void pxe_netdev_close (void)
 Close PXE network device.
static void pxe_dump_mcast_list (struct s_PXENV_UNDI_MCAST_ADDRESS *mcast)
 Dump multicast address list.
static PXENV_EXIT_t pxenv_undi_startup (struct s_PXENV_UNDI_STARTUP *undi_startup)
static PXENV_EXIT_t pxenv_undi_cleanup (struct s_PXENV_UNDI_CLEANUP *undi_cleanup)
static PXENV_EXIT_t pxenv_undi_initialize (struct s_PXENV_UNDI_INITIALIZE *undi_initialize)
static PXENV_EXIT_t pxenv_undi_reset_adapter (struct s_PXENV_UNDI_RESET *undi_reset_adapter)
static PXENV_EXIT_t pxenv_undi_shutdown (struct s_PXENV_UNDI_SHUTDOWN *undi_shutdown)
static PXENV_EXIT_t pxenv_undi_open (struct s_PXENV_UNDI_OPEN *undi_open)
static PXENV_EXIT_t pxenv_undi_close (struct s_PXENV_UNDI_CLOSE *undi_close)
static PXENV_EXIT_t pxenv_undi_transmit (struct s_PXENV_UNDI_TRANSMIT *undi_transmit)
static PXENV_EXIT_t pxenv_undi_set_mcast_address (struct s_PXENV_UNDI_SET_MCAST_ADDRESS *undi_set_mcast_address)
static PXENV_EXIT_t pxenv_undi_set_station_address (struct s_PXENV_UNDI_SET_STATION_ADDRESS *undi_set_station_address)
static PXENV_EXIT_t pxenv_undi_set_packet_filter (struct s_PXENV_UNDI_SET_PACKET_FILTER *undi_set_packet_filter)
static PXENV_EXIT_t pxenv_undi_get_information (struct s_PXENV_UNDI_GET_INFORMATION *undi_get_information)
static PXENV_EXIT_t pxenv_undi_get_statistics (struct s_PXENV_UNDI_GET_STATISTICS *undi_get_statistics)
static PXENV_EXIT_t pxenv_undi_clear_statistics (struct s_PXENV_UNDI_CLEAR_STATISTICS *undi_clear_statistics)
static PXENV_EXIT_t pxenv_undi_initiate_diags (struct s_PXENV_UNDI_INITIATE_DIAGS *undi_initiate_diags)
static PXENV_EXIT_t pxenv_undi_force_interrupt (struct s_PXENV_UNDI_FORCE_INTERRUPT *undi_force_interrupt)
static PXENV_EXIT_t pxenv_undi_get_mcast_address (struct s_PXENV_UNDI_GET_MCAST_ADDRESS *undi_get_mcast_address)
static PXENV_EXIT_t pxenv_undi_get_nic_type (struct s_PXENV_UNDI_GET_NIC_TYPE *undi_get_nic_type)
static PXENV_EXIT_t pxenv_undi_get_iface_info (struct s_PXENV_UNDI_GET_IFACE_INFO *undi_get_iface_info)
static PXENV_EXIT_t pxenv_undi_isr (struct s_PXENV_UNDI_ISR *undi_isr)

Variables

static int undi_tx_count = 0
 Count of outstanding transmitted packets.
struct net_devicepxe_netdev = NULL
static struct profiler
undi_tx_profiler 
__profiler = { .name = "undi.tx" }
 Transmit profiler.
struct pxe_api_call pxe_undi_api[] __pxe_api_call
 PXE UNDI API.

Detailed Description

PXE UNDI API.

Definition in file pxe_undi.c.


Function Documentation

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL  )
void pxe_set_netdev ( struct net_device netdev)

Set network device as current PXE network device.

Parameters:
netdevNetwork device, or NULL

Definition at line 69 of file pxe_undi.c.

References netdev_get(), netdev_put(), netdev_rx_unfreeze(), and NULL.

Referenced by pxe_activate(), and pxe_deactivate().

                                                  {

        if ( pxe_netdev ) {
                netdev_rx_unfreeze ( pxe_netdev );
                netdev_put ( pxe_netdev );
        }

        pxe_netdev = NULL;

        if ( netdev )
                pxe_netdev = netdev_get ( netdev );
}
static int pxe_netdev_open ( void  ) [static]

Open PXE network device.

Return values:
rcReturn status code

Definition at line 87 of file pxe_undi.c.

References assert, netdev_irq(), netdev_open(), netdev_rx_freeze(), NULL, and rc.

Referenced by pxenv_undi_open(), and pxenv_undi_reset_adapter().

                                    {
        int rc;

        assert ( pxe_netdev != NULL );

        if ( ( rc = netdev_open ( pxe_netdev ) ) != 0 )
                return rc;

        netdev_rx_freeze ( pxe_netdev );
        netdev_irq ( pxe_netdev, 1 );

        return 0;
}
static void pxe_netdev_close ( void  ) [static]
static void pxe_dump_mcast_list ( struct s_PXENV_UNDI_MCAST_ADDRESS mcast) [static]

Dump multicast address list.

Parameters:
mcastPXE multicast address list

Definition at line 119 of file pxe_undi.c.

References DBGC, net_device::ll_protocol, s_PXENV_UNDI_MCAST_ADDRESS::McastAddr, s_PXENV_UNDI_MCAST_ADDRESS::MCastAddrCount, and ll_protocol::ntoa.

Referenced by pxenv_undi_open(), pxenv_undi_reset_adapter(), and pxenv_undi_set_mcast_address().

                                                                             {
        struct ll_protocol *ll_protocol = pxe_netdev->ll_protocol;
        unsigned int i;

        for ( i = 0 ; i < mcast->MCastAddrCount ; i++ ) {
                DBGC ( &pxe_netdev, " %s",
                       ll_protocol->ntoa ( mcast->McastAddr[i] ) );
        }
}
static PXENV_EXIT_t pxenv_undi_startup ( struct s_PXENV_UNDI_STARTUP undi_startup) [static]

Definition at line 134 of file pxe_undi.c.

References DBGC, PXENV_EXIT_FAILURE, PXENV_EXIT_SUCCESS, PXENV_STATUS_SUCCESS, PXENV_STATUS_UNDI_INVALID_STATE, and s_PXENV_UNDI_STARTUP::Status.

                                                                 {
        DBGC ( &pxe_netdev, "PXENV_UNDI_STARTUP\n" );

        /* Sanity check */
        if ( ! pxe_netdev ) {
                DBGC ( &pxe_netdev, "PXENV_UNDI_STARTUP called with no "
                       "network device\n" );
                undi_startup->Status = PXENV_STATUS_UNDI_INVALID_STATE;
                return PXENV_EXIT_FAILURE;
        }

        undi_startup->Status = PXENV_STATUS_SUCCESS;
        return PXENV_EXIT_SUCCESS;
}
static PXENV_EXIT_t pxenv_undi_cleanup ( struct s_PXENV_UNDI_CLEANUP undi_cleanup) [static]

Definition at line 154 of file pxe_undi.c.

References DBGC, pxe_netdev_close(), PXENV_EXIT_FAILURE, PXENV_EXIT_SUCCESS, PXENV_STATUS_SUCCESS, PXENV_STATUS_UNDI_INVALID_STATE, and s_PXENV_UNDI_CLEANUP::Status.

                                                                 {
        DBGC ( &pxe_netdev, "PXENV_UNDI_CLEANUP\n" );

        /* Sanity check */
        if ( ! pxe_netdev ) {
                DBGC ( &pxe_netdev, "PXENV_UNDI_CLEANUP called with no "
                       "network device\n" );
                undi_cleanup->Status = PXENV_STATUS_UNDI_INVALID_STATE;
                return PXENV_EXIT_FAILURE;
        }

        /* Close network device */
        pxe_netdev_close();

        undi_cleanup->Status = PXENV_STATUS_SUCCESS;
        return PXENV_EXIT_SUCCESS;
}
static PXENV_EXIT_t pxenv_undi_initialize ( struct s_PXENV_UNDI_INITIALIZE undi_initialize) [static]

Definition at line 177 of file pxe_undi.c.

References DBGC, s_PXENV_UNDI_INITIALIZE::ProtocolIni, PXENV_EXIT_FAILURE, PXENV_EXIT_SUCCESS, PXENV_STATUS_SUCCESS, PXENV_STATUS_UNDI_INVALID_STATE, and s_PXENV_UNDI_INITIALIZE::Status.

                                                                          {
        DBGC ( &pxe_netdev, "PXENV_UNDI_INITIALIZE protocolini %08x\n",
               undi_initialize->ProtocolIni );

        /* Sanity check */
        if ( ! pxe_netdev ) {
                DBGC ( &pxe_netdev, "PXENV_UNDI_INITIALIZE called with no "
                       "network device\n" );
                undi_initialize->Status = PXENV_STATUS_UNDI_INVALID_STATE;
                return PXENV_EXIT_FAILURE;
        }

        undi_initialize->Status = PXENV_STATUS_SUCCESS;
        return PXENV_EXIT_SUCCESS;
}
static PXENV_EXIT_t pxenv_undi_reset_adapter ( struct s_PXENV_UNDI_RESET undi_reset_adapter) [static]

Definition at line 198 of file pxe_undi.c.

References DBGC, net_device::name, pxe_dump_mcast_list(), pxe_netdev_close(), pxe_netdev_open(), PXENV_EXIT_FAILURE, PXENV_EXIT_SUCCESS, PXENV_STATUS, PXENV_STATUS_SUCCESS, PXENV_STATUS_UNDI_INVALID_STATE, s_PXENV_UNDI_RESET::R_Mcast_Buf, rc, s_PXENV_UNDI_RESET::Status, and strerror().

                                                                           {
        int rc;

        DBGC ( &pxe_netdev, "PXENV_UNDI_RESET_ADAPTER" );
        pxe_dump_mcast_list ( &undi_reset_adapter->R_Mcast_Buf );
        DBGC ( &pxe_netdev, "\n" );

        /* Sanity check */
        if ( ! pxe_netdev ) {
                DBGC ( &pxe_netdev, "PXENV_UNDI_RESET_ADAPTER called with no "
                       "network device\n" );
                undi_reset_adapter->Status = PXENV_STATUS_UNDI_INVALID_STATE;
                return PXENV_EXIT_FAILURE;
        }

        /* Close and reopen network device */
        pxe_netdev_close();
        if ( ( rc = pxe_netdev_open() ) != 0 ) {
                DBGC ( &pxe_netdev, "PXENV_UNDI_RESET_ADAPTER could not "
                       "reopen %s: %s\n", pxe_netdev->name, strerror ( rc ) );
                undi_reset_adapter->Status = PXENV_STATUS ( rc );
                return PXENV_EXIT_FAILURE;
        }

        undi_reset_adapter->Status = PXENV_STATUS_SUCCESS;
        return PXENV_EXIT_SUCCESS;
}
static PXENV_EXIT_t pxenv_undi_shutdown ( struct s_PXENV_UNDI_SHUTDOWN undi_shutdown) [static]

Definition at line 231 of file pxe_undi.c.

References DBGC, pxe_netdev_close(), PXENV_EXIT_FAILURE, PXENV_EXIT_SUCCESS, PXENV_STATUS_SUCCESS, PXENV_STATUS_UNDI_INVALID_STATE, and s_PXENV_UNDI_SHUTDOWN::Status.

                                                                    {
        DBGC ( &pxe_netdev, "PXENV_UNDI_SHUTDOWN\n" );

        /* Sanity check */
        if ( ! pxe_netdev ) {
                DBGC ( &pxe_netdev, "PXENV_UNDI_SHUTDOWN called with no "
                       "network device\n" );
                undi_shutdown->Status = PXENV_STATUS_UNDI_INVALID_STATE;
                return PXENV_EXIT_FAILURE;
        }

        /* Close network device */
        pxe_netdev_close();

        undi_shutdown->Status = PXENV_STATUS_SUCCESS;
        return PXENV_EXIT_SUCCESS;
}
static PXENV_EXIT_t pxenv_undi_open ( struct s_PXENV_UNDI_OPEN undi_open) [static]

Definition at line 253 of file pxe_undi.c.

References DBGC, net_device::name, s_PXENV_UNDI_OPEN::OpenFlag, s_PXENV_UNDI_OPEN::PktFilter, pxe_dump_mcast_list(), pxe_netdev_open(), PXENV_EXIT_FAILURE, PXENV_EXIT_SUCCESS, PXENV_STATUS, PXENV_STATUS_SUCCESS, PXENV_STATUS_UNDI_INVALID_STATE, s_PXENV_UNDI_OPEN::R_Mcast_Buf, rc, s_PXENV_UNDI_OPEN::Status, and strerror().

                                                                            {
        int rc;

        DBGC ( &pxe_netdev, "PXENV_UNDI_OPEN flag %04x filter %04x",
               undi_open->OpenFlag, undi_open->PktFilter );
        pxe_dump_mcast_list ( &undi_open->R_Mcast_Buf );
        DBGC ( &pxe_netdev, "\n" );

        /* Sanity check */
        if ( ! pxe_netdev ) {
                DBGC ( &pxe_netdev, "PXENV_UNDI_OPEN called with no "
                       "network device\n" );
                undi_open->Status = PXENV_STATUS_UNDI_INVALID_STATE;
                return PXENV_EXIT_FAILURE;
        }

        /* Open network device */
        if ( ( rc = pxe_netdev_open() ) != 0 ) {
                DBGC ( &pxe_netdev, "PXENV_UNDI_OPEN could not open %s: %s\n",
                       pxe_netdev->name, strerror ( rc ) );
                undi_open->Status = PXENV_STATUS ( rc );
                return PXENV_EXIT_FAILURE;
        }

        undi_open->Status = PXENV_STATUS_SUCCESS;
        return PXENV_EXIT_SUCCESS;
}
static PXENV_EXIT_t pxenv_undi_close ( struct s_PXENV_UNDI_CLOSE undi_close) [static]

Definition at line 285 of file pxe_undi.c.

References DBGC, pxe_netdev_close(), PXENV_EXIT_FAILURE, PXENV_EXIT_SUCCESS, PXENV_STATUS_SUCCESS, PXENV_STATUS_UNDI_INVALID_STATE, and s_PXENV_UNDI_CLOSE::Status.

                                                                               {
        DBGC ( &pxe_netdev, "PXENV_UNDI_CLOSE\n" );

        /* Sanity check */
        if ( ! pxe_netdev ) {
                DBGC ( &pxe_netdev, "PXENV_UNDI_CLOSE called with no "
                       "network device\n" );
                undi_close->Status = PXENV_STATUS_UNDI_INVALID_STATE;
                return PXENV_EXIT_FAILURE;
        }

        /* Close network device */
        pxe_netdev_close();

        undi_close->Status = PXENV_STATUS_SUCCESS;
        return PXENV_EXIT_SUCCESS;
}
static PXENV_EXIT_t pxenv_undi_transmit ( struct s_PXENV_UNDI_TRANSMIT undi_transmit) [static]

Definition at line 308 of file pxe_undi.c.

References alloc_iob(), copy_from_real, s_PXENV_UNDI_TBD::DataBlkCount, s_PXENV_UNDI_TBD::DataBlock, DBGC, DBGC2, s_PXENV_UNDI_TRANSMIT::DestAddr, free_iob(), s_PXENV_UNDI_TBD::ImmedLength, iob_put, iob_reserve, IOB_ZLEN, len, net_device::ll_addr, ll_protocol::ll_addr_len, net_device::ll_broadcast, net_device::ll_protocol, MAX_LL_ADDR_LEN, MAX_LL_HEADER_LEN, net_protocol::name, net_protocol::net_proto, netdev_irq(), netdev_rx_freeze(), netdev_rx_frozen(), netdev_tx(), ll_protocol::ntoa, NULL, P_ARP, P_IP, P_RARP, P_UNKNOWN, profile_start(), profile_stop(), s_PXENV_UNDI_TRANSMIT::Protocol, ll_protocol::push, PXENV_EXIT_FAILURE, PXENV_EXIT_SUCCESS, PXENV_STATUS, PXENV_STATUS_OUT_OF_RESOURCES, PXENV_STATUS_SUCCESS, PXENV_STATUS_UNDI_INVALID_PARAMETER, PXENV_STATUS_UNDI_INVALID_STATE, rc, s_PXENV_UNDI_TRANSMIT::Status, strerror(), s_PXENV_UNDI_TRANSMIT::TBD, DataBlk::TDDataLen, DataBlk::TDDataPtr, undi_tx_count, s_PXENV_UNDI_TBD::Xmit, s_PXENV_UNDI_TRANSMIT::XmitFlag, and XMT_DESTADDR.

                                                                    {
        struct s_PXENV_UNDI_TBD tbd;
        struct DataBlk *datablk;
        struct io_buffer *iobuf;
        struct net_protocol *net_protocol;
        struct ll_protocol *ll_protocol;
        char destaddr[MAX_LL_ADDR_LEN];
        const void *ll_dest;
        size_t len;
        unsigned int i;
        int rc;

        /* Start profiling */
        profile_start ( &undi_tx_profiler );

        /* Sanity check */
        if ( ! pxe_netdev ) {
                DBGC ( &pxe_netdev, "PXENV_UNDI_TRANSMIT called with no "
                       "network device\n" );
                undi_transmit->Status = PXENV_STATUS_UNDI_INVALID_STATE;
                return PXENV_EXIT_FAILURE;
        }

        DBGC2 ( &pxe_netdev, "PXENV_UNDI_TRANSMIT" );

        /* Forcibly enable interrupts and freeze receive queue
         * processing at this point, to work around callers that never
         * call PXENV_UNDI_OPEN before attempting to use the UNDI API.
         */
        if ( ! netdev_rx_frozen ( pxe_netdev ) ) {
                netdev_rx_freeze ( pxe_netdev );
                netdev_irq ( pxe_netdev, 1 );
        }

        /* Identify network-layer protocol */
        switch ( undi_transmit->Protocol ) {
        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:
                DBGC2 ( &pxe_netdev, " %02x invalid protocol\n",
                        undi_transmit->Protocol );
                undi_transmit->Status = PXENV_STATUS_UNDI_INVALID_PARAMETER;
                return PXENV_EXIT_FAILURE;
        }
        DBGC2 ( &pxe_netdev, " %s",
                ( net_protocol ? net_protocol->name : "RAW" ) );

        /* Calculate total packet length */
        copy_from_real ( &tbd, undi_transmit->TBD.segment,
                         undi_transmit->TBD.offset, sizeof ( tbd ) );
        len = tbd.ImmedLength;
        DBGC2 ( &pxe_netdev, " %04x:%04x+%x", tbd.Xmit.segment, tbd.Xmit.offset,
                tbd.ImmedLength );
        for ( i = 0 ; i < tbd.DataBlkCount ; i++ ) {
                datablk = &tbd.DataBlock[i];
                len += datablk->TDDataLen;
                DBGC2 ( &pxe_netdev, " %04x:%04x+%x",
                        datablk->TDDataPtr.segment, datablk->TDDataPtr.offset,
                        datablk->TDDataLen );
        }

        /* Allocate and fill I/O buffer */
        iobuf = alloc_iob ( MAX_LL_HEADER_LEN +
                            ( ( len > IOB_ZLEN ) ? len : IOB_ZLEN ) );
        if ( ! iobuf ) {
                DBGC2 ( &pxe_netdev, " could not allocate iobuf\n" );
                undi_transmit->Status = PXENV_STATUS_OUT_OF_RESOURCES;
                return PXENV_EXIT_FAILURE;
        }
        iob_reserve ( iobuf, MAX_LL_HEADER_LEN );
        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 );
        }

        /* Add link-layer header, if required to do so */
        if ( net_protocol != NULL ) {

                /* Calculate destination address */
                ll_protocol = pxe_netdev->ll_protocol;
                if ( undi_transmit->XmitFlag == XMT_DESTADDR ) {
                        copy_from_real ( destaddr,
                                         undi_transmit->DestAddr.segment,
                                         undi_transmit->DestAddr.offset,
                                         ll_protocol->ll_addr_len );
                        ll_dest = destaddr;
                        DBGC2 ( &pxe_netdev, " DEST %s",
                                ll_protocol->ntoa ( ll_dest ) );
                } else {
                        ll_dest = pxe_netdev->ll_broadcast;
                        DBGC2 ( &pxe_netdev, " BCAST" );
                }

                /* Add link-layer header */
                if ( ( rc = ll_protocol->push ( pxe_netdev, iobuf, ll_dest,
                                                pxe_netdev->ll_addr,
                                                net_protocol->net_proto ))!=0){
                        DBGC2 ( &pxe_netdev, " could not add link-layer "
                                "header: %s\n", strerror ( rc ) );
                        free_iob ( iobuf );
                        undi_transmit->Status = PXENV_STATUS ( rc );
                        return PXENV_EXIT_FAILURE;
                }
        }

        /* Flag transmission as in-progress.  Do this before starting
         * to transmit the packet, because the ISR may trigger before
         * we return from netdev_tx().
         */
        undi_tx_count++;

        /* Transmit packet */
        DBGC2 ( &pxe_netdev, "\n" );
        if ( ( rc = netdev_tx ( pxe_netdev, iobuf ) ) != 0 ) {
                DBGC2 ( &pxe_netdev, "PXENV_UNDI_TRANSMIT could not transmit: "
                        "%s\n", strerror ( rc ) );
                undi_tx_count--;
                undi_transmit->Status = PXENV_STATUS ( rc );
                return PXENV_EXIT_FAILURE;
        }

        profile_stop ( &undi_tx_profiler );
        undi_transmit->Status = PXENV_STATUS_SUCCESS;
        return PXENV_EXIT_SUCCESS;
}
static PXENV_EXIT_t pxenv_undi_set_mcast_address ( struct s_PXENV_UNDI_SET_MCAST_ADDRESS undi_set_mcast_address) [static]

Definition at line 448 of file pxe_undi.c.

References DBGC, pxe_dump_mcast_list(), PXENV_EXIT_FAILURE, PXENV_EXIT_SUCCESS, PXENV_STATUS_SUCCESS, PXENV_STATUS_UNDI_INVALID_STATE, s_PXENV_UNDI_SET_MCAST_ADDRESS::R_Mcast_Buf, and s_PXENV_UNDI_SET_MCAST_ADDRESS::Status.

                                                         {
        DBGC ( &pxe_netdev, "PXENV_UNDI_SET_MCAST_ADDRESS" );
        pxe_dump_mcast_list ( &undi_set_mcast_address->R_Mcast_Buf );
        DBGC ( &pxe_netdev, "\n" );

        /* Sanity check */
        if ( ! pxe_netdev ) {
                DBGC ( &pxe_netdev, "PXENV_UNDI_SET_MCAST_ADDRESS called with "
                       "no network device\n" );
                undi_set_mcast_address->Status =
                        PXENV_STATUS_UNDI_INVALID_STATE;
                return PXENV_EXIT_FAILURE;
        }

        undi_set_mcast_address->Status = PXENV_STATUS_SUCCESS;
        return PXENV_EXIT_SUCCESS;
}
static PXENV_EXIT_t pxenv_undi_set_station_address ( struct s_PXENV_UNDI_SET_STATION_ADDRESS undi_set_station_address) [static]

Definition at line 472 of file pxe_undi.c.

References DBGC, net_device::ll_addr, ll_protocol::ll_addr_len, net_device::ll_protocol, memcpy(), netdev_is_open(), ll_protocol::ntoa, PXENV_EXIT_FAILURE, PXENV_EXIT_SUCCESS, PXENV_STATUS_SUCCESS, PXENV_STATUS_UNDI_INVALID_STATE, s_PXENV_UNDI_SET_STATION_ADDRESS::StationAddress, and s_PXENV_UNDI_SET_STATION_ADDRESS::Status.

                                                             {
        struct ll_protocol *ll_protocol;

        /* Sanity check */
        if ( ! pxe_netdev ) {
                DBGC ( &pxe_netdev, "PXENV_UNDI_SET_STATION_ADDRESS called "
                       "with no network device\n" );
                undi_set_station_address->Status =
                        PXENV_STATUS_UNDI_INVALID_STATE;
                return PXENV_EXIT_FAILURE;
        }

        ll_protocol = pxe_netdev->ll_protocol;
        DBGC ( &pxe_netdev, "PXENV_UNDI_SET_STATION_ADDRESS %s",
               ll_protocol->ntoa ( undi_set_station_address->StationAddress ) );

        /* If adapter is open, the change will have no effect; return
         * an error
         */
        if ( netdev_is_open ( pxe_netdev ) ) {
                DBGC ( &pxe_netdev, " failed: netdev is open\n" );
                undi_set_station_address->Status =
                        PXENV_STATUS_UNDI_INVALID_STATE;
                return PXENV_EXIT_FAILURE;
        }

        /* Update MAC address */
        memcpy ( pxe_netdev->ll_addr,
                 &undi_set_station_address->StationAddress,
                 ll_protocol->ll_addr_len );

        DBGC ( &pxe_netdev, "\n" );
        undi_set_station_address->Status = PXENV_STATUS_SUCCESS;
        return PXENV_EXIT_SUCCESS;
}
static PXENV_EXIT_t pxenv_undi_set_packet_filter ( struct s_PXENV_UNDI_SET_PACKET_FILTER undi_set_packet_filter) [static]

Definition at line 515 of file pxe_undi.c.

References DBGC, s_PXENV_UNDI_SET_PACKET_FILTER::filter, PXENV_EXIT_FAILURE, PXENV_EXIT_SUCCESS, PXENV_STATUS_SUCCESS, PXENV_STATUS_UNDI_INVALID_STATE, and s_PXENV_UNDI_SET_PACKET_FILTER::Status.

                                                         {

        DBGC ( &pxe_netdev, "PXENV_UNDI_SET_PACKET_FILTER %02x\n",
               undi_set_packet_filter->filter );

        /* Sanity check */
        if ( ! pxe_netdev ) {
                DBGC ( &pxe_netdev, "PXENV_UNDI_SET_PACKET_FILTER called with "
                       "no network device\n" );
                undi_set_packet_filter->Status =
                        PXENV_STATUS_UNDI_INVALID_STATE;
                return PXENV_EXIT_FAILURE;
        }

        /* Pretend that we succeeded, otherwise the 3Com DOS UNDI
         * driver refuses to load.  (We ignore the filter value in the
         * PXENV_UNDI_OPEN call anyway.)
         */
        undi_set_packet_filter->Status = PXENV_STATUS_SUCCESS;

        return PXENV_EXIT_SUCCESS;
}
static PXENV_EXIT_t pxenv_undi_get_information ( struct s_PXENV_UNDI_GET_INFORMATION undi_get_information) [static]

Definition at line 544 of file pxe_undi.c.

References assert, s_PXENV_UNDI_GET_INFORMATION::BaseIo, s_PXENV_UNDI_GET_INFORMATION::CurrentNodeAddress, DBGC, device::desc, net_device::dev, net_device::hw_addr, s_PXENV_UNDI_GET_INFORMATION::HwAddrLen, s_PXENV_UNDI_GET_INFORMATION::HwType, ll_protocol::init_addr, s_PXENV_UNDI_GET_INFORMATION::IntNumber, device_description::ioaddr, device_description::irq, net_device::ll_addr, ll_protocol::ll_addr_len, ll_protocol::ll_proto, net_device::ll_protocol, s_PXENV_UNDI_GET_INFORMATION::MaxTranUnit, memcpy(), ll_protocol::name, netdev_irq_supported(), ll_protocol::ntoa, ntohs, s_PXENV_UNDI_GET_INFORMATION::PermNodeAddress, PXENV_EXIT_FAILURE, PXENV_EXIT_SUCCESS, PXENV_STATUS_SUCCESS, PXENV_STATUS_UNDI_INVALID_STATE, s_PXENV_UNDI_GET_INFORMATION::ROMAddress, s_PXENV_UNDI_GET_INFORMATION::RxBufCt, s_PXENV_UNDI_GET_INFORMATION::Status, and s_PXENV_UNDI_GET_INFORMATION::TxBufCt.

                                                     {
        struct device *dev;
        struct ll_protocol *ll_protocol;

        /* Sanity check */
        if ( ! pxe_netdev ) {
                DBGC ( &pxe_netdev, "PXENV_UNDI_GET_INFORMATION called with no "
                       "network device\n" );
                undi_get_information->Status = PXENV_STATUS_UNDI_INVALID_STATE;
                return PXENV_EXIT_FAILURE;
        }

        DBGC ( &pxe_netdev, "PXENV_UNDI_GET_INFORMATION" );

        /* Fill in information */
        dev = pxe_netdev->dev;
        ll_protocol = pxe_netdev->ll_protocol;
        undi_get_information->BaseIo = dev->desc.ioaddr;
        undi_get_information->IntNumber =
                ( netdev_irq_supported ( pxe_netdev ) ? dev->desc.irq : 0 );
        /* Cheat: assume all cards can cope with this */
        undi_get_information->MaxTranUnit = ETH_MAX_MTU;
        undi_get_information->HwType = ntohs ( ll_protocol->ll_proto );
        undi_get_information->HwAddrLen = ll_protocol->ll_addr_len;
        assert ( ll_protocol->ll_addr_len <=
                 sizeof ( undi_get_information->CurrentNodeAddress ) );
        memcpy ( &undi_get_information->CurrentNodeAddress,
                 pxe_netdev->ll_addr,
                 sizeof ( undi_get_information->CurrentNodeAddress ) );
        ll_protocol->init_addr ( pxe_netdev->hw_addr,
                                 &undi_get_information->PermNodeAddress );
        undi_get_information->ROMAddress = 0;
                /* nic.rom_info->rom_segment; */
        /* We only provide the ability to receive or transmit a single
         * packet at a time.  This is a bootloader, not an OS.
         */
        undi_get_information->RxBufCt = 1;
        undi_get_information->TxBufCt = 1;

        DBGC ( &pxe_netdev, " io %04x irq %d mtu %d %s %s\n",
               undi_get_information->BaseIo, undi_get_information->IntNumber,
               undi_get_information->MaxTranUnit, ll_protocol->name,
               ll_protocol->ntoa ( &undi_get_information->CurrentNodeAddress ));
        undi_get_information->Status = PXENV_STATUS_SUCCESS;
        return PXENV_EXIT_SUCCESS;
}
static PXENV_EXIT_t pxenv_undi_get_statistics ( struct s_PXENV_UNDI_GET_STATISTICS undi_get_statistics) [static]

Definition at line 597 of file pxe_undi.c.

References net_device_stats::bad, DBGC, net_device_stats::good, PXENV_EXIT_FAILURE, PXENV_EXIT_SUCCESS, PXENV_STATUS_SUCCESS, PXENV_STATUS_UNDI_INVALID_STATE, s_PXENV_UNDI_GET_STATISTICS::RcvCRCErrors, s_PXENV_UNDI_GET_STATISTICS::RcvGoodFrames, s_PXENV_UNDI_GET_STATISTICS::RcvResourceErrors, net_device::rx_stats, s_PXENV_UNDI_GET_STATISTICS::Status, net_device::tx_stats, and s_PXENV_UNDI_GET_STATISTICS::XmtGoodFrames.

                                                   {

        /* Sanity check */
        if ( ! pxe_netdev ) {
                DBGC ( &pxe_netdev, "PXENV_UNDI_GET_STATISTICS called with no "
                       "network device\n" );
                undi_get_statistics->Status = PXENV_STATUS_UNDI_INVALID_STATE;
                return PXENV_EXIT_FAILURE;
        }

        DBGC ( &pxe_netdev, "PXENV_UNDI_GET_STATISTICS" );

        /* Report statistics */
        undi_get_statistics->XmtGoodFrames = pxe_netdev->tx_stats.good;
        undi_get_statistics->RcvGoodFrames = pxe_netdev->rx_stats.good;
        undi_get_statistics->RcvCRCErrors = pxe_netdev->rx_stats.bad;
        undi_get_statistics->RcvResourceErrors = pxe_netdev->rx_stats.bad;
        DBGC ( &pxe_netdev, " txok %d rxok %d rxcrc %d rxrsrc %d\n",
               undi_get_statistics->XmtGoodFrames,
               undi_get_statistics->RcvGoodFrames,
               undi_get_statistics->RcvCRCErrors,
               undi_get_statistics->RcvResourceErrors );

        undi_get_statistics->Status = PXENV_STATUS_SUCCESS;
        return PXENV_EXIT_SUCCESS;
}
static PXENV_EXIT_t pxenv_undi_clear_statistics ( struct s_PXENV_UNDI_CLEAR_STATISTICS undi_clear_statistics) [static]

Definition at line 630 of file pxe_undi.c.

References DBGC, memset(), PXENV_EXIT_FAILURE, PXENV_EXIT_SUCCESS, PXENV_STATUS_SUCCESS, PXENV_STATUS_UNDI_INVALID_STATE, net_device::rx_stats, s_PXENV_UNDI_CLEAR_STATISTICS::Status, and net_device::tx_stats.

                                                       {
        DBGC ( &pxe_netdev, "PXENV_UNDI_CLEAR_STATISTICS\n" );

        /* Sanity check */
        if ( ! pxe_netdev ) {
                DBGC ( &pxe_netdev, "PXENV_UNDI_CLEAR_STATISTICS called with "
                       "no network device\n" );
                undi_clear_statistics->Status = PXENV_STATUS_UNDI_INVALID_STATE;
                return PXENV_EXIT_FAILURE;
        }

        /* Clear statistics */
        memset ( &pxe_netdev->tx_stats, 0, sizeof ( pxe_netdev->tx_stats ) );
        memset ( &pxe_netdev->rx_stats, 0, sizeof ( pxe_netdev->rx_stats ) );

        undi_clear_statistics->Status = PXENV_STATUS_SUCCESS;
        return PXENV_EXIT_SUCCESS;
}
static PXENV_EXIT_t pxenv_undi_initiate_diags ( struct s_PXENV_UNDI_INITIATE_DIAGS undi_initiate_diags) [static]

Definition at line 656 of file pxe_undi.c.

References DBGC, PXENV_EXIT_FAILURE, PXENV_STATUS_UNDI_INVALID_STATE, PXENV_STATUS_UNSUPPORTED, and s_PXENV_UNDI_INITIATE_DIAGS::Status.

                                                   {
        DBGC ( &pxe_netdev, "PXENV_UNDI_INITIATE_DIAGS failed: unsupported\n" );

        /* Sanity check */
        if ( ! pxe_netdev ) {
                DBGC ( &pxe_netdev, "PXENV_UNDI_INITIATE_DIAGS called with no "
                       "network device\n" );
                undi_initiate_diags->Status = PXENV_STATUS_UNDI_INVALID_STATE;
                return PXENV_EXIT_FAILURE;
        }

        undi_initiate_diags->Status = PXENV_STATUS_UNSUPPORTED;
        return PXENV_EXIT_FAILURE;
}
static PXENV_EXIT_t pxenv_undi_force_interrupt ( struct s_PXENV_UNDI_FORCE_INTERRUPT undi_force_interrupt) [static]

Definition at line 678 of file pxe_undi.c.

References DBGC, PXENV_EXIT_FAILURE, PXENV_STATUS_UNDI_INVALID_STATE, PXENV_STATUS_UNSUPPORTED, and s_PXENV_UNDI_FORCE_INTERRUPT::Status.

                                                     {
        DBGC ( &pxe_netdev,
               "PXENV_UNDI_FORCE_INTERRUPT failed: unsupported\n" );

        /* Sanity check */
        if ( ! pxe_netdev ) {
                DBGC ( &pxe_netdev, "PXENV_UNDI_FORCE_INTERRUPT called with no "
                       "network device\n" );
                undi_force_interrupt->Status = PXENV_STATUS_UNDI_INVALID_STATE;
                return PXENV_EXIT_FAILURE;
        }

        undi_force_interrupt->Status = PXENV_STATUS_UNSUPPORTED;
        return PXENV_EXIT_FAILURE;
}
static PXENV_EXIT_t pxenv_undi_get_mcast_address ( struct s_PXENV_UNDI_GET_MCAST_ADDRESS undi_get_mcast_address) [static]

Definition at line 700 of file pxe_undi.c.

References AF_INET, DBGC, inet_ntoa(), s_PXENV_UNDI_GET_MCAST_ADDRESS::InetAddr, net_device::ll_protocol, ll_protocol::mc_hash, s_PXENV_UNDI_GET_MCAST_ADDRESS::MediaAddr, ll_protocol::ntoa, PXENV_EXIT_FAILURE, PXENV_EXIT_SUCCESS, PXENV_STATUS, PXENV_STATUS_SUCCESS, PXENV_STATUS_UNDI_INVALID_STATE, rc, in_addr::s_addr, s_PXENV_UNDI_GET_MCAST_ADDRESS::Status, and strerror().

                                                         {
        struct ll_protocol *ll_protocol;
        struct in_addr ip = { .s_addr = undi_get_mcast_address->InetAddr };
        int rc;

        /* Sanity check */
        if ( ! pxe_netdev ) {
                DBGC ( &pxe_netdev, "PXENV_UNDI_GET_MCAST_ADDRESS called with "
                       "no network device\n" );
                undi_get_mcast_address->Status =
                        PXENV_STATUS_UNDI_INVALID_STATE;
                return PXENV_EXIT_FAILURE;
        }

        DBGC ( &pxe_netdev, "PXENV_UNDI_GET_MCAST_ADDRESS %s",
               inet_ntoa ( ip ) );

        /* Hash address using the network device's link-layer protocol */
        ll_protocol = pxe_netdev->ll_protocol;
        if ( ( rc = ll_protocol->mc_hash ( AF_INET, &ip,
                                      undi_get_mcast_address->MediaAddr ))!=0){
                DBGC ( &pxe_netdev, " failed: %s\n", strerror ( rc ) );
                undi_get_mcast_address->Status = PXENV_STATUS ( rc );
                return PXENV_EXIT_FAILURE;
        }
        DBGC ( &pxe_netdev, "=>%s\n",
               ll_protocol->ntoa ( undi_get_mcast_address->MediaAddr ) );

        undi_get_mcast_address->Status = PXENV_STATUS_SUCCESS;
        return PXENV_EXIT_SUCCESS;
}
static PXENV_EXIT_t pxenv_undi_get_nic_type ( struct s_PXENV_UNDI_GET_NIC_TYPE undi_get_nic_type) [static]

Definition at line 737 of file pxe_undi.c.

References pci_nic_info::Base_Class, pnp_nic_info::Base_Class, device_description::bus_type, BUS_TYPE_ISAPNP, BUS_TYPE_PCI, pci_nic_info::BusDevFunc, pnp_nic_info::CardSelNum, device_description::class, DBGC, device::desc, net_device::dev, pci_nic_info::Dev_ID, device_description::device, pnp_nic_info::EISA_Dev_ID, info, s_PXENV_UNDI_GET_NIC_TYPE::info, device_description::location, memset(), s_PXENV_UNDI_GET_NIC_TYPE::NicType, s_PXENV_UNDI_GET_NIC_TYPE::nic_type_info::pci, PCI_BASE_CLASS, PCI_BUS, PCI_FUNC, PCI_NIC, PCI_PROG_INTF, PCI_SLOT, PCI_SUB_CLASS, s_PXENV_UNDI_GET_NIC_TYPE::nic_type_info::pnp, PnP_NIC, pci_nic_info::Prog_Intf, pnp_nic_info::Prog_Intf, PXENV_EXIT_FAILURE, PXENV_EXIT_SUCCESS, PXENV_STATUS_FAILURE, PXENV_STATUS_SUCCESS, PXENV_STATUS_UNDI_INVALID_STATE, pci_nic_info::Rev, s_PXENV_UNDI_GET_NIC_TYPE::Status, pci_nic_info::Sub_Class, pnp_nic_info::Sub_Class, pci_nic_info::SubDevice_ID, pci_nic_info::SubVendor_ID, device_description::vendor, and pci_nic_info::Vendor_ID.

                                                                   {
        struct device *dev;

        /* Sanity check */
        if ( ! pxe_netdev ) {
                DBGC ( &pxe_netdev, "PXENV_UNDI_GET_NIC_TYPE called with "
                       "no network device\n" );
                undi_get_nic_type->Status = PXENV_STATUS_UNDI_INVALID_STATE;
                return PXENV_EXIT_FAILURE;
        }

        DBGC ( &pxe_netdev, "PXENV_UNDI_GET_NIC_TYPE" );

        /* Fill in information */
        memset ( &undi_get_nic_type->info, 0,
                 sizeof ( undi_get_nic_type->info ) );
        dev = pxe_netdev->dev;
        switch ( dev->desc.bus_type ) {
        case BUS_TYPE_PCI: {
                struct pci_nic_info *info = &undi_get_nic_type->info.pci;

                undi_get_nic_type->NicType = PCI_NIC;
                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;
                /* Earlier versions of the PXE specification do not
                 * have the SubVendor_ID and SubDevice_ID fields.  It
                 * is possible that some NBPs will not provide space
                 * for them, and so we must not fill them in.
                 */
                DBGC ( &pxe_netdev, " PCI %02x:%02x.%x %04x:%04x "
                       "('%04x:%04x') %02x%02x%02x rev %02x\n",
                       PCI_BUS ( info->BusDevFunc ),
                       PCI_SLOT ( info->BusDevFunc ),
                       PCI_FUNC ( info->BusDevFunc ), info->Vendor_ID,
                       info->Dev_ID, info->SubVendor_ID, info->SubDevice_ID,
                       info->Base_Class, info->Sub_Class, info->Prog_Intf,
                       info->Rev );
                break; }
        case BUS_TYPE_ISAPNP: {
                struct pnp_nic_info *info = &undi_get_nic_type->info.pnp;

                undi_get_nic_type->NicType = PnP_NIC;
                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.
                 */
                DBGC ( &pxe_netdev, " ISAPnP CSN %04x %08x %02x%02x%02x\n",
                       info->CardSelNum, info->EISA_Dev_ID,
                       info->Base_Class, info->Sub_Class, info->Prog_Intf );
                break; }
        default:
                DBGC ( &pxe_netdev, " failed: unknown bus type\n" );
                undi_get_nic_type->Status = PXENV_STATUS_FAILURE;
                return PXENV_EXIT_FAILURE;
        }

        undi_get_nic_type->Status = PXENV_STATUS_SUCCESS;
        return PXENV_EXIT_SUCCESS;
}
static PXENV_EXIT_t pxenv_undi_get_iface_info ( struct s_PXENV_UNDI_GET_IFACE_INFO undi_get_iface_info) [static]

Definition at line 809 of file pxe_undi.c.

References DBGC, s_PXENV_UNDI_GET_IFACE_INFO::IfaceType, s_PXENV_UNDI_GET_IFACE_INFO::LinkSpeed, memset(), netdev_irq_supported(), PXENV_EXIT_FAILURE, PXENV_EXIT_SUCCESS, PXENV_STATUS_SUCCESS, PXENV_STATUS_UNDI_INVALID_STATE, s_PXENV_UNDI_GET_IFACE_INFO::Reserved, s_PXENV_UNDI_GET_IFACE_INFO::ServiceFlags, snprintf(), s_PXENV_UNDI_GET_IFACE_INFO::Status, SUPPORTED_BROADCAST, SUPPORTED_IRQ, SUPPORTED_MULTICAST, SUPPORTED_OPEN_CLOSE, SUPPORTED_RESET, and SUPPORTED_SET_STATION_ADDRESS.

                                                   {

        /* Sanity check */
        if ( ! pxe_netdev ) {
                DBGC ( &pxe_netdev, "PXENV_UNDI_GET_IFACE_INFO called with "
                       "no network device\n" );
                undi_get_iface_info->Status = PXENV_STATUS_UNDI_INVALID_STATE;
                return PXENV_EXIT_FAILURE;
        }

        DBGC ( &pxe_netdev, "PXENV_UNDI_GET_IFACE_INFO" );

        /* Just hand back some info, doesn't really matter what it is.
         * Most PXE stacks seem to take this approach.
         */
        snprintf ( ( char * ) undi_get_iface_info->IfaceType,
                   sizeof ( undi_get_iface_info->IfaceType ), "DIX+802.3" );
        undi_get_iface_info->LinkSpeed = 10000000; /* 10 Mbps */
        undi_get_iface_info->ServiceFlags =
                ( SUPPORTED_BROADCAST | SUPPORTED_MULTICAST |
                  SUPPORTED_SET_STATION_ADDRESS | SUPPORTED_RESET |
                  SUPPORTED_OPEN_CLOSE );
        if ( netdev_irq_supported ( pxe_netdev ) )
                undi_get_iface_info->ServiceFlags |= SUPPORTED_IRQ;
        memset ( undi_get_iface_info->Reserved, 0,
                 sizeof(undi_get_iface_info->Reserved) );

        DBGC ( &pxe_netdev, " %s %dbps flags %08x\n",
               undi_get_iface_info->IfaceType, undi_get_iface_info->LinkSpeed,
               undi_get_iface_info->ServiceFlags );
        undi_get_iface_info->Status = PXENV_STATUS_SUCCESS;
        return PXENV_EXIT_SUCCESS;
}
static PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR undi_isr) [static]

Definition at line 853 of file pxe_undi.c.

References __from_data16, basemem_packet, s_PXENV_UNDI_ISR::BufferLength, io_buffer::data, DBGC, DBGC2, ETH_P_ARP, ETH_P_IP, ETH_P_RARP, flags, s_PXENV_UNDI_ISR::Frame, s_PXENV_UNDI_ISR::FrameHeaderLength, s_PXENV_UNDI_ISR::FrameLength, free_iob(), s_PXENV_UNDI_ISR::FuncFlag, htons, iob_len(), len, list_empty, LL_BROADCAST, LL_MULTICAST, net_device::ll_protocol, memcpy(), net_protocol::name, net_poll(), net_proto, netdev_irq(), netdev_irq_enabled(), netdev_rx_dequeue(), NULL, P_ARP, P_BROADCAST, P_DIRECTED, P_IP, P_MULTICAST, P_RARP, P_UNKNOWN, s_PXENV_UNDI_ISR::PktType, s_PXENV_UNDI_ISR::ProtType, ll_protocol::pull, PXENV_EXIT_FAILURE, PXENV_EXIT_SUCCESS, PXENV_STATUS_SUCCESS, PXENV_STATUS_UNDI_INVALID_PARAMETER, PXENV_STATUS_UNDI_INVALID_STATE, PXENV_UNDI_ISR_IN_GET_NEXT, PXENV_UNDI_ISR_IN_PROCESS, PXENV_UNDI_ISR_IN_START, PXENV_UNDI_ISR_OUT_DONE, PXENV_UNDI_ISR_OUT_NOT_OURS, PXENV_UNDI_ISR_OUT_OURS, PXENV_UNDI_ISR_OUT_RECEIVE, PXENV_UNDI_ISR_OUT_TRANSMIT, rc, rm_ds, s_PXENV_UNDI_ISR::Status, net_device::tx_queue, and undi_tx_count.

                                                                         {
        struct io_buffer *iobuf;
        size_t len;
        struct ll_protocol *ll_protocol;
        const void *ll_dest;
        const void *ll_source;
        uint16_t net_proto;
        unsigned int flags;
        size_t ll_hlen;
        struct net_protocol *net_protocol;
        unsigned int prottype;
        int rc;

        /* Use a different debug colour, since UNDI ISR messages are
         * likely to be interspersed amongst other UNDI messages.
         */

        /* Sanity check */
        if ( ! pxe_netdev ) {
                DBGC ( &pxenv_undi_isr, "PXENV_UNDI_ISR called with "
                       "no network device\n" );
                undi_isr->Status = PXENV_STATUS_UNDI_INVALID_STATE;
                return PXENV_EXIT_FAILURE;
        }

        DBGC2 ( &pxenv_undi_isr, "PXENV_UNDI_ISR" );

        /* Just in case some idiot actually looks at these fields when
         * we weren't meant to fill them in...
         */
        undi_isr->BufferLength = 0;
        undi_isr->FrameLength = 0;
        undi_isr->FrameHeaderLength = 0;
        undi_isr->ProtType = 0;
        undi_isr->PktType = 0;

        switch ( undi_isr->FuncFlag ) {
        case PXENV_UNDI_ISR_IN_START :
                DBGC2 ( &pxenv_undi_isr, " START" );

                /* Call poll().  This should acknowledge the device
                 * interrupt and queue up any received packet.
                 */
                net_poll();

                /* A 100% accurate determination of "OURS" vs "NOT
                 * OURS" is difficult to achieve without invasive and
                 * unpleasant changes to the driver model.  We settle
                 * for always returning "OURS" if interrupts are
                 * currently enabled.
                 *
                 * Returning "NOT OURS" when interrupts are disabled
                 * allows us to avoid a potential interrupt storm when
                 * we are on a shared interrupt line; if we were to
                 * always return "OURS" then the other device's ISR
                 * may never be called.
                 */
                if ( netdev_irq_enabled ( pxe_netdev ) ) {
                        DBGC2 ( &pxenv_undi_isr, " OURS" );
                        undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_OURS;
                } else {
                        DBGC2 ( &pxenv_undi_isr, " NOT OURS" );
                        undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_NOT_OURS;
                }

                /* Disable interrupts */
                netdev_irq ( pxe_netdev, 0 );

                break;
        case PXENV_UNDI_ISR_IN_PROCESS :
        case PXENV_UNDI_ISR_IN_GET_NEXT :
                DBGC2 ( &pxenv_undi_isr, " %s",
                        ( ( undi_isr->FuncFlag == PXENV_UNDI_ISR_IN_PROCESS ) ?
                          "PROCESS" : "GET_NEXT" ) );

                /* Some dumb NBPs (e.g. emBoot's winBoot/i) never call
                 * PXENV_UNDI_ISR with FuncFlag=PXENV_UNDI_ISR_START;
                 * they just sit in a tight polling loop merrily
                 * violating the PXE spec with repeated calls to
                 * PXENV_UNDI_ISR_IN_PROCESS.  Force extra polls to
                 * cope with these out-of-spec clients.
                 */
                net_poll();

                /* If we have not yet marked a TX as complete, and the
                 * netdev TX queue is empty, report the TX completion.
                 */
                if ( undi_tx_count && list_empty ( &pxe_netdev->tx_queue ) ) {
                        DBGC2 ( &pxenv_undi_isr, " TXC" );
                        undi_tx_count--;
                        undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_TRANSMIT;
                        break;
                }

                /* Remove first packet from netdev RX queue */
                iobuf = netdev_rx_dequeue ( pxe_netdev );
                if ( ! iobuf ) {
                        DBGC2 ( &pxenv_undi_isr, " DONE" );
                        /* No more packets remaining */
                        undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE;
                        /* Re-enable interrupts */
                        netdev_irq ( pxe_netdev, 1 );
                        break;
                }

                /* Copy packet to base memory buffer */
                len = iob_len ( iobuf );
                DBGC2 ( &pxenv_undi_isr, " RX" );
                if ( len > sizeof ( basemem_packet ) ) {
                        /* Should never happen */
                        DBGC2 ( &pxenv_undi_isr, " overlength (%zx)", len );
                        len = sizeof ( basemem_packet );
                }
                memcpy ( basemem_packet, iobuf->data, len );

                /* Strip link-layer header */
                ll_protocol = pxe_netdev->ll_protocol;
                if ( ( rc = ll_protocol->pull ( pxe_netdev, iobuf, &ll_dest,
                                                &ll_source, &net_proto,
                                                &flags ) ) != 0 ) {
                        /* Assume unknown net_proto and no ll_source */
                        net_proto = 0;
                        ll_source = NULL;
                }
                ll_hlen = ( len - iob_len ( iobuf ) );

                /* Determine network-layer protocol */
                switch ( net_proto ) {
                case htons ( ETH_P_IP ):
                        net_protocol = &ipv4_protocol;
                        prottype = P_IP;
                        break;
                case htons ( ETH_P_ARP ):
                        net_protocol = &arp_protocol;
                        prottype = P_ARP;
                        break;
                case htons ( ETH_P_RARP ):
                        net_protocol = &rarp_protocol;
                        prottype = P_RARP;
                        break;
                default:
                        net_protocol = NULL;
                        prottype = P_UNKNOWN;
                        break;
                }

                /* Fill in UNDI_ISR structure */
                undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_RECEIVE;
                undi_isr->BufferLength = len;
                undi_isr->FrameLength = len;
                undi_isr->FrameHeaderLength = ll_hlen;
                undi_isr->Frame.segment = rm_ds;
                undi_isr->Frame.offset = __from_data16 ( basemem_packet );
                undi_isr->ProtType = prottype;
                if ( flags & LL_BROADCAST ) {
                        undi_isr->PktType = P_BROADCAST;
                } else if ( flags & LL_MULTICAST ) {
                        undi_isr->PktType = P_MULTICAST;
                } else {
                        undi_isr->PktType = P_DIRECTED;
                }
                DBGC2 ( &pxenv_undi_isr, " %04x:%04x+%x(%x) %s hlen %d",
                        undi_isr->Frame.segment, undi_isr->Frame.offset,
                        undi_isr->BufferLength, undi_isr->FrameLength,
                        ( net_protocol ? net_protocol->name : "RAW" ),
                        undi_isr->FrameHeaderLength );

                /* Free packet */
                free_iob ( iobuf );
                break;
        default :
                DBGC2 ( &pxenv_undi_isr, " INVALID(%04x)\n",
                        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;
        }

        DBGC2 ( &pxenv_undi_isr, "\n" );
        undi_isr->Status = PXENV_STATUS_SUCCESS;
        return PXENV_EXIT_SUCCESS;
}

Variable Documentation

int undi_tx_count = 0 [static]

Count of outstanding transmitted packets.

This is incremented each time PXENV_UNDI_TRANSMIT is called, and decremented each time that PXENV_UNDI_ISR is called with the TX queue empty, stopping when the count reaches zero. This allows us to provide a pessimistic approximation of TX completion events to the PXE NBP simply by monitoring the netdev's TX queue.

Definition at line 57 of file pxe_undi.c.

Referenced by pxe_netdev_close(), pxenv_undi_isr(), and pxenv_undi_transmit().

struct profiler undi_tx_profiler __profiler = { .name = "undi.tx" } [static]

Transmit profiler.

Definition at line 62 of file pxe_undi.c.

struct pxe_api_call pxe_undi_api [] __pxe_api_call

PXE UNDI API.

Definition at line 1039 of file pxe_undi.c.