diff options
author | RajithaY <rajithax.yerrumsetty@intel.com> | 2017-04-25 03:31:15 -0700 |
---|---|---|
committer | Rajitha Yerrumchetty <rajithax.yerrumsetty@intel.com> | 2017-05-22 06:48:08 +0000 |
commit | bb756eebdac6fd24e8919e2c43f7d2c8c4091f59 (patch) | |
tree | ca11e03542edf2d8f631efeca5e1626d211107e3 /qemu/roms/ipxe/src/net/rndis.c | |
parent | a14b48d18a9ed03ec191cf16b162206998a895ce (diff) |
Adding qemu as a submodule of KVMFORNFV
This Patch includes the changes to add qemu as a submodule to
kvmfornfv repo and make use of the updated latest qemu for the
execution of all testcase
Change-Id: I1280af507a857675c7f81d30c95255635667bdd7
Signed-off-by:RajithaY<rajithax.yerrumsetty@intel.com>
Diffstat (limited to 'qemu/roms/ipxe/src/net/rndis.c')
-rw-r--r-- | qemu/roms/ipxe/src/net/rndis.c | 1052 |
1 files changed, 0 insertions, 1052 deletions
diff --git a/qemu/roms/ipxe/src/net/rndis.c b/qemu/roms/ipxe/src/net/rndis.c deleted file mode 100644 index 8c4fe8b30..000000000 --- a/qemu/roms/ipxe/src/net/rndis.c +++ /dev/null @@ -1,1052 +0,0 @@ -/* - * Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - * You can also choose to distribute this program under the terms of - * the Unmodified Binary Distribution Licence (as given in the file - * COPYING.UBDL), provided that you have satisfied its requirements. - */ - -FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); - -/** @file - * - * Remote Network Driver Interface Specification - * - */ - -#include <unistd.h> -#include <string.h> -#include <errno.h> -#include <byteswap.h> -#include <ipxe/iobuf.h> -#include <ipxe/netdevice.h> -#include <ipxe/ethernet.h> -#include <ipxe/device.h> -#include <ipxe/rndis.h> - -/** - * Allocate I/O buffer - * - * @v len Length - * @ret iobuf I/O buffer, or NULL - */ -static struct io_buffer * rndis_alloc_iob ( size_t len ) { - struct rndis_header *header; - struct io_buffer *iobuf; - - /* Allocate I/O buffer and reserve space */ - iobuf = alloc_iob ( sizeof ( *header ) + len ); - if ( iobuf ) - iob_reserve ( iobuf, sizeof ( *header ) ); - - return iobuf; -} - -/** - * Wait for completion - * - * @v rndis RNDIS device - * @v wait_id Request ID - * @ret rc Return status code - */ -static int rndis_wait ( struct rndis_device *rndis, unsigned int wait_id ) { - unsigned int i; - - /* Record query ID */ - rndis->wait_id = wait_id; - - /* Wait for operation to complete */ - for ( i = 0 ; i < RNDIS_MAX_WAIT_MS ; i++ ) { - - /* Check for completion */ - if ( ! rndis->wait_id ) - return rndis->wait_rc; - - /* Poll RNDIS device */ - rndis->op->poll ( rndis ); - - /* Delay for 1ms */ - mdelay ( 1 ); - } - - DBGC ( rndis, "RNDIS %s timed out waiting for ID %#08x\n", - rndis->name, wait_id ); - return -ETIMEDOUT; -} - -/** - * Transmit message - * - * @v rndis RNDIS device - * @v iobuf I/O buffer - * @v type Message type - * @ret rc Return status code - */ -static int rndis_tx_message ( struct rndis_device *rndis, - struct io_buffer *iobuf, unsigned int type ) { - struct rndis_header *header; - int rc; - - /* Prepend RNDIS header */ - header = iob_push ( iobuf, sizeof ( *header ) ); - header->type = cpu_to_le32 ( type ); - header->len = cpu_to_le32 ( iob_len ( iobuf ) ); - - /* Transmit message */ - if ( ( rc = rndis->op->transmit ( rndis, iobuf ) ) != 0 ) { - DBGC ( rndis, "RNDIS %s could not transmit: %s\n", - rndis->name, strerror ( rc ) ); - return rc; - } - - return 0; -} - -/** - * Complete message transmission - * - * @v rndis RNDIS device - * @v iobuf I/O buffer - * @v rc Packet status code - */ -void rndis_tx_complete_err ( struct rndis_device *rndis, - struct io_buffer *iobuf, int rc ) { - struct net_device *netdev = rndis->netdev; - struct rndis_header *header; - size_t len = iob_len ( iobuf ); - - /* Sanity check */ - if ( len < sizeof ( *header ) ) { - DBGC ( rndis, "RNDIS %s completed underlength transmission:\n", - rndis->name ); - DBGC_HDA ( rndis, 0, iobuf->data, len ); - netdev_tx_err ( netdev, NULL, -EINVAL ); - return; - } - header = iobuf->data; - - /* Complete buffer */ - if ( header->type == cpu_to_le32 ( RNDIS_PACKET_MSG ) ) { - netdev_tx_complete_err ( netdev, iobuf, rc ); - } else { - free_iob ( iobuf ); - } -} - -/** - * Transmit data packet - * - * @v rndis RNDIS device - * @v iobuf I/O buffer - * @ret rc Return status code - */ -static int rndis_tx_data ( struct rndis_device *rndis, - struct io_buffer *iobuf ) { - struct rndis_packet_message *msg; - size_t len = iob_len ( iobuf ); - int rc; - - /* Prepend packet message header */ - msg = iob_push ( iobuf, sizeof ( *msg ) ); - memset ( msg, 0, sizeof ( *msg ) ); - msg->data.offset = cpu_to_le32 ( sizeof ( *msg ) ); - msg->data.len = cpu_to_le32 ( len ); - - /* Transmit message */ - if ( ( rc = rndis_tx_message ( rndis, iobuf, RNDIS_PACKET_MSG ) ) != 0 ) - return rc; - - return 0; -} - -/** - * Defer transmitted packet - * - * @v rndis RNDIS device - * @v iobuf I/O buffer - * @ret rc Return status code - * - * As with netdev_tx_defer(), the caller must ensure that space in the - * transmit descriptor ring is freed up before calling - * rndis_tx_complete(). - * - * Unlike netdev_tx_defer(), this call may fail. - */ -int rndis_tx_defer ( struct rndis_device *rndis, struct io_buffer *iobuf ) { - struct net_device *netdev = rndis->netdev; - struct rndis_header *header; - struct rndis_packet_message *msg; - - /* Fail unless this was a packet message. Only packet - * messages correspond to I/O buffers in the network device's - * TX queue; other messages cannot be deferred in this way. - */ - assert ( iob_len ( iobuf ) >= sizeof ( *header ) ); - header = iobuf->data; - if ( header->type != cpu_to_le32 ( RNDIS_PACKET_MSG ) ) - return -ENOTSUP; - - /* Strip RNDIS header and packet message header, to return - * this packet to the state in which we received it. - */ - iob_pull ( iobuf, ( sizeof ( *header ) + sizeof ( *msg ) ) ); - - /* Defer packet */ - netdev_tx_defer ( netdev, iobuf ); - - return 0; -} - -/** - * Receive data packet - * - * @v rndis RNDIS device - * @v iobuf I/O buffer - */ -static void rndis_rx_data ( struct rndis_device *rndis, - struct io_buffer *iobuf ) { - struct net_device *netdev = rndis->netdev; - struct rndis_packet_message *msg; - size_t len = iob_len ( iobuf ); - size_t data_offset; - size_t data_len; - int rc; - - /* Sanity check */ - if ( len < sizeof ( *msg ) ) { - DBGC ( rndis, "RNDIS %s received underlength data packet:\n", - rndis->name ); - DBGC_HDA ( rndis, 0, iobuf->data, len ); - rc = -EINVAL; - goto err_len; - } - msg = iobuf->data; - - /* Locate and sanity check data buffer */ - data_offset = le32_to_cpu ( msg->data.offset ); - data_len = le32_to_cpu ( msg->data.len ); - if ( ( data_offset > len ) || ( data_len > ( len - data_offset ) ) ) { - DBGC ( rndis, "RNDIS %s data packet data exceeds packet:\n", - rndis->name ); - DBGC_HDA ( rndis, 0, iobuf->data, len ); - rc = -EINVAL; - goto err_data; - } - - /* Strip non-data portions */ - iob_pull ( iobuf, data_offset ); - iob_unput ( iobuf, ( iob_len ( iobuf ) - data_len ) ); - - /* Hand off to network stack */ - netdev_rx ( netdev, iob_disown ( iobuf ) ); - - return; - - err_data: - err_len: - /* Report error to network stack */ - netdev_rx_err ( netdev, iob_disown ( iobuf ), rc ); -} - -/** - * Transmit initialisation message - * - * @v rndis RNDIS device - * @v id Request ID - * @ret rc Return status code - */ -static int rndis_tx_initialise ( struct rndis_device *rndis, unsigned int id ) { - struct io_buffer *iobuf; - struct rndis_initialise_message *msg; - int rc; - - /* Allocate I/O buffer */ - iobuf = rndis_alloc_iob ( sizeof ( *msg ) ); - if ( ! iobuf ) { - rc = -ENOMEM; - goto err_alloc; - } - - /* Construct message */ - msg = iob_put ( iobuf, sizeof ( *msg ) ); - memset ( msg, 0, sizeof ( *msg ) ); - msg->id = id; /* Non-endian */ - msg->major = cpu_to_le32 ( RNDIS_VERSION_MAJOR ); - msg->minor = cpu_to_le32 ( RNDIS_VERSION_MINOR ); - msg->mtu = cpu_to_le32 ( RNDIS_MTU ); - - /* Transmit message */ - if ( ( rc = rndis_tx_message ( rndis, iobuf, - RNDIS_INITIALISE_MSG ) ) != 0 ) - goto err_tx; - - return 0; - - err_tx: - free_iob ( iobuf ); - err_alloc: - return rc; -} - -/** - * Receive initialisation completion - * - * @v rndis RNDIS device - * @v iobuf I/O buffer - */ -static void rndis_rx_initialise ( struct rndis_device *rndis, - struct io_buffer *iobuf ) { - struct rndis_initialise_completion *cmplt; - size_t len = iob_len ( iobuf ); - unsigned int id; - int rc; - - /* Sanity check */ - if ( len < sizeof ( *cmplt ) ) { - DBGC ( rndis, "RNDIS %s received underlength initialisation " - "completion:\n", rndis->name ); - DBGC_HDA ( rndis, 0, iobuf->data, len ); - rc = -EINVAL; - goto err_len; - } - cmplt = iobuf->data; - - /* Extract request ID */ - id = cmplt->id; /* Non-endian */ - - /* Check status */ - if ( cmplt->status ) { - DBGC ( rndis, "RNDIS %s received initialisation completion " - "failure %#08x\n", rndis->name, - le32_to_cpu ( cmplt->status ) ); - rc = -EIO; - goto err_status; - } - - /* Success */ - rc = 0; - - err_status: - /* Record completion result if applicable */ - if ( id == rndis->wait_id ) { - rndis->wait_id = 0; - rndis->wait_rc = rc; - } - err_len: - free_iob ( iobuf ); -} - -/** - * Initialise RNDIS - * - * @v rndis RNDIS device - * @ret rc Return status code - */ -static int rndis_initialise ( struct rndis_device *rndis ) { - int rc; - - /* Transmit initialisation message */ - if ( ( rc = rndis_tx_initialise ( rndis, RNDIS_INIT_ID ) ) != 0 ) - return rc; - - /* Wait for response */ - if ( ( rc = rndis_wait ( rndis, RNDIS_INIT_ID ) ) != 0 ) - return rc; - - return 0; -} - -/** - * Transmit halt message - * - * @v rndis RNDIS device - * @ret rc Return status code - */ -static int rndis_tx_halt ( struct rndis_device *rndis ) { - struct io_buffer *iobuf; - struct rndis_halt_message *msg; - int rc; - - /* Allocate I/O buffer */ - iobuf = rndis_alloc_iob ( sizeof ( *msg ) ); - if ( ! iobuf ) { - rc = -ENOMEM; - goto err_alloc; - } - - /* Construct message */ - msg = iob_put ( iobuf, sizeof ( *msg ) ); - memset ( msg, 0, sizeof ( *msg ) ); - - /* Transmit message */ - if ( ( rc = rndis_tx_message ( rndis, iobuf, RNDIS_HALT_MSG ) ) != 0 ) - goto err_tx; - - return 0; - - err_tx: - free_iob ( iobuf ); - err_alloc: - return rc; -} - -/** - * Halt RNDIS - * - * @v rndis RNDIS device - * @ret rc Return status code - */ -static int rndis_halt ( struct rndis_device *rndis ) { - int rc; - - /* Transmit halt message */ - if ( ( rc = rndis_tx_halt ( rndis ) ) != 0 ) - return rc; - - return 0; -} - -/** - * Transmit OID message - * - * @v rndis RNDIS device - * @v oid Object ID - * @v data New OID value (or NULL to query current value) - * @v len Length of new OID value - * @ret rc Return status code - */ -static int rndis_tx_oid ( struct rndis_device *rndis, unsigned int oid, - const void *data, size_t len ) { - struct io_buffer *iobuf; - struct rndis_oid_message *msg; - unsigned int type; - int rc; - - /* Allocate I/O buffer */ - iobuf = rndis_alloc_iob ( sizeof ( *msg ) + len ); - if ( ! iobuf ) { - rc = -ENOMEM; - goto err_alloc; - } - - /* Construct message. We use the OID as the request ID. */ - msg = iob_put ( iobuf, sizeof ( *msg ) ); - memset ( msg, 0, sizeof ( *msg ) ); - msg->id = oid; /* Non-endian */ - msg->oid = cpu_to_le32 ( oid ); - msg->offset = cpu_to_le32 ( sizeof ( *msg ) ); - msg->len = cpu_to_le32 ( len ); - memcpy ( iob_put ( iobuf, len ), data, len ); - - /* Transmit message */ - type = ( data ? RNDIS_SET_MSG : RNDIS_QUERY_MSG ); - if ( ( rc = rndis_tx_message ( rndis, iobuf, type ) ) != 0 ) - goto err_tx; - - return 0; - - err_tx: - free_iob ( iobuf ); - err_alloc: - return rc; -} - -/** - * Receive query OID completion - * - * @v rndis RNDIS device - * @v iobuf I/O buffer - */ -static void rndis_rx_query_oid ( struct rndis_device *rndis, - struct io_buffer *iobuf ) { - struct net_device *netdev = rndis->netdev; - struct rndis_query_completion *cmplt; - size_t len = iob_len ( iobuf ); - size_t info_offset; - size_t info_len; - unsigned int id; - void *info; - uint32_t *link_status; - int rc; - - /* Sanity check */ - if ( len < sizeof ( *cmplt ) ) { - DBGC ( rndis, "RNDIS %s received underlength query " - "completion:\n", rndis->name ); - DBGC_HDA ( rndis, 0, iobuf->data, len ); - rc = -EINVAL; - goto err_len; - } - cmplt = iobuf->data; - - /* Extract request ID */ - id = cmplt->id; /* Non-endian */ - - /* Check status */ - if ( cmplt->status ) { - DBGC ( rndis, "RNDIS %s received query completion failure " - "%#08x\n", rndis->name, le32_to_cpu ( cmplt->status ) ); - DBGC_HDA ( rndis, 0, iobuf->data, len ); - rc = -EIO; - goto err_status; - } - - /* Locate and sanity check information buffer */ - info_offset = le32_to_cpu ( cmplt->offset ); - info_len = le32_to_cpu ( cmplt->len ); - if ( ( info_offset > len ) || ( info_len > ( len - info_offset ) ) ) { - DBGC ( rndis, "RNDIS %s query completion information exceeds " - "packet:\n", rndis->name ); - DBGC_HDA ( rndis, 0, iobuf->data, len ); - rc = -EINVAL; - goto err_info; - } - info = ( ( ( void * ) cmplt ) + info_offset ); - - /* Handle OID */ - switch ( id ) { - - case RNDIS_OID_802_3_PERMANENT_ADDRESS: - if ( info_len > sizeof ( netdev->hw_addr ) ) - info_len = sizeof ( netdev->hw_addr ); - memcpy ( netdev->hw_addr, info, info_len ); - break; - - case RNDIS_OID_802_3_CURRENT_ADDRESS: - if ( info_len > sizeof ( netdev->ll_addr ) ) - info_len = sizeof ( netdev->ll_addr ); - memcpy ( netdev->ll_addr, info, info_len ); - break; - - case RNDIS_OID_GEN_MEDIA_CONNECT_STATUS: - if ( info_len != sizeof ( *link_status ) ) { - DBGC ( rndis, "RNDIS %s invalid link status:\n", - rndis->name ); - DBGC_HDA ( rndis, 0, iobuf->data, len ); - rc = -EPROTO; - goto err_link_status; - } - link_status = info; - if ( *link_status == 0 ) { - DBGC ( rndis, "RNDIS %s link is up\n", rndis->name ); - netdev_link_up ( netdev ); - } else { - DBGC ( rndis, "RNDIS %s link is down: %#08x\n", - rndis->name, le32_to_cpu ( *link_status ) ); - netdev_link_down ( netdev ); - } - break; - - default: - DBGC ( rndis, "RNDIS %s unexpected query completion ID %#08x\n", - rndis->name, id ); - DBGC_HDA ( rndis, 0, iobuf->data, len ); - rc = -EPROTO; - goto err_id; - } - - /* Success */ - rc = 0; - - err_id: - err_link_status: - err_info: - err_status: - /* Record completion result if applicable */ - if ( id == rndis->wait_id ) { - rndis->wait_id = 0; - rndis->wait_rc = rc; - } - err_len: - /* Free I/O buffer */ - free_iob ( iobuf ); -} - -/** - * Receive set OID completion - * - * @v rndis RNDIS device - * @v iobuf I/O buffer - */ -static void rndis_rx_set_oid ( struct rndis_device *rndis, - struct io_buffer *iobuf ) { - struct rndis_set_completion *cmplt; - size_t len = iob_len ( iobuf ); - unsigned int id; - int rc; - - /* Sanity check */ - if ( len < sizeof ( *cmplt ) ) { - DBGC ( rndis, "RNDIS %s received underlength set completion:\n", - rndis->name ); - DBGC_HDA ( rndis, 0, iobuf->data, len ); - rc = -EINVAL; - goto err_len; - } - cmplt = iobuf->data; - - /* Extract request ID */ - id = cmplt->id; /* Non-endian */ - - /* Check status */ - if ( cmplt->status ) { - DBGC ( rndis, "RNDIS %s received set completion failure " - "%#08x\n", rndis->name, le32_to_cpu ( cmplt->status ) ); - DBGC_HDA ( rndis, 0, iobuf->data, len ); - rc = -EIO; - goto err_status; - } - - /* Success */ - rc = 0; - - err_status: - /* Record completion result if applicable */ - if ( id == rndis->wait_id ) { - rndis->wait_id = 0; - rndis->wait_rc = rc; - } - err_len: - /* Free I/O buffer */ - free_iob ( iobuf ); -} - -/** - * Query or set OID - * - * @v rndis RNDIS device - * @v oid Object ID - * @v data New OID value (or NULL to query current value) - * @v len Length of new OID value - * @ret rc Return status code - */ -static int rndis_oid ( struct rndis_device *rndis, unsigned int oid, - const void *data, size_t len ) { - int rc; - - /* Transmit query */ - if ( ( rc = rndis_tx_oid ( rndis, oid, data, len ) ) != 0 ) - return rc; - - /* Wait for response */ - if ( ( rc = rndis_wait ( rndis, oid ) ) != 0 ) - return rc; - - return 0; -} - -/** - * Receive indicate status message - * - * @v rndis RNDIS device - * @v iobuf I/O buffer - */ -static void rndis_rx_status ( struct rndis_device *rndis, - struct io_buffer *iobuf ) { - struct net_device *netdev = rndis->netdev; - struct rndis_indicate_status_message *msg; - size_t len = iob_len ( iobuf ); - unsigned int status; - int rc; - - /* Sanity check */ - if ( len < sizeof ( *msg ) ) { - DBGC ( rndis, "RNDIS %s received underlength status message:\n", - rndis->name ); - DBGC_HDA ( rndis, 0, iobuf->data, len ); - rc = -EINVAL; - goto err_len; - } - msg = iobuf->data; - - /* Extract status */ - status = le32_to_cpu ( msg->status ); - - /* Handle status */ - switch ( msg->status ) { - - case RNDIS_STATUS_MEDIA_CONNECT: - DBGC ( rndis, "RNDIS %s link is up\n", rndis->name ); - netdev_link_up ( netdev ); - break; - - case RNDIS_STATUS_MEDIA_DISCONNECT: - DBGC ( rndis, "RNDIS %s link is down\n", rndis->name ); - netdev_link_down ( netdev ); - break; - - case RNDIS_STATUS_WTF_WORLD: - /* Ignore */ - break; - - default: - DBGC ( rndis, "RNDIS %s unexpected status %#08x:\n", - rndis->name, status ); - DBGC_HDA ( rndis, 0, iobuf->data, len ); - rc = -ENOTSUP; - goto err_status; - } - - /* Free I/O buffer */ - free_iob ( iobuf ); - - return; - - err_status: - err_len: - /* Report error via network device statistics */ - netdev_rx_err ( netdev, iobuf, rc ); -} - -/** - * Receive RNDIS message - * - * @v rndis RNDIS device - * @v iobuf I/O buffer - * @v type Message type - */ -static void rndis_rx_message ( struct rndis_device *rndis, - struct io_buffer *iobuf, unsigned int type ) { - struct net_device *netdev = rndis->netdev; - int rc; - - /* Handle packet */ - switch ( type ) { - - case RNDIS_PACKET_MSG: - rndis_rx_data ( rndis, iob_disown ( iobuf ) ); - break; - - case RNDIS_INITIALISE_CMPLT: - rndis_rx_initialise ( rndis, iob_disown ( iobuf ) ); - break; - - case RNDIS_QUERY_CMPLT: - rndis_rx_query_oid ( rndis, iob_disown ( iobuf ) ); - break; - - case RNDIS_SET_CMPLT: - rndis_rx_set_oid ( rndis, iob_disown ( iobuf ) ); - break; - - case RNDIS_INDICATE_STATUS_MSG: - rndis_rx_status ( rndis, iob_disown ( iobuf ) ); - break; - - default: - DBGC ( rndis, "RNDIS %s received unexpected type %#08x\n", - rndis->name, type ); - DBGC_HDA ( rndis, 0, iobuf->data, iob_len ( iobuf ) ); - rc = -EPROTO; - goto err_type; - } - - return; - - err_type: - /* Report error via network device statistics */ - netdev_rx_err ( netdev, iobuf, rc ); -} - -/** - * Receive packet from underlying transport layer - * - * @v rndis RNDIS device - * @v iobuf I/O buffer - */ -void rndis_rx ( struct rndis_device *rndis, struct io_buffer *iobuf ) { - struct net_device *netdev = rndis->netdev; - struct rndis_header *header; - unsigned int type; - int rc; - - /* Sanity check */ - if ( iob_len ( iobuf ) < sizeof ( *header ) ) { - DBGC ( rndis, "RNDIS %s received underlength packet:\n", - rndis->name ); - DBGC_HDA ( rndis, 0, iobuf->data, iob_len ( iobuf ) ); - rc = -EINVAL; - goto drop; - } - header = iobuf->data; - - /* Parse and strip header */ - type = le32_to_cpu ( header->type ); - iob_pull ( iobuf, sizeof ( *header ) ); - - /* Handle message */ - rndis_rx_message ( rndis, iob_disown ( iobuf ), type ); - - return; - - drop: - /* Record error */ - netdev_rx_err ( netdev, iob_disown ( iobuf ), rc ); -} - -/** - * Discard packet from underlying transport layer - * - * @v rndis RNDIS device - * @v iobuf I/O buffer - * @v rc Packet status code - */ -void rndis_rx_err ( struct rndis_device *rndis, struct io_buffer *iobuf, - int rc ) { - struct net_device *netdev = rndis->netdev; - - /* Record error */ - netdev_rx_err ( netdev, iob_disown ( iobuf ), rc ); -} - -/** - * Set receive filter - * - * @v rndis RNDIS device - * @v filter Receive filter - * @ret rc Return status code - */ -static int rndis_filter ( struct rndis_device *rndis, unsigned int filter ) { - uint32_t value = cpu_to_le32 ( filter ); - int rc; - - /* Set receive filter */ - if ( ( rc = rndis_oid ( rndis, RNDIS_OID_GEN_CURRENT_PACKET_FILTER, - &value, sizeof ( value ) ) ) != 0 ) { - DBGC ( rndis, "RNDIS %s could not set receive filter to %#08x: " - "%s\n", rndis->name, filter, strerror ( rc ) ); - return rc; - } - - return 0; -} - -/** - * Open network device - * - * @v netdev Network device - * @ret rc Return status code - */ -static int rndis_open ( struct net_device *netdev ) { - struct rndis_device *rndis = netdev->priv; - int rc; - - /* Open RNDIS device */ - if ( ( rc = rndis->op->open ( rndis ) ) != 0 ) { - DBGC ( rndis, "RNDIS %s could not open: %s\n", - rndis->name, strerror ( rc ) ); - goto err_open; - } - - /* Initialise RNDIS */ - if ( ( rc = rndis_initialise ( rndis ) ) != 0 ) - goto err_initialise; - - /* Set receive filter */ - if ( ( rc = rndis_filter ( rndis, ( RNDIS_FILTER_UNICAST | - RNDIS_FILTER_MULTICAST | - RNDIS_FILTER_ALL_MULTICAST | - RNDIS_FILTER_BROADCAST | - RNDIS_FILTER_PROMISCUOUS ) ) ) != 0) - goto err_set_filter; - - /* Update link status */ - if ( ( rc = rndis_oid ( rndis, RNDIS_OID_GEN_MEDIA_CONNECT_STATUS, - NULL, 0 ) ) != 0 ) - goto err_query_link; - - return 0; - - err_query_link: - err_set_filter: - rndis_halt ( rndis ); - err_initialise: - rndis->op->close ( rndis ); - err_open: - return rc; -} - -/** - * Close network device - * - * @v netdev Network device - */ -static void rndis_close ( struct net_device *netdev ) { - struct rndis_device *rndis = netdev->priv; - - /* Clear receive filter */ - rndis_filter ( rndis, 0 ); - - /* Halt RNDIS device */ - rndis_halt ( rndis ); - - /* Close RNDIS device */ - rndis->op->close ( rndis ); -} - -/** - * Transmit packet - * - * @v netdev Network device - * @v iobuf I/O buffer - * @ret rc Return status code - */ -static int rndis_transmit ( struct net_device *netdev, - struct io_buffer *iobuf ) { - struct rndis_device *rndis = netdev->priv; - - /* Transmit data packet */ - return rndis_tx_data ( rndis, iobuf ); -} - -/** - * Poll for completed and received packets - * - * @v netdev Network device - */ -static void rndis_poll ( struct net_device *netdev ) { - struct rndis_device *rndis = netdev->priv; - - /* Poll RNDIS device */ - rndis->op->poll ( rndis ); -} - -/** Network device operations */ -static struct net_device_operations rndis_operations = { - .open = rndis_open, - .close = rndis_close, - .transmit = rndis_transmit, - .poll = rndis_poll, -}; - -/** - * Allocate RNDIS device - * - * @v priv_len Length of private data - * @ret rndis RNDIS device, or NULL on allocation failure - */ -struct rndis_device * alloc_rndis ( size_t priv_len ) { - struct net_device *netdev; - struct rndis_device *rndis; - - /* Allocate and initialise structure */ - netdev = alloc_etherdev ( sizeof ( *rndis ) + priv_len ); - if ( ! netdev ) - return NULL; - netdev_init ( netdev, &rndis_operations ); - rndis = netdev->priv; - rndis->netdev = netdev; - rndis->priv = ( ( ( void * ) rndis ) + sizeof ( *rndis ) ); - - return rndis; -} - -/** - * Register RNDIS device - * - * @v rndis RNDIS device - * @ret rc Return status code - * - * Note that this routine will open and use the RNDIS device in order - * to query the MAC address. The device must be immediately ready for - * use prior to registration. - */ -int register_rndis ( struct rndis_device *rndis ) { - struct net_device *netdev = rndis->netdev; - int rc; - - /* Assign device name (for debugging) */ - rndis->name = netdev->dev->name; - - /* Register network device */ - if ( ( rc = register_netdev ( netdev ) ) != 0 ) { - DBGC ( rndis, "RNDIS %s could not register: %s\n", - rndis->name, strerror ( rc ) ); - goto err_register; - } - - /* Open RNDIS device to read MAC addresses */ - if ( ( rc = rndis->op->open ( rndis ) ) != 0 ) { - DBGC ( rndis, "RNDIS %s could not open: %s\n", - rndis->name, strerror ( rc ) ); - goto err_open; - } - - /* Initialise RNDIS */ - if ( ( rc = rndis_initialise ( rndis ) ) != 0 ) - goto err_initialise; - - /* Query permanent MAC address */ - if ( ( rc = rndis_oid ( rndis, RNDIS_OID_802_3_PERMANENT_ADDRESS, - NULL, 0 ) ) != 0 ) - goto err_query_permanent; - - /* Query current MAC address */ - if ( ( rc = rndis_oid ( rndis, RNDIS_OID_802_3_CURRENT_ADDRESS, - NULL, 0 ) ) != 0 ) - goto err_query_current; - - /* Get link status */ - if ( ( rc = rndis_oid ( rndis, RNDIS_OID_GEN_MEDIA_CONNECT_STATUS, - NULL, 0 ) ) != 0 ) - goto err_query_link; - - /* Halt RNDIS device */ - rndis_halt ( rndis ); - - /* Close RNDIS device */ - rndis->op->close ( rndis ); - - return 0; - - err_query_link: - err_query_current: - err_query_permanent: - rndis_halt ( rndis ); - err_initialise: - rndis->op->close ( rndis ); - err_open: - unregister_netdev ( netdev ); - err_register: - return rc; -} - -/** - * Unregister RNDIS device - * - * @v rndis RNDIS device - */ -void unregister_rndis ( struct rndis_device *rndis ) { - struct net_device *netdev = rndis->netdev; - - /* Unregister network device */ - unregister_netdev ( netdev ); -} - -/** - * Free RNDIS device - * - * @v rndis RNDIS device - */ -void free_rndis ( struct rndis_device *rndis ) { - struct net_device *netdev = rndis->netdev; - - /* Free network device */ - netdev_nullify ( netdev ); - netdev_put ( netdev ); -} |