static void rndis_unbind(struct usbnet *dev, struct usb_interface *intf)
{
	struct rndis_halt	*halt;

	/* try to clear any rndis state/activity (no i/o from stack!) */
	halt = kzalloc(sizeof *halt, GFP_KERNEL);
	if (halt) {
		halt->msg_type = RNDIS_MSG_HALT;
		halt->msg_len = ccpu2(sizeof *halt);
		(void) rndis_command(dev, (void *)halt);
		kfree(halt);
	}

	return usbnet_cdc_unbind(dev, intf);
}
Exemplo n.º 2
0
void rndis_unbind(struct usbnet *dev, struct usb_interface *intf)
{
    struct rndis_halt	*halt;

    /* try to clear any rndis state/activity (no i/o from stack!) */
    halt = kzalloc(CONTROL_BUFFER_SIZE, GFP_KERNEL);
    if (halt) {
        halt->msg_type = cpu_to_le32(RNDIS_MSG_HALT);
        halt->msg_len = cpu_to_le32(sizeof *halt);
        (void) rndis_command(dev, (void *)halt, CONTROL_BUFFER_SIZE);
        kfree(halt);
    }

    usbnet_cdc_unbind(dev, intf);
}
Exemplo n.º 3
0
void rndis_unbind(struct usbnet *dev, struct usb_interface *intf)
{
	struct rndis_halt	*halt;

	
	halt = kzalloc(CONTROL_BUFFER_SIZE, GFP_KERNEL);
	if (halt) {
		halt->msg_type = RNDIS_MSG_HALT;
		halt->msg_len = cpu_to_le32(sizeof *halt);
		(void) rndis_command(dev, (void *)halt, CONTROL_BUFFER_SIZE);
		kfree(halt);
	}

	usbnet_cdc_unbind(dev, intf);
}
/*
 * rndis_query:
 *
 * Performs a query for @oid along with 0 or more bytes of payload as
 * specified by @in_len. If @reply_len is not set to -1 then the reply
 * length is checked against this value, resulting in an error if it
 * doesn't match.
 *
 * NOTE: Adding a payload exactly or greater than the size of the expected
 * response payload is an evident requirement MSFT added for ActiveSync.
 *
 * The only exception is for OIDs that return a variably sized response,
 * in which case no payload should be added.  This undocumented (and
 * nonsensical!) issue was found by sniffing protocol requests from the
 * ActiveSync 4.1 Windows driver.
 */
