diff options
| author | Simon Rettberg | 2023-10-06 18:37:21 +0200 |
|---|---|---|
| committer | Simon Rettberg | 2023-10-06 18:37:21 +0200 |
| commit | 95a57769874a70456670984debc05084feb75f6b (patch) | |
| tree | 9943c86b682e1b1d21a0439637b3849840a50137 /src/net | |
| parent | [efi] Remove old RDRAND hack; now officially supported (diff) | |
| parent | [libc] Use wall clock time as seed for the (non-cryptographic) RNG (diff) | |
| download | ipxe-95a57769874a70456670984debc05084feb75f6b.tar.gz ipxe-95a57769874a70456670984debc05084feb75f6b.tar.xz ipxe-95a57769874a70456670984debc05084feb75f6b.zip | |
Merge branch 'master' into openslx
Diffstat (limited to 'src/net')
| -rw-r--r-- | src/net/80211/wpa.c | 11 | ||||
| -rw-r--r-- | src/net/eap.c | 43 | ||||
| -rw-r--r-- | src/net/eapol.c | 196 | ||||
| -rw-r--r-- | src/net/fcoe.c | 88 | ||||
| -rw-r--r-- | src/net/infiniband/xsigo.c | 4 | ||||
| -rw-r--r-- | src/net/ipv6.c | 39 | ||||
| -rw-r--r-- | src/net/lldp.c | 95 | ||||
| -rw-r--r-- | src/net/neighbour.c | 3 | ||||
| -rw-r--r-- | src/net/netdevice.c | 77 | ||||
| -rw-r--r-- | src/net/udp/dhcp.c | 7 | ||||
| -rw-r--r-- | src/net/udp/ntp.c | 10 | ||||
| -rw-r--r-- | src/net/vlan.c | 9 |
12 files changed, 382 insertions, 200 deletions
diff --git a/src/net/80211/wpa.c b/src/net/80211/wpa.c index 1484d0e80..17c11b8ed 100644 --- a/src/net/80211/wpa.c +++ b/src/net/80211/wpa.c @@ -761,13 +761,14 @@ static int wpa_handle_1_of_2 ( struct wpa_common_ctx *ctx, /** * Handle receipt of EAPOL-Key frame for WPA * - * @v iob I/O buffer - * @v netdev Network device - * @v ll_source Source link-layer address + * @v supplicant EAPoL supplicant + * @v iob I/O buffer + * @v ll_source Source link-layer address */ -static int eapol_key_rx ( struct io_buffer *iob, struct net_device *netdev, - const void *ll_source ) +static int eapol_key_rx ( struct eapol_supplicant *supplicant, + struct io_buffer *iob, const void *ll_source ) { + struct net_device *netdev = supplicant->eap.netdev; struct net80211_device *dev = net80211_get ( netdev ); struct eapol_header *eapol; struct eapol_key_pkt *pkt; diff --git a/src/net/eap.c b/src/net/eap.c index 8d1d540fb..beaeb61d2 100644 --- a/src/net/eap.c +++ b/src/net/eap.c @@ -36,10 +36,11 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); /** * Handle EAP Request-Identity * - * @v netdev Network device + * @v supplicant EAP supplicant * @ret rc Return status code */ -static int eap_rx_request_identity ( struct net_device *netdev ) { +static int eap_rx_request_identity ( struct eap_supplicant *supplicant ) { + struct net_device *netdev = supplicant->netdev; /* Treat Request-Identity as blocking the link */ DBGC ( netdev, "EAP %s Request-Identity blocking link\n", @@ -52,13 +53,14 @@ static int eap_rx_request_identity ( struct net_device *netdev ) { /** * Handle EAP Request * - * @v netdev Network device + * @v supplicant EAP supplicant * @v req EAP request * @v len Length of EAP request * @ret rc Return status code */ -static int eap_rx_request ( struct net_device *netdev, +static int eap_rx_request ( struct eap_supplicant *supplicant, const struct eap_request *req, size_t len ) { + struct net_device *netdev = supplicant->netdev; /* Sanity check */ if ( len < sizeof ( *req ) ) { @@ -67,10 +69,13 @@ static int eap_rx_request ( struct net_device *netdev, return -EINVAL; } + /* Mark authentication as incomplete */ + supplicant->done = 0; + /* Handle according to type */ switch ( req->type ) { case EAP_TYPE_IDENTITY: - return eap_rx_request_identity ( netdev ); + return eap_rx_request_identity ( supplicant ); default: DBGC ( netdev, "EAP %s requested type %d unknown:\n", netdev->name, req->type ); @@ -82,10 +87,14 @@ static int eap_rx_request ( struct net_device *netdev, /** * Handle EAP Success * - * @v netdev Network device + * @v supplicant EAP supplicant * @ret rc Return status code */ -static int eap_rx_success ( struct net_device *netdev ) { +static int eap_rx_success ( struct eap_supplicant *supplicant ) { + struct net_device *netdev = supplicant->netdev; + + /* Mark authentication as complete */ + supplicant->done = 1; /* Mark link as unblocked */ DBGC ( netdev, "EAP %s Success\n", netdev->name ); @@ -97,10 +106,14 @@ static int eap_rx_success ( struct net_device *netdev ) { /** * Handle EAP Failure * - * @v netdev Network device + * @v supplicant EAP supplicant * @ret rc Return status code */ -static int eap_rx_failure ( struct net_device *netdev ) { +static int eap_rx_failure ( struct eap_supplicant *supplicant ) { + struct net_device *netdev = supplicant->netdev; + + /* Mark authentication as complete */ + supplicant->done = 1; /* Record error */ DBGC ( netdev, "EAP %s Failure\n", netdev->name ); @@ -110,12 +123,14 @@ static int eap_rx_failure ( struct net_device *netdev ) { /** * Handle EAP packet * - * @v netdev Network device + * @v supplicant EAP supplicant * @v data EAP packet * @v len Length of EAP packet * @ret rc Return status code */ -int eap_rx ( struct net_device *netdev, const void *data, size_t len ) { +int eap_rx ( struct eap_supplicant *supplicant, const void *data, + size_t len ) { + struct net_device *netdev = supplicant->netdev; const union eap_packet *eap = data; /* Sanity check */ @@ -128,11 +143,11 @@ int eap_rx ( struct net_device *netdev, const void *data, size_t len ) { /* Handle according to code */ switch ( eap->hdr.code ) { case EAP_CODE_REQUEST: - return eap_rx_request ( netdev, &eap->req, len ); + return eap_rx_request ( supplicant, &eap->req, len ); case EAP_CODE_SUCCESS: - return eap_rx_success ( netdev ); + return eap_rx_success ( supplicant ); case EAP_CODE_FAILURE: - return eap_rx_failure ( netdev ); + return eap_rx_failure ( supplicant ); default: DBGC ( netdev, "EAP %s unsupported code %d\n", netdev->name, eap->hdr.code ); diff --git a/src/net/eapol.c b/src/net/eapol.c index 3578f0e37..1b843e896 100644 --- a/src/net/eapol.c +++ b/src/net/eapol.c @@ -28,7 +28,10 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include <byteswap.h> #include <ipxe/iobuf.h> #include <ipxe/if_ether.h> +#include <ipxe/if_arp.h> #include <ipxe/netdevice.h> +#include <ipxe/vlan.h> +#include <ipxe/retry.h> #include <ipxe/eap.h> #include <ipxe/eapol.h> @@ -38,6 +41,44 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * */ +struct net_driver eapol_driver __net_driver; + +/** EAPoL destination MAC address */ +static const uint8_t eapol_mac[ETH_ALEN] = { + 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 +}; + +/** + * Update EAPoL supplicant state + * + * @v supplicant EAPoL supplicant + * @v timeout Timer ticks until next EAPoL-Start (if applicable) + */ +static void eapol_update ( struct eapol_supplicant *supplicant, + unsigned long timeout ) { + struct net_device *netdev = supplicant->eap.netdev; + + /* Check device and EAP state */ + if ( netdev_is_open ( netdev ) && netdev_link_ok ( netdev ) ) { + if ( supplicant->eap.done ) { + + /* EAP has completed: stop sending EAPoL-Start */ + stop_timer ( &supplicant->timer ); + + } else if ( ! timer_running ( &supplicant->timer ) ) { + + /* EAP has not yet begun: start sending EAPoL-Start */ + start_timer_fixed ( &supplicant->timer, timeout ); + } + + } else { + + /* Not ready: clear completion and stop sending EAPoL-Start */ + supplicant->eap.done = 0; + stop_timer ( &supplicant->timer ); + } +} + /** * Process EAPoL packet * @@ -51,12 +92,25 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); static int eapol_rx ( struct io_buffer *iobuf, struct net_device *netdev, const void *ll_dest __unused, const void *ll_source, unsigned int flags __unused ) { + struct eapol_supplicant *supplicant; struct eapol_header *eapol; struct eapol_handler *handler; size_t remaining; size_t len; int rc; + /* Find matching supplicant */ + supplicant = netdev_priv ( netdev, &eapol_driver ); + + /* Ignore non-EAPoL devices */ + if ( ! supplicant->eap.netdev ) { + DBGC ( netdev, "EAPOL %s is not an EAPoL device\n", + netdev->name ); + DBGC_HDA ( netdev, 0, iobuf->data, iob_len ( iobuf ) ); + rc = -ENOTTY; + goto drop; + } + /* Sanity checks */ if ( iob_len ( iobuf ) < sizeof ( *eapol ) ) { DBGC ( netdev, "EAPOL %s underlength header:\n", @@ -83,7 +137,7 @@ static int eapol_rx ( struct io_buffer *iobuf, struct net_device *netdev, /* Handle according to type */ for_each_table_entry ( handler, EAPOL_HANDLERS ) { if ( handler->type == eapol->type ) { - return handler->rx ( iob_disown ( iobuf ) , netdev, + return handler->rx ( supplicant, iob_disown ( iobuf ), ll_source ); } } @@ -107,12 +161,14 @@ struct net_protocol eapol_protocol __net_protocol = { /** * Process EAPoL-encapsulated EAP packet * - * @v netdev Network device + * @v supplicant EAPoL supplicant * @v ll_source Link-layer source address * @ret rc Return status code */ -static int eapol_eap_rx ( struct io_buffer *iobuf, struct net_device *netdev, +static int eapol_eap_rx ( struct eapol_supplicant *supplicant, + struct io_buffer *iobuf, const void *ll_source __unused ) { + struct net_device *netdev = supplicant->eap.netdev; struct eapol_header *eapol; int rc; @@ -123,12 +179,16 @@ static int eapol_eap_rx ( struct io_buffer *iobuf, struct net_device *netdev, eapol = iob_pull ( iobuf, sizeof ( *eapol ) ); /* Process EAP packet */ - if ( ( rc = eap_rx ( netdev, iobuf->data, iob_len ( iobuf ) ) ) != 0 ) { + if ( ( rc = eap_rx ( &supplicant->eap, iobuf->data, + iob_len ( iobuf ) ) ) != 0 ) { DBGC ( netdev, "EAPOL %s v%d EAP failed: %s\n", netdev->name, eapol->version, strerror ( rc ) ); goto drop; } + /* Update supplicant state */ + eapol_update ( supplicant, EAPOL_START_INTERVAL ); + drop: free_iob ( iobuf ); return rc; @@ -139,3 +199,131 @@ struct eapol_handler eapol_eap __eapol_handler = { .type = EAPOL_TYPE_EAP, .rx = eapol_eap_rx, }; + +/** + * Transmit EAPoL packet + * + * @v supplicant EAPoL supplicant + * @v type Packet type + * @v data Packet body + * @v len Length of packet body + * @ret rc Return status code + */ +static int eapol_tx ( struct eapol_supplicant *supplicant, unsigned int type, + const void *data, size_t len ) { + struct net_device *netdev = supplicant->eap.netdev; + struct io_buffer *iobuf; + struct eapol_header *eapol; + int rc; + + /* Allocate I/O buffer */ + iobuf = alloc_iob ( MAX_LL_HEADER_LEN + sizeof ( *eapol ) + len ); + if ( ! iobuf ) + return -ENOMEM; + iob_reserve ( iobuf, MAX_LL_HEADER_LEN ); + + /* Construct EAPoL header */ + eapol = iob_put ( iobuf, sizeof ( *eapol ) ); + eapol->version = EAPOL_VERSION_2001; + eapol->type = type; + eapol->len = htons ( len ); + + /* Append packet body */ + memcpy ( iob_put ( iobuf, len ), data, len ); + + /* Transmit packet */ + if ( ( rc = net_tx ( iob_disown ( iobuf ), netdev, &eapol_protocol, + &eapol_mac, netdev->ll_addr ) ) != 0 ) { + DBGC ( netdev, "EAPOL %s could not transmit type %d: %s\n", + netdev->name, type, strerror ( rc ) ); + DBGC_HDA ( netdev, 0, data, len ); + return rc; + } + + return 0; +} + +/** + * Transmit EAPoL-encapsulated EAP packet + * + * @v supplicant EAPoL supplicant + * @v ll_source Link-layer source address + * @ret rc Return status code + */ +static int eapol_eap_tx ( struct eap_supplicant *eap, const void *data, + size_t len ) { + struct eapol_supplicant *supplicant = + container_of ( eap, struct eapol_supplicant, eap ); + + /* Transmit encapsulated packet */ + return eapol_tx ( supplicant, EAPOL_TYPE_EAP, data, len ); +} + +/** + * (Re)transmit EAPoL-Start packet + * + * @v timer EAPoL-Start timer + * @v expired Failure indicator + */ +static void eapol_expired ( struct retry_timer *timer, int fail __unused ) { + struct eapol_supplicant *supplicant = + container_of ( timer, struct eapol_supplicant, timer ); + struct net_device *netdev = supplicant->eap.netdev; + + /* Schedule next transmission */ + start_timer_fixed ( timer, EAPOL_START_INTERVAL ); + + /* Transmit EAPoL-Start, ignoring errors */ + DBGC2 ( netdev, "EAPOL %s transmitting Start\n", netdev->name ); + eapol_tx ( supplicant, EAPOL_TYPE_START, NULL, 0 ); +} + +/** + * Create EAPoL supplicant + * + * @v netdev Network device + * @v priv Private data + * @ret rc Return status code + */ +static int eapol_probe ( struct net_device *netdev, void *priv ) { + struct eapol_supplicant *supplicant = priv; + struct ll_protocol *ll_protocol = netdev->ll_protocol; + + /* Ignore non-EAPoL devices */ + if ( ll_protocol->ll_proto != htons ( ARPHRD_ETHER ) ) + return 0; + if ( vlan_tag ( netdev ) ) + return 0; + + /* Initialise structure */ + supplicant->eap.netdev = netdev; + supplicant->eap.tx = eapol_eap_tx; + timer_init ( &supplicant->timer, eapol_expired, &netdev->refcnt ); + + return 0; +} + +/** + * Handle EAPoL supplicant state change + * + * @v netdev Network device + * @v priv Private data + */ +static void eapol_notify ( struct net_device *netdev __unused, void *priv ) { + struct eapol_supplicant *supplicant = priv; + + /* Ignore non-EAPoL devices */ + if ( ! supplicant->eap.netdev ) + return; + + /* Update supplicant state */ + eapol_update ( supplicant, 0 ); +} + +/** EAPoL driver */ +struct net_driver eapol_driver __net_driver = { + .name = "EAPoL", + .priv_len = sizeof ( struct eapol_supplicant ), + .probe = eapol_probe, + .notify = eapol_notify, +}; diff --git a/src/net/fcoe.c b/src/net/fcoe.c index f910eeead..9f3ddf88b 100644 --- a/src/net/fcoe.c +++ b/src/net/fcoe.c @@ -69,10 +69,6 @@ FEATURE ( FEATURE_PROTOCOL, "FCoE", DHCP_EB_FEATURE_FCOE, 1 ); /** An FCoE port */ struct fcoe_port { - /** Reference count */ - struct refcnt refcnt; - /** List of FCoE ports */ - struct list_head list; /** Transport interface */ struct interface transport; /** Network device */ @@ -115,6 +111,7 @@ enum fcoe_flags { FCOE_VLAN_TIMED_OUT = 0x0020, }; +struct net_driver fcoe_driver __net_driver; struct net_protocol fcoe_protocol __net_protocol; struct net_protocol fip_protocol __net_protocol; @@ -152,9 +149,6 @@ static uint8_t default_fcf_mac[ETH_ALEN] = /** Maximum number of missing discovery advertisements */ #define FCOE_MAX_FIP_MISSING_KEEPALIVES 4 -/** List of FCoE ports */ -static LIST_HEAD ( fcoe_ports ); - /****************************************************************************** * * FCoE protocol @@ -163,22 +157,6 @@ static LIST_HEAD ( fcoe_ports ); */ /** - * Identify FCoE port by network device - * - * @v netdev Network device - * @ret fcoe FCoE port, or NULL - */ -static struct fcoe_port * fcoe_demux ( struct net_device *netdev ) { - struct fcoe_port *fcoe; - - list_for_each_entry ( fcoe, &fcoe_ports, list ) { - if ( fcoe->netdev == netdev ) - return fcoe; - } - return NULL; -} - -/** * Reset FCoE port * * @v fcoe FCoE port @@ -348,7 +326,8 @@ static int fcoe_rx ( struct io_buffer *iobuf, struct net_device *netdev, int rc; /* Identify FCoE port */ - if ( ( fcoe = fcoe_demux ( netdev ) ) == NULL ) { + fcoe = netdev_priv ( netdev, &fcoe_driver ); + if ( ! fcoe->netdev ) { DBG ( "FCoE received frame for net device %s missing FCoE " "port\n", netdev->name ); rc = -ENOTCONN; @@ -448,9 +427,6 @@ static void fcoe_close ( struct fcoe_port *fcoe, int rc ) { stop_timer ( &fcoe->timer ); intf_shutdown ( &fcoe->transport, rc ); - netdev_put ( fcoe->netdev ); - list_del ( &fcoe->list ); - ref_put ( &fcoe->refcnt ); } /** @@ -947,7 +923,8 @@ static int fcoe_fip_rx ( struct io_buffer *iobuf, int rc; /* Identify FCoE port */ - if ( ( fcoe = fcoe_demux ( netdev ) ) == NULL ) { + fcoe = netdev_priv ( netdev, &fcoe_driver ); + if ( ! fcoe->netdev ) { DBG ( "FCoE received FIP frame for net device %s missing FCoE " "port\n", netdev->name ); rc = -ENOTCONN; @@ -1110,31 +1087,24 @@ static void fcoe_expired ( struct retry_timer *timer, int over __unused ) { * Create FCoE port * * @v netdev Network device + * @v priv Private data * @ret rc Return status code */ -static int fcoe_probe ( struct net_device *netdev ) { +static int fcoe_probe ( struct net_device *netdev, void *priv ) { struct ll_protocol *ll_protocol = netdev->ll_protocol; - struct fcoe_port *fcoe; - int rc; + struct fcoe_port *fcoe = priv; /* Sanity check */ if ( ll_protocol->ll_proto != htons ( ARPHRD_ETHER ) ) { /* Not an error; simply skip this net device */ DBG ( "FCoE skipping non-Ethernet device %s\n", netdev->name ); - rc = 0; - goto err_non_ethernet; + return 0; } - /* Allocate and initialise structure */ - fcoe = zalloc ( sizeof ( *fcoe ) ); - if ( ! fcoe ) { - rc = -ENOMEM; - goto err_zalloc; - } - ref_init ( &fcoe->refcnt, NULL ); - intf_init ( &fcoe->transport, &fcoe_transport_desc, &fcoe->refcnt ); - timer_init ( &fcoe->timer, fcoe_expired, &fcoe->refcnt ); - fcoe->netdev = netdev_get ( netdev ); + /* Initialise structure */ + intf_init ( &fcoe->transport, &fcoe_transport_desc, &netdev->refcnt ); + timer_init ( &fcoe->timer, fcoe_expired, &netdev->refcnt ); + fcoe->netdev = netdev; /* Construct node and port names */ fcoe->node_wwn.fcoe.authority = htons ( FCOE_AUTHORITY_IEEE ); @@ -1148,30 +1118,21 @@ static int fcoe_probe ( struct net_device *netdev ) { fc_ntoa ( &fcoe->node_wwn.fc ) ); DBGC ( fcoe, " port %s\n", fc_ntoa ( &fcoe->port_wwn.fc ) ); - /* Transfer reference to port list */ - list_add ( &fcoe->list, &fcoe_ports ); return 0; - - netdev_put ( fcoe->netdev ); - err_zalloc: - err_non_ethernet: - return rc; } /** * Handle FCoE port device or link state change * * @v netdev Network device + * @v priv Private data */ -static void fcoe_notify ( struct net_device *netdev ) { - struct fcoe_port *fcoe; +static void fcoe_notify ( struct net_device *netdev, void *priv ) { + struct fcoe_port *fcoe = priv; - /* Sanity check */ - if ( ( fcoe = fcoe_demux ( netdev ) ) == NULL ) { - DBG ( "FCoE notification for net device %s missing FCoE " - "port\n", netdev->name ); + /* Skip non-FCoE net devices */ + if ( ! fcoe->netdev ) return; - } /* Reset the FCoE link if necessary */ if ( ! ( netdev_is_open ( netdev ) && @@ -1185,16 +1146,14 @@ static void fcoe_notify ( struct net_device *netdev ) { * Destroy FCoE port * * @v netdev Network device + * @v priv Private data */ -static void fcoe_remove ( struct net_device *netdev ) { - struct fcoe_port *fcoe; +static void fcoe_remove ( struct net_device *netdev __unused, void *priv ) { + struct fcoe_port *fcoe = priv; - /* Sanity check */ - if ( ( fcoe = fcoe_demux ( netdev ) ) == NULL ) { - DBG ( "FCoE removal of net device %s missing FCoE port\n", - netdev->name ); + /* Skip non-FCoE net devices */ + if ( ! fcoe->netdev ) return; - } /* Close FCoE device */ fcoe_close ( fcoe, 0 ); @@ -1203,6 +1162,7 @@ static void fcoe_remove ( struct net_device *netdev ) { /** FCoE driver */ struct net_driver fcoe_driver __net_driver = { .name = "FCoE", + .priv_len = sizeof ( struct fcoe_port ), .probe = fcoe_probe, .notify = fcoe_notify, .remove = fcoe_remove, diff --git a/src/net/infiniband/xsigo.c b/src/net/infiniband/xsigo.c index 4f5c618d7..5e805fa02 100644 --- a/src/net/infiniband/xsigo.c +++ b/src/net/infiniband/xsigo.c @@ -1829,8 +1829,10 @@ struct ib_driver xsigo_ib_driver __ib_driver = { * Handle device or link status change * * @v netdev Network device + * @v priv Private data */ -static void xsigo_net_notify ( struct net_device *netdev ) { +static void xsigo_net_notify ( struct net_device *netdev, + void *priv __unused ) { struct xsigo_device *xdev; struct ib_device *ibdev; struct xsigo_manager *xcm; diff --git a/src/net/ipv6.c b/src/net/ipv6.c index ef5e51daa..8ee0804d3 100644 --- a/src/net/ipv6.c +++ b/src/net/ipv6.c @@ -1212,50 +1212,33 @@ static struct settings_operations ipv6_settings_operations = { .fetch = ipv6_fetch, }; -/** IPv6 link-local address settings */ -struct ipv6_settings { - /** Reference counter */ - struct refcnt refcnt; - /** Settings interface */ - struct settings settings; -}; - /** * Register IPv6 link-local address settings * * @v netdev Network device + * @v priv Private data * @ret rc Return status code */ -static int ipv6_register_settings ( struct net_device *netdev ) { +static int ipv6_register_settings ( struct net_device *netdev, void *priv ) { struct settings *parent = netdev_settings ( netdev ); - struct ipv6_settings *ipv6set; + struct settings *settings = priv; int rc; - /* Allocate and initialise structure */ - ipv6set = zalloc ( sizeof ( *ipv6set ) ); - if ( ! ipv6set ) { - rc = -ENOMEM; - goto err_alloc; - } - ref_init ( &ipv6set->refcnt, NULL ); - settings_init ( &ipv6set->settings, &ipv6_settings_operations, - &ipv6set->refcnt, &ipv6_settings_scope ); - ipv6set->settings.order = IPV6_ORDER_LINK_LOCAL; - - /* Register settings */ - if ( ( rc = register_settings ( &ipv6set->settings, parent, + /* Initialise and register settings */ + settings_init ( settings, &ipv6_settings_operations, + &netdev->refcnt, &ipv6_settings_scope ); + settings->order = IPV6_ORDER_LINK_LOCAL; + if ( ( rc = register_settings ( settings, parent, IPV6_SETTINGS_NAME ) ) != 0 ) - goto err_register; + return rc; - err_register: - ref_put ( &ipv6set->refcnt ); - err_alloc: - return rc; + return 0; } /** IPv6 network device driver */ struct net_driver ipv6_driver __net_driver = { .name = "IPv6", + .priv_len = sizeof ( struct settings ), .probe = ipv6_register_settings, }; diff --git a/src/net/lldp.c b/src/net/lldp.c index 72e3ecdf6..a854d0ace 100644 --- a/src/net/lldp.c +++ b/src/net/lldp.c @@ -40,12 +40,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); /** An LLDP settings block */ struct lldp_settings { - /** Reference counter */ - struct refcnt refcnt; /** Settings interface */ struct settings settings; - /** List of LLDP settings blocks */ - struct list_head list; /** Name */ const char *name; /** LLDP data */ @@ -54,45 +50,12 @@ struct lldp_settings { size_t len; }; +/* Forward declaration */ +struct net_driver lldp_driver __net_driver; + /** LLDP settings scope */ static const struct settings_scope lldp_settings_scope; -/** List of LLDP settings blocks */ -static LIST_HEAD ( lldp_settings ); - -/** - * Free LLDP settings block - * - * @v refcnt Reference counter - */ -static void lldp_free ( struct refcnt *refcnt ) { - struct lldp_settings *lldpset = - container_of ( refcnt, struct lldp_settings, refcnt ); - - DBGC ( lldpset, "LLDP %s freed\n", lldpset->name ); - list_del ( &lldpset->list ); - free ( lldpset->data ); - free ( lldpset ); -} - -/** - * Find LLDP settings block - * - * @v netdev Network device - * @ret lldpset LLDP settings block - */ -static struct lldp_settings * lldp_find ( struct net_device *netdev ) { - struct lldp_settings *lldpset; - - /* Find matching LLDP settings block */ - list_for_each_entry ( lldpset, &lldp_settings, list ) { - if ( netdev_settings ( netdev ) == lldpset->settings.parent ) - return lldpset; - } - - return NULL; -} - /** * Check applicability of LLDP setting * @@ -246,13 +209,7 @@ static int lldp_rx ( struct io_buffer *iobuf, struct net_device *netdev, int rc; /* Find matching LLDP settings block */ - lldpset = lldp_find ( netdev ); - if ( ! lldpset ) { - DBGC ( netdev, "LLDP %s has no \"%s\" settings block\n", - netdev->name, LLDP_SETTINGS_NAME ); - rc = -ENOENT; - goto err_find; - } + lldpset = netdev_priv ( netdev, &lldp_driver ); /* Create trimmed copy of received LLDP data */ len = iob_len ( iobuf ); @@ -280,7 +237,6 @@ static int lldp_rx ( struct io_buffer *iobuf, struct net_device *netdev, free ( data ); err_alloc: - err_find: free_iob ( iobuf ); return rc; } @@ -296,26 +252,21 @@ struct net_protocol lldp_protocol __net_protocol = { * Create LLDP settings block * * @v netdev Network device + * @v priv Private data * @ret rc Return status code */ -static int lldp_probe ( struct net_device *netdev ) { - struct lldp_settings *lldpset; +static int lldp_probe ( struct net_device *netdev, void *priv ) { + struct lldp_settings *lldpset = priv; int rc; - /* Allocate LLDP settings block */ - lldpset = zalloc ( sizeof ( *lldpset ) ); - if ( ! lldpset ) { - rc = -ENOMEM; - goto err_alloc; - } - ref_init ( &lldpset->refcnt, lldp_free ); + /* Initialise LLDP settings block */ settings_init ( &lldpset->settings, &lldp_settings_operations, - &lldpset->refcnt, &lldp_settings_scope ); - list_add_tail ( &lldpset->list, &lldp_settings ); + &netdev->refcnt, &lldp_settings_scope ); lldpset->name = netdev->name; /* Register settings */ - if ( ( rc = register_settings ( &lldpset->settings, netdev_settings ( netdev ), + if ( ( rc = register_settings ( &lldpset->settings, + netdev_settings ( netdev ), LLDP_SETTINGS_NAME ) ) != 0 ) { DBGC ( lldpset, "LLDP %s could not register settings: %s\n", lldpset->name, strerror ( rc ) ); @@ -323,18 +274,36 @@ static int lldp_probe ( struct net_device *netdev ) { } DBGC ( lldpset, "LLDP %s registered\n", lldpset->name ); - ref_put ( &lldpset->refcnt ); return 0; unregister_settings ( &lldpset->settings ); err_register: - ref_put ( &lldpset->refcnt ); - err_alloc: + assert ( lldpset->data == NULL ); return rc; } +/** + * Remove LLDP settings block + * + * @v netdev Network device + * @v priv Private data + */ +static void lldp_remove ( struct net_device *netdev __unused, void *priv ) { + struct lldp_settings *lldpset = priv; + + /* Unregister settings */ + unregister_settings ( &lldpset->settings ); + DBGC ( lldpset, "LLDP %s unregistered\n", lldpset->name ); + + /* Free any LLDP data */ + free ( lldpset->data ); + lldpset->data = NULL; +} + /** LLDP driver */ struct net_driver lldp_driver __net_driver = { .name = "LLDP", + .priv_len = sizeof ( struct lldp_settings ), .probe = lldp_probe, + .remove = lldp_remove, }; diff --git a/src/net/neighbour.c b/src/net/neighbour.c index 7f66d9992..13a8bc3ba 100644 --- a/src/net/neighbour.c +++ b/src/net/neighbour.c @@ -383,8 +383,9 @@ int neighbour_define ( struct net_device *netdev, * Update neighbour cache on network device state change or removal * * @v netdev Network device + * @v priv Private data */ -static void neighbour_flush ( struct net_device *netdev ) { +static void neighbour_flush ( struct net_device *netdev, void *priv __unused ) { struct neighbour *neighbour; struct neighbour *tmp; diff --git a/src/net/netdevice.c b/src/net/netdevice.c index 07961bf20..a9ed18134 100644 --- a/src/net/netdevice.c +++ b/src/net/netdevice.c @@ -110,16 +110,63 @@ static int netdev_has_ll_addr ( struct net_device *netdev ) { } /** + * Get offset of network device driver private data + * + * @v driver Upper-layer driver, or NULL for device driver + * @ret offset Offset of driver private data + */ +static size_t netdev_priv_offset ( struct net_driver *driver ) { + struct net_device *netdev; + unsigned int num_configs; + size_t offset; + + /* Allow space for network device */ + offset = sizeof ( *netdev ); + + /* Allow space for configurations */ + num_configs = table_num_entries ( NET_DEVICE_CONFIGURATORS ); + offset += ( num_configs * sizeof ( netdev->configs[0] ) ); + + /* Place variable-length device driver private data at end */ + if ( ! driver ) + driver = table_end ( NET_DRIVERS ); + + /* Allow space for preceding upper-layer drivers' private data */ + for_each_table_entry_continue_reverse ( driver, NET_DRIVERS ) { + offset += driver->priv_len; + } + + /* Sanity check */ + assert ( ( offset & ( sizeof ( void * ) - 1 ) ) == 0 ); + + return offset; +} + +/** + * Get network device driver private data + * + * @v netdev Network device + * @v driver Upper-layer driver, or NULL for device driver + * @ret priv Driver private data + */ +void * netdev_priv ( struct net_device *netdev, struct net_driver *driver ) { + + return ( ( ( void * ) netdev ) + netdev_priv_offset ( driver ) ); +} + +/** * 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; + void *priv; for_each_table_entry ( driver, NET_DRIVERS ) { + priv = netdev_priv ( netdev, driver ); if ( driver->notify ) - driver->notify ( netdev ); + driver->notify ( netdev, priv ); } } @@ -656,7 +703,7 @@ static void free_netdev ( struct refcnt *refcnt ) { struct net_device *netdev = container_of ( refcnt, struct net_device, refcnt ); - stop_timer ( &netdev->link_block ); + assert ( ! timer_running ( &netdev->link_block ) ); netdev_tx_flush ( netdev ); netdev_rx_flush ( netdev ); clear_settings ( netdev_settings ( netdev ) ); @@ -675,14 +722,8 @@ struct net_device * alloc_netdev ( size_t priv_len ) { struct net_device *netdev; struct net_device_configurator *configurator; struct net_device_configuration *config; - unsigned int num_configs; - size_t confs_len; - size_t total_len; - num_configs = table_num_entries ( NET_DEVICE_CONFIGURATORS ); - confs_len = ( num_configs * sizeof ( netdev->configs[0] ) ); - total_len = ( sizeof ( *netdev ) + confs_len + priv_len ); - netdev = zalloc ( total_len ); + netdev = zalloc ( netdev_priv_offset ( NULL ) + priv_len ); if ( netdev ) { ref_init ( &netdev->refcnt, free_netdev ); netdev->link_rc = -EUNKNOWN_LINK_STATUS; @@ -701,8 +742,7 @@ struct net_device * alloc_netdev ( size_t priv_len ) { &netdev->refcnt ); config++; } - netdev->priv = ( ( ( void * ) netdev ) + sizeof ( *netdev ) + - confs_len ); + netdev->priv = netdev_priv ( netdev, NULL ); } return netdev; } @@ -722,6 +762,7 @@ int register_netdev ( struct net_device *netdev ) { struct net_device *duplicate; unsigned int i; uint32_t seed; + void *priv; int rc; /* Set initial link-layer address, if not already set */ @@ -784,7 +825,9 @@ int register_netdev ( struct net_device *netdev ) { /* Probe device */ for_each_table_entry ( driver, NET_DRIVERS ) { - if ( driver->probe && ( rc = driver->probe ( netdev ) ) != 0 ) { + priv = netdev_priv ( netdev, driver ); + if ( driver->probe && + ( rc = driver->probe ( netdev, priv ) ) != 0 ) { DBGC ( netdev, "NETDEV %s could not add %s device: " "%s\n", netdev->name, driver->name, strerror ( rc ) ); @@ -796,8 +839,9 @@ int register_netdev ( struct net_device *netdev ) { err_probe: for_each_table_entry_continue_reverse ( driver, NET_DRIVERS ) { + priv = netdev_priv ( netdev, driver ); if ( driver->remove ) - driver->remove ( netdev ); + driver->remove ( netdev, priv ); } clear_settings ( netdev_settings ( netdev ) ); unregister_settings ( netdev_settings ( netdev ) ); @@ -879,6 +923,9 @@ void netdev_close ( struct net_device *netdev ) { /* Close the device */ netdev->op->close ( netdev ); + /* Stop link block timer */ + stop_timer ( &netdev->link_block ); + /* Flush TX and RX queues */ netdev_tx_flush ( netdev ); netdev_rx_flush ( netdev ); @@ -893,14 +940,16 @@ void netdev_close ( struct net_device *netdev ) { */ void unregister_netdev ( struct net_device *netdev ) { struct net_driver *driver; + void *priv; /* Ensure device is closed */ netdev_close ( netdev ); /* Remove device */ for_each_table_entry_reverse ( driver, NET_DRIVERS ) { + priv = netdev_priv ( netdev, driver ); if ( driver->remove ) - driver->remove ( netdev ); + driver->remove ( netdev, priv ); } /* Unregister per-netdev configuration settings */ diff --git a/src/net/udp/dhcp.c b/src/net/udp/dhcp.c index bd2c4a197..8e2e97f10 100644 --- a/src/net/udp/dhcp.c +++ b/src/net/udp/dhcp.c @@ -91,9 +91,10 @@ static uint8_t dhcp_request_options_data[] = { DHCP_PARAMETER_REQUEST_LIST, DHCP_OPTION ( DHCP_SUBNET_MASK, DHCP_ROUTERS, DHCP_DNS_SERVERS, DHCP_LOG_SERVERS, DHCP_HOST_NAME, DHCP_DOMAIN_NAME, - DHCP_ROOT_PATH, DHCP_MTU, DHCP_VENDOR_ENCAP, - DHCP_VENDOR_CLASS_ID, DHCP_TFTP_SERVER_NAME, - DHCP_BOOTFILE_NAME, DHCP_DOMAIN_SEARCH, + DHCP_ROOT_PATH, DHCP_MTU, DHCP_NTP_SERVERS, + DHCP_VENDOR_ENCAP, DHCP_VENDOR_CLASS_ID, + DHCP_TFTP_SERVER_NAME, DHCP_BOOTFILE_NAME, + DHCP_DOMAIN_SEARCH, 128, 129, 130, 131, 132, 133, 134, 135, /* for PXE */ DHCP_EB_ENCAP, DHCP_ISCSI_INITIATOR_IQN ), DHCP_END diff --git a/src/net/udp/ntp.c b/src/net/udp/ntp.c index 11f8ccc00..559233575 100644 --- a/src/net/udp/ntp.c +++ b/src/net/udp/ntp.c @@ -36,6 +36,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include <ipxe/timer.h> #include <ipxe/time.h> #include <ipxe/tcpip.h> +#include <ipxe/dhcp.h> +#include <ipxe/settings.h> #include <ipxe/ntp.h> /** @file @@ -273,3 +275,11 @@ int start_ntp ( struct interface *job, const char *hostname ) { err_alloc: return rc; } + +/** IPv4 NTP server setting */ +const struct setting ntp_setting __setting ( SETTING_IP4_EXTRA, ntp ) = { + .name = "ntp", + .description = "NTP server", + .tag = DHCP_NTP_SERVERS, + .type = &setting_type_ipv4, +}; diff --git a/src/net/vlan.c b/src/net/vlan.c index d73a95711..c61bb850e 100644 --- a/src/net/vlan.c +++ b/src/net/vlan.c @@ -470,9 +470,10 @@ void vlan_auto ( const void *ll_addr, unsigned int tag ) { * Create automatic VLAN device * * @v trunk Trunk network device + * @v priv Private data * @ret rc Return status code */ -static int vlan_probe ( struct net_device *trunk ) { +static int vlan_probe ( struct net_device *trunk, void *priv __unused ) { int rc; /* Do nothing unless an automatic VLAN exists */ @@ -498,8 +499,9 @@ static int vlan_probe ( struct net_device *trunk ) { * Handle trunk network device link state change * * @v trunk Trunk network device + * @v priv Private data */ -static void vlan_notify ( struct net_device *trunk ) { +static void vlan_notify ( struct net_device *trunk, void *priv __unused ) { struct net_device *netdev; struct vlan_device *vlan; @@ -538,8 +540,9 @@ static int vlan_remove_first ( struct net_device *trunk ) { * Destroy all VLAN devices for a given trunk * * @v trunk Trunk network device + * @v priv Private data */ -static void vlan_remove ( struct net_device *trunk ) { +static void vlan_remove ( struct net_device *trunk, void *priv __unused ) { /* Remove all VLAN devices attached to this trunk, safe * against arbitrary net device removal. |
