|
|
|
@ -70,6 +70,14 @@
|
|
|
|
|
(CONFIG_NET_ETH_PKTSIZE + CONFIG_NET_GUARDSIZE + RNDIS_PACKET_HDR_SIZE)
|
|
|
|
|
#define CONFIG_RNDIS_BULKOUT_REQLEN CONFIG_RNDIS_BULKIN_REQLEN
|
|
|
|
|
|
|
|
|
|
static_assert(CONFIG_NET_LL_GUARDSIZE >= RNDIS_PACKET_HDR_SIZE + ETH_HDRLEN,
|
|
|
|
|
"CONFIG_NET_LL_GUARDSIZE cannot be less than ETH_HDRLEN"
|
|
|
|
|
" + RNDIS_PACKET_HDR_SIZE");
|
|
|
|
|
|
|
|
|
|
static_assert((CONFIG_NET_LL_GUARDSIZE % 4) == 2,
|
|
|
|
|
"CONFIG_NET_LL_GUARDSIZE - ETH_HDRLEN "
|
|
|
|
|
"should be aligned to 4 bytes");
|
|
|
|
|
|
|
|
|
|
#define RNDIS_NCONFIGS (1)
|
|
|
|
|
#define RNDIS_CONFIGID (1)
|
|
|
|
|
#define RNDIS_CONFIGIDNONE (0)
|
|
|
|
@ -108,6 +116,8 @@ struct rndis_req_s
|
|
|
|
|
{
|
|
|
|
|
FAR struct rndis_req_s *flink; /* Implements a singly linked list */
|
|
|
|
|
FAR struct usbdev_req_s *req; /* The contained request */
|
|
|
|
|
FAR struct iob_s *iob; /* IOB offload */
|
|
|
|
|
FAR uint8_t *buf; /* Use malloc buffer when config IOB_LEN < CONFIG_RNDIS_BULKIN_REQLEN */
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* This structure describes the internal state of the driver */
|
|
|
|
@ -632,6 +642,14 @@ static void rndis_freewrreq(FAR struct rndis_dev_s *priv,
|
|
|
|
|
FAR struct rndis_req_s *req)
|
|
|
|
|
{
|
|
|
|
|
DEBUGASSERT(req != NULL);
|
|
|
|
|
if (req->iob)
|
|
|
|
|
{
|
|
|
|
|
/* In ep submit case, need release iob chain when write complete */
|
|
|
|
|
|
|
|
|
|
iob_free_chain(req->iob);
|
|
|
|
|
req->iob = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sq_addlast((FAR sq_entry_t *)req, &priv->reqlist);
|
|
|
|
|
rndis_submit_rdreq(priv);
|
|
|
|
|
}
|
|
|
|
@ -665,11 +683,6 @@ static bool rndis_allocnetreq(FAR struct rndis_dev_s *priv)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
priv->net_req = rndis_allocwrreq(priv);
|
|
|
|
|
if (priv->net_req)
|
|
|
|
|
{
|
|
|
|
|
priv->netdev.d_buf = &priv->net_req->req->buf[RNDIS_PACKET_HDR_SIZE];
|
|
|
|
|
priv->netdev.d_len = CONFIG_NET_ETH_PKTSIZE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
leave_critical_section(flags);
|
|
|
|
|
return priv->net_req != NULL;
|
|
|
|
@ -699,8 +712,6 @@ static void rndis_sendnetreq(FAR struct rndis_dev_s *priv)
|
|
|
|
|
EP_SUBMIT(priv->epbulkin, priv->net_req->req);
|
|
|
|
|
|
|
|
|
|
priv->net_req = NULL;
|
|
|
|
|
priv->netdev.d_buf = NULL;
|
|
|
|
|
priv->netdev.d_len = 0;
|
|
|
|
|
leave_critical_section(flags);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -723,12 +734,56 @@ static void rndis_freenetreq(FAR struct rndis_dev_s *priv)
|
|
|
|
|
irqstate_t flags = enter_critical_section();
|
|
|
|
|
|
|
|
|
|
rndis_freewrreq(priv, priv->net_req);
|
|
|
|
|
priv->net_req = NULL;
|
|
|
|
|
priv->netdev.d_buf = NULL;
|
|
|
|
|
priv->netdev.d_len = 0;
|
|
|
|
|
priv->net_req = NULL;
|
|
|
|
|
|
|
|
|
|
leave_critical_section(flags);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
|
* Name: rndis_iob2buf
|
|
|
|
|
*
|
|
|
|
|
* Description:
|
|
|
|
|
* Map the appropriate location of req iob to buf.
|
|
|
|
|
*
|
|
|
|
|
* Input Parameters:
|
|
|
|
|
* priv: pointer to RNDIS device driver structure
|
|
|
|
|
* req: the request whose buffer we should fill
|
|
|
|
|
* Assumptions:
|
|
|
|
|
* Caller holds the network lock
|
|
|
|
|
*
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static void rndis_iob2buf(FAR struct rndis_dev_s *priv,
|
|
|
|
|
FAR struct rndis_req_s *req)
|
|
|
|
|
{
|
|
|
|
|
uint16_t llhdrlen = NET_LL_HDRLEN(&priv->netdev);
|
|
|
|
|
uint32_t offset = CONFIG_NET_LL_GUARDSIZE - llhdrlen -
|
|
|
|
|
RNDIS_PACKET_HDR_SIZE;
|
|
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
|
|
|
|
* |<--- CONFIG_NET_LL_GUARDSIZE ---->|<-- io_len/io_pktlen(0) -->|
|
|
|
|
|
* ---------------------------------------------------------------|
|
|
|
|
|
* |unused | rndis hdr size |llhdrlen |<-- io_len/io_pktlen(0) -->|
|
|
|
|
|
* ---------------------------------------------------------------|
|
|
|
|
|
* |unused | req->buf(0) |
|
|
|
|
|
* ---------------------------------------------------------------|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (req->iob->io_flink == NULL)
|
|
|
|
|
{
|
|
|
|
|
req->req->buf = &req->iob->io_data[offset];
|
|
|
|
|
req->req->len = CONFIG_RNDIS_BULKIN_REQLEN;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
req->req->buf = req->buf;
|
|
|
|
|
iob_copyout(&req->req->buf[RNDIS_PACKET_HDR_SIZE], req->iob,
|
|
|
|
|
req->iob->io_pktlen + llhdrlen, -llhdrlen);
|
|
|
|
|
iob_free_chain(req->iob);
|
|
|
|
|
req->iob = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
|
* Name: rndis_allocrxreq
|
|
|
|
|
*
|
|
|
|
@ -748,13 +803,33 @@ static void rndis_freenetreq(FAR struct rndis_dev_s *priv)
|
|
|
|
|
|
|
|
|
|
static bool rndis_allocrxreq(FAR struct rndis_dev_s *priv)
|
|
|
|
|
{
|
|
|
|
|
FAR struct iob_s *iob;
|
|
|
|
|
|
|
|
|
|
if (priv->rx_req != NULL)
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
priv->rx_req = rndis_allocwrreq(priv);
|
|
|
|
|
return priv->rx_req != NULL;
|
|
|
|
|
/* Prepare buffer to receivce data from usb driver */
|
|
|
|
|
|
|
|
|
|
iob = iob_tryalloc(false);
|
|
|
|
|
if (iob == NULL)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
iob_reserve(iob, CONFIG_NET_LL_GUARDSIZE);
|
|
|
|
|
|
|
|
|
|
if ((priv->rx_req = rndis_allocwrreq(priv)) == NULL)
|
|
|
|
|
{
|
|
|
|
|
iob_free_chain(iob);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
priv->rx_req->iob = iob;
|
|
|
|
|
rndis_iob2buf(priv, priv->rx_req);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
@ -776,10 +851,16 @@ static void rndis_giverxreq(FAR struct rndis_dev_s *priv)
|
|
|
|
|
DEBUGASSERT(priv->rx_req != NULL);
|
|
|
|
|
DEBUGASSERT(priv->net_req == NULL);
|
|
|
|
|
|
|
|
|
|
priv->net_req = priv->rx_req;
|
|
|
|
|
priv->netdev.d_buf = &priv->net_req->req->buf[RNDIS_PACKET_HDR_SIZE];
|
|
|
|
|
priv->netdev.d_len = CONFIG_NET_ETH_PKTSIZE;
|
|
|
|
|
priv->rx_req = NULL;
|
|
|
|
|
priv->net_req = priv->rx_req;
|
|
|
|
|
priv->rx_req = NULL;
|
|
|
|
|
|
|
|
|
|
/* Move iob from net_req to netdev */
|
|
|
|
|
|
|
|
|
|
netdev_iob_release(&priv->netdev);
|
|
|
|
|
|
|
|
|
|
priv->netdev.d_iob = priv->net_req->iob;
|
|
|
|
|
priv->netdev.d_len = priv->net_req->iob->io_pktlen;
|
|
|
|
|
priv->net_req->iob = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
@ -801,20 +882,23 @@ static void rndis_giverxreq(FAR struct rndis_dev_s *priv)
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static uint16_t rndis_fillrequest(FAR struct rndis_dev_s *priv,
|
|
|
|
|
FAR struct usbdev_req_s *req)
|
|
|
|
|
FAR struct rndis_req_s *req)
|
|
|
|
|
{
|
|
|
|
|
size_t datalen;
|
|
|
|
|
|
|
|
|
|
req->len = 0;
|
|
|
|
|
req->req->len = 0;
|
|
|
|
|
|
|
|
|
|
datalen = MIN(priv->netdev.d_len,
|
|
|
|
|
CONFIG_RNDIS_BULKIN_REQLEN - RNDIS_PACKET_HDR_SIZE);
|
|
|
|
|
if (datalen > 0)
|
|
|
|
|
{
|
|
|
|
|
/* Send the required headers */
|
|
|
|
|
/* Move iob from netdev to net_req and send the required headers */
|
|
|
|
|
|
|
|
|
|
req->iob = priv->netdev.d_iob;
|
|
|
|
|
netdev_iob_clear(&priv->netdev);
|
|
|
|
|
rndis_iob2buf(priv, req);
|
|
|
|
|
FAR struct rndis_packet_msg *msg =
|
|
|
|
|
(FAR struct rndis_packet_msg *)req->buf;
|
|
|
|
|
(FAR struct rndis_packet_msg *)req->req->buf;
|
|
|
|
|
memset(msg, 0, RNDIS_PACKET_HDR_SIZE);
|
|
|
|
|
|
|
|
|
|
msg->msgtype = RNDIS_PACKET_MSG;
|
|
|
|
@ -822,11 +906,11 @@ static uint16_t rndis_fillrequest(FAR struct rndis_dev_s *priv,
|
|
|
|
|
msg->dataoffset = RNDIS_PACKET_HDR_SIZE - 8;
|
|
|
|
|
msg->datalen = datalen;
|
|
|
|
|
|
|
|
|
|
req->flags = USBDEV_REQFLAGS_NULLPKT;
|
|
|
|
|
req->len = datalen + RNDIS_PACKET_HDR_SIZE;
|
|
|
|
|
req->req->flags = USBDEV_REQFLAGS_NULLPKT;
|
|
|
|
|
req->req->len = datalen + RNDIS_PACKET_HDR_SIZE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return req->len;
|
|
|
|
|
return req->req->len;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
@ -852,7 +936,9 @@ static void rndis_rxdispatch(FAR void *arg)
|
|
|
|
|
priv->netdev.d_len = priv->current_rx_datagram_size;
|
|
|
|
|
leave_critical_section(flags);
|
|
|
|
|
|
|
|
|
|
hdr = (FAR struct eth_hdr_s *)priv->netdev.d_buf;
|
|
|
|
|
hdr = (FAR struct eth_hdr_s *)
|
|
|
|
|
&priv->netdev.d_iob->io_data[CONFIG_NET_LL_GUARDSIZE -
|
|
|
|
|
NET_LL_HDRLEN(&priv->netdev)];
|
|
|
|
|
|
|
|
|
|
/* We only accept IP packets of the configured type and ARP packets */
|
|
|
|
|
|
|
|
|
@ -965,7 +1051,7 @@ static int rndis_transmit(FAR struct rndis_dev_s *priv)
|
|
|
|
|
|
|
|
|
|
/* Queue the packet */
|
|
|
|
|
|
|
|
|
|
rndis_fillrequest(priv, priv->net_req->req);
|
|
|
|
|
rndis_fillrequest(priv, priv->net_req);
|
|
|
|
|
rndis_sendnetreq(priv);
|
|
|
|
|
|
|
|
|
|
if (!rndis_allocnetreq(priv))
|
|
|
|
@ -1110,9 +1196,10 @@ static inline int rndis_recvpacket(FAR struct rndis_dev_s *priv,
|
|
|
|
|
priv->current_rx_datagram_offset = msg->dataoffset + 8;
|
|
|
|
|
if (priv->current_rx_datagram_offset < reqlen)
|
|
|
|
|
{
|
|
|
|
|
memcpy(&priv->rx_req->req->buf[RNDIS_PACKET_HDR_SIZE],
|
|
|
|
|
&reqbuf[priv->current_rx_datagram_offset],
|
|
|
|
|
reqlen - priv->current_rx_datagram_offset);
|
|
|
|
|
iob_trycopyin(priv->rx_req->iob,
|
|
|
|
|
&reqbuf[priv->current_rx_datagram_offset],
|
|
|
|
|
reqlen - priv->current_rx_datagram_offset,
|
|
|
|
|
-NET_LL_HDRLEN(&priv->netdev), false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
@ -1136,8 +1223,8 @@ static inline int rndis_recvpacket(FAR struct rndis_dev_s *priv,
|
|
|
|
|
|
|
|
|
|
if ((index + copysize) <= CONFIG_NET_ETH_PKTSIZE)
|
|
|
|
|
{
|
|
|
|
|
memcpy(&priv->rx_req->req->buf[RNDIS_PACKET_HDR_SIZE + index],
|
|
|
|
|
reqbuf, copysize);
|
|
|
|
|
iob_trycopyin(priv->rx_req->iob, reqbuf, copysize,
|
|
|
|
|
priv->rx_req->iob->io_pktlen, false);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
@ -1721,13 +1808,24 @@ static FAR struct usbdev_req_s *usbclass_allocreq(FAR struct usbdev_ep_s *ep,
|
|
|
|
|
req = EP_ALLOCREQ(ep);
|
|
|
|
|
if (req != NULL)
|
|
|
|
|
{
|
|
|
|
|
req->len = len;
|
|
|
|
|
req->buf = EP_ALLOCBUFFER(ep, len);
|
|
|
|
|
/* rdreq/epintin_req/ctrlreq use fixed memory
|
|
|
|
|
* reqcontainer use iob dynamically when needed
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (req->buf == NULL)
|
|
|
|
|
req->len = len;
|
|
|
|
|
if (len > 0)
|
|
|
|
|
{
|
|
|
|
|
EP_FREEREQ(ep, req);
|
|
|
|
|
req = NULL;
|
|
|
|
|
req->buf = EP_ALLOCBUFFER(ep, len);
|
|
|
|
|
|
|
|
|
|
if (req->buf == NULL)
|
|
|
|
|
{
|
|
|
|
|
EP_FREEREQ(ep, req);
|
|
|
|
|
req = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
req->buf = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -2109,9 +2207,11 @@ static int usbclass_bind(FAR struct usbdevclass_driver_s *driver,
|
|
|
|
|
* size.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
reqlen = 64;
|
|
|
|
|
|
|
|
|
|
if (CONFIG_RNDIS_BULKIN_REQLEN > reqlen)
|
|
|
|
|
if (CONFIG_IOB_BUFSIZE >= CONFIG_RNDIS_BULKIN_REQLEN)
|
|
|
|
|
{
|
|
|
|
|
reqlen = 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
reqlen = CONFIG_RNDIS_BULKIN_REQLEN;
|
|
|
|
|
}
|
|
|
|
@ -2128,6 +2228,7 @@ static int usbclass_bind(FAR struct usbdevclass_driver_s *driver,
|
|
|
|
|
goto errout;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
reqcontainer->buf = reqcontainer->req->buf;
|
|
|
|
|
reqcontainer->req->priv = reqcontainer;
|
|
|
|
|
reqcontainer->req->callback = rndis_wrcomplete;
|
|
|
|
|
|
|
|
|
@ -2269,6 +2370,7 @@ static void usbclass_unbind(FAR struct usbdevclass_driver_s *driver,
|
|
|
|
|
reqcontainer = (struct rndis_req_s *)sq_remfirst(&priv->reqlist);
|
|
|
|
|
if (reqcontainer->req != NULL)
|
|
|
|
|
{
|
|
|
|
|
reqcontainer->req->buf = reqcontainer->buf;
|
|
|
|
|
usbclass_freereq(priv->epbulkin, reqcontainer->req);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|