コード例 #1
0
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;
}
コード例 #2
0
ファイル: usbd_rndis_core.c プロジェクト: nandojve/lrndis
static uint8_t usbd_rndis_ep0_recv(void  *pdev)
{
	switch (((rndis_generic_msg_t *)encapsulated_buffer)->MessageType)
	{
		case REMOTE_NDIS_INITIALIZE_MSG:
			{
				rndis_initialize_cmplt_t *m;
				m = ((rndis_initialize_cmplt_t *)encapsulated_buffer);
				//m->MessageID is same as before
				m->MessageType = REMOTE_NDIS_INITIALIZE_CMPLT;
				m->MessageLength = sizeof(rndis_initialize_cmplt_t);
				m->MajorVersion = RNDIS_MAJOR_VERSION;
				m->MinorVersion = RNDIS_MINOR_VERSION;
				m->Status = RNDIS_STATUS_SUCCESS;
				m->DeviceFlags = RNDIS_DF_CONNECTIONLESS;
				m->Medium = RNDIS_MEDIUM_802_3;
				m->MaxPacketsPerTransfer = 1;
				m->MaxTransferSize = RNDIS_RX_BUFFER_SIZE;
				m->PacketAlignmentFactor = 0;
				m->AfListOffset = 0;
				m->AfListSize = 0;
				rndis_state = rndis_initialized;
				DCD_EP_Tx(pdev, RNDIS_NOTIFICATION_IN_EP, (uint8_t *)"\x01\x00\x00\x00\x00\x00\x00\x00", 8);
			}
			break;

		case REMOTE_NDIS_QUERY_MSG:
			rndis_query(pdev);
			break;
			
		case REMOTE_NDIS_SET_MSG:
			rndis_handle_set_msg(pdev);
			break;

		case REMOTE_NDIS_RESET_MSG:
			{
				rndis_reset_cmplt_t * m;
				m = ((rndis_reset_cmplt_t *)encapsulated_buffer);
				rndis_state = rndis_uninitialized;
				m->MessageType = REMOTE_NDIS_RESET_CMPLT;
				m->MessageLength = sizeof(rndis_reset_cmplt_t);
				m->Status = RNDIS_STATUS_SUCCESS;
				m->AddressingReset = 1; /* Make it look like we did something */
			//	m->AddressingReset = 0; //Windows halts if set to 1 for some reason
				DCD_EP_Tx(pdev, RNDIS_NOTIFICATION_IN_EP, (uint8_t *)"\x01\x00\x00\x00\x00\x00\x00\x00", 8);
			}
			break;

		case REMOTE_NDIS_KEEPALIVE_MSG:
			{
				rndis_keepalive_cmplt_t * m;
				m = (rndis_keepalive_cmplt_t *)encapsulated_buffer;
				m->MessageType = REMOTE_NDIS_KEEPALIVE_CMPLT;
				m->MessageLength = sizeof(rndis_keepalive_cmplt_t);
				m->Status = RNDIS_STATUS_SUCCESS;
			}
			// We have data to send back
			DCD_EP_Tx(pdev, RNDIS_NOTIFICATION_IN_EP, (uint8_t *)"\x01\x00\x00\x00\x00\x00\x00\x00", 8);
			break;

		default:
			break;
	}
  return USBD_OK;
}
コード例 #3
0
ファイル: rndis_host.c プロジェクト: serrvius/huawei-p6
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;
}
コード例 #4
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;
}