[rndis] Clear receive filter when closing the device

On Windows Server 2012 R2, closing and reopening the device will
sometimes result in a non-functional RX datapath.  The root cause is
unknown.  Clearing the receive filter before closing the device seems
to fix the problem.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
pull/33/head
Michael Brown 2014-12-20 12:06:35 +00:00
parent cd68d93b6e
commit 67291465ea
1 changed files with 30 additions and 11 deletions

View File

@ -828,6 +828,28 @@ void rndis_rx ( struct rndis_device *rndis, struct io_buffer *iobuf ) {
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
*
@ -836,7 +858,6 @@ void rndis_rx ( struct rndis_device *rndis, struct io_buffer *iobuf ) {
*/
static int rndis_open ( struct net_device *netdev ) {
struct rndis_device *rndis = netdev->priv;
uint32_t filter;
int rc;
/* Open RNDIS device */
@ -851,17 +872,12 @@ static int rndis_open ( struct net_device *netdev ) {
goto err_initialise;
/* Set receive filter */
filter = cpu_to_le32 ( RNDIS_FILTER_UNICAST |
RNDIS_FILTER_MULTICAST |
RNDIS_FILTER_ALL_MULTICAST |
RNDIS_FILTER_BROADCAST |
RNDIS_FILTER_PROMISCUOUS );
if ( ( rc = rndis_oid ( rndis, RNDIS_OID_GEN_CURRENT_PACKET_FILTER,
&filter, sizeof ( filter ) ) ) != 0 ) {
DBGC ( rndis, "RNDIS %s could not set receive filter: %s\n",
rndis->name, strerror ( rc ) );
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,
@ -887,6 +903,9 @@ static int rndis_open ( struct net_device *netdev ) {
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 );