From 0c03bb5a9a0649ec7009e334c0e42290af330437 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 4 Jan 2007 04:20:08 +0000 Subject: [PATCH] Make open() and close() an official part of the netdevice API. Call netdevice's poll() and transmit() methods only when device is open. --- src/drivers/net/legacy.c | 10 ++++++ src/drivers/net/pnic.c | 16 +++++++++ src/drivers/net/rtl8139.c | 12 ++----- src/include/gpxe/netdevice.h | 33 +++++++++++++++++ src/net/netdevice.c | 68 ++++++++++++++++++++++++++++++++---- src/usr/autoboot.c | 18 ++++++++-- 6 files changed, 138 insertions(+), 19 deletions(-) diff --git a/src/drivers/net/legacy.c b/src/drivers/net/legacy.c index b0023b18..0c205aed 100644 --- a/src/drivers/net/legacy.c +++ b/src/drivers/net/legacy.c @@ -56,6 +56,14 @@ static void legacy_poll ( struct net_device *netdev ) { } } +static int legacy_open ( struct net_device *netdev __unused ) { + return 0; +} + +static void legacy_close ( struct net_device *netdev __unused ) { + /* Nothing to do */ +} + int legacy_probe ( struct pci_device *pci, const struct pci_device_id *id __unused, int ( * probe ) ( struct nic *nic, @@ -74,6 +82,8 @@ int legacy_probe ( struct pci_device *pci, memset ( &nic, 0, sizeof ( nic ) ); pci_set_drvdata ( pci, netdev ); + netdev->open = legacy_open; + netdev->close = legacy_close; netdev->transmit = legacy_transmit; netdev->poll = legacy_poll; nic.node_addr = netdev->ll_addr; diff --git a/src/drivers/net/pnic.c b/src/drivers/net/pnic.c index ad98c609..d8f2544e 100644 --- a/src/drivers/net/pnic.c +++ b/src/drivers/net/pnic.c @@ -185,6 +185,20 @@ static void pnic_irq ( struct net_device *netdev, irq_action_t action ) { } #endif +/************************************************************************** +OPEN - Open network device +***************************************************************************/ +static int pnic_open ( struct net_device *netdev __unused ) { + return 0; +} + +/************************************************************************** +CLOSE - Close network device +***************************************************************************/ +static void pnic_close ( struct net_device *netdev __unused ) { + /* Nothing to do */ +} + /************************************************************************** DISABLE - Turn off ethernet interface ***************************************************************************/ @@ -238,6 +252,8 @@ static int pnic_probe ( struct pci_device *pci, netdev->ll_addr, ETH_ALEN, NULL ); /* Point to NIC specific routines */ + netdev->open = pnic_open; + netdev->close = pnic_close; netdev->poll = pnic_poll; netdev->transmit = pnic_transmit; diff --git a/src/drivers/net/rtl8139.c b/src/drivers/net/rtl8139.c index 86c9c805..4592ed7d 100644 --- a/src/drivers/net/rtl8139.c +++ b/src/drivers/net/rtl8139.c @@ -542,8 +542,8 @@ static int rtl_probe ( struct pci_device *pci, nvs_read ( &rtl->eeprom.nvs, EE_MAC, netdev->ll_addr, ETH_ALEN ); /* Point to NIC specific routines */ - // netdev->open = rtl_open; - // netdev->close = rtl_close; + netdev->open = rtl_open; + netdev->close = rtl_close; netdev->transmit = rtl_transmit; netdev->poll = rtl_poll; @@ -558,10 +558,6 @@ static int rtl_probe ( struct pci_device *pci, goto err; } -#warning "Hack alert" - rtl_open ( netdev ); - - return 0; err: @@ -584,10 +580,6 @@ static void rtl_remove ( struct pci_device *pci ) { struct net_device *netdev = pci_get_drvdata ( pci ); struct rtl8139_nic *rtl = netdev->priv; - -#warning "Hack alert" - rtl_close ( netdev ); - if ( rtl->nvo.nvs ) nvo_unregister ( &rtl->nvo ); unregister_netdev ( netdev ); diff --git a/src/include/gpxe/netdevice.h b/src/include/gpxe/netdevice.h index 7551be74..20df7919 100644 --- a/src/include/gpxe/netdevice.h +++ b/src/include/gpxe/netdevice.h @@ -142,6 +142,23 @@ struct net_device { /** List of persistent reference holders */ struct list_head references; + /** Open network device + * + * @v netdev Network device + * @ret rc Return status code + * + * This method should allocate RX packet buffers and enable + * the hardware to start transmitting and receiving packets. + */ + int ( * open ) ( struct net_device *netdev ); + /** Close network device + * + * @v netdev Network device + * + * This method should stop the flow of packets, and free up + * any packets that are currently in the device's TX queue. + */ + void ( * close ) ( struct net_device *netdev ); /** Transmit packet * * @v netdev Network device @@ -154,6 +171,9 @@ struct net_device { * Ownership of the packet buffer is transferred to the @c * net_device, which must eventually call free_pkb() to * release the buffer. + * + * This method is guaranteed to be called only when the device + * is open. */ int ( * transmit ) ( struct net_device *netdev, struct pk_buff *pkb ); /** Poll for received packet @@ -163,6 +183,9 @@ struct net_device { * This method should cause the hardware to check for received * packets. Any received packets should be delivered via * netdev_rx(). + * + * This method is guaranteed to be called only when the device + * is open. */ void ( * poll ) ( struct net_device *netdev ); @@ -174,6 +197,11 @@ struct net_device { */ uint8_t ll_addr[MAX_LL_ADDR_LEN]; + /** Current device state + * + * This is the bitwise-OR of zero or more NETDEV_XXX constants. + */ + unsigned int state; /** Received packet queue */ struct list_head rx_queue; @@ -181,6 +209,9 @@ struct net_device { void *priv; }; +/** Network device is open */ +#define NETDEV_OPEN 0x0001 + /** Declare a link-layer protocol */ #define __ll_protocol __table ( ll_protocols, 01 ) @@ -209,6 +240,8 @@ extern int netdev_poll ( struct net_device *netdev ); extern struct pk_buff * netdev_rx_dequeue ( struct net_device *netdev ); extern struct net_device * alloc_netdev ( size_t priv_size ); extern int register_netdev ( struct net_device *netdev ); +extern int netdev_open ( struct net_device *netdev ); +extern void netdev_close ( struct net_device *netdev ); extern void unregister_netdev ( struct net_device *netdev ); extern void free_netdev ( struct net_device *netdev ); extern struct net_device * next_netdev ( void ); diff --git a/src/net/netdevice.c b/src/net/netdevice.c index 3949d26d..76ff3777 100644 --- a/src/net/netdevice.c +++ b/src/net/netdevice.c @@ -54,6 +54,12 @@ static LIST_HEAD ( net_devices ); int netdev_tx ( struct net_device *netdev, struct pk_buff *pkb ) { DBG ( "%s transmitting %p+%zx\n", netdev_name ( netdev ), pkb->data, pkb_len ( pkb ) ); + + if ( ! ( netdev->state & NETDEV_OPEN ) ) { + free_pkb ( pkb ); + return -ENETUNREACH; + } + return netdev->transmit ( netdev, pkb ); } @@ -100,7 +106,7 @@ int net_tx ( struct pk_buff *pkb, struct net_device *netdev, * @ret rc Return status code */ int net_rx ( struct pk_buff *pkb, struct net_device *netdev, - uint16_t net_proto, const void *ll_source ) { + uint16_t net_proto, const void *ll_source ) { struct net_protocol *net_protocol; /* Hand off to network-layer protocol, if any */ @@ -125,7 +131,10 @@ int net_rx ( struct pk_buff *pkb, struct net_device *netdev, * packets will be added to the RX packet queue via netdev_rx(). */ int netdev_poll ( struct net_device *netdev ) { - netdev->poll ( netdev ); + + if ( netdev->state & NETDEV_OPEN ) + netdev->poll ( netdev ); + return ( ! list_empty ( &netdev->rx_queue ) ); } @@ -186,15 +195,46 @@ int register_netdev ( struct net_device *netdev ) { } /** - * Unregister network device + * Open network device * * @v netdev Network device - * - * Removes the network device from the list of network devices. + * @ret rc Return status code */ -void unregister_netdev ( struct net_device *netdev ) { +int netdev_open ( struct net_device *netdev ) { + int rc; + + /* Do nothing if device is already open */ + if ( netdev->state & NETDEV_OPEN ) + return 0; + + DBG ( "%s opening\n", netdev_name ( netdev ) ); + + /* Open the device */ + if ( ( rc = netdev->open ( netdev ) ) != 0 ) + return rc; + + /* Mark as opened */ + netdev->state |= NETDEV_OPEN; + return 0; +} + +/** + * Close network device + * + * @v netdev Network device + */ +void netdev_close ( struct net_device *netdev ) { struct pk_buff *pkb; + /* Do nothing if device is already closed */ + if ( ! ( netdev->state & NETDEV_OPEN ) ) + return; + + DBG ( "%s closing\n", netdev_name ( netdev ) ); + + /* Close the device */ + netdev->close ( netdev ); + /* Discard any packets in the RX queue */ while ( ( pkb = netdev_rx_dequeue ( netdev ) ) ) { DBG ( "%s discarding %p+%zx\n", netdev_name ( netdev ), @@ -202,6 +242,22 @@ void unregister_netdev ( struct net_device *netdev ) { free_pkb ( pkb ); } + /* Mark as closed */ + netdev->state &= ~NETDEV_OPEN; +} + +/** + * Unregister network device + * + * @v netdev Network device + * + * Removes the network device from the list of network devices. + */ +void unregister_netdev ( struct net_device *netdev ) { + + /* Ensure device is closed */ + netdev_close ( netdev ); + /* Kill off any persistent references to this device */ forget_references ( &netdev->references ); diff --git a/src/usr/autoboot.c b/src/usr/autoboot.c index ddfc3781..e6772298 100644 --- a/src/usr/autoboot.c +++ b/src/usr/autoboot.c @@ -16,7 +16,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include #include +#include #include /** @file @@ -30,11 +32,21 @@ void test_dhcp ( struct net_device *netdev ); void autoboot ( void ) { struct net_device *netdev; + int rc; netdev = next_netdev (); - if ( netdev ) { - test_dhcp ( netdev ); - } else { + if ( ! netdev ) { printf ( "No network device found\n" ); + return; } + + if ( ( rc = netdev_open ( netdev ) ) != 0 ) { + printf ( "Could not open %s: %s\n", netdev_name ( netdev ), + strerror ( rc ) ); + return; + } + + test_dhcp ( netdev ); + + netdev_close ( netdev ); }