diff options
| author | Michael Brown | 2010-09-05 01:55:23 +0200 |
|---|---|---|
| committer | Michael Brown | 2010-09-05 04:03:38 +0200 |
| commit | ca4df90a6383d47617038328fb506bf273f1e80e (patch) | |
| tree | b079979a9eaccfa94f4453c547a425694cfdd43b /src | |
| parent | [netdevice] Call netdev_link_[up|down|err]() only while registered (diff) | |
| download | ipxe-ca4df90a6383d47617038328fb506bf273f1e80e.tar.gz ipxe-ca4df90a6383d47617038328fb506bf273f1e80e.tar.xz ipxe-ca4df90a6383d47617038328fb506bf273f1e80e.zip | |
[netdevice] Add the concept of a network upper-layer driver
Add the concept of a network upper-layer driver, which can create
arbitrary devices on top of network devices.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src')
| -rw-r--r-- | src/include/ipxe/netdevice.h | 60 | ||||
| -rw-r--r-- | src/net/netdevice.c | 89 |
2 files changed, 114 insertions, 35 deletions
diff --git a/src/include/ipxe/netdevice.h b/src/include/ipxe/netdevice.h index f829327c5..80bc1c6e2 100644 --- a/src/include/ipxe/netdevice.h +++ b/src/include/ipxe/netdevice.h @@ -344,6 +344,34 @@ struct net_device { /** Declare a network-layer protocol */ #define __net_protocol __table_entry ( NET_PROTOCOLS, 01 ) +/** A network upper-layer driver */ +struct net_driver { + /** Name */ + const char *name; + /** Probe device + * + * @v netdev Network device + * @ret rc Return status code + */ + int ( * probe ) ( struct net_device *netdev ); + /** Notify of device or link state change + * + * @v netdev Network device + */ + void ( * notify ) ( struct net_device *netdev ); + /** Remove device + * + * @v netdev Network device + */ + void ( * remove ) ( struct net_device *netdev ); +}; + +/** Network driver table */ +#define NET_DRIVERS __table ( struct net_driver, "net_drivers" ) + +/** Declare a network driver */ +#define __net_driver __table_entry ( NET_DRIVERS, 01 ) + extern struct list_head net_devices; extern struct net_device_operations null_netdev_operations; extern struct settings_operations netdev_settings_operations; @@ -452,27 +480,6 @@ netdev_settings_init ( struct net_device *netdev ) { } /** - * Mark network device as having link up - * - * @v netdev Network device - */ -static inline __attribute__ (( always_inline )) void -netdev_link_up ( struct net_device *netdev ) { - netdev->link_rc = 0; -} - -/** - * Mark network device as having link down due to a specific error - * - * @v netdev Network device - * @v rc Link status code - */ -static inline __attribute__ (( always_inline )) void -netdev_link_err ( struct net_device *netdev, int rc ) { - netdev->link_rc = rc; -} - -/** * Check link state of network device * * @v netdev Network device @@ -505,6 +512,7 @@ netdev_irq_enabled ( struct net_device *netdev ) { return ( netdev->state & NETDEV_IRQ_ENABLED ); } +extern void netdev_link_err ( struct net_device *netdev, int rc ); extern void netdev_link_down ( struct net_device *netdev ); extern int netdev_tx ( struct net_device *netdev, struct io_buffer *iobuf ); extern void netdev_tx_complete_err ( struct net_device *netdev, @@ -554,4 +562,14 @@ static inline void netdev_tx_complete_next ( struct net_device *netdev ) { netdev_tx_complete_next_err ( netdev, 0 ); } +/** + * Mark network device as having link up + * + * @v netdev Network device + */ +static inline __attribute__ (( always_inline )) void +netdev_link_up ( struct net_device *netdev ) { + netdev_link_err ( netdev, 0 ); +} + #endif /* _IPXE_NETDEVICE_H */ diff --git a/src/net/netdevice.c b/src/net/netdevice.c index 3fa966600..51bd344b2 100644 --- a/src/net/netdevice.c +++ b/src/net/netdevice.c @@ -57,6 +57,39 @@ struct errortab netdev_errors[] __errortab = { }; /** + * Notify drivers of network device or link state change + * + * @v netdev Network device + */ +static void netdev_notify ( struct net_device *netdev ) { + struct net_driver *driver; + + for_each_table_entry ( driver, NET_DRIVERS ) + driver->notify ( netdev ); +} + +/** + * Mark network device as having a specific link state + * + * @v netdev Network device + * @v rc Link status code + */ +void netdev_link_err ( struct net_device *netdev, int rc ) { + + /* Record link state */ + netdev->link_rc = rc; + if ( netdev->link_rc == 0 ) { + DBGC ( netdev, "NETDEV %p link is up\n", netdev ); + } else { + DBGC ( netdev, "NETDEV %p link is down: %s\n", + netdev, strerror ( netdev->link_rc ) ); + } + + /* Notify drivers of link state change */ + netdev_notify ( netdev ); +} + +/** * Mark network device as having link down * * @v netdev Network device @@ -68,7 +101,7 @@ void netdev_link_down ( struct net_device *netdev ) { */ if ( ( netdev->link_rc == 0 ) || ( netdev->link_rc == -EUNKNOWN_LINK_STATUS ) ) { - netdev->link_rc = -ENOTCONN; + netdev_link_err ( netdev, -ENOTCONN ); } } @@ -367,6 +400,7 @@ struct net_device * alloc_netdev ( size_t priv_size ) { */ int register_netdev ( struct net_device *netdev ) { static unsigned int ifindex = 0; + struct net_driver *driver; int rc; /* Create device name */ @@ -376,22 +410,38 @@ int register_netdev ( struct net_device *netdev ) { /* Set initial link-layer address */ netdev->ll_protocol->init_addr ( netdev->hw_addr, netdev->ll_addr ); + /* Add to device list */ + netdev_get ( netdev ); + list_add_tail ( &netdev->list, &net_devices ); + DBGC ( netdev, "NETDEV %p registered as %s (phys %s hwaddr %s)\n", + netdev, netdev->name, netdev->dev->name, + netdev_addr ( netdev ) ); + /* Register per-netdev configuration settings */ if ( ( rc = register_settings ( netdev_settings ( netdev ), NULL ) ) != 0 ) { DBGC ( netdev, "NETDEV %p could not register settings: %s\n", netdev, strerror ( rc ) ); - return rc; + goto err_register_settings; } - /* Add to device list */ - netdev_get ( netdev ); - list_add_tail ( &netdev->list, &net_devices ); - DBGC ( netdev, "NETDEV %p registered as %s (phys %s hwaddr %s)\n", - netdev, netdev->name, netdev->dev->name, - netdev_addr ( netdev ) ); + /* Probe device */ + for_each_table_entry ( driver, NET_DRIVERS ) { + if ( ( rc = driver->probe ( netdev ) ) != 0 ) { + DBGC ( netdev, "NETDEV %p could not add %s device: " + "%s\n", netdev, driver->name, strerror ( rc ) ); + goto err_probe; + } + } return 0; + + err_probe: + for_each_table_entry_continue_reverse ( driver, NET_DRIVERS ) + driver->remove ( netdev ); + unregister_settings ( netdev_settings ( netdev ) ); + err_register_settings: + return rc; } /** @@ -419,6 +469,9 @@ int netdev_open ( struct net_device *netdev ) { /* Add to head of open devices list */ list_add ( &netdev->open_list, &open_net_devices ); + /* Notify drivers of device state change */ + netdev_notify ( netdev ); + return 0; } @@ -435,18 +488,21 @@ void netdev_close ( struct net_device *netdev ) { DBGC ( netdev, "NETDEV %p closing\n", netdev ); + /* Remove from open devices list */ + list_del ( &netdev->open_list ); + + /* Mark as closed */ + netdev->state &= ~NETDEV_OPEN; + + /* Notify drivers of device state change */ + netdev_notify ( netdev ); + /* Close the device */ netdev->op->close ( netdev ); /* Flush TX and RX queues */ netdev_tx_flush ( netdev ); netdev_rx_flush ( netdev ); - - /* Mark as closed */ - netdev->state &= ~NETDEV_OPEN; - - /* Remove from open devices list */ - list_del ( &netdev->open_list ); } /** @@ -457,10 +513,15 @@ void netdev_close ( struct net_device *netdev ) { * Removes the network device from the list of network devices. */ void unregister_netdev ( struct net_device *netdev ) { + struct net_driver *driver; /* Ensure device is closed */ netdev_close ( netdev ); + /* Remove device */ + for_each_table_entry_reverse ( driver, NET_DRIVERS ) + driver->remove ( netdev ); + /* Unregister per-netdev configuration settings */ unregister_settings ( netdev_settings ( netdev ) ); |
