summaryrefslogtreecommitdiffstats
path: root/src/net
diff options
context:
space:
mode:
Diffstat (limited to 'src/net')
-rw-r--r--src/net/netdevice.c66
1 files changed, 61 insertions, 5 deletions
diff --git a/src/net/netdevice.c b/src/net/netdevice.c
index 3949d26de..76ff3777b 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
+ * @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 );