static int rndis_query(struct usbnet *dev, struct usb_interface *intf,
		void *buf, u32 oid, u32 in_len,
		void **reply, int *reply_len)
{
	int retval;
	union {
		void			*buf;
		struct rndis_msg_hdr	*header;
		struct rndis_query	*get;
		struct rndis_query_c	*get_c;
	} u;
	u32 off, len;

	u.buf = buf;

	memset(u.get, 0, sizeof *u.get + in_len);
	u.get->msg_type = RNDIS_MSG_QUERY;
	u.get->msg_len = cpu_to_le32(sizeof *u.get + in_len);
	u.get->oid = oid;
	u.get->len = cpu_to_le32(in_len);
	u.get->offset = ccpu2(20);

	retval = rndis_command(dev, u.header);
	if (unlikely(retval < 0)) {
		dev_err(&intf->dev, "RNDIS_MSG_QUERY(0x%08x) failed, %d\n",
				oid, retval);
		return retval;
	}

	off = le32_to_cpu(u.get_c->offset);
	len = le32_to_cpu(u.get_c->len);
	if (unlikely((8 + off + len) > CONTROL_BUFFER_SIZE))
		goto response_error;

	if (*reply_len != -1 && len != *reply_len)
		goto response_error;

	*reply = (unsigned char *) &u.get_c->request_id + off;
	*reply_len = len;

	return retval;

response_error:
	dev_err(&intf->dev, "RNDIS_MSG_QUERY(0x%08x) "
			"invalid response - off %d len %d\n",
		oid, off, len);
	return -EDOM;
}
static int rndis_bind(struct usbnet *dev, struct usb_interface *intf)
{
	int			retval;
	struct net_device	*net = dev->net;
	struct cdc_state	*info = (void *) &dev->data;
	union {
		void			*buf;
		struct rndis_msg_hdr	*header;
		struct rndis_init	*init;
		struct rndis_init_c	*init_c;
		struct rndis_query	*get;
		struct rndis_query_c	*get_c;
		struct rndis_set	*set;
		struct rndis_set_c	*set_c;
	} u;
	u32			tmp;
	int			reply_len;
	unsigned char		*bp;

	/* we can't rely on i/o from stack working, or stack allocation */
	u.buf = kmalloc(CONTROL_BUFFER_SIZE, GFP_KERNEL);
	if (!u.buf)
		return -ENOMEM;
	retval = usbnet_generic_cdc_bind(dev, intf);
	if (retval < 0)
		goto fail;

	u.init->msg_type = RNDIS_MSG_INIT;
	u.init->msg_len = ccpu2(sizeof *u.init);
	u.init->major_version = ccpu2(1);
	u.init->minor_version = ccpu2(0);

	/* max transfer (in spec) is 0x4000 at full speed, but for
	 * TX we'll stick to one Ethernet packet plus RNDIS framing.
	 * For RX we handle drivers that zero-pad to end-of-packet.
	 * Don't let userspace change these settings.
	 *
	 * NOTE: there still seems to be wierdness here, as if we need
	 * to do some more things to make sure WinCE targets accept this.
	 * They default to jumbograms of 8KB or 16KB, which is absurd
	 * for such low data rates and which is also more than Linux
	 * can usually expect to allocate for SKB data...
	 */
	net->hard_header_len += sizeof (struct rndis_data_hdr);
	dev->hard_mtu = net->mtu + net->hard_header_len;

        dev->maxpacket = usb_maxpacket(dev->udev, dev->out, 1);
        if (dev->maxpacket == 0) {
                if (netif_msg_probe(dev))
                        dev_dbg(&intf->dev, "dev->maxpacket can't be 0\n");
                retval = -EINVAL;
                goto fail_and_release;
        }

	dev->rx_urb_size = dev->hard_mtu + (dev->maxpacket + 1);
	dev->rx_urb_size &= ~(dev->maxpacket - 1);
	u.init->max_transfer_size = cpu_to_le32(dev->rx_urb_size);

	net->change_mtu = NULL;
	retval = rndis_command(dev, u.header);
	if (unlikely(retval < 0)) {
		/* it might not even be an RNDIS device!! */
		dev_err(&intf->dev, "RNDIS init failed, %d\n", retval);
		goto fail_and_release;
	}
	tmp = le32_to_cpu(u.init_c->max_transfer_size);
	if (tmp < dev->hard_mtu) {
		dev_err(&intf->dev,
			"dev can't take %u byte packets (max %u)\n",
			dev->hard_mtu, tmp);
		retval = -EINVAL;
		goto fail_and_release;
	}

	/* REVISIT:  peripheral "alignment" request is ignored ... */
	dev_dbg(&intf->dev,
		"hard mtu %u (%u from dev), rx buflen %Zu, align %d\n",
		dev->hard_mtu, tmp, dev->rx_urb_size,
		1 << le32_to_cpu(u.init_c->packet_alignment));

	/* Get designated host ethernet address */
	reply_len = ETH_ALEN;
	retval = rndis_query(dev, intf, u.buf, OID_802_3_PERMANENT_ADDRESS,
			48, (void **) &bp, &reply_len);
	if (unlikely(retval< 0)) {
		dev_err(&intf->dev, "rndis get ethaddr, %d\n", retval);
		goto fail_and_release;
	}
	memcpy(net->dev_addr, bp, ETH_ALEN);

	/* set a nonzero filter to enable data transfers */
	memset(u.set, 0, sizeof *u.set);
	u.set->msg_type = RNDIS_MSG_SET;
	u.set->msg_len = ccpu2(4 + sizeof *u.set);
	u.set->oid = OID_GEN_CURRENT_PACKET_FILTER;
	u.set->len = ccpu2(4);
	u.set->offset = ccpu2((sizeof *u.set) - 8);
	*(__le32 *)(u.buf + sizeof *u.set) = ccpu2(DEFAULT_FILTER);

	retval = rndis_command(dev, u.header);
	if (unlikely(retval < 0)) {
		dev_err(&intf->dev, "rndis set packet filter, %d\n", retval);
		goto fail_and_release;
	}

	retval = 0;

	kfree(u.buf);
	return retval;

fail_and_release:
	usb_set_intfdata(info->data, NULL);
	usb_driver_release_interface(driver_of(intf), info->data);
	info->data = NULL;
fail:
	kfree(u.buf);
	return retval;
}
Exemplo n.º 6
0
int
generic_rndis_bind(struct usbnet *dev, struct usb_interface *intf, int flags)
{
    int			retval;
    struct net_device	*net = dev->net;
    struct cdc_state	*info = (void *) &dev->data;
    union {
        void			*buf;
        struct rndis_msg_hdr	*header;
        struct rndis_init	*init;
        struct rndis_init_c	*init_c;
        struct rndis_query	*get;
        struct rndis_query_c	*get_c;
        struct rndis_set	*set;
        struct rndis_set_c	*set_c;
        struct rndis_halt	*halt;
    } u;
    u32			tmp;
    __le32			phym_unspec, *phym;
    int			reply_len;
    unsigned char		*bp;

    /* we can't rely on i/o from stack working, or stack allocation */
    u.buf = kmalloc(CONTROL_BUFFER_SIZE, GFP_KERNEL);
    if (!u.buf)
        return -ENOMEM;
    retval = usbnet_generic_cdc_bind(dev, intf);
    if (retval < 0)
        goto fail;

    u.init->msg_type = cpu_to_le32(RNDIS_MSG_INIT);
    u.init->msg_len = cpu_to_le32(sizeof *u.init);
    u.init->major_version = cpu_to_le32(1);
    u.init->minor_version = cpu_to_le32(0);

#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29))
    /* can't we remove this? */
    net->change_mtu = NULL;
#endif

    /* max transfer (in spec) is 0x4000 at full speed, but for
     * TX we'll stick to one Ethernet packet plus RNDIS framing.
     * For RX we handle drivers that zero-pad to end-of-packet.
     * Don't let userspace change these settings.
     *
     * NOTE: there still seems to be wierdness here, as if we need
     * to do some more things to make sure WinCE targets accept this.
     * They default to jumbograms of 8KB or 16KB, which is absurd
     * for such low data rates and which is also more than Linux
     * can usually expect to allocate for SKB data...
     */
    net->hard_header_len += sizeof (struct rndis_data_hdr);
    dev->hard_mtu = net->mtu + net->hard_header_len;

    dev->maxpacket = usb_maxpacket(dev->udev, dev->out, 1);
    if (dev->maxpacket == 0) {
        netif_dbg(dev, probe, dev->net,
                  "dev->maxpacket can't be 0\n");
        retval = -EINVAL;
        goto fail_and_release;
    }

    dev->rx_urb_size = dev->hard_mtu + (dev->maxpacket + 1);
    dev->rx_urb_size &= ~(dev->maxpacket - 1);
    u.init->max_transfer_size = cpu_to_le32(dev->rx_urb_size);

    netdev_attach_ops(net, &rndis_netdev_ops);

    retval = rndis_command(dev, u.header, CONTROL_BUFFER_SIZE);
    if (unlikely(retval < 0)) {
        /* it might not even be an RNDIS device!! */
        dev_err(&intf->dev, "RNDIS init failed, %d\n", retval);
        goto fail_and_release;
    }
    tmp = le32_to_cpu(u.init_c->max_transfer_size);
    if (tmp < dev->hard_mtu) {
        if (tmp <= net->hard_header_len) {
            dev_err(&intf->dev,
                    "dev can't take %u byte packets (max %u)\n",
                    dev->hard_mtu, tmp);
            retval = -EINVAL;
            goto halt_fail_and_release;
        }
        dev_warn(&intf->dev,
                 "dev can't take %u byte packets (max %u), "
                 "adjusting MTU to %u\n",
                 dev->hard_mtu, tmp, tmp - net->hard_header_len);
        dev->hard_mtu = tmp;
        net->mtu = dev->hard_mtu - net->hard_header_len;
    }

    /* REVISIT:  peripheral "alignment" request is ignored ... */
    dev_dbg(&intf->dev,
            "hard mtu %u (%u from dev), rx buflen %Zu, align %d\n",
            dev->hard_mtu, tmp, dev->rx_urb_size,
            1 << le32_to_cpu(u.init_c->packet_alignment));

    /* module has some device initialization code needs to be done right
     * after RNDIS_INIT */
    if (dev->driver_info->early_init &&
            dev->driver_info->early_init(dev) != 0)
        goto halt_fail_and_release;

    /* Check physical medium */
    phym = NULL;
    reply_len = sizeof *phym;
    retval = rndis_query(dev, intf, u.buf,
                         RNDIS_OID_GEN_PHYSICAL_MEDIUM,
                         0, (void **) &phym, &reply_len);
    if (retval != 0 || !phym) {
        /* OID is optional so don't fail here. */
        phym_unspec = cpu_to_le32(RNDIS_PHYSICAL_MEDIUM_UNSPECIFIED);
        phym = &phym_unspec;
    }
    if ((flags & FLAG_RNDIS_PHYM_WIRELESS) &&
            le32_to_cpup(phym) != RNDIS_PHYSICAL_MEDIUM_WIRELESS_LAN) {
        netif_dbg(dev, probe, dev->net,
                  "driver requires wireless physical medium, but device is not\n");
        retval = -ENODEV;
        goto halt_fail_and_release;
    }
    if ((flags & FLAG_RNDIS_PHYM_NOT_WIRELESS) &&
            le32_to_cpup(phym) == RNDIS_PHYSICAL_MEDIUM_WIRELESS_LAN) {
        netif_dbg(dev, probe, dev->net,
                  "driver requires non-wireless physical medium, but device is wireless.\n");
        retval = -ENODEV;
        goto halt_fail_and_release;
    }

    /* Get designated host ethernet address */
    reply_len = ETH_ALEN;
    retval = rndis_query(dev, intf, u.buf,
                         RNDIS_OID_802_3_PERMANENT_ADDRESS,
                         48, (void **) &bp, &reply_len);
    if (unlikely(retval< 0)) {
        dev_err(&intf->dev, "rndis get ethaddr, %d\n", retval);
        goto halt_fail_and_release;
    }
    memcpy(net->dev_addr, bp, ETH_ALEN);
    memcpy(net->perm_addr, bp, ETH_ALEN);

    /* set a nonzero filter to enable data transfers */
    memset(u.set, 0, sizeof *u.set);
    u.set->msg_type = cpu_to_le32(RNDIS_MSG_SET);
    u.set->msg_len = cpu_to_le32(4 + sizeof *u.set);
    u.set->oid = cpu_to_le32(RNDIS_OID_GEN_CURRENT_PACKET_FILTER);
    u.set->len = cpu_to_le32(4);
    u.set->offset = cpu_to_le32((sizeof *u.set) - 8);
    *(__le32 *)(u.buf + sizeof *u.set) = cpu_to_le32(RNDIS_DEFAULT_FILTER);

    retval = rndis_command(dev, u.header, CONTROL_BUFFER_SIZE);
    if (unlikely(retval < 0)) {
        dev_err(&intf->dev, "rndis set packet filter, %d\n", retval);
        goto halt_fail_and_release;
    }

    retval = 0;

    kfree(u.buf);
    return retval;

halt_fail_and_release:
    memset(u.halt, 0, sizeof *u.halt);
    u.halt->msg_type = cpu_to_le32(RNDIS_MSG_HALT);
    u.halt->msg_len = cpu_to_le32(sizeof *u.halt);
    (void) rndis_command(dev, (void *)u.halt, CONTROL_BUFFER_SIZE);
fail_and_release:
    usb_set_intfdata(info->data, NULL);
    usb_driver_release_interface(driver_of(intf), info->data);
    info->data = NULL;
fail:
    kfree(u.buf);
    return retval;
}
Exemplo n.º 7
0
static int rndis_bind(struct usbnet *dev, struct usb_interface *intf)
{
	int			retval;
	struct net_device	*net = dev->net;
	union {
		void			*buf;
		struct rndis_msg_hdr	*header;
		struct rndis_init	*init;
		struct rndis_init_c	*init_c;
		struct rndis_query	*get;
		struct rndis_query_c	*get_c;
		struct rndis_set	*set;
		struct rndis_set_c	*set_c;
	} u;
	u32			tmp;

	/* we can't rely on i/o from stack working, or stack allocation */
	u.buf = kmalloc(1024, GFP_KERNEL);
	if (!u.buf)
		return -ENOMEM;
	retval = usbnet_generic_cdc_bind(dev, intf);
	if (retval < 0)
		goto done;

	net->hard_header_len += sizeof (struct rndis_data_hdr);

	/* initialize; max transfer is 16KB at full speed */
	u.init->msg_type = RNDIS_MSG_INIT;
	u.init->msg_len = ccpu2(sizeof *u.init);
	u.init->major_version = ccpu2(1);
	u.init->minor_version = ccpu2(0);
	u.init->max_transfer_size = ccpu2(net->mtu + net->hard_header_len);

	retval = rndis_command(dev, u.header);
	if (unlikely(retval < 0)) {
		/* it might not even be an RNDIS device!! */
		dev_err(&intf->dev, "RNDIS init failed, %d\n", retval);
fail:
		usb_driver_release_interface(driver_of(intf),
			((struct cdc_state *)&(dev->data))->data);
		goto done;
	}
	dev->hard_mtu = le32_to_cpu(u.init_c->max_transfer_size);
	/* REVISIT:  peripheral "alignment" request is ignored ... */
	dev_dbg(&intf->dev, "hard mtu %u, align %d\n", dev->hard_mtu,
		1 << le32_to_cpu(u.init_c->packet_alignment));

	/* get designated host ethernet address */
	memset(u.get, 0, sizeof *u.get);
	u.get->msg_type = RNDIS_MSG_QUERY;
	u.get->msg_len = ccpu2(sizeof *u.get);
	u.get->oid = OID_802_3_PERMANENT_ADDRESS;

	retval = rndis_command(dev, u.header);
	if (unlikely(retval < 0)) {
		dev_err(&intf->dev, "rndis get ethaddr, %d\n", retval);
		goto fail;
	}
	tmp = le32_to_cpu(u.get_c->offset);
	if (unlikely((tmp + 8) > (1024 - ETH_ALEN)
			|| u.get_c->len != ccpu2(ETH_ALEN))) {
		dev_err(&intf->dev, "rndis ethaddr off %d len %d ?\n",
			tmp, le32_to_cpu(u.get_c->len));
		retval = -EDOM;
		goto fail;
	}
	memcpy(net->dev_addr, tmp + (char *)&u.get_c->request_id, ETH_ALEN);

	/* set a nonzero filter to enable data transfers */
	memset(u.set, 0, sizeof *u.set);
	u.set->msg_type = RNDIS_MSG_SET;
	u.set->msg_len = ccpu2(4 + sizeof *u.set);
	u.set->oid = OID_GEN_CURRENT_PACKET_FILTER;
	u.set->len = ccpu2(4);
	u.set->offset = ccpu2((sizeof *u.set) - 8);
	*(__le32 *)(u.buf + sizeof *u.set) = ccpu2(DEFAULT_FILTER);

	retval = rndis_command(dev, u.header);
	if (unlikely(retval < 0)) {
		dev_err(&intf->dev, "rndis set packet filter, %d\n", retval);
		goto fail;
	}

	retval = 0;
done:
	kfree(u.buf);
	return retval;
}
Exemplo n.º 8
0
int
generic_rndis_bind(struct usbnet *dev, struct usb_interface *intf, int flags)
{
	int			retval;
	struct net_device	*net = dev->net;
	struct cdc_state	*info = (void *) &dev->data;
	union {
		void			*buf;
		struct rndis_msg_hdr	*header;
		struct rndis_init	*init;
		struct rndis_init_c	*init_c;
		struct rndis_query	*get;
		struct rndis_query_c	*get_c;
		struct rndis_set	*set;
		struct rndis_set_c	*set_c;
		struct rndis_halt	*halt;
	} u;
	u32			tmp;
	__le32			phym_unspec, *phym;
	int			reply_len;
	unsigned char		*bp;

	
	u.buf = kmalloc(CONTROL_BUFFER_SIZE, GFP_KERNEL);
	if (!u.buf)
		return -ENOMEM;
	retval = usbnet_generic_cdc_bind(dev, intf);
	if (retval < 0)
		goto fail;

	u.init->msg_type = RNDIS_MSG_INIT;
	u.init->msg_len = cpu_to_le32(sizeof *u.init);
	u.init->major_version = cpu_to_le32(1);
	u.init->minor_version = cpu_to_le32(0);

	
	net->hard_header_len += sizeof (struct rndis_data_hdr);
	dev->hard_mtu = net->mtu + net->hard_header_len;

	dev->maxpacket = usb_maxpacket(dev->udev, dev->out, 1);
	if (dev->maxpacket == 0) {
		if (netif_msg_probe(dev))
			dev_dbg(&intf->dev, "dev->maxpacket can't be 0\n");
		retval = -EINVAL;
		goto fail_and_release;
	}

	dev->rx_urb_size = dev->hard_mtu + (dev->maxpacket + 1);
	dev->rx_urb_size &= ~(dev->maxpacket - 1);
	u.init->max_transfer_size = cpu_to_le32(dev->rx_urb_size);

	net->netdev_ops = &rndis_netdev_ops;

	retval = rndis_command(dev, u.header, CONTROL_BUFFER_SIZE);
	if (unlikely(retval < 0)) {
		
		dev_err(&intf->dev, "RNDIS init failed, %d\n", retval);
		goto fail_and_release;
	}
	tmp = le32_to_cpu(u.init_c->max_transfer_size);
	if (tmp < dev->hard_mtu) {
		if (tmp <= net->hard_header_len) {
			dev_err(&intf->dev,
				"dev can't take %u byte packets (max %u)\n",
				dev->hard_mtu, tmp);
			retval = -EINVAL;
			goto halt_fail_and_release;
		}
		dev_warn(&intf->dev,
			 "dev can't take %u byte packets (max %u), "
			 "adjusting MTU to %u\n",
			 dev->hard_mtu, tmp, tmp - net->hard_header_len);
		dev->hard_mtu = tmp;
		net->mtu = dev->hard_mtu - net->hard_header_len;
	}

	
	dev_dbg(&intf->dev,
		"hard mtu %u (%u from dev), rx buflen %Zu, align %d\n",
		dev->hard_mtu, tmp, dev->rx_urb_size,
		1 << le32_to_cpu(u.init_c->packet_alignment));

	
	if (dev->driver_info->early_init &&
			dev->driver_info->early_init(dev) != 0)
		goto halt_fail_and_release;

	
	phym = NULL;
	reply_len = sizeof *phym;
	retval = rndis_query(dev, intf, u.buf, OID_GEN_PHYSICAL_MEDIUM,
			0, (void **) &phym, &reply_len);
	if (retval != 0 || !phym) {
		
		phym_unspec = RNDIS_PHYSICAL_MEDIUM_UNSPECIFIED;
		phym = &phym_unspec;
	}
	if ((flags & FLAG_RNDIS_PHYM_WIRELESS) &&
			*phym != RNDIS_PHYSICAL_MEDIUM_WIRELESS_LAN) {
		if (netif_msg_probe(dev))
			dev_dbg(&intf->dev, "driver requires wireless "
				"physical medium, but device is not.\n");
		retval = -ENODEV;
		goto halt_fail_and_release;
	}
	if ((flags & FLAG_RNDIS_PHYM_NOT_WIRELESS) &&
			*phym == RNDIS_PHYSICAL_MEDIUM_WIRELESS_LAN) {
		if (netif_msg_probe(dev))
			dev_dbg(&intf->dev, "driver requires non-wireless "
				"physical medium, but device is wireless.\n");
		retval = -ENODEV;
		goto halt_fail_and_release;
	}

	
	reply_len = ETH_ALEN;
	retval = rndis_query(dev, intf, u.buf, OID_802_3_PERMANENT_ADDRESS,
			48, (void **) &bp, &reply_len);
	if (unlikely(retval< 0)) {
		dev_err(&intf->dev, "rndis get ethaddr, %d\n", retval);
		goto halt_fail_and_release;
	}
	memcpy(net->dev_addr, bp, ETH_ALEN);
	memcpy(net->perm_addr, bp, ETH_ALEN);

	
	memset(u.set, 0, sizeof *u.set);
	u.set->msg_type = RNDIS_MSG_SET;
	u.set->msg_len = cpu_to_le32(4 + sizeof *u.set);
	u.set->oid = OID_GEN_CURRENT_PACKET_FILTER;
	u.set->len = cpu_to_le32(4);
	u.set->offset = cpu_to_le32((sizeof *u.set) - 8);
	*(__le32 *)(u.buf + sizeof *u.set) = RNDIS_DEFAULT_FILTER;

	retval = rndis_command(dev, u.header, CONTROL_BUFFER_SIZE);
	if (unlikely(retval < 0)) {
		dev_err(&intf->dev, "rndis set packet filter, %d\n", retval);
		goto halt_fail_and_release;
	}

	retval = 0;

	kfree(u.buf);
	return retval;

halt_fail_and_release:
	memset(u.halt, 0, sizeof *u.halt);
	u.halt->msg_type = RNDIS_MSG_HALT;
	u.halt->msg_len = cpu_to_le32(sizeof *u.halt);
	(void) rndis_command(dev, (void *)u.halt, CONTROL_BUFFER_SIZE);
fail_and_release:
	usb_set_intfdata(info->data, NULL);
	usb_driver_release_interface(driver_of(intf), info->data);
	info->data = NULL;
fail:
	kfree(u.buf);
	return retval;
}