439 lines
16 KiB
C
439 lines
16 KiB
C
#include <rtthread.h>
|
||
#include <include/rttusb_host.h>
|
||
#include "rndis.h"
|
||
#include "cdc.h"
|
||
#include "hal/usb_device.h"
|
||
#include "lib/usb/usb_device_rndis.h"
|
||
#include "lwip/err.h"
|
||
#include "lwip/sockets.h"
|
||
#include "lwip/netdb.h"
|
||
#include "lwip/sys.h"
|
||
#include "lwip/ip_addr.h"
|
||
#include "lwip/tcpip.h"
|
||
#include "netif/ethernetif.h"
|
||
|
||
#if defined(RT_USBH_WIRELESS) && defined(RT_USBH_WIRELESS_RNDIS)
|
||
|
||
static rt_err_t rt_rndis_msg_send_recv(struct usb_rndis *rndis, rt_uint8_t *send_buf, rt_uint32_t send_len,
|
||
rt_uint8_t *recv_buf, rt_uint32_t recv_size, rt_uint32_t *recv_len)
|
||
{
|
||
USBD_CDC_RNDIS_MsgTypeDef *msg = (USBD_CDC_RNDIS_MsgTypeDef *)recv_buf;
|
||
uinst_t device = rndis->device;
|
||
int ret = 0;
|
||
rt_uint32_t rndis_avial[2 + (USB_RX_BUFF_RESERVE_SIZE / 4)] = {0}; // 防止越界
|
||
rt_uint32_t req_type = msg->Ctrl.MsgType;
|
||
|
||
ret = rt_usbh_cdc_send_command(device, send_buf, send_len);
|
||
if (ret == send_len) {
|
||
__retry:
|
||
/* waite for the interrupt ep */
|
||
ret = rt_usb_hcd_pipe_xfer(device->hcd, rndis->pipe_int, rndis_avial, 8, USB_TIMEOUT_BASIC);
|
||
if (ret == 8 && rndis_avial[0] == 1 && rndis_avial[1] == 0) {
|
||
ret = rt_usbh_cdc_get_response(device, recv_buf, recv_size);
|
||
if (ret > 0) {
|
||
*recv_len = ret;
|
||
if (msg->Resp.MsgType != (0x80000000UL | req_type) ||
|
||
msg->Resp.ReqId != rndis->req_id ||
|
||
msg->Resp.Status != CDC_RNDIS_STATUS_SUCCESS) {
|
||
//os_printf("retry,%d,%d,%d,%d,%d\r\n", msg->Resp.MsgType, req_type, msg->Resp.ReqId, rndis->req_id, msg->Resp.Status);
|
||
goto __retry;
|
||
}
|
||
return RET_OK;
|
||
}
|
||
}
|
||
ret = RET_ERR;
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
static rt_err_t rt_rndis_msg_init(struct usb_rndis *rndis)
|
||
{
|
||
USBD_CDC_RNDIS_MsgTypeDef *msg = (USBD_CDC_RNDIS_MsgTypeDef *)rndis->msg_buffer;
|
||
rt_uint32_t recv_len = 0;
|
||
int ret = 0;
|
||
|
||
// 清理buffer空间
|
||
os_memset(rndis->msg_buffer, 0, sizeof(USBD_CDC_RNDIS_InitMsgTypeDef));
|
||
msg->Init.MsgType = CDC_RNDIS_INITIALIZE_MSG_ID;
|
||
msg->Init.MsgLength = sizeof(USBD_CDC_RNDIS_InitMsgTypeDef);
|
||
msg->Init.ReqId = ++rndis->req_id;
|
||
msg->Init.MajorVersion = CDC_RNDIS_VERSION_MAJOR;
|
||
msg->Init.MinorVersion = CDC_RNDIS_VERSION_MINOR;
|
||
msg->Init.MaxTransferSize = 2048;
|
||
ret = rt_rndis_msg_send_recv(rndis, rndis->msg_buffer, msg->Init.MsgLength,
|
||
rndis->msg_buffer, 128, &recv_len);
|
||
return ret;
|
||
}
|
||
|
||
static rt_err_t rt_rndis_msg_keepalive(struct usb_rndis *rndis)
|
||
{
|
||
USBD_CDC_RNDIS_MsgTypeDef *msg = (USBD_CDC_RNDIS_MsgTypeDef *)rndis->msg_buffer;
|
||
rt_uint32_t recv_len = 0;
|
||
int ret = 0;
|
||
|
||
os_memset(rndis->msg_buffer, 0, sizeof(USBD_CDC_RNDIS_KpAliveMsgTypeDef));
|
||
msg->KpAlive.MsgType = CDC_RNDIS_KEEPALIVE_MSG_ID;
|
||
msg->KpAlive.MsgLength = sizeof(USBD_CDC_RNDIS_KpAliveMsgTypeDef);
|
||
msg->KpAlive.ReqId = ++rndis->req_id;
|
||
ret = rt_rndis_msg_send_recv(rndis, rndis->msg_buffer, msg->KpAlive.MsgLength,
|
||
rndis->msg_buffer, 128, &recv_len);
|
||
return ret;
|
||
}
|
||
|
||
rt_err_t rt_rndis_msg_query(struct usb_rndis *rndis, rt_uint32_t oid, rt_uint8_t *buff, rt_uint32_t *len)
|
||
{
|
||
USBD_CDC_RNDIS_MsgTypeDef *msg = (USBD_CDC_RNDIS_MsgTypeDef *)rndis->msg_buffer;
|
||
rt_uint32_t recv_len = 0;
|
||
int ret = 0;
|
||
|
||
os_memset(rndis->msg_buffer, 0, sizeof(USBD_CDC_RNDIS_QueryMsgTypeDef));
|
||
msg->Query.MsgType = CDC_RNDIS_QUERY_MSG_ID;
|
||
msg->Query.MsgLength = sizeof(USBD_CDC_RNDIS_QueryMsgTypeDef);
|
||
msg->Query.RequestId = ++rndis->req_id;
|
||
msg->Query.Oid = oid;
|
||
msg->Query.InfoBufLength = 0;
|
||
msg->Query.InfoBufOffset = 20;
|
||
msg->Query.DeviceVcHandle = 0;
|
||
ret = rt_rndis_msg_send_recv(rndis, rndis->msg_buffer, msg->Query.MsgLength,
|
||
rndis->msg_buffer, 128, &recv_len);
|
||
if (ret == RET_OK) {
|
||
os_memcpy(buff, msg->QueryCplt.InfoBuf, msg->QueryCplt.InfoBufLength);
|
||
*len = msg->QueryCplt.InfoBufLength;
|
||
return RET_OK;
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
rt_err_t rt_rndis_msg_set(struct usb_rndis *rndis, rt_uint32_t oid, rt_uint8_t *buff, rt_uint32_t len)
|
||
{
|
||
USBD_CDC_RNDIS_MsgTypeDef *msg = (USBD_CDC_RNDIS_MsgTypeDef *)rndis->msg_buffer;
|
||
uinst_t device = rndis->device;
|
||
rt_uint32_t recv_len = 0;
|
||
rt_uint32_t rndis_avial[2 + (USB_RX_BUFF_RESERVE_SIZE / 4)] = {0}; // 防止越界
|
||
int ret = 0;
|
||
|
||
os_memset(rndis->msg_buffer, 0, sizeof(USBD_CDC_RNDIS_SetMsgTypeDef));
|
||
msg->Set.MsgType = CDC_RNDIS_SET_MSG_ID;
|
||
msg->Set.MsgLength = sizeof(USBD_CDC_RNDIS_SetMsgTypeDef) + len;
|
||
msg->Set.ReqId = ++rndis->req_id;
|
||
msg->Set.Oid = oid;
|
||
msg->Set.InfoBufLength = 0;
|
||
msg->Set.InfoBufOffset = 20;
|
||
msg->Set.DeviceVcHandle = 0;
|
||
ret = rt_rndis_msg_send_recv(rndis, rndis->msg_buffer, msg->Set.MsgLength,
|
||
rndis->msg_buffer, 128, &recv_len);
|
||
return ret;
|
||
}
|
||
|
||
static void rt_usbh_rndis_keepalive_timer(void *args)
|
||
{
|
||
struct usb_rndis *rndis = args;
|
||
|
||
// os_printf("keep alive\r\n");
|
||
rt_rndis_msg_keepalive(rndis);
|
||
os_timer_start(&rndis->keepalive_timer, 5000);
|
||
}
|
||
|
||
static rt_err_t rt_usbh_rndis_open(struct netdev *ndev, netdev_input_cb input_cb, netdev_event_cb evt_cb, void *priv)
|
||
{
|
||
rt_uint32_t flags;
|
||
struct usb_rndis *rndis = container_of(ndev, struct usb_rndis, ndev);
|
||
|
||
flags = disable_irq();
|
||
rndis->input_cb = input_cb;
|
||
rndis->input_priv = priv;
|
||
enable_irq(flags);
|
||
|
||
return RET_OK;
|
||
}
|
||
|
||
static rt_err_t rt_usbh_rndis_ioctl(struct netdev *ndev, rt_uint32_t cmd, rt_uint32_t param1, rt_uint32_t param2)
|
||
{
|
||
struct usb_rndis *rndis = container_of(ndev, struct usb_rndis, ndev);
|
||
|
||
switch (cmd) {
|
||
case NETDEV_IOCTL_GET_ADDR:
|
||
os_memcpy((rt_uint8_t *)param1, rndis->mac, 6);
|
||
break;
|
||
default:
|
||
return -ENOTSUPP;
|
||
}
|
||
return RET_OK;
|
||
}
|
||
|
||
// 注意:send_data直接将data指针前移获取预留的空间
|
||
// 必须确认调用方是skb申请有预留足够空间,否则存在风险
|
||
// 由于USB DMA需要4字节对齐,skb->data经过处理后,IP包头不是4字节对齐,不能前移处理
|
||
static rt_err_t rt_usbh_rndis_send_data(struct netdev *ndev, rt_uint8_t *p_data, rt_uint32_t size)
|
||
{
|
||
struct usb_rndis *rndis = container_of(ndev, struct usb_rndis, ndev);
|
||
uinst_t device = rndis->device;
|
||
USBD_CDC_RNDIS_PacketMsgTypeDef *packet = NULL;
|
||
|
||
if (p_data == NULL || size == 0) {
|
||
return -EINVAL;
|
||
}
|
||
if (!rndis->ready) {
|
||
// usb没准备好就不发包
|
||
os_printf("rndis send no ready\r\n");
|
||
return -EIO;
|
||
}
|
||
packet = (USBD_CDC_RNDIS_PacketMsgTypeDef *)os_malloc(size + sizeof(USBD_CDC_RNDIS_PacketMsgTypeDef));
|
||
if (packet == NULL) {
|
||
return -ENOMEM;
|
||
}
|
||
os_memset(packet, 0, sizeof(USBD_CDC_RNDIS_PacketMsgTypeDef));
|
||
packet->MsgType = CDC_RNDIS_PACKET_MSG_ID;
|
||
packet->MsgLength = size + 44;
|
||
packet->DataOffset = 36; // 明明是44,但是抓包看全是36,不知道为什么
|
||
packet->DataLength = size;
|
||
hw_memcpy(packet + 1, p_data, size);
|
||
rt_usb_hcd_pipe_xfer(device->hcd, rndis->pipe_out, packet, packet->MsgLength, 1000);
|
||
os_free(packet);
|
||
return RET_OK;
|
||
}
|
||
|
||
// 注意:USB驱动大部分不支持scatter发送,因此需要额外拷贝
|
||
// 调用方多数来自于LWIP,数据量可能小一点
|
||
static rt_err_t rt_usbh_rndis_send_scatter_data(struct netdev *ndev, scatter_data *data, rt_uint32_t count)
|
||
{
|
||
struct usb_rndis *rndis = container_of(ndev, struct usb_rndis, ndev);
|
||
uinst_t device = rndis->device;
|
||
USBD_CDC_RNDIS_PacketMsgTypeDef *packet = NULL;
|
||
rt_uint8_t *p_data;
|
||
rt_uint32_t size = 0;
|
||
rt_uint32_t offset = 0;
|
||
rt_uint32_t i;
|
||
|
||
if (data == NULL || count == 0) {
|
||
return -EINVAL;
|
||
}
|
||
if (!rndis->ready) {
|
||
// usb没准备好就不发包
|
||
os_printf("rndis scatter send no ready\r\n");
|
||
return -EIO;
|
||
}
|
||
for (i = 0; i < count; ++i) size += data[i].size;
|
||
packet = (USBD_CDC_RNDIS_PacketMsgTypeDef *)os_malloc(size + sizeof(USBD_CDC_RNDIS_PacketMsgTypeDef));
|
||
if (packet == NULL) {
|
||
return -ENOMEM;
|
||
}
|
||
os_memset(packet, 0, sizeof(USBD_CDC_RNDIS_PacketMsgTypeDef));
|
||
packet->MsgType = CDC_RNDIS_PACKET_MSG_ID;
|
||
packet->MsgLength = size + 44;
|
||
packet->DataOffset = 36; // 明明是44,但是抓包看全是36,不知道为什么
|
||
packet->DataLength = size;
|
||
// 拷贝scatter中数据
|
||
p_data = (rt_uint8_t *)(packet + 1);
|
||
for (i = 0; i < count; ++i) {
|
||
hw_memcpy(p_data + offset, data[i].addr, data[i].size);
|
||
offset += data[i].size;
|
||
}
|
||
rt_usb_hcd_pipe_xfer(device->hcd, rndis->pipe_out, packet, packet->MsgLength, 1000);
|
||
os_free(packet);
|
||
return RET_OK;
|
||
}
|
||
|
||
void rt_usbh_rndis_network_init(struct usb_rndis *rndis)
|
||
{
|
||
struct netdev *ndev = &rndis->ndev;
|
||
rt_uint8_t mac[8]; // 有些设备返回mac会多些字节
|
||
rt_uint32_t recv_len = 0;
|
||
rt_uint32_t packet_filter = CDC_RNDIS_PACKET_DIRECTED | \
|
||
CDC_RNDIS_PACKET_ALL_MULTICAST | \
|
||
CDC_RNDIS_PACKET_BROADCAST | \
|
||
CDC_RNDIS_PACKET_PROMISCUOUS;
|
||
|
||
if (ndev) {
|
||
// tcpip_init(NULL, NULL); // 外面wifi应该初始化过了
|
||
rt_rndis_msg_query(rndis, OID_802_3_CURRENT_ADDRESS, mac, &recv_len);
|
||
os_memcpy(rndis->mac, mac, 6);
|
||
rt_rndis_msg_set(rndis, OID_GEN_CURRENT_PACKET_FILTER, (rt_uint8_t *)&packet_filter, 4);
|
||
lwip_netif_add(ndev, "l0", NULL, NULL, NULL);
|
||
// 利用事件驱动
|
||
os_printf("add l0 interface!\r\n");
|
||
}
|
||
}
|
||
|
||
static const struct netdev_hal_ops rndis_ops = {
|
||
.open = rt_usbh_rndis_open,
|
||
.close = NULL,
|
||
.ioctl = rt_usbh_rndis_ioctl,
|
||
.send_data = rt_usbh_rndis_send_data,
|
||
.send_scatter_data = rt_usbh_rndis_send_scatter_data,
|
||
};
|
||
|
||
rt_err_t rt_usbh_rndis_attach(struct usb_rndis *rndis)
|
||
{
|
||
if (rndis == NULL) {
|
||
return -EIO;
|
||
}
|
||
// 绑定处理函数
|
||
rndis->ndev.dev.ops = (const struct devobj_ops *)&rndis_ops;
|
||
// 顺便注册devid
|
||
return dev_register(HG_LTE_RNDIS_DEVID, (struct dev_obj *)rndis);
|
||
}
|
||
|
||
rt_err_t rt_usbh_rndis_attach2(void)
|
||
{
|
||
struct usb_rndis *rndis = (struct usb_rndis *)os_zalloc(sizeof(struct usb_rndis));
|
||
|
||
ASSERT(rndis);
|
||
rndis->ndev.dev.ops = (const struct devobj_ops *)&rndis_ops;
|
||
return dev_register(HG_LTE_RNDIS_DEVID, (struct dev_obj *)rndis);
|
||
}
|
||
|
||
void rndis_data_recv(void *context)
|
||
{
|
||
struct usb_rndis *rndis = context;
|
||
uinst_t device = rndis->device;
|
||
USBD_CDC_RNDIS_PacketMsgTypeDef *packet = NULL;
|
||
rt_uint32_t flags;
|
||
int recv_size;
|
||
int offset;
|
||
int shift;
|
||
netdev_input_cb input_cb;
|
||
void *input_priv;
|
||
rt_uint32_t target_copyLength = 0;
|
||
|
||
while (1) {
|
||
if (!rndis->ready) {
|
||
os_sleep_ms(10); // 需要有点延迟给线程,不然占住不释放
|
||
continue;
|
||
}
|
||
offset = 0;
|
||
recv_size = rt_usb_hcd_pipe_xfer(device->hcd, rndis->pipe_in, rndis->data_buffer, 2048, 0);
|
||
while (recv_size > 0) {
|
||
shift = offset % 4;
|
||
if (shift != 0) {
|
||
os_memmove(rndis->data_buffer + offset - shift , rndis->data_buffer + offset, recv_size);
|
||
offset -= shift;
|
||
}
|
||
/*上一个usb包余下的新rndis包数据*/
|
||
if (rndis->ts_saveLength) {
|
||
/*暂存的rndis包里有存储到该包的包头信息*/
|
||
if (rndis->ts_saveLength < sizeof(USBD_CDC_RNDIS_PacketMsgTypeDef)) {
|
||
/*先拷贝rndis包头大小的长度,确保能读取到该rndis包的长度信息*/
|
||
os_memcpy(rndis->ts_buffer + rndis->ts_saveLength,
|
||
rndis->data_buffer + offset,
|
||
MIN(recv_size, sizeof(USBD_CDC_RNDIS_PacketMsgTypeDef)));
|
||
rndis->ts_saveLength += MIN(recv_size, sizeof(USBD_CDC_RNDIS_PacketMsgTypeDef));
|
||
offset += MIN(recv_size, sizeof(USBD_CDC_RNDIS_PacketMsgTypeDef));
|
||
recv_size -= MIN(recv_size, sizeof(USBD_CDC_RNDIS_PacketMsgTypeDef));
|
||
}
|
||
packet = (USBD_CDC_RNDIS_PacketMsgTypeDef *)(rndis->ts_buffer);
|
||
} else {
|
||
packet = (USBD_CDC_RNDIS_PacketMsgTypeDef *)(rndis->data_buffer + offset);
|
||
/*没有余留的rndis包,包类型也不对,则丢掉该包,可能丢掉一整个聚合的包,正常不应该出现这种情况*/
|
||
if ((recv_size >= sizeof(uint32_t)) && (packet->MsgType != CDC_RNDIS_PACKET_MSG_ID)) {
|
||
os_printf("WRONG RNDIS ID!\r\n");
|
||
break;
|
||
}
|
||
/*包头对齐且长度大于一个完整包,则不用拷贝到暂存buf,直接传进lwip*/
|
||
if ((recv_size >= sizeof(USBD_CDC_RNDIS_PacketMsgTypeDef)) && (recv_size >= packet->MsgLength)) {
|
||
flags = disable_irq();
|
||
input_cb = rndis->input_cb;
|
||
input_priv = rndis->input_priv;
|
||
enable_irq(flags);
|
||
if (input_cb) {
|
||
input_cb(&rndis->ndev,
|
||
(rt_uint8_t *)packet + packet->DataOffset + 8,
|
||
packet->DataLength,
|
||
input_priv);
|
||
}
|
||
offset += packet->MsgLength;
|
||
recv_size -= packet->MsgLength;
|
||
continue;
|
||
}
|
||
}
|
||
if (recv_size > (2 * sizeof(uint32_t))) {
|
||
target_copyLength = (packet->MsgLength - rndis->ts_saveLength);
|
||
} else {
|
||
target_copyLength = recv_size;
|
||
}
|
||
if (recv_size) {
|
||
os_memcpy(rndis->ts_buffer + rndis->ts_saveLength,
|
||
rndis->data_buffer + offset,
|
||
MIN(recv_size, target_copyLength));
|
||
}
|
||
offset += MIN(recv_size, target_copyLength);
|
||
rndis->ts_saveLength += MIN(recv_size, target_copyLength);
|
||
recv_size -= MIN(recv_size, target_copyLength);
|
||
packet = (USBD_CDC_RNDIS_PacketMsgTypeDef *)(rndis->ts_buffer);
|
||
|
||
if ((packet->MsgType == CDC_RNDIS_PACKET_MSG_ID) && (rndis->ts_saveLength >= packet->MsgLength)) {
|
||
flags = disable_irq();
|
||
input_cb = rndis->input_cb;
|
||
input_priv = rndis->input_priv;
|
||
enable_irq(flags);
|
||
if (input_cb) {
|
||
input_cb(&rndis->ndev,
|
||
(rt_uint8_t *)packet + packet->DataOffset + 8,
|
||
packet->DataLength,
|
||
input_priv);
|
||
}
|
||
rndis->ts_saveLength -= packet->MsgLength;
|
||
}
|
||
}
|
||
if (recv_size < 0) {
|
||
// 返回负数大概是usb断线了,不再循环读数,准备释放线程了
|
||
rndis->ready = 0;
|
||
}
|
||
}
|
||
}
|
||
|
||
rt_err_t rt_usbh_rndis_run(struct usb_rndis *rndis)
|
||
{
|
||
if (rndis == NULL) {
|
||
return RET_ERR;
|
||
}
|
||
os_printf("rndis\r\n");
|
||
#ifndef STATIC_RNDIS_NETDEV
|
||
rt_usbh_rndis_attach(rndis);
|
||
rt_usbh_rndis_network_init(rndis);
|
||
#endif
|
||
|
||
rt_rndis_msg_init(rndis);
|
||
rndis->ready = 1;
|
||
|
||
os_timer_init(&rndis->keepalive_timer, rt_usbh_rndis_keepalive_timer,
|
||
OS_TIMER_MODE_ONCE, rndis);
|
||
os_timer_start(&rndis->keepalive_timer, 5000);
|
||
rt_thread_init(&rndis->recv_task, "rndis_recv", rndis_data_recv, rndis,
|
||
NULL, 512, OS_TASK_PRIORITY_HIGH-1, 20);
|
||
rt_thread_startup(&rndis->recv_task);
|
||
|
||
return RET_OK;
|
||
}
|
||
|
||
rt_err_t rt_usbh_rndis_stop(struct usb_rndis *rndis)
|
||
{
|
||
rt_uint32_t flags;
|
||
|
||
if (rndis == NULL) {
|
||
return RET_ERR;
|
||
}
|
||
|
||
rndis->ready = 0;
|
||
flags = disable_irq();
|
||
rndis->input_cb = NULL;
|
||
rndis->input_priv = NULL;
|
||
enable_irq(flags);
|
||
#ifndef STATIC_RNDIS_NETDEV
|
||
dev_unregister((struct dev_obj *)rndis);
|
||
lwip_netif_remove(&rndis->ndev);
|
||
#endif
|
||
os_timer_stop(&rndis->keepalive_timer);
|
||
os_timer_del(&rndis->keepalive_timer);
|
||
rt_thread_detach(&rndis->recv_task);
|
||
os_free(rndis->msg_buffer);
|
||
os_free(rndis->data_buffer);
|
||
os_free(rndis->ts_buffer);
|
||
#ifndef STATIC_RNDIS_NETDEV
|
||
os_free(rndis);
|
||
#endif
|
||
|
||
return RET_OK;
|
||
}
|
||
|
||
#endif |