#include "u_ether.h"
#include "rndis.h"
+#define F_RNDIS_LOG "USB_RNDIS"
+
+#define f_rndis_debug 0
/*
* This function is an RNDIS Ethernet port -- a Microsoft protocol that's
* - MS-Windows drivers sometimes emit undocumented requests.
*/
+static unsigned int rndis_dl_max_pkt_per_xfer = 3;
+module_param(rndis_dl_max_pkt_per_xfer, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(rndis_dl_max_pkt_per_xfer,
+ "Maximum packets per transfer for DL aggregation");
+
+static unsigned int rndis_ul_max_pkt_per_xfer = 1;
+module_param(rndis_ul_max_pkt_per_xfer, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(rndis_ul_max_pkt_per_xfer,
+ "Maximum packets per transfer for UL aggregation");
+
struct f_rndis {
struct gether port;
u8 ctrl_id, data_id;
NULL,
};
+u32 rndis_test_last_resp_id = 0;
+
/*-------------------------------------------------------------------------*/
static struct sk_buff *rndis_add_header(struct gether *port,
struct sk_buff *skb)
{
struct sk_buff *skb2;
-
- skb2 = skb_realloc_headroom(skb, sizeof(struct rndis_packet_msg_type));
- if (skb2)
- rndis_add_hdr(skb2);
-
- dev_kfree_skb_any(skb);
- return skb2;
+ struct rndis_packet_msg_type *header = NULL;
+ struct f_rndis *rndis = func_to_rndis(&port->func);
+
+ if (rndis->port.multi_pkt_xfer) {
+ if (port->header) {
+ header = port->header;
+ memset(header, 0, sizeof(*header));
+ header->MessageType = cpu_to_le32(RNDIS_MSG_PACKET);
+ header->MessageLength = cpu_to_le32(skb->len +
+ sizeof(*header));
+ header->DataOffset = cpu_to_le32(36);
+ header->DataLength = cpu_to_le32(skb->len);
+ pr_debug("MessageLength:%d DataLength:%d\n",
+ header->MessageLength,
+ header->DataLength);
+ return skb;
+ } else {
+ pr_err("RNDIS header is NULL.\n");
+ return NULL;
+ }
+ } else {
+ skb2 = skb_realloc_headroom(skb,
+ sizeof(struct rndis_packet_msg_type));
+ if (skb2)
+ rndis_add_hdr(skb2);
+
+ dev_kfree_skb(skb);
+ return skb2;
+ }
}
static void rndis_response_available(void *_rndis)
static void rndis_response_complete(struct usb_ep *ep, struct usb_request *req)
{
struct f_rndis *rndis = req->context;
- struct usb_composite_dev *cdev = rndis->port.func.config->cdev;
+ struct usb_composite_dev *cdev;
int status = req->status;
+ if (!rndis->port.func.config || !rndis->port.func.config->cdev)
+ return;
+ else
+ cdev = rndis->port.func.config->cdev;
+
/* after TX:
* - USB_CDC_GET_ENCAPSULATED_RESPONSE (ep0/control)
* - RNDIS_RESPONSE_AVAILABLE (status/irq)
static void rndis_command_complete(struct usb_ep *ep, struct usb_request *req)
{
struct f_rndis *rndis = req->context;
+ struct usb_composite_dev *cdev;
int status;
+ rndis_init_msg_type *buf;
+
+ if (!rndis->port.func.config || !rndis->port.func.config->cdev)
+ return;
+ else
+ cdev = rndis->port.func.config->cdev;
/* received RNDIS command from USB_CDC_SEND_ENCAPSULATED_COMMAND */
// spin_lock(&dev->lock);
if (status < 0)
pr_err("RNDIS command error %d, %d/%d\n",
status, req->actual, req->length);
+
+ buf = (rndis_init_msg_type *)req->buf;
+
+ if (buf->MessageType == RNDIS_MSG_INIT) {
+ if (buf->MaxTransferSize > 2048){
+ rndis->port.multi_pkt_xfer = 1;
+ rndis->port.dl_max_transfer_len = buf->MaxTransferSize;
+ }else{
+ rndis->port.multi_pkt_xfer = 0;
+ }
+ DBG(cdev, "%s: MaxTransferSize: %d : Multi_pkt_txr: %s\n",
+ __func__, buf->MaxTransferSize,
+ rndis->port.multi_pkt_xfer ? "enabled" :
+ "disabled");
+ if (rndis_dl_max_pkt_per_xfer <= 1)
+ rndis->port.multi_pkt_xfer = 0;
+ }
// spin_unlock(&dev->lock);
}
/* composite driver infrastructure handles everything except
* CDC class messages; interface activation uses set_alt().
*/
+
+ if (f_rndis_debug){
+ pr_debug("rndis_setup , ctrl->bRequestType is 0x%x, ctrl->bRequest is 0x%x, w_index is 0x%x, w_value is 0x%x\n" ,
+ ctrl->bRequestType , ctrl->bRequest, w_index, w_value) ;
+ }
+
switch ((ctrl->bRequestType << 8) | ctrl->bRequest) {
/* RNDIS uses the CDC command encapsulation mechanism to implement
else {
u8 *buf;
u32 n;
+ u32 MsgType, MsgLength, MsgID;
+ __le32 *tmp;
/* return the result */
buf = rndis_get_next_response(rndis->config, &n);
memcpy(req->buf, buf, n);
req->complete = rndis_response_complete;
req->context = rndis;
+ tmp = (__le32 *)buf;
+ MsgType = get_unaligned_le32(tmp++);
+ MsgLength = get_unaligned_le32(tmp++);
+ MsgID = get_unaligned_le32(tmp++);
+
rndis_free_response(rndis->config, buf);
value = n;
+
+ if (f_rndis_debug){
+ pr_debug("rndis_setup, rndis response MsgLength %d, msg type is 0x%x, RequestID is 0x%x\n", MsgLength, MsgType, MsgID);
+ }
+ rndis_test_last_resp_id = MsgID ;
}
/* else stalls ... spec says to avoid that */
}
default:
invalid:
+ pr_err("invalid control req%02x.%02x v%04x i%04x l%d\n",
+ ctrl->bRequestType, ctrl->bRequest,
+ w_value, w_index, w_length);
+
VDBG(cdev, "invalid control req%02x.%02x v%04x i%04x l%d\n",
ctrl->bRequestType, ctrl->bRequest,
w_value, w_index, w_length);
struct usb_composite_dev *cdev = f->config->cdev;
/* we know alt == 0 */
+ printk( F_RNDIS_LOG "rndis_set_alt - interface : %d, rndis ctrl id : %d, rndis data id : %d\n" ,
+ intf, rndis->ctrl_id, rndis->data_id);
if (intf == rndis->ctrl_id) {
if (rndis->notify->driver_data) {
VDBG(cdev, "reset rndis control %d\n", intf);
+ printk( F_RNDIS_LOG "reset rndis control %d\n", intf);
usb_ep_disable(rndis->notify);
}
if (!rndis->notify->desc) {
VDBG(cdev, "init rndis ctrl %d\n", intf);
+ printk( F_RNDIS_LOG "init rndis ctrl %d\n", intf);
if (config_ep_by_speed(cdev->gadget, f, rndis->notify))
goto fail;
}
if (rndis->port.in_ep->driver_data) {
DBG(cdev, "reset rndis\n");
+ printk( F_RNDIS_LOG "reset rndis\n");
gether_disconnect(&rndis->port);
}
if (!rndis->port.in_ep->desc || !rndis->port.out_ep->desc) {
DBG(cdev, "init rndis\n");
+ printk( F_RNDIS_LOG "init rndis\n");
if (config_ep_by_speed(cdev->gadget, f,
rndis->port.in_ep) ||
config_ep_by_speed(cdev->gadget, f,
return;
DBG(cdev, "rndis deactivated\n");
+ printk( F_RNDIS_LOG "rndis deactivated\n");
rndis_uninit(rndis->config);
gether_disconnect(&rndis->port);
struct usb_composite_dev *cdev = geth->func.config->cdev;
DBG(cdev, "%s\n", __func__);
+ printk( F_RNDIS_LOG "%s\n", __func__);
rndis_set_param_medium(rndis->config, RNDIS_MEDIUM_802_3,
bitrate(cdev->gadget) / 100);
struct f_rndis *rndis = func_to_rndis(&geth->func);
DBG(geth->func.config->cdev, "%s\n", __func__);
+ printk( F_RNDIS_LOG "%s\n", __func__);
rndis_set_param_medium(rndis->config, RNDIS_MEDIUM_802_3, 0);
rndis_signal_disconnect(rndis->config);
int status;
struct usb_ep *ep;
+ printk( F_RNDIS_LOG \
+ "%s: rndis_bind begin \n", \
+ __func__);
+
/* allocate instance-specific interface IDs */
status = usb_interface_id(c, f);
if (status < 0)
rndis_set_param_medium(rndis->config, RNDIS_MEDIUM_802_3, 0);
rndis_set_host_mac(rndis->config, rndis->ethaddr);
+ rndis_set_max_pkt_xfer(rndis->config, rndis_ul_max_pkt_per_xfer);
if (rndis->manufacturer && rndis->vendorID &&
rndis_set_param_vendor(rndis->config, rndis->vendorID,
* until we're activated via set_alt().
*/
+ printk( F_RNDIS_LOG
+ "RNDIS: %s speed IN/%s OUT/%s NOTIFY/%s\n",
+ gadget_is_superspeed(c->cdev->gadget) ? "super" :
+ gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
+ rndis->port.in_ep->name, rndis->port.out_ep->name,
+ rndis->notify->name);
+
DBG(cdev, "RNDIS: %s speed IN/%s OUT/%s NOTIFY/%s\n",
gadget_is_superspeed(c->cdev->gadget) ? "super" :
gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
{
struct f_rndis *rndis = func_to_rndis(f);
+ printk( F_RNDIS_LOG \
+ "%s: rndis_unbind \n", \
+ __func__);
+
+
rndis_deregister(rndis->config);
rndis_exit();
if (!can_support_rndis(c) || !ethaddr)
return -EINVAL;
- if (rndis_string_defs[0].id == 0) {
- /* ... and setup RNDIS itself */
- status = rndis_init();
- if (status < 0)
- return status;
+ /* setup RNDIS itself */
+ status = rndis_init();
+ if (status < 0)
+ return status;
+ if (rndis_string_defs[0].id == 0) {
status = usb_string_ids_tab(c->cdev, rndis_string_defs);
if (status)
return status;
rndis->port.header_len = sizeof(struct rndis_packet_msg_type);
rndis->port.wrap = rndis_add_header;
rndis->port.unwrap = rndis_rm_hdr;
+ rndis->port.ul_max_pkts_per_xfer = rndis_ul_max_pkt_per_xfer;
+ rndis->port.dl_max_pkts_per_xfer = rndis_dl_max_pkt_per_xfer;
rndis->port.func.name = "rndis";
rndis->port.func.strings = rndis_strings;
fail:
rndis_exit();
}
+
+ printk( F_RNDIS_LOG \
+ "%s: rndis_bind_config_vendor done, status is %d \n", \
+ __func__, status);
return status;
}