Loading drivers/usb/gadget/function/Makefile +4 −1 Original line number Diff line number Diff line Loading @@ -62,5 +62,8 @@ usb_f_ccid-y := f_ccid.o obj-$(CONFIG_USB_F_CCID) += usb_f_ccid.o usb_f_cdev-y := f_cdev.o obj-$(CONFIG_USB_F_CDEV) += usb_f_cdev.o usb_f_gsi-y := f_gsi.o rndis.o usb_f_gsi-y := f_gsi.o ifeq ($(CONFIG_USB_F_RNDIS),) usb_f_gsi-y += rndis.o endif obj-$(CONFIG_USB_F_GSI) += usb_f_gsi.o drivers/usb/gadget/function/f_gsi.c +67 −26 Original line number Diff line number Diff line Loading @@ -2038,20 +2038,47 @@ static void gsi_rndis_command_complete(struct usb_ep *ep, struct usb_request *req) { struct f_gsi *gsi = req->context; rndis_init_msg_type *buf; int status; u32 MsgType; if (!req->buf || !gsi->params) return; MsgType = get_unaligned_le32((__le32 *)req->buf); /* intercept halt message to perform flow control */ if (MsgType == RNDIS_MSG_HALT) { log_event_dbg("RNDIS_MSG_HALT, state:%d\n", gsi->params->state); if (gsi->params->state == RNDIS_DATA_INITIALIZED) gsi_rndis_flow_ctrl_enable(true, gsi->params); gsi->params->state = RNDIS_UNINITIALIZED; return; } status = rndis_msg_parser(gsi->params, (u8 *) req->buf); if (status < 0) log_event_err("RNDIS command error %d, %d/%d", status, req->actual, req->length); buf = (rndis_init_msg_type *)req->buf; if (le32_to_cpu(buf->MessageType) == RNDIS_MSG_INIT) { if (MsgType == RNDIS_MSG_INIT) { rndis_init_msg_type *buf = (rndis_init_msg_type *)req->buf; log_event_dbg("RNDIS host major:%d minor:%d version\n", le32_to_cpu(buf->MajorVersion), le32_to_cpu(buf->MinorVersion)); /* honor host dl aggr size */ gsi->d_port.in_aggr_size = gsi->params->dl_max_xfer_size; log_event_dbg("RNDIS host dl_aggr_size:%d\n", gsi->params->dl_max_xfer_size); gsi->d_port.in_aggr_size = le32_to_cpu(buf->MaxTransferSize); log_event_dbg("RNDIS host DL MaxTransferSize:%d\n", le32_to_cpu(buf->MaxTransferSize)); } else if (MsgType == RNDIS_MSG_SET) { rndis_set_msg_type *buf = (rndis_set_msg_type *)req->buf; if (le32_to_cpu(buf->OID) == RNDIS_OID_GEN_CURRENT_PACKET_FILTER) gsi_rndis_flow_ctrl_enable(!(*gsi->params->filter), gsi->params); } } Loading Loading @@ -2182,13 +2209,37 @@ gsi_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) goto invalid; if (gsi->prot_id == IPA_USB_RNDIS) { rndis_init_cmplt_type *res; /* return the result */ buf = rndis_get_next_response(gsi->params, &n); if (buf) { if (!buf) break; res = (rndis_init_cmplt_type *)buf; if (le32_to_cpu(res->MessageType) == RNDIS_MSG_INIT_C) { log_event_dbg("%s: max_pkt_per_xfer : %d", __func__, DEFAULT_MAX_PKT_PER_XFER); res->MaxPacketsPerTransfer = cpu_to_le32(DEFAULT_MAX_PKT_PER_XFER); res->MaxTransferSize = cpu_to_le32( le32_to_cpu(res->MaxTransferSize) * DEFAULT_MAX_PKT_PER_XFER); /* In case of aggregated packets QC device * will request aliment to 4 (2^2). */ log_event_dbg("%s: pkt_alignment_factor : %d", __func__, DEFAULT_PKT_ALIGNMENT_FACTOR); res->PacketAlignmentFactor = cpu_to_le32( DEFAULT_PKT_ALIGNMENT_FACTOR); } memcpy(req->buf, buf, n); rndis_free_response(gsi->params, buf); value = n; } break; } Loading Loading @@ -2545,8 +2596,11 @@ static void gsi_resume(struct usb_function *f) */ if (gsi->prot_id == IPA_USB_RNDIS && !usb_gsi_remote_wakeup_allowed(f) && gsi->host_supports_flow_control) rndis_flow_control(gsi->params, false); gsi->host_supports_flow_control && gsi->params) { if (gsi->params->state != RNDIS_DATA_INITIALIZED) gsi_rndis_flow_ctrl_enable(false, gsi->params); gsi->params->state = RNDIS_DATA_INITIALIZED; } post_event(&gsi->d_port, EVT_RESUMED); queue_delayed_work(gsi->d_port.ipa_usb_wq, &gsi->d_port.usb_ipa_w, 0); Loading Loading @@ -2831,8 +2885,7 @@ static int gsi_bind(struct usb_configuration *c, struct usb_function *f) info.out_req_num_buf = GSI_NUM_OUT_BUFFERS; info.notify_buf_len = sizeof(struct usb_cdc_notification); params = rndis_register(gsi_rndis_response_available, gsi, gsi_rndis_flow_ctrl_enable); params = rndis_register(gsi_rndis_response_available, gsi); if (IS_ERR(params)) goto fail; Loading @@ -2855,18 +2908,6 @@ static int gsi_bind(struct usb_configuration *c, struct usb_function *f) gsi->manufacturer)) goto dereg_rndis; log_event_dbg("%s: max_pkt_per_xfer : %d", __func__, DEFAULT_MAX_PKT_PER_XFER); rndis_set_max_pkt_xfer(gsi->params, DEFAULT_MAX_PKT_PER_XFER); /* In case of aggregated packets QC device will request * aliment to 4 (2^2). */ log_event_dbg("%s: pkt_alignment_factor : %d", __func__, DEFAULT_PKT_ALIGNMENT_FACTOR); rndis_set_pkt_alignment_factor(gsi->params, DEFAULT_PKT_ALIGNMENT_FACTOR); /* Windows7/Windows10 automatically loads RNDIS drivers for * class drivers which represents MISC_ACTIVE_SYNC, * MISC_RNDIS_OVER_ETHERNET & WIRELESS_CONTROLLER_REMOTE_NDIS. Loading drivers/usb/gadget/function/f_rndis.c +1 −16 Original line number Diff line number Diff line Loading @@ -66,8 +66,6 @@ * - MS-Windows drivers sometimes emit undocumented requests. */ #define RNDIS_UL_MAX_PKT_PER_XFER 3 struct f_rndis { struct gether port; u8 ctrl_id, data_id; Loading Loading @@ -673,7 +671,6 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) struct usb_string *us; int status; struct usb_ep *ep; unsigned int max; struct f_rndis_opts *rndis_opts; Loading Loading @@ -799,11 +796,6 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) rndis_set_param_medium(rndis->params, RNDIS_MEDIUM_802_3, 0); rndis_set_host_mac(rndis->params, rndis->ethaddr); max = gether_get_ul_max_pkts_per_xfer(rndis_opts->net); if (!max) max = RNDIS_UL_MAX_PKT_PER_XFER; rndis_set_max_pkt_xfer(rndis->params, max); if (rndis->manufacturer && rndis->vendorID && rndis_set_param_vendor(rndis->params, rndis->vendorID, Loading Loading @@ -884,10 +876,6 @@ USB_ETHER_CONFIGFS_ITEM_ATTR_U8_RW(rndis, subclass); /* f_rndis_opts_protocol */ USB_ETHER_CONFIGFS_ITEM_ATTR_U8_RW(rndis, protocol); /* f_rndis_opts_ul_max_pkt_per_xfer */ USB_ETHER_CONFIGFS_ITEM_ATTR_UL_MAX_PKT_PER_XFER(rndis); static struct configfs_attribute *rndis_attrs[] = { &rndis_opts_attr_dev_addr, &rndis_opts_attr_host_addr, Loading @@ -896,7 +884,6 @@ static struct configfs_attribute *rndis_attrs[] = { &rndis_opts_attr_class, &rndis_opts_attr_subclass, &rndis_opts_attr_protocol, &rndis_opts_attr_ul_max_pkt_per_xfer, NULL, }; Loading Loading @@ -1018,8 +1005,6 @@ static struct usb_function *rndis_alloc(struct usb_function_instance *fi) rndis->port.header_len = sizeof(struct rndis_packet_msg_type); rndis->port.wrap = rndis_add_header; rndis->port.unwrap = rndis_rm_hdr; if (!gether_get_ul_max_pkts_per_xfer(opts->net)) rndis->port.ul_max_pkts_per_xfer = RNDIS_UL_MAX_PKT_PER_XFER; rndis->port.func.name = "rndis"; /* descriptors are per-instance copies */ Loading @@ -1030,7 +1015,7 @@ static struct usb_function *rndis_alloc(struct usb_function_instance *fi) rndis->port.func.disable = rndis_disable; rndis->port.func.free_func = rndis_free; params = rndis_register(rndis_response_available, rndis, NULL); params = rndis_register(rndis_response_available, rndis); if (IS_ERR(params)) { kfree(rndis); return ERR_CAST(params); Loading drivers/usb/gadget/function/rndis.c +34 −150 Original line number Diff line number Diff line Loading @@ -39,6 +39,7 @@ #include "rndis.h" /* The driver for your USB chip needs to support ep0 OUT to work with * RNDIS, plus all three CDC Ethernet endpoints (interrupt not optional). * Loading Loading @@ -522,11 +523,14 @@ static int gen_ndis_set_resp(struct rndis_params *params, u32 OID, */ retval = 0; if (*params->filter) { pr_debug("%s(): disable flow control\n", __func__); rndis_flow_control(params, false); params->state = RNDIS_DATA_INITIALIZED; netif_carrier_on(params->dev); if (netif_running(params->dev)) netif_wake_queue(params->dev); } else { pr_err("%s(): enable flow control\n", __func__); rndis_flow_control(params, true); params->state = RNDIS_INITIALIZED; netif_carrier_off(params->dev); netif_stop_queue(params->dev); } break; Loading Loading @@ -570,13 +574,13 @@ static int rndis_init_response(struct rndis_params *params, resp->MinorVersion = cpu_to_le32(RNDIS_MINOR_VERSION); resp->DeviceFlags = cpu_to_le32(RNDIS_DF_CONNECTIONLESS); resp->Medium = cpu_to_le32(RNDIS_MEDIUM_802_3); resp->MaxPacketsPerTransfer = cpu_to_le32(params->max_pkt_per_xfer); resp->MaxTransferSize = cpu_to_le32(params->max_pkt_per_xfer * (params->dev->mtu resp->MaxPacketsPerTransfer = cpu_to_le32(1); resp->MaxTransferSize = cpu_to_le32( params->dev->mtu + sizeof(struct ethhdr) + sizeof(struct rndis_packet_msg_type) + 22)); resp->PacketAlignmentFactor = cpu_to_le32(params->pkt_alignment_factor); + 22); resp->PacketAlignmentFactor = cpu_to_le32(0); resp->AFListOffset = cpu_to_le32(0); resp->AFListSize = cpu_to_le32(0); Loading Loading @@ -803,34 +807,19 @@ int rndis_msg_parser(struct rndis_params *params, u8 *buf) /* For USB: responses may take up to 10 seconds */ switch (MsgType) { case RNDIS_MSG_INIT: pr_debug("%s: RNDIS_MSG_INIT\n", __func__); tmp++; /* to get RequestID */ params->host_rndis_major_ver = get_unaligned_le32(tmp++); params->host_rndis_minor_ver = get_unaligned_le32(tmp++); params->dl_max_xfer_size = get_unaligned_le32(tmp++); pr_debug("%s(): RNDIS Host Major:%d Minor:%d version\n", __func__, params->host_rndis_major_ver, params->host_rndis_minor_ver); pr_debug("%s(): DL Max Transfer size:%x\n", __func__, params->dl_max_xfer_size); pr_debug("%s: RNDIS_MSG_INIT\n", __func__); params->state = RNDIS_INITIALIZED; return rndis_init_response(params, (rndis_init_msg_type *)buf); case RNDIS_MSG_HALT: pr_debug("%s: RNDIS_MSG_HALT\n", __func__); if (params->state == RNDIS_DATA_INITIALIZED) { if (params->flow_ctrl_enable) { params->flow_ctrl_enable(true, params); } else { params->state = RNDIS_UNINITIALIZED; if (params->dev) { netif_carrier_off(params->dev); netif_stop_queue(params->dev); } } params->state = RNDIS_UNINITIALIZED; } return 0; case RNDIS_MSG_QUERY: Loading Loading @@ -884,8 +873,7 @@ static inline void rndis_put_nr(int nr) ida_simple_remove(&rndis_ida, nr); } struct rndis_params *rndis_register(void (*resp_avail)(void *v), void *v, void (*flow_ctrl_enable)(bool enable, struct rndis_params *params)) struct rndis_params *rndis_register(void (*resp_avail)(void *v), void *v) { struct rndis_params *params; int i; Loading Loading @@ -929,7 +917,6 @@ struct rndis_params *rndis_register(void (*resp_avail)(void *v), void *v, params->state = RNDIS_UNINITIALIZED; params->media_state = RNDIS_MEDIA_STATE_DISCONNECTED; params->resp_avail = resp_avail; params->flow_ctrl_enable = flow_ctrl_enable; params->v = v; INIT_LIST_HEAD(¶ms->resp_queue); pr_debug("%s: configNr = %d\n", __func__, i); Loading Loading @@ -1006,56 +993,6 @@ int rndis_set_param_medium(struct rndis_params *params, u32 medium, u32 speed) } EXPORT_SYMBOL_GPL(rndis_set_param_medium); void rndis_set_max_pkt_xfer(struct rndis_params *params, u8 max_pkt_per_xfer) { pr_debug("%s:\n", __func__); params->max_pkt_per_xfer = max_pkt_per_xfer; } /** * rndis_flow_control: enable/disable flow control with USB RNDIS interface * params - RNDIS network parameter * enable_flow_control - true: perform flow control, false: disable flow control * * In hw accelerated mode, this function triggers functionality to start/stop * endless transfers, otherwise it enables/disables RNDIS network interface. */ void rndis_flow_control(struct rndis_params *params, bool enable_flow_control) { if (!params) { pr_err("%s: failed, params NULL\n", __func__); return; } pr_debug("%s(): params->state:%x\n", __func__, params->state); if (enable_flow_control) { if (params->state == RNDIS_DATA_INITIALIZED) { if (params->flow_ctrl_enable) { params->flow_ctrl_enable(enable_flow_control, params); } else { netif_carrier_off(params->dev); netif_stop_queue(params->dev); } } params->state = RNDIS_INITIALIZED; } else { if (params->state != RNDIS_DATA_INITIALIZED) { if (params->flow_ctrl_enable) { params->flow_ctrl_enable(enable_flow_control, params); } else { netif_carrier_on(params->dev); if (netif_running(params->dev)) netif_wake_queue(params->dev); } } params->state = RNDIS_DATA_INITIALIZED; } } void rndis_add_hdr(struct sk_buff *skb) { struct rndis_packet_msg_type *header; Loading Loading @@ -1122,82 +1059,29 @@ int rndis_rm_hdr(struct gether *port, struct sk_buff *skb, struct sk_buff_head *list) { while (skb->len) { struct rndis_packet_msg_type *hdr; struct sk_buff *skb2; u32 msg_len, data_offset, data_len; /* some rndis hosts send extra byte to avoid zlp, ignore it */ if (skb->len == 1) { dev_kfree_skb_any(skb); return 0; } /* tmp points to a struct rndis_packet_msg_type */ __le32 *tmp = (void *)skb->data; if (skb->len < sizeof(*hdr)) { pr_err("invalid rndis pkt: skblen:%u hdr_len:%lu\n", skb->len, sizeof(*hdr)); /* MessageType, MessageLength */ if (cpu_to_le32(RNDIS_MSG_PACKET) != get_unaligned(tmp++)) { dev_kfree_skb_any(skb); return -EINVAL; } tmp++; hdr = (void *)skb->data; msg_len = le32_to_cpu(hdr->MessageLength); data_offset = le32_to_cpu(hdr->DataOffset); data_len = le32_to_cpu(hdr->DataLength); if (skb->len < msg_len || ((data_offset + data_len + 8) > msg_len)) { pr_err("invalid rndis message: %d/%d/%d/%d, len:%d\n", le32_to_cpu(hdr->MessageType), msg_len, data_offset, data_len, skb->len); /* DataOffset, DataLength */ if (!skb_pull(skb, get_unaligned_le32(tmp++) + 8)) { dev_kfree_skb_any(skb); return -EOVERFLOW; } if (le32_to_cpu(hdr->MessageType) != RNDIS_MSG_PACKET) { pr_err("invalid rndis message: %d/%d/%d/%d, len:%d\n", le32_to_cpu(hdr->MessageType), msg_len, data_offset, data_len, skb->len); dev_kfree_skb_any(skb); return -EINVAL; } skb_pull(skb, data_offset + 8); if (msg_len == skb->len) { skb_trim(skb, data_len); break; } skb2 = skb_clone(skb, GFP_ATOMIC); if (!skb2) { pr_err("%s:skb clone failed\n", __func__); dev_kfree_skb_any(skb); return -ENOMEM; } skb_pull(skb, msg_len - sizeof(*hdr)); skb_trim(skb2, data_len); skb_queue_tail(list, skb2); } skb_trim(skb, get_unaligned_le32(tmp++)); skb_queue_tail(list, skb); return 0; } EXPORT_SYMBOL_GPL(rndis_rm_hdr); void rndis_set_pkt_alignment_factor(struct rndis_params *params, u8 pkt_alignment_factor) { pr_debug("%s:\n", __func__); if (!params) { pr_err("%s: failed, params NULL\n", __func__); return; } params->pkt_alignment_factor = pkt_alignment_factor; } #ifdef CONFIG_USB_GADGET_DEBUG_FILES static int rndis_proc_show(struct seq_file *m, void *v) Loading drivers/usb/gadget/function/rndis.h +1 −14 Original line number Diff line number Diff line Loading @@ -170,24 +170,15 @@ typedef struct rndis_params { struct net_device *dev; u32 vendorID; u8 max_pkt_per_xfer; u32 host_rndis_major_ver; u32 host_rndis_minor_ver; u32 dl_max_xfer_size; const char *vendorDescr; u8 pkt_alignment_factor; void (*resp_avail)(void *v); void (*flow_ctrl_enable)(bool enable, struct rndis_params *params); void *v; struct list_head resp_queue; } rndis_params; /* RNDIS Message parser and other useless functions */ int rndis_msg_parser(struct rndis_params *params, u8 *buf); struct rndis_params *rndis_register(void (*resp_avail)(void *v), void *v, void (*flow_ctrl_enable)(bool enable, struct rndis_params *params)); struct rndis_params *rndis_register(void (*resp_avail)(void *v), void *v); void rndis_deregister(struct rndis_params *params); int rndis_set_param_dev(struct rndis_params *params, struct net_device *dev, u16 *cdc_filter); Loading @@ -195,7 +186,6 @@ int rndis_set_param_vendor(struct rndis_params *params, u32 vendorID, const char *vendorDescr); int rndis_set_param_medium(struct rndis_params *params, u32 medium, u32 speed); void rndis_set_max_pkt_xfer(struct rndis_params *params, u8 max_pkt_per_xfer); void rndis_add_hdr(struct sk_buff *skb); int rndis_rm_hdr(struct gether *port, struct sk_buff *skb, struct sk_buff_head *list); Loading @@ -207,8 +197,5 @@ int rndis_signal_connect(struct rndis_params *params); int rndis_signal_disconnect(struct rndis_params *params); int rndis_state(struct rndis_params *params); extern void rndis_set_host_mac(struct rndis_params *params, const u8 *addr); void rndis_flow_control(struct rndis_params *params, bool enable_flow_control); void rndis_set_pkt_alignment_factor(struct rndis_params *params, u8 pkt_alignment_factor); #endif /* _LINUX_RNDIS_H */ Loading
drivers/usb/gadget/function/Makefile +4 −1 Original line number Diff line number Diff line Loading @@ -62,5 +62,8 @@ usb_f_ccid-y := f_ccid.o obj-$(CONFIG_USB_F_CCID) += usb_f_ccid.o usb_f_cdev-y := f_cdev.o obj-$(CONFIG_USB_F_CDEV) += usb_f_cdev.o usb_f_gsi-y := f_gsi.o rndis.o usb_f_gsi-y := f_gsi.o ifeq ($(CONFIG_USB_F_RNDIS),) usb_f_gsi-y += rndis.o endif obj-$(CONFIG_USB_F_GSI) += usb_f_gsi.o
drivers/usb/gadget/function/f_gsi.c +67 −26 Original line number Diff line number Diff line Loading @@ -2038,20 +2038,47 @@ static void gsi_rndis_command_complete(struct usb_ep *ep, struct usb_request *req) { struct f_gsi *gsi = req->context; rndis_init_msg_type *buf; int status; u32 MsgType; if (!req->buf || !gsi->params) return; MsgType = get_unaligned_le32((__le32 *)req->buf); /* intercept halt message to perform flow control */ if (MsgType == RNDIS_MSG_HALT) { log_event_dbg("RNDIS_MSG_HALT, state:%d\n", gsi->params->state); if (gsi->params->state == RNDIS_DATA_INITIALIZED) gsi_rndis_flow_ctrl_enable(true, gsi->params); gsi->params->state = RNDIS_UNINITIALIZED; return; } status = rndis_msg_parser(gsi->params, (u8 *) req->buf); if (status < 0) log_event_err("RNDIS command error %d, %d/%d", status, req->actual, req->length); buf = (rndis_init_msg_type *)req->buf; if (le32_to_cpu(buf->MessageType) == RNDIS_MSG_INIT) { if (MsgType == RNDIS_MSG_INIT) { rndis_init_msg_type *buf = (rndis_init_msg_type *)req->buf; log_event_dbg("RNDIS host major:%d minor:%d version\n", le32_to_cpu(buf->MajorVersion), le32_to_cpu(buf->MinorVersion)); /* honor host dl aggr size */ gsi->d_port.in_aggr_size = gsi->params->dl_max_xfer_size; log_event_dbg("RNDIS host dl_aggr_size:%d\n", gsi->params->dl_max_xfer_size); gsi->d_port.in_aggr_size = le32_to_cpu(buf->MaxTransferSize); log_event_dbg("RNDIS host DL MaxTransferSize:%d\n", le32_to_cpu(buf->MaxTransferSize)); } else if (MsgType == RNDIS_MSG_SET) { rndis_set_msg_type *buf = (rndis_set_msg_type *)req->buf; if (le32_to_cpu(buf->OID) == RNDIS_OID_GEN_CURRENT_PACKET_FILTER) gsi_rndis_flow_ctrl_enable(!(*gsi->params->filter), gsi->params); } } Loading Loading @@ -2182,13 +2209,37 @@ gsi_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) goto invalid; if (gsi->prot_id == IPA_USB_RNDIS) { rndis_init_cmplt_type *res; /* return the result */ buf = rndis_get_next_response(gsi->params, &n); if (buf) { if (!buf) break; res = (rndis_init_cmplt_type *)buf; if (le32_to_cpu(res->MessageType) == RNDIS_MSG_INIT_C) { log_event_dbg("%s: max_pkt_per_xfer : %d", __func__, DEFAULT_MAX_PKT_PER_XFER); res->MaxPacketsPerTransfer = cpu_to_le32(DEFAULT_MAX_PKT_PER_XFER); res->MaxTransferSize = cpu_to_le32( le32_to_cpu(res->MaxTransferSize) * DEFAULT_MAX_PKT_PER_XFER); /* In case of aggregated packets QC device * will request aliment to 4 (2^2). */ log_event_dbg("%s: pkt_alignment_factor : %d", __func__, DEFAULT_PKT_ALIGNMENT_FACTOR); res->PacketAlignmentFactor = cpu_to_le32( DEFAULT_PKT_ALIGNMENT_FACTOR); } memcpy(req->buf, buf, n); rndis_free_response(gsi->params, buf); value = n; } break; } Loading Loading @@ -2545,8 +2596,11 @@ static void gsi_resume(struct usb_function *f) */ if (gsi->prot_id == IPA_USB_RNDIS && !usb_gsi_remote_wakeup_allowed(f) && gsi->host_supports_flow_control) rndis_flow_control(gsi->params, false); gsi->host_supports_flow_control && gsi->params) { if (gsi->params->state != RNDIS_DATA_INITIALIZED) gsi_rndis_flow_ctrl_enable(false, gsi->params); gsi->params->state = RNDIS_DATA_INITIALIZED; } post_event(&gsi->d_port, EVT_RESUMED); queue_delayed_work(gsi->d_port.ipa_usb_wq, &gsi->d_port.usb_ipa_w, 0); Loading Loading @@ -2831,8 +2885,7 @@ static int gsi_bind(struct usb_configuration *c, struct usb_function *f) info.out_req_num_buf = GSI_NUM_OUT_BUFFERS; info.notify_buf_len = sizeof(struct usb_cdc_notification); params = rndis_register(gsi_rndis_response_available, gsi, gsi_rndis_flow_ctrl_enable); params = rndis_register(gsi_rndis_response_available, gsi); if (IS_ERR(params)) goto fail; Loading @@ -2855,18 +2908,6 @@ static int gsi_bind(struct usb_configuration *c, struct usb_function *f) gsi->manufacturer)) goto dereg_rndis; log_event_dbg("%s: max_pkt_per_xfer : %d", __func__, DEFAULT_MAX_PKT_PER_XFER); rndis_set_max_pkt_xfer(gsi->params, DEFAULT_MAX_PKT_PER_XFER); /* In case of aggregated packets QC device will request * aliment to 4 (2^2). */ log_event_dbg("%s: pkt_alignment_factor : %d", __func__, DEFAULT_PKT_ALIGNMENT_FACTOR); rndis_set_pkt_alignment_factor(gsi->params, DEFAULT_PKT_ALIGNMENT_FACTOR); /* Windows7/Windows10 automatically loads RNDIS drivers for * class drivers which represents MISC_ACTIVE_SYNC, * MISC_RNDIS_OVER_ETHERNET & WIRELESS_CONTROLLER_REMOTE_NDIS. Loading
drivers/usb/gadget/function/f_rndis.c +1 −16 Original line number Diff line number Diff line Loading @@ -66,8 +66,6 @@ * - MS-Windows drivers sometimes emit undocumented requests. */ #define RNDIS_UL_MAX_PKT_PER_XFER 3 struct f_rndis { struct gether port; u8 ctrl_id, data_id; Loading Loading @@ -673,7 +671,6 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) struct usb_string *us; int status; struct usb_ep *ep; unsigned int max; struct f_rndis_opts *rndis_opts; Loading Loading @@ -799,11 +796,6 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) rndis_set_param_medium(rndis->params, RNDIS_MEDIUM_802_3, 0); rndis_set_host_mac(rndis->params, rndis->ethaddr); max = gether_get_ul_max_pkts_per_xfer(rndis_opts->net); if (!max) max = RNDIS_UL_MAX_PKT_PER_XFER; rndis_set_max_pkt_xfer(rndis->params, max); if (rndis->manufacturer && rndis->vendorID && rndis_set_param_vendor(rndis->params, rndis->vendorID, Loading Loading @@ -884,10 +876,6 @@ USB_ETHER_CONFIGFS_ITEM_ATTR_U8_RW(rndis, subclass); /* f_rndis_opts_protocol */ USB_ETHER_CONFIGFS_ITEM_ATTR_U8_RW(rndis, protocol); /* f_rndis_opts_ul_max_pkt_per_xfer */ USB_ETHER_CONFIGFS_ITEM_ATTR_UL_MAX_PKT_PER_XFER(rndis); static struct configfs_attribute *rndis_attrs[] = { &rndis_opts_attr_dev_addr, &rndis_opts_attr_host_addr, Loading @@ -896,7 +884,6 @@ static struct configfs_attribute *rndis_attrs[] = { &rndis_opts_attr_class, &rndis_opts_attr_subclass, &rndis_opts_attr_protocol, &rndis_opts_attr_ul_max_pkt_per_xfer, NULL, }; Loading Loading @@ -1018,8 +1005,6 @@ static struct usb_function *rndis_alloc(struct usb_function_instance *fi) rndis->port.header_len = sizeof(struct rndis_packet_msg_type); rndis->port.wrap = rndis_add_header; rndis->port.unwrap = rndis_rm_hdr; if (!gether_get_ul_max_pkts_per_xfer(opts->net)) rndis->port.ul_max_pkts_per_xfer = RNDIS_UL_MAX_PKT_PER_XFER; rndis->port.func.name = "rndis"; /* descriptors are per-instance copies */ Loading @@ -1030,7 +1015,7 @@ static struct usb_function *rndis_alloc(struct usb_function_instance *fi) rndis->port.func.disable = rndis_disable; rndis->port.func.free_func = rndis_free; params = rndis_register(rndis_response_available, rndis, NULL); params = rndis_register(rndis_response_available, rndis); if (IS_ERR(params)) { kfree(rndis); return ERR_CAST(params); Loading
drivers/usb/gadget/function/rndis.c +34 −150 Original line number Diff line number Diff line Loading @@ -39,6 +39,7 @@ #include "rndis.h" /* The driver for your USB chip needs to support ep0 OUT to work with * RNDIS, plus all three CDC Ethernet endpoints (interrupt not optional). * Loading Loading @@ -522,11 +523,14 @@ static int gen_ndis_set_resp(struct rndis_params *params, u32 OID, */ retval = 0; if (*params->filter) { pr_debug("%s(): disable flow control\n", __func__); rndis_flow_control(params, false); params->state = RNDIS_DATA_INITIALIZED; netif_carrier_on(params->dev); if (netif_running(params->dev)) netif_wake_queue(params->dev); } else { pr_err("%s(): enable flow control\n", __func__); rndis_flow_control(params, true); params->state = RNDIS_INITIALIZED; netif_carrier_off(params->dev); netif_stop_queue(params->dev); } break; Loading Loading @@ -570,13 +574,13 @@ static int rndis_init_response(struct rndis_params *params, resp->MinorVersion = cpu_to_le32(RNDIS_MINOR_VERSION); resp->DeviceFlags = cpu_to_le32(RNDIS_DF_CONNECTIONLESS); resp->Medium = cpu_to_le32(RNDIS_MEDIUM_802_3); resp->MaxPacketsPerTransfer = cpu_to_le32(params->max_pkt_per_xfer); resp->MaxTransferSize = cpu_to_le32(params->max_pkt_per_xfer * (params->dev->mtu resp->MaxPacketsPerTransfer = cpu_to_le32(1); resp->MaxTransferSize = cpu_to_le32( params->dev->mtu + sizeof(struct ethhdr) + sizeof(struct rndis_packet_msg_type) + 22)); resp->PacketAlignmentFactor = cpu_to_le32(params->pkt_alignment_factor); + 22); resp->PacketAlignmentFactor = cpu_to_le32(0); resp->AFListOffset = cpu_to_le32(0); resp->AFListSize = cpu_to_le32(0); Loading Loading @@ -803,34 +807,19 @@ int rndis_msg_parser(struct rndis_params *params, u8 *buf) /* For USB: responses may take up to 10 seconds */ switch (MsgType) { case RNDIS_MSG_INIT: pr_debug("%s: RNDIS_MSG_INIT\n", __func__); tmp++; /* to get RequestID */ params->host_rndis_major_ver = get_unaligned_le32(tmp++); params->host_rndis_minor_ver = get_unaligned_le32(tmp++); params->dl_max_xfer_size = get_unaligned_le32(tmp++); pr_debug("%s(): RNDIS Host Major:%d Minor:%d version\n", __func__, params->host_rndis_major_ver, params->host_rndis_minor_ver); pr_debug("%s(): DL Max Transfer size:%x\n", __func__, params->dl_max_xfer_size); pr_debug("%s: RNDIS_MSG_INIT\n", __func__); params->state = RNDIS_INITIALIZED; return rndis_init_response(params, (rndis_init_msg_type *)buf); case RNDIS_MSG_HALT: pr_debug("%s: RNDIS_MSG_HALT\n", __func__); if (params->state == RNDIS_DATA_INITIALIZED) { if (params->flow_ctrl_enable) { params->flow_ctrl_enable(true, params); } else { params->state = RNDIS_UNINITIALIZED; if (params->dev) { netif_carrier_off(params->dev); netif_stop_queue(params->dev); } } params->state = RNDIS_UNINITIALIZED; } return 0; case RNDIS_MSG_QUERY: Loading Loading @@ -884,8 +873,7 @@ static inline void rndis_put_nr(int nr) ida_simple_remove(&rndis_ida, nr); } struct rndis_params *rndis_register(void (*resp_avail)(void *v), void *v, void (*flow_ctrl_enable)(bool enable, struct rndis_params *params)) struct rndis_params *rndis_register(void (*resp_avail)(void *v), void *v) { struct rndis_params *params; int i; Loading Loading @@ -929,7 +917,6 @@ struct rndis_params *rndis_register(void (*resp_avail)(void *v), void *v, params->state = RNDIS_UNINITIALIZED; params->media_state = RNDIS_MEDIA_STATE_DISCONNECTED; params->resp_avail = resp_avail; params->flow_ctrl_enable = flow_ctrl_enable; params->v = v; INIT_LIST_HEAD(¶ms->resp_queue); pr_debug("%s: configNr = %d\n", __func__, i); Loading Loading @@ -1006,56 +993,6 @@ int rndis_set_param_medium(struct rndis_params *params, u32 medium, u32 speed) } EXPORT_SYMBOL_GPL(rndis_set_param_medium); void rndis_set_max_pkt_xfer(struct rndis_params *params, u8 max_pkt_per_xfer) { pr_debug("%s:\n", __func__); params->max_pkt_per_xfer = max_pkt_per_xfer; } /** * rndis_flow_control: enable/disable flow control with USB RNDIS interface * params - RNDIS network parameter * enable_flow_control - true: perform flow control, false: disable flow control * * In hw accelerated mode, this function triggers functionality to start/stop * endless transfers, otherwise it enables/disables RNDIS network interface. */ void rndis_flow_control(struct rndis_params *params, bool enable_flow_control) { if (!params) { pr_err("%s: failed, params NULL\n", __func__); return; } pr_debug("%s(): params->state:%x\n", __func__, params->state); if (enable_flow_control) { if (params->state == RNDIS_DATA_INITIALIZED) { if (params->flow_ctrl_enable) { params->flow_ctrl_enable(enable_flow_control, params); } else { netif_carrier_off(params->dev); netif_stop_queue(params->dev); } } params->state = RNDIS_INITIALIZED; } else { if (params->state != RNDIS_DATA_INITIALIZED) { if (params->flow_ctrl_enable) { params->flow_ctrl_enable(enable_flow_control, params); } else { netif_carrier_on(params->dev); if (netif_running(params->dev)) netif_wake_queue(params->dev); } } params->state = RNDIS_DATA_INITIALIZED; } } void rndis_add_hdr(struct sk_buff *skb) { struct rndis_packet_msg_type *header; Loading Loading @@ -1122,82 +1059,29 @@ int rndis_rm_hdr(struct gether *port, struct sk_buff *skb, struct sk_buff_head *list) { while (skb->len) { struct rndis_packet_msg_type *hdr; struct sk_buff *skb2; u32 msg_len, data_offset, data_len; /* some rndis hosts send extra byte to avoid zlp, ignore it */ if (skb->len == 1) { dev_kfree_skb_any(skb); return 0; } /* tmp points to a struct rndis_packet_msg_type */ __le32 *tmp = (void *)skb->data; if (skb->len < sizeof(*hdr)) { pr_err("invalid rndis pkt: skblen:%u hdr_len:%lu\n", skb->len, sizeof(*hdr)); /* MessageType, MessageLength */ if (cpu_to_le32(RNDIS_MSG_PACKET) != get_unaligned(tmp++)) { dev_kfree_skb_any(skb); return -EINVAL; } tmp++; hdr = (void *)skb->data; msg_len = le32_to_cpu(hdr->MessageLength); data_offset = le32_to_cpu(hdr->DataOffset); data_len = le32_to_cpu(hdr->DataLength); if (skb->len < msg_len || ((data_offset + data_len + 8) > msg_len)) { pr_err("invalid rndis message: %d/%d/%d/%d, len:%d\n", le32_to_cpu(hdr->MessageType), msg_len, data_offset, data_len, skb->len); /* DataOffset, DataLength */ if (!skb_pull(skb, get_unaligned_le32(tmp++) + 8)) { dev_kfree_skb_any(skb); return -EOVERFLOW; } if (le32_to_cpu(hdr->MessageType) != RNDIS_MSG_PACKET) { pr_err("invalid rndis message: %d/%d/%d/%d, len:%d\n", le32_to_cpu(hdr->MessageType), msg_len, data_offset, data_len, skb->len); dev_kfree_skb_any(skb); return -EINVAL; } skb_pull(skb, data_offset + 8); if (msg_len == skb->len) { skb_trim(skb, data_len); break; } skb2 = skb_clone(skb, GFP_ATOMIC); if (!skb2) { pr_err("%s:skb clone failed\n", __func__); dev_kfree_skb_any(skb); return -ENOMEM; } skb_pull(skb, msg_len - sizeof(*hdr)); skb_trim(skb2, data_len); skb_queue_tail(list, skb2); } skb_trim(skb, get_unaligned_le32(tmp++)); skb_queue_tail(list, skb); return 0; } EXPORT_SYMBOL_GPL(rndis_rm_hdr); void rndis_set_pkt_alignment_factor(struct rndis_params *params, u8 pkt_alignment_factor) { pr_debug("%s:\n", __func__); if (!params) { pr_err("%s: failed, params NULL\n", __func__); return; } params->pkt_alignment_factor = pkt_alignment_factor; } #ifdef CONFIG_USB_GADGET_DEBUG_FILES static int rndis_proc_show(struct seq_file *m, void *v) Loading
drivers/usb/gadget/function/rndis.h +1 −14 Original line number Diff line number Diff line Loading @@ -170,24 +170,15 @@ typedef struct rndis_params { struct net_device *dev; u32 vendorID; u8 max_pkt_per_xfer; u32 host_rndis_major_ver; u32 host_rndis_minor_ver; u32 dl_max_xfer_size; const char *vendorDescr; u8 pkt_alignment_factor; void (*resp_avail)(void *v); void (*flow_ctrl_enable)(bool enable, struct rndis_params *params); void *v; struct list_head resp_queue; } rndis_params; /* RNDIS Message parser and other useless functions */ int rndis_msg_parser(struct rndis_params *params, u8 *buf); struct rndis_params *rndis_register(void (*resp_avail)(void *v), void *v, void (*flow_ctrl_enable)(bool enable, struct rndis_params *params)); struct rndis_params *rndis_register(void (*resp_avail)(void *v), void *v); void rndis_deregister(struct rndis_params *params); int rndis_set_param_dev(struct rndis_params *params, struct net_device *dev, u16 *cdc_filter); Loading @@ -195,7 +186,6 @@ int rndis_set_param_vendor(struct rndis_params *params, u32 vendorID, const char *vendorDescr); int rndis_set_param_medium(struct rndis_params *params, u32 medium, u32 speed); void rndis_set_max_pkt_xfer(struct rndis_params *params, u8 max_pkt_per_xfer); void rndis_add_hdr(struct sk_buff *skb); int rndis_rm_hdr(struct gether *port, struct sk_buff *skb, struct sk_buff_head *list); Loading @@ -207,8 +197,5 @@ int rndis_signal_connect(struct rndis_params *params); int rndis_signal_disconnect(struct rndis_params *params); int rndis_state(struct rndis_params *params); extern void rndis_set_host_mac(struct rndis_params *params, const u8 *addr); void rndis_flow_control(struct rndis_params *params, bool enable_flow_control); void rndis_set_pkt_alignment_factor(struct rndis_params *params, u8 pkt_alignment_factor); #endif /* _LINUX_RNDIS_H */