2021-10-01 18:48:38 +03:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <libopencm3/usb/usbd.h>
|
|
|
|
#include <libopencm3/usb/cdc.h>
|
|
|
|
|
|
|
|
#include <SEGGER_RTT.h>
|
2021-10-03 22:39:29 +03:00
|
|
|
#include <string.h>
|
2021-10-01 18:48:38 +03:00
|
|
|
|
|
|
|
#include "rndis.h"
|
2021-10-03 22:39:29 +03:00
|
|
|
#include "util.h"
|
|
|
|
#include "rndis_protocol.h"
|
2021-10-01 18:48:38 +03:00
|
|
|
|
|
|
|
/* Buffer to be used for control requests. */
|
2021-10-03 22:39:29 +03:00
|
|
|
static uint8_t usbd_control_buffer[1025];
|
|
|
|
|
|
|
|
static const uint8_t station_hwaddr[6] = { RNDIS_HWADDR };
|
|
|
|
static const uint8_t permanent_hwaddr[6] = { RNDIS_HWADDR };
|
2021-10-01 18:48:38 +03:00
|
|
|
|
|
|
|
static const struct usb_device_descriptor dev = {
|
|
|
|
.bLength = USB_DT_DEVICE_SIZE,
|
|
|
|
.bDescriptorType = USB_DT_DEVICE,
|
|
|
|
.bcdUSB = 0x0200,
|
|
|
|
.bDeviceClass = 0xE0, // Wireless Controller
|
|
|
|
.bDeviceSubClass = 0,
|
|
|
|
.bDeviceProtocol = 0,
|
|
|
|
.bMaxPacketSize0 = 64,
|
|
|
|
.idVendor = 0x4E44,
|
|
|
|
.idProduct = 0x4953,
|
|
|
|
.bcdDevice = 0xffff,
|
|
|
|
.iManufacturer = 1,
|
|
|
|
.iProduct = 2,
|
|
|
|
.iSerialNumber = 3,
|
|
|
|
.bNumConfigurations = 1,
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct usb_endpoint_descriptor comm_endp[] = {{
|
|
|
|
.bLength = USB_DT_ENDPOINT_SIZE,
|
|
|
|
.bDescriptorType = USB_DT_ENDPOINT,
|
2021-10-03 22:39:29 +03:00
|
|
|
.bEndpointAddress = 0x83,
|
2021-10-01 18:48:38 +03:00
|
|
|
.bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,
|
|
|
|
.wMaxPacketSize = 8,
|
2021-10-03 22:39:29 +03:00
|
|
|
.bInterval = 0xf,
|
2021-10-01 18:48:38 +03:00
|
|
|
}};
|
|
|
|
|
|
|
|
static const struct {
|
|
|
|
struct usb_cdc_header_descriptor header;
|
|
|
|
struct usb_cdc_call_management_descriptor call_mgmt;
|
|
|
|
struct usb_cdc_acm_descriptor acm;
|
|
|
|
struct usb_cdc_union_descriptor cdc_union;
|
|
|
|
} __attribute__((packed)) cdcacm_functional_descriptors = {
|
|
|
|
.header = {
|
|
|
|
.bFunctionLength = sizeof(struct usb_cdc_header_descriptor),
|
|
|
|
.bDescriptorType = CS_INTERFACE,
|
|
|
|
.bDescriptorSubtype = USB_CDC_TYPE_HEADER,
|
|
|
|
.bcdCDC = 0x0110,
|
|
|
|
},
|
|
|
|
.call_mgmt = {
|
|
|
|
.bFunctionLength =
|
|
|
|
sizeof(struct usb_cdc_call_management_descriptor),
|
|
|
|
.bDescriptorType = CS_INTERFACE,
|
|
|
|
.bDescriptorSubtype = USB_CDC_TYPE_CALL_MANAGEMENT,
|
|
|
|
.bmCapabilities = 0,
|
|
|
|
.bDataInterface = 1,
|
|
|
|
},
|
|
|
|
.acm = {
|
|
|
|
.bFunctionLength = sizeof(struct usb_cdc_acm_descriptor),
|
|
|
|
.bDescriptorType = CS_INTERFACE,
|
|
|
|
.bDescriptorSubtype = USB_CDC_TYPE_ACM,
|
|
|
|
.bmCapabilities = 0,
|
|
|
|
},
|
|
|
|
.cdc_union = {
|
|
|
|
.bFunctionLength = sizeof(struct usb_cdc_union_descriptor),
|
|
|
|
.bDescriptorType = CS_INTERFACE,
|
|
|
|
.bDescriptorSubtype = USB_CDC_TYPE_UNION,
|
|
|
|
.bControlInterface = 0,
|
|
|
|
.bSubordinateInterface0 = 1,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
// RNDIS Communications Control
|
|
|
|
static const struct usb_interface_descriptor comm_iface[] = {{
|
|
|
|
.bLength = USB_DT_INTERFACE_SIZE,
|
|
|
|
.bDescriptorType = USB_DT_INTERFACE,
|
|
|
|
.bInterfaceNumber = 0,
|
|
|
|
.bAlternateSetting = 0,
|
|
|
|
.bNumEndpoints = 1,
|
2021-10-03 22:39:29 +03:00
|
|
|
// Linux kernel calls this "RNDIS for tethering"
|
|
|
|
.bInterfaceClass = 0xE0, // Wireless Controller Class
|
2021-10-01 18:48:38 +03:00
|
|
|
.bInterfaceSubClass = 0x01,
|
|
|
|
.bInterfaceProtocol = 0x03,
|
2021-10-03 22:39:29 +03:00
|
|
|
|
|
|
|
// https://docs.microsoft.com/en-us/windows-hardware/drivers/network/communication-class-interface
|
|
|
|
// .bInterfaceClass = 0x02,
|
|
|
|
// .bInterfaceSubClass = 0x02,
|
|
|
|
// .bInterfaceProtocol = 0xff,
|
|
|
|
|
2021-10-01 18:48:38 +03:00
|
|
|
.iInterface = 0,
|
|
|
|
|
|
|
|
.endpoint = comm_endp,
|
|
|
|
|
|
|
|
.extra = &cdcacm_functional_descriptors,
|
|
|
|
.extralen = sizeof(cdcacm_functional_descriptors),
|
|
|
|
}};
|
|
|
|
|
|
|
|
static const struct usb_endpoint_descriptor data_endp[] = {{
|
|
|
|
.bLength = USB_DT_ENDPOINT_SIZE,
|
|
|
|
.bDescriptorType = USB_DT_ENDPOINT,
|
|
|
|
.bEndpointAddress = 0x01,
|
|
|
|
.bmAttributes = USB_ENDPOINT_ATTR_BULK,
|
|
|
|
.wMaxPacketSize = 64,
|
|
|
|
.bInterval = 0,
|
|
|
|
}, {
|
|
|
|
.bLength = USB_DT_ENDPOINT_SIZE,
|
|
|
|
.bDescriptorType = USB_DT_ENDPOINT,
|
|
|
|
.bEndpointAddress = 0x82,
|
|
|
|
.bmAttributes = USB_ENDPOINT_ATTR_BULK,
|
|
|
|
.wMaxPacketSize = 64,
|
|
|
|
.bInterval = 0,
|
|
|
|
}};
|
|
|
|
|
|
|
|
static const struct usb_interface_descriptor data_iface[] = {{
|
|
|
|
.bLength = USB_DT_INTERFACE_SIZE,
|
|
|
|
.bDescriptorType = USB_DT_INTERFACE,
|
|
|
|
.bInterfaceNumber = 1,
|
|
|
|
.bAlternateSetting = 0,
|
|
|
|
.bNumEndpoints = 2,
|
|
|
|
.bInterfaceClass = USB_CLASS_DATA,
|
|
|
|
.bInterfaceSubClass = 0,
|
|
|
|
.bInterfaceProtocol = 0,
|
|
|
|
.iInterface = 0,
|
|
|
|
|
|
|
|
.endpoint = data_endp,
|
|
|
|
}};
|
|
|
|
|
|
|
|
static const struct usb_interface ifaces[] = {{
|
|
|
|
.num_altsetting = 1,
|
|
|
|
.altsetting = comm_iface,
|
|
|
|
}, {
|
|
|
|
.num_altsetting = 1,
|
|
|
|
.altsetting = data_iface,
|
|
|
|
}};
|
|
|
|
|
|
|
|
static const struct usb_config_descriptor config = {
|
|
|
|
.bLength = USB_DT_CONFIGURATION_SIZE,
|
|
|
|
.bDescriptorType = USB_DT_CONFIGURATION,
|
|
|
|
.wTotalLength = 0,
|
|
|
|
.bNumInterfaces = 2,
|
|
|
|
.bConfigurationValue = 1,
|
|
|
|
.iConfiguration = 0,
|
|
|
|
.bmAttributes = 0x80,
|
|
|
|
.bMaxPower = 0x32,
|
|
|
|
|
|
|
|
.interface = ifaces,
|
|
|
|
};
|
|
|
|
|
|
|
|
static const char *usb_strings[] = {
|
2021-10-03 22:39:29 +03:00
|
|
|
"Arti", // iManufacturer
|
2021-10-01 18:48:38 +03:00
|
|
|
"STM32-RNDIS", // iProduct
|
|
|
|
"lrndis demo", // iSerialNumber
|
|
|
|
};
|
|
|
|
|
2021-10-03 22:39:29 +03:00
|
|
|
static void rndis_query_cmplt32(uint8_t **buf, uint32_t status, uint32_t data)
|
|
|
|
{
|
2022-06-30 22:55:25 +03:00
|
|
|
rndis_query_cmplt_t *c = (rndis_query_cmplt_t *)*buf;
|
2021-10-03 22:39:29 +03:00
|
|
|
c->MessageType = REMOTE_NDIS_QUERY_CMPLT;
|
|
|
|
c->MessageLength = sizeof(rndis_query_cmplt_t) + 4;
|
|
|
|
c->Status = status;
|
|
|
|
c->InformationBufferLength = 4;
|
|
|
|
c->InformationBufferOffset = 16;
|
|
|
|
*(uint32_t *)(c + 1) = data;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void rndis_query_cmplt(uint8_t **buf, uint32_t status, const void *data, uint32_t size){
|
2022-06-30 22:55:25 +03:00
|
|
|
rndis_query_cmplt_t *c = (rndis_query_cmplt_t *)*buf;
|
2021-10-03 22:39:29 +03:00
|
|
|
c->MessageType = REMOTE_NDIS_QUERY_CMPLT;
|
|
|
|
c->MessageLength = sizeof(rndis_query_cmplt_t) + size;
|
|
|
|
c->Status = status;
|
|
|
|
c->InformationBufferLength = size;
|
|
|
|
c->InformationBufferOffset = 16;
|
|
|
|
memcpy(c + 1, data, size);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void rndis_handle_query(uint8_t **buf, uint16_t *len)
|
|
|
|
{
|
|
|
|
union {
|
|
|
|
void *buf;
|
|
|
|
rndis_generic_msg_t *header;
|
|
|
|
rndis_query_msg_t *get;
|
|
|
|
rndis_query_cmplt_t *get_c;
|
|
|
|
} u;
|
|
|
|
|
|
|
|
u.buf = *buf;
|
2022-06-30 22:55:25 +03:00
|
|
|
|
2021-10-03 22:39:29 +03:00
|
|
|
SEGGER_RTT_printf(0, "NDIS Query oid: 0x%08x, len: 0x%02x\n", u.get->Oid, u.get->InformationBufferLength);
|
|
|
|
|
|
|
|
switch (u.get->Oid)
|
|
|
|
{
|
|
|
|
case OID_GEN_PHYSICAL_MEDIUM:
|
2022-06-30 22:55:25 +03:00
|
|
|
rndis_query_cmplt32(buf, RNDIS_STATUS_SUCCESS, NDIS_MEDIUM_802_3);
|
2021-10-03 22:39:29 +03:00
|
|
|
return;
|
|
|
|
case OID_802_3_PERMANENT_ADDRESS:
|
2022-06-30 22:55:25 +03:00
|
|
|
rndis_query_cmplt(buf, RNDIS_STATUS_SUCCESS, &permanent_hwaddr, sizeof(permanent_hwaddr));
|
|
|
|
return;
|
|
|
|
default:
|
|
|
|
rndis_query_cmplt(buf, RNDIS_STATUS_FAILURE, NULL, 0);
|
2021-10-03 22:39:29 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static enum usbd_request_return_codes rndis_control_request(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf,
|
|
|
|
uint16_t *len, void (**complete)(usbd_device *usbd_dev, struct usb_setup_data *req))
|
|
|
|
{
|
2022-06-30 22:55:25 +03:00
|
|
|
(void)req;
|
|
|
|
(void)complete;
|
|
|
|
|
2021-10-03 22:39:29 +03:00
|
|
|
union {
|
|
|
|
void *buf;
|
|
|
|
rndis_generic_msg_t *header;
|
|
|
|
rndis_initialize_msg_t *init;
|
|
|
|
rndis_initialize_cmplt_t *init_c;
|
|
|
|
rndis_query_msg_t *get;
|
|
|
|
rndis_query_cmplt_t *get_c;
|
|
|
|
rndis_set_msg_t *set;
|
|
|
|
rndis_set_cmplt_t *set_c;
|
2022-06-30 22:55:25 +03:00
|
|
|
rndis_indicate_status_t *indic;
|
2021-10-03 22:39:29 +03:00
|
|
|
} u;
|
|
|
|
|
|
|
|
//SEGGER_RTT_printf(0, "bmRequestType: 0x%02x, bRequest: 0x%02x\n", req->bmRequestType, req->bRequest);
|
|
|
|
|
|
|
|
u.buf = *buf;
|
|
|
|
switch (u.header->MessageType)
|
|
|
|
{
|
|
|
|
case REMOTE_NDIS_INITIALIZE_MSG:
|
2022-06-30 22:55:25 +03:00
|
|
|
SEGGER_RTT_printf(0, "NDIS Init: HOST Ver %d.%d, Max MTU: %dbytes \n", u.init->MajorVersion, u.init->MinorVersion, u.init->MaxTransferSize);
|
2021-10-03 22:39:29 +03:00
|
|
|
u.init_c->MessageType = REMOTE_NDIS_INITIALIZE_CMPLT;
|
|
|
|
return USBD_REQ_HANDLED;
|
|
|
|
case REMOTE_NDIS_INITIALIZE_CMPLT:
|
2022-06-30 22:55:25 +03:00
|
|
|
SEGGER_RTT_printf(0, "NDIS Init complete, MTU: %d\n", RNDIS_RX_BUFFER_SIZE);
|
2021-10-03 22:39:29 +03:00
|
|
|
u.init_c->MessageType = REMOTE_NDIS_INITIALIZE_CMPLT;
|
|
|
|
u.init_c->MessageLength = sizeof(rndis_initialize_cmplt_t);
|
|
|
|
// u.int_c->RequestId stays the same
|
|
|
|
u.init_c->Status = RNDIS_STATUS_SUCCESS;
|
|
|
|
u.init_c->MajorVersion = RNDIS_MAJOR_VERSION;
|
|
|
|
u.init_c->MinorVersion = RNDIS_MINOR_VERSION;
|
|
|
|
u.init_c->DeviceFlags = RNDIS_DF_CONNECTIONLESS;
|
|
|
|
u.init_c->Medium = RNDIS_MEDIUM_802_3;
|
|
|
|
u.init_c->MaxPacketsPerTransfer = 1;
|
|
|
|
u.init_c->MaxTransferSize = RNDIS_RX_BUFFER_SIZE;
|
|
|
|
u.init_c->PacketAlignmentFactor = 0;
|
|
|
|
u.init_c->AfListOffset = 0;
|
|
|
|
u.init_c->AfListSize = 0;
|
|
|
|
//*len = sizeof(rndis_initialize_cmplt_t);
|
|
|
|
usbd_ep_write_packet(usbd_dev, 0x83, "\x01\x00\x00\x00\x00\x00\x00\x00", 8);
|
|
|
|
return USBD_REQ_HANDLED;
|
|
|
|
case REMOTE_NDIS_QUERY_MSG:
|
2022-06-30 22:55:25 +03:00
|
|
|
rndis_handle_query(buf, len);
|
2021-10-03 22:39:29 +03:00
|
|
|
usbd_ep_write_packet(usbd_dev, 0x83, "\x01\x00\x00\x00\x00\x00\x00\x00", 8);
|
|
|
|
//*len = u.get_c->MessageLength;
|
|
|
|
return USBD_REQ_HANDLED;
|
|
|
|
case REMOTE_NDIS_QUERY_CMPLT:
|
|
|
|
SEGGER_RTT_printf(0, "NDIS Query complete\n");
|
|
|
|
*len = u.get_c->MessageLength;
|
2022-06-30 22:55:25 +03:00
|
|
|
usbd_ep_write_packet(usbd_dev, 0x83, "\x01\x00\x00\x00\x00\x00\x00\x00", 8);
|
2021-10-03 22:39:29 +03:00
|
|
|
return USBD_REQ_HANDLED;
|
|
|
|
case REMOTE_NDIS_SET_MSG:
|
|
|
|
SEGGER_RTT_printf(0, "NDIS Set oid: 0x%08x, len 0x%02x\n", u.set->Oid, u.set->InformationBufferLength);
|
|
|
|
u.set_c->MessageType = REMOTE_NDIS_SET_CMPLT;
|
|
|
|
u.set_c->MessageLength = sizeof(rndis_set_cmplt_t);
|
|
|
|
u.set_c->Status = RNDIS_STATUS_SUCCESS;
|
|
|
|
*len = u.set_c->MessageLength;
|
|
|
|
usbd_ep_write_packet(usbd_dev, 0x83, "\x01\x00\x00\x00\x00\x00\x00\x00", 8);
|
|
|
|
return USBD_REQ_HANDLED;
|
|
|
|
case REMOTE_NDIS_SET_CMPLT:
|
|
|
|
SEGGER_RTT_printf(0, "NDIS Set complete\n");
|
|
|
|
*len = u.set_c->MessageLength;
|
2022-06-30 22:55:25 +03:00
|
|
|
usbd_ep_write_packet(usbd_dev, 0x83, "\x01\x00\x00\x00\x00\x00\x00\x00", 8);
|
2021-10-03 22:39:29 +03:00
|
|
|
return USBD_REQ_HANDLED;
|
|
|
|
}
|
|
|
|
SEGGER_RTT_printf(0, "NDIS unknown MessageType: 0x%08x, MessageLength: %d, max len: %d\n", u.header->MessageType, u.header->MessageLength, *len);
|
|
|
|
return USBD_REQ_NEXT_CALLBACK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void rndis_data_rx_cb(usbd_device *usbd_dev, uint8_t ep)
|
|
|
|
{
|
2022-06-30 22:55:25 +03:00
|
|
|
(void)ep;
|
|
|
|
|
2021-10-03 22:39:29 +03:00
|
|
|
char buf[64];
|
|
|
|
int len = usbd_ep_read_packet(usbd_dev, 0x01, buf, 64);
|
|
|
|
|
|
|
|
if (len) {
|
|
|
|
SEGGER_RTT_printf(0, "RX: %d\n", len);
|
|
|
|
hexdump(buf, len, 16);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void rndis_set_config(usbd_device *usbd_dev, uint16_t wValue)
|
|
|
|
{
|
|
|
|
(void)wValue;
|
|
|
|
(void)usbd_dev;
|
|
|
|
//SEGGER_RTT_printf(0, "USB Set config %d\n", wValue);
|
|
|
|
|
|
|
|
usbd_ep_setup(usbd_dev, 0x01, USB_ENDPOINT_ATTR_BULK, 64, rndis_data_rx_cb);
|
|
|
|
usbd_ep_setup(usbd_dev, 0x82, USB_ENDPOINT_ATTR_BULK, 64, NULL);
|
2022-06-30 22:55:25 +03:00
|
|
|
// Interrupt endpoint is used to only send notification that some data is ready to read
|
2021-10-03 22:39:29 +03:00
|
|
|
usbd_ep_setup(usbd_dev, 0x83, USB_ENDPOINT_ATTR_INTERRUPT, 8, NULL);
|
|
|
|
|
|
|
|
usbd_register_control_callback(usbd_dev,
|
|
|
|
USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE,
|
|
|
|
USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT,
|
|
|
|
rndis_control_request);
|
|
|
|
}
|
|
|
|
|
2021-10-01 18:48:38 +03:00
|
|
|
usbd_device *start_rdnis(void) {
|
2021-10-03 22:39:29 +03:00
|
|
|
usbd_device *usbd_dev;
|
2021-10-01 18:48:38 +03:00
|
|
|
|
2021-10-03 22:39:29 +03:00
|
|
|
usbd_dev = usbd_init(
|
2021-10-01 18:48:38 +03:00
|
|
|
&st_usbfs_v1_usb_driver, &dev, &config,
|
|
|
|
usb_strings, 3,
|
|
|
|
usbd_control_buffer, sizeof(usbd_control_buffer)
|
|
|
|
);
|
2021-10-03 22:39:29 +03:00
|
|
|
usbd_register_set_config_callback(usbd_dev, rndis_set_config);
|
2021-10-01 18:48:38 +03:00
|
|
|
|
2021-10-03 22:39:29 +03:00
|
|
|
return usbd_dev;
|
2021-10-01 18:48:38 +03:00
|
|
|
}
|