summaryrefslogtreecommitdiffstats
path: root/src/net
diff options
context:
space:
mode:
Diffstat (limited to 'src/net')
-rw-r--r--src/net/80211/wpa.c11
-rw-r--r--src/net/eap.c43
-rw-r--r--src/net/eapol.c196
-rw-r--r--src/net/fcoe.c88
-rw-r--r--src/net/infiniband/xsigo.c4
-rw-r--r--src/net/ipv6.c39
-rw-r--r--src/net/lldp.c95
-rw-r--r--src/net/neighbour.c3
-rw-r--r--src/net/netdevice.c77
-rw-r--r--src/net/udp/dhcp.c7
-rw-r--r--src/net/udp/ntp.c10
-rw-r--r--src/net/vlan.c9
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.