summaryrefslogtreecommitdiff
path: root/gpxe/src/net/netdevice.c
diff options
context:
space:
mode:
Diffstat (limited to 'gpxe/src/net/netdevice.c')
-rw-r--r--gpxe/src/net/netdevice.c62
1 files changed, 51 insertions, 11 deletions
diff --git a/gpxe/src/net/netdevice.c b/gpxe/src/net/netdevice.c
index 3721b334..e8587a9d 100644
--- a/gpxe/src/net/netdevice.c
+++ b/gpxe/src/net/netdevice.c
@@ -46,6 +46,45 @@ static struct net_protocol net_protocols_end[0]
struct list_head net_devices = LIST_HEAD_INIT ( net_devices );
/**
+ * Record network device statistic
+ *
+ * @v stats Network device statistics
+ * @v rc Status code
+ */
+static void netdev_record_stat ( struct net_device_stats *stats, int rc ) {
+ struct net_device_error *error;
+ struct net_device_error *least_common_error;
+ unsigned int i;
+
+ /* If this is not an error, just update the good counter */
+ if ( rc == 0 ) {
+ stats->good++;
+ return;
+ }
+
+ /* Update the bad counter */
+ stats->bad++;
+
+ /* Locate the appropriate error record */
+ least_common_error = &stats->errors[0];
+ for ( i = 0 ; i < ( sizeof ( stats->errors ) /
+ sizeof ( stats->errors[0] ) ) ; i++ ) {
+ error = &stats->errors[i];
+ /* Update matching record, if found */
+ if ( error->rc == rc ) {
+ error->count++;
+ return;
+ }
+ if ( error->count < least_common_error->count )
+ least_common_error = error;
+ }
+
+ /* Overwrite the least common error record */
+ least_common_error->rc = rc;
+ least_common_error->count = 1;
+}
+
+/**
* Transmit raw packet via network device
*
* @v netdev Network device
@@ -91,12 +130,11 @@ void netdev_tx_complete_err ( struct net_device *netdev,
struct io_buffer *iobuf, int rc ) {
/* Update statistics counter */
+ netdev_record_stat ( &netdev->tx_stats, rc );
if ( rc == 0 ) {
- netdev->stats.tx_ok++;
DBGC ( netdev, "NETDEV %p transmission %p complete\n",
netdev, iobuf );
} else {
- netdev->stats.tx_err++;
DBGC ( netdev, "NETDEV %p transmission %p failed: %s\n",
netdev, iobuf, strerror ( rc ) );
}
@@ -158,7 +196,7 @@ void netdev_rx ( struct net_device *netdev, struct io_buffer *iobuf ) {
list_add_tail ( &iobuf->list, &netdev->rx_queue );
/* Update statistics counter */
- netdev->stats.rx_ok++;
+ netdev_record_stat ( &netdev->rx_stats, 0 );
}
/**
@@ -183,7 +221,7 @@ void netdev_rx_err ( struct net_device *netdev,
free_iob ( iobuf );
/* Update statistics counter */
- netdev->stats.rx_err++;
+ netdev_record_stat ( &netdev->rx_stats, rc );
}
/**
@@ -268,7 +306,7 @@ struct net_device * alloc_netdev ( size_t priv_size ) {
INIT_LIST_HEAD ( &netdev->rx_queue );
settings_init ( netdev_settings ( netdev ),
&netdev_settings_operations, &netdev->refcnt,
- netdev->name );
+ netdev->name, 0 );
netdev->priv = ( ( ( void * ) netdev ) + sizeof ( *netdev ) );
}
return netdev;
@@ -439,6 +477,7 @@ struct net_device * find_netdev_by_location ( unsigned int bus_type,
*/
int net_tx ( struct io_buffer *iobuf, struct net_device *netdev,
struct net_protocol *net_protocol, const void *ll_dest ) {
+ struct ll_protocol *ll_protocol = netdev->ll_protocol;
int rc;
/* Force a poll on the netdevice to (potentially) clear any
@@ -449,8 +488,8 @@ int net_tx ( struct io_buffer *iobuf, struct net_device *netdev,
netdev_poll ( netdev );
/* Add link-layer header */
- if ( ( rc = netdev->ll_protocol->push ( iobuf, netdev, net_protocol,
- ll_dest ) ) != 0 ) {
+ if ( ( rc = ll_protocol->push ( iobuf, ll_dest, netdev->ll_addr,
+ net_protocol->net_proto ) ) != 0 ) {
free_iob ( iobuf );
return rc;
}
@@ -495,8 +534,9 @@ static void net_step ( struct process *process __unused ) {
struct net_device *netdev;
struct io_buffer *iobuf;
struct ll_protocol *ll_protocol;
- uint16_t net_proto;
+ const void *ll_dest;
const void *ll_source;
+ uint16_t net_proto;
int rc;
/* Poll and process each network device */
@@ -519,9 +559,9 @@ static void net_step ( struct process *process __unused ) {
/* Remove link-layer header */
ll_protocol = netdev->ll_protocol;
- if ( ( rc = ll_protocol->pull ( iobuf, netdev,
- &net_proto,
- &ll_source ) ) != 0 ) {
+ if ( ( rc = ll_protocol->pull ( iobuf, &ll_dest,
+ &ll_source,
+ &net_proto ) ) != 0 ) {
free_iob ( iobuf );
continue;
}