Make open() and close() an official part of the netdevice API.
authorMichael Brown <mcb30@etherboot.org>
Thu, 4 Jan 2007 04:20:08 +0000 (04:20 +0000)
committerMichael Brown <mcb30@etherboot.org>
Thu, 4 Jan 2007 04:20:08 +0000 (04:20 +0000)
Call netdevice's poll() and transmit() methods only when device is open.

src/drivers/net/legacy.c
src/drivers/net/pnic.c
src/drivers/net/rtl8139.c
src/include/gpxe/netdevice.h
src/net/netdevice.c
src/usr/autoboot.c

index b0023b1..0c205ae 100644 (file)
@@ -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;
index ad98c60..d8f2544 100644 (file)
@@ -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;
 
index 86c9c80..4592ed7 100644 (file)
@@ -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 );
index 7551be7..20df791 100644 (file)
@@ -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 );
index 3949d26..76ff377 100644 (file)
@@ -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
+ * @ret rc             Return status code
+ */
+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
  *
- * Removes the network device from the list of network devices.
+ * @v netdev           Network device
  */
-void unregister_netdev ( struct net_device *netdev ) {
+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 );
 
index ddfc378..e677229 100644 (file)
@@ -16,7 +16,9 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#include <string.h>
 #include <vsprintf.h>
+#include <gpxe/netdevice.h>
 #include <gpxe/autoboot.h>
 
 /** @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 );
 }