176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>. 376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This program is free software; you can redistribute it and/or 576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * modify it under the terms of the GNU General Public License as 676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * published by the Free Software Foundation; either version 2 of the 776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * License, or any later version. 876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This program is distributed in the hope that it will be useful, but 1076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * WITHOUT ANY WARRANTY; without even the implied warranty of 1176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * General Public License for more details. 1376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 1476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * You should have received a copy of the GNU General Public License 1576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * along with this program; if not, write to the Free Software 1676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 1776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 1876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 1976d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanFILE_LICENCE ( GPL2_OR_LATER ); 2076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 2176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <stdint.h> 2276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <stdlib.h> 2376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <stdio.h> 2476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <byteswap.h> 2576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <string.h> 2676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <errno.h> 2776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/if_ether.h> 2876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/iobuf.h> 2976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/tables.h> 3076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/process.h> 3176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/init.h> 3276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/device.h> 3376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/errortab.h> 3476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/netdevice.h> 3576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 3676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** @file 3776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 3876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Network device management 3976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 4076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 4176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 4276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** List of network devices */ 4376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstruct list_head net_devices = LIST_HEAD_INIT ( net_devices ); 4476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 4576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** List of open network devices, in reverse order of opening */ 4676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic struct list_head open_net_devices = LIST_HEAD_INIT ( open_net_devices ); 4776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 4876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** Default link status code */ 4976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define EUNKNOWN_LINK_STATUS EINPROGRESS 5076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 5176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** Human-readable message for the default link status */ 5276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstruct errortab netdev_errors[] __errortab = { 5376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman { EUNKNOWN_LINK_STATUS, "Unknown" }, 5476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}; 5576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 5676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 5776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Mark network device as having link down 5876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 5976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v netdev Network device 6076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 6176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid netdev_link_down ( struct net_device *netdev ) { 6276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 6376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman switch ( netdev->link_rc ) { 6476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case 0: 6576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case -EUNKNOWN_LINK_STATUS: 6676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev->link_rc = -ENOTCONN; 6776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 6876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman default: 6976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Avoid clobbering a more detailed link status code, 7076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * if one is already set. 7176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 7276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 7376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 7476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 7576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 7676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 7776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Record network device statistic 7876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 7976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v stats Network device statistics 8076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v rc Status code 8176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 8276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void netdev_record_stat ( struct net_device_stats *stats, int rc ) { 8376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct net_device_error *error; 8476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct net_device_error *least_common_error; 8576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned int i; 8676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 8776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* If this is not an error, just update the good counter */ 8876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( rc == 0 ) { 8976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman stats->good++; 9076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return; 9176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 9276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 9376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Update the bad counter */ 9476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman stats->bad++; 9576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 9676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Locate the appropriate error record */ 9776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman least_common_error = &stats->errors[0]; 9876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for ( i = 0 ; i < ( sizeof ( stats->errors ) / 9976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman sizeof ( stats->errors[0] ) ) ; i++ ) { 10076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman error = &stats->errors[i]; 10176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Update matching record, if found */ 10276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( error->rc == rc ) { 10376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman error->count++; 10476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return; 10576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 10676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( error->count < least_common_error->count ) 10776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman least_common_error = error; 10876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 10976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 11076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Overwrite the least common error record */ 11176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman least_common_error->rc = rc; 11276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman least_common_error->count = 1; 11376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 11476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 11576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 11676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Transmit raw packet via network device 11776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 11876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v netdev Network device 11976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v iobuf I/O buffer 12076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret rc Return status code 12176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 12276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Transmits the packet via the specified network device. This 12376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * function takes ownership of the I/O buffer. 12476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 12576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint netdev_tx ( struct net_device *netdev, struct io_buffer *iobuf ) { 12676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int rc; 12776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 12876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBGC ( netdev, "NETDEV %p transmitting %p (%p+%zx)\n", 12976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev, iobuf, iobuf->data, iob_len ( iobuf ) ); 13076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 13176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman list_add_tail ( &iobuf->list, &netdev->tx_queue ); 13276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 13376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( ! ( netdev->state & NETDEV_OPEN ) ) { 13476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rc = -ENETUNREACH; 13576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto err; 13676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 13776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 13876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( ( rc = netdev->op->transmit ( netdev, iobuf ) ) != 0 ) 13976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto err; 14076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 14176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 14276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 14376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman err: 14476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev_tx_complete_err ( netdev, iobuf, rc ); 14576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return rc; 14676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 14776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 14876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 14976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Complete network transmission 15076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 15176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v netdev Network device 15276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v iobuf I/O buffer 15376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v rc Packet status code 15476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 15576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * The packet must currently be in the network device's TX queue. 15676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 15776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid netdev_tx_complete_err ( struct net_device *netdev, 15876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct io_buffer *iobuf, int rc ) { 15976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 16076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Update statistics counter */ 16176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev_record_stat ( &netdev->tx_stats, rc ); 16276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( rc == 0 ) { 16376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBGC ( netdev, "NETDEV %p transmission %p complete\n", 16476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev, iobuf ); 16576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 16676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBGC ( netdev, "NETDEV %p transmission %p failed: %s\n", 16776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev, iobuf, strerror ( rc ) ); 16876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 16976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 17076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Catch data corruption as early as possible */ 17176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman assert ( iobuf->list.next != NULL ); 17276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman assert ( iobuf->list.prev != NULL ); 17376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 17476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Dequeue and free I/O buffer */ 17576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman list_del ( &iobuf->list ); 17676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman free_iob ( iobuf ); 17776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 17876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 17976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 18076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Complete network transmission 18176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 18276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v netdev Network device 18376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v rc Packet status code 18476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 18576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Completes the oldest outstanding packet in the TX queue. 18676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 18776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid netdev_tx_complete_next_err ( struct net_device *netdev, int rc ) { 18876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct io_buffer *iobuf; 18976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 19076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman list_for_each_entry ( iobuf, &netdev->tx_queue, list ) { 19176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev_tx_complete_err ( netdev, iobuf, rc ); 19276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return; 19376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 19476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 19576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 19676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 19776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Flush device's transmit queue 19876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 19976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v netdev Network device 20076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 20176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void netdev_tx_flush ( struct net_device *netdev ) { 20276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 20376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Discard any packets in the TX queue */ 20476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman while ( ! list_empty ( &netdev->tx_queue ) ) { 20576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev_tx_complete_next_err ( netdev, -ECANCELED ); 20676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 20776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 20876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 20976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 21076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Add packet to receive queue 21176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 21276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v netdev Network device 21376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v iobuf I/O buffer, or NULL 21476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 21576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * The packet is added to the network device's RX queue. This 21676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * function takes ownership of the I/O buffer. 21776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 21876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid netdev_rx ( struct net_device *netdev, struct io_buffer *iobuf ) { 21976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 22076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBGC ( netdev, "NETDEV %p received %p (%p+%zx)\n", 22176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev, iobuf, iobuf->data, iob_len ( iobuf ) ); 22276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 22376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Enqueue packet */ 22476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman list_add_tail ( &iobuf->list, &netdev->rx_queue ); 22576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 22676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Update statistics counter */ 22776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev_record_stat ( &netdev->rx_stats, 0 ); 22876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 22976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 23076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 23176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Discard received packet 23276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 23376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v netdev Network device 23476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v iobuf I/O buffer, or NULL 23576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v rc Packet status code 23676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 23776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * The packet is discarded and an RX error is recorded. This function 23876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * takes ownership of the I/O buffer. @c iobuf may be NULL if, for 23976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * example, the net device wishes to report an error due to being 24076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * unable to allocate an I/O buffer. 24176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 24276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid netdev_rx_err ( struct net_device *netdev, 24376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct io_buffer *iobuf, int rc ) { 24476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 24576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBGC ( netdev, "NETDEV %p failed to receive %p: %s\n", 24676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev, iobuf, strerror ( rc ) ); 24776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 24876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Discard packet */ 24976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman free_iob ( iobuf ); 25076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 25176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Update statistics counter */ 25276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev_record_stat ( &netdev->rx_stats, rc ); 25376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 25476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 25576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 25676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Poll for completed and received packets on network device 25776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 25876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v netdev Network device 25976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 26076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Polls the network device for completed transmissions and received 26176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * packets. Any received packets will be added to the RX packet queue 26276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * via netdev_rx(). 26376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 26476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid netdev_poll ( struct net_device *netdev ) { 26576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 26676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( netdev->state & NETDEV_OPEN ) 26776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev->op->poll ( netdev ); 26876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 26976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 27076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 27176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Remove packet from device's receive queue 27276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 27376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v netdev Network device 27476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret iobuf I/O buffer, or NULL 27576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 27676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Removes the first packet from the device's RX queue and returns it. 27776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Ownership of the packet is transferred to the caller. 27876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 27976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstruct io_buffer * netdev_rx_dequeue ( struct net_device *netdev ) { 28076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct io_buffer *iobuf; 28176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 28276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman list_for_each_entry ( iobuf, &netdev->rx_queue, list ) { 28376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman list_del ( &iobuf->list ); 28476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return iobuf; 28576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 28676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return NULL; 28776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 28876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 28976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 29076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Flush device's receive queue 29176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 29276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v netdev Network device 29376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 29476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void netdev_rx_flush ( struct net_device *netdev ) { 29576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct io_buffer *iobuf; 29676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 29776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Discard any packets in the RX queue */ 29876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman while ( ( iobuf = netdev_rx_dequeue ( netdev ) ) ) { 29976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev_rx_err ( netdev, iobuf, -ECANCELED ); 30076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 30176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 30276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 30376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 30476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Free network device 30576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 30676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v refcnt Network device reference counter 30776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 30876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void free_netdev ( struct refcnt *refcnt ) { 30976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct net_device *netdev = 31076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman container_of ( refcnt, struct net_device, refcnt ); 31176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 31276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev_tx_flush ( netdev ); 31376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev_rx_flush ( netdev ); 31476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman clear_settings ( netdev_settings ( netdev ) ); 31576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman free ( netdev ); 31676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 31776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 31876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 31976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Allocate network device 32076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 32176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v priv_size Size of private data area (net_device::priv) 32276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret netdev Network device, or NULL 32376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 32476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Allocates space for a network device and its private data area. 32576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 32676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstruct net_device * alloc_netdev ( size_t priv_size ) { 32776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct net_device *netdev; 32876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman size_t total_len; 32976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 33076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman total_len = ( sizeof ( *netdev ) + priv_size ); 33176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev = zalloc ( total_len ); 33276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( netdev ) { 33376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev->refcnt.free = free_netdev; 33476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev->link_rc = -EUNKNOWN_LINK_STATUS; 33576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman INIT_LIST_HEAD ( &netdev->tx_queue ); 33676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman INIT_LIST_HEAD ( &netdev->rx_queue ); 33776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev_settings_init ( netdev ); 33876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev->priv = ( ( ( void * ) netdev ) + sizeof ( *netdev ) ); 33976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 34076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return netdev; 34176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 34276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 34376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 34476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Register network device 34576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 34676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v netdev Network device 34776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret rc Return status code 34876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 34976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Gives the network device a name and adds it to the list of network 35076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * devices. 35176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 35276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint register_netdev ( struct net_device *netdev ) { 35376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman static unsigned int ifindex = 0; 35476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int rc; 35576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 35676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Create device name */ 35776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman snprintf ( netdev->name, sizeof ( netdev->name ), "net%d", 35876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ifindex++ ); 35976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 36076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Set initial link-layer address */ 36176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev->ll_protocol->init_addr ( netdev->hw_addr, netdev->ll_addr ); 36276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 36376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Register per-netdev configuration settings */ 36476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( ( rc = register_settings ( netdev_settings ( netdev ), 36576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman NULL ) ) != 0 ) { 36676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBGC ( netdev, "NETDEV %p could not register settings: %s\n", 36776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev, strerror ( rc ) ); 36876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return rc; 36976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 37076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 37176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Add to device list */ 37276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev_get ( netdev ); 37376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman list_add_tail ( &netdev->list, &net_devices ); 37476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBGC ( netdev, "NETDEV %p registered as %s (phys %s hwaddr %s)\n", 37576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev, netdev->name, netdev->dev->name, 37676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev_addr ( netdev ) ); 37776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 37876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 37976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 38076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 38176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 38276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Open network device 38376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 38476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v netdev Network device 38576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret rc Return status code 38676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 38776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint netdev_open ( struct net_device *netdev ) { 38876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int rc; 38976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 39076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Do nothing if device is already open */ 39176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( netdev->state & NETDEV_OPEN ) 39276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 39376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 39476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBGC ( netdev, "NETDEV %p opening\n", netdev ); 39576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 39676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Open the device */ 39776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( ( rc = netdev->op->open ( netdev ) ) != 0 ) 39876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return rc; 39976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 40076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Mark as opened */ 40176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev->state |= NETDEV_OPEN; 40276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 40376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Add to head of open devices list */ 40476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman list_add ( &netdev->open_list, &open_net_devices ); 40576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 40676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 40776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 40876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 40976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 41076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Close network device 41176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 41276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v netdev Network device 41376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 41476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid netdev_close ( struct net_device *netdev ) { 41576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 41676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Do nothing if device is already closed */ 41776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( ! ( netdev->state & NETDEV_OPEN ) ) 41876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return; 41976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 42076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBGC ( netdev, "NETDEV %p closing\n", netdev ); 42176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 42276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Close the device */ 42376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev->op->close ( netdev ); 42476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 42576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Flush TX and RX queues */ 42676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev_tx_flush ( netdev ); 42776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev_rx_flush ( netdev ); 42876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 42976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Mark as closed */ 43076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev->state &= ~NETDEV_OPEN; 43176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 43276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Remove from open devices list */ 43376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman list_del ( &netdev->open_list ); 43476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 43576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 43676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 43776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Unregister network device 43876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 43976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v netdev Network device 44076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 44176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Removes the network device from the list of network devices. 44276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 44376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid unregister_netdev ( struct net_device *netdev ) { 44476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 44576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Ensure device is closed */ 44676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev_close ( netdev ); 44776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 44876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Unregister per-netdev configuration settings */ 44976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unregister_settings ( netdev_settings ( netdev ) ); 45076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 45176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Remove from device list */ 45276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman list_del ( &netdev->list ); 45376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev_put ( netdev ); 45476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBGC ( netdev, "NETDEV %p unregistered\n", netdev ); 45576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 45676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 45776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** Enable or disable interrupts 45876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 45976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v netdev Network device 46076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v enable Interrupts should be enabled 46176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 46276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid netdev_irq ( struct net_device *netdev, int enable ) { 46376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev->op->irq ( netdev, enable ); 46476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 46576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 46676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 46776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Get network device by name 46876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 46976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v name Network device name 47076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret netdev Network device, or NULL 47176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 47276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstruct net_device * find_netdev ( const char *name ) { 47376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct net_device *netdev; 47476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 47576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman list_for_each_entry ( netdev, &net_devices, list ) { 47676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( strcmp ( netdev->name, name ) == 0 ) 47776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return netdev; 47876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 47976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 48076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return NULL; 48176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 48276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 48376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 48476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Get network device by PCI bus:dev.fn address 48576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 48676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v bus_type Bus type 48776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v location Bus location 48876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret netdev Network device, or NULL 48976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 49076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstruct net_device * find_netdev_by_location ( unsigned int bus_type, 49176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned int location ) { 49276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct net_device *netdev; 49376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 49476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman list_for_each_entry ( netdev, &net_devices, list ) { 49576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( ( netdev->dev->desc.bus_type == bus_type ) && 49676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ( netdev->dev->desc.location == location ) ) 49776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return netdev; 49876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 49976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 50076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return NULL; 50176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 50276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 50376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 50476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Get most recently opened network device 50576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 50676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret netdev Most recently opened network device, or NULL 50776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 50876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstruct net_device * last_opened_netdev ( void ) { 50976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct net_device *netdev; 51076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 51176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman list_for_each_entry ( netdev, &open_net_devices, open_list ) { 51276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman assert ( netdev->state & NETDEV_OPEN ); 51376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return netdev; 51476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 51576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 51676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return NULL; 51776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 51876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 51976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 52076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Transmit network-layer packet 52176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 52276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v iobuf I/O buffer 52376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v netdev Network device 52476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v net_protocol Network-layer protocol 52576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v ll_dest Destination link-layer address 52676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret rc Return status code 52776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 52876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Prepends link-layer headers to the I/O buffer and transmits the 52976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * packet via the specified network device. This function takes 53076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * ownership of the I/O buffer. 53176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 53276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint net_tx ( struct io_buffer *iobuf, struct net_device *netdev, 53376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct net_protocol *net_protocol, const void *ll_dest ) { 53476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ll_protocol *ll_protocol = netdev->ll_protocol; 53576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int rc; 53676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 53776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Force a poll on the netdevice to (potentially) clear any 53876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * backed-up TX completions. This is needed on some network 53976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * devices to avoid excessive losses due to small TX ring 54076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * sizes. 54176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 54276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev_poll ( netdev ); 54376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 54476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Add link-layer header */ 54576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( ( rc = ll_protocol->push ( netdev, iobuf, ll_dest, netdev->ll_addr, 54676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman net_protocol->net_proto ) ) != 0 ) { 54776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman free_iob ( iobuf ); 54876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return rc; 54976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 55076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 55176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Transmit packet */ 55276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return netdev_tx ( netdev, iobuf ); 55376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 55476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 55576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 55676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Process received network-layer packet 55776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 55876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v iobuf I/O buffer 55976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v netdev Network device 56076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v net_proto Network-layer protocol, in network-byte order 56176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v ll_source Source link-layer address 56276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret rc Return status code 56376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 56476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint net_rx ( struct io_buffer *iobuf, struct net_device *netdev, 56576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint16_t net_proto, const void *ll_source ) { 56676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct net_protocol *net_protocol; 56776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 56876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Hand off to network-layer protocol, if any */ 56976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for_each_table_entry ( net_protocol, NET_PROTOCOLS ) { 57076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( net_protocol->net_proto == net_proto ) 57176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return net_protocol->rx ( iobuf, netdev, ll_source ); 57276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 57376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 57476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBGC ( netdev, "NETDEV %p unknown network protocol %04x\n", 57576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev, ntohs ( net_proto ) ); 57676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman free_iob ( iobuf ); 57776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 57876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 57976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 58076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 58176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Single-step the network stack 58276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 58376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v process Network stack process 58476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 58576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This polls all interfaces for received packets, and processes 58676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * packets from the RX queue. 58776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 58876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void net_step ( struct process *process __unused ) { 58976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct net_device *netdev; 59076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct io_buffer *iobuf; 59176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ll_protocol *ll_protocol; 59276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman const void *ll_dest; 59376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman const void *ll_source; 59476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint16_t net_proto; 59576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int rc; 59676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 59776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Poll and process each network device */ 59876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman list_for_each_entry ( netdev, &net_devices, list ) { 59976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 60076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Poll for new packets */ 60176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev_poll ( netdev ); 60276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 60376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Process at most one received packet. Give priority 60476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * to getting packets out of the NIC over processing 60576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * the received packets, because we advertise a window 60676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * that assumes that we can receive packets from the 60776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * NIC faster than they arrive. 60876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 60976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( ( iobuf = netdev_rx_dequeue ( netdev ) ) ) { 61076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 61176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBGC ( netdev, "NETDEV %p processing %p (%p+%zx)\n", 61276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev, iobuf, iobuf->data, 61376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman iob_len ( iobuf ) ); 61476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 61576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Remove link-layer header */ 61676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ll_protocol = netdev->ll_protocol; 61776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( ( rc = ll_protocol->pull ( netdev, iobuf, 61876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman &ll_dest, &ll_source, 61976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman &net_proto ) ) != 0 ) { 62076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman free_iob ( iobuf ); 62176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman continue; 62276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 62376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 62476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman net_rx ( iobuf, netdev, net_proto, ll_source ); 62576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 62676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 62776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 62876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 62976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** Networking stack process */ 63076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstruct process net_process __permanent_process = { 63176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .list = LIST_HEAD_INIT ( net_process.list ), 63276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .step = net_step, 63376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}; 634