Loading drivers/usb/gadget/function/f_rndis.c +79 −10 Original line number Diff line number Diff line Loading @@ -93,6 +93,9 @@ struct f_rndis { atomic_t notify_count; }; static struct f_rndis *__rndis; static spinlock_t _rndis_lock; static inline struct f_rndis *func_to_rndis(struct usb_function *f) { return container_of(f, struct f_rndis, port.func); Loading Loading @@ -383,10 +386,31 @@ static struct sk_buff *rndis_add_header(struct gether *port, struct sk_buff *skb) { struct sk_buff *skb2; struct rndis_packet_msg_type *header = NULL; struct f_rndis *rndis = func_to_rndis(&port->func); if (!skb) return NULL; if (rndis->port.multi_pkt_xfer) { if (port->header) { header = port->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; } dev_kfree_skb(skb); pr_err("RNDIS header is NULL.\n"); return NULL; } skb2 = skb_realloc_headroom(skb, sizeof(struct rndis_packet_msg_type)); rndis_add_hdr(skb2); Loading Loading @@ -422,10 +446,19 @@ 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 f_rndis *rndis; struct usb_composite_dev *cdev; int status = req->status; struct usb_ep *notify_ep; spin_lock(&_rndis_lock); rndis = __rndis; if (!rndis || !rndis->notify) { spin_unlock(&_rndis_lock); return; } cdev = rndis->port.func.config->cdev; /* after TX: * - USB_CDC_GET_ENCAPSULATED_RESPONSE (ep0/control) * - RNDIS_RESPONSE_AVAILABLE (status/irq) Loading @@ -435,7 +468,7 @@ static void rndis_response_complete(struct usb_ep *ep, struct usb_request *req) case -ESHUTDOWN: /* connection gone */ atomic_set(&rndis->notify_count, 0); break; goto out; default: DBG(cdev, "RNDIS %s response error %d, %d/%d\n", ep->name, status, Loading @@ -443,29 +476,54 @@ static void rndis_response_complete(struct usb_ep *ep, struct usb_request *req) /* FALLTHROUGH */ case 0: if (ep != rndis->notify) break; goto out; /* handle multiple pending RNDIS_RESPONSE_AVAILABLE * notifications by resending until we're done */ if (atomic_dec_and_test(&rndis->notify_count)) break; status = usb_ep_queue(rndis->notify, req, GFP_ATOMIC); goto out; notify_ep = rndis->notify; spin_unlock(&_rndis_lock); status = usb_ep_queue(notify_ep, req, GFP_ATOMIC); if (status) { atomic_dec(&rndis->notify_count); spin_lock(&_rndis_lock); if (!__rndis) goto out; atomic_dec(&__rndis->notify_count); DBG(cdev, "notify/1 --> %d\n", status); spin_unlock(&_rndis_lock); } break; } return; out: spin_unlock(&_rndis_lock); } static void rndis_command_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 f_rndis *rndis; struct usb_composite_dev *cdev; int status; rndis_init_msg_type *buf; if (req->status != 0) { pr_err("%s: RNDIS command completion error:%d\n", __func__, req->status); return; } spin_lock(&_rndis_lock); rndis = __rndis; if (!rndis || !rndis->notify) { spin_unlock(&_rndis_lock); return; } cdev = rndis->port.func.config->cdev; /* received RNDIS command from USB_CDC_SEND_ENCAPSULATED_COMMAND */ // spin_lock(&dev->lock); status = rndis_msg_parser(rndis->params, (u8 *) req->buf); Loading @@ -488,6 +546,7 @@ static void rndis_command_complete(struct usb_ep *ep, struct usb_request *req) rndis->port.multi_pkt_xfer = 0; } // spin_unlock(&dev->lock); spin_unlock(&_rndis_lock); } static int Loading Loading @@ -639,13 +698,16 @@ static void rndis_disable(struct usb_function *f) { struct f_rndis *rndis = func_to_rndis(f); struct usb_composite_dev *cdev = f->config->cdev; unsigned long flags; if (!rndis->notify->enabled) return; DBG(cdev, "rndis deactivated\n"); spin_lock_irqsave(&_rndis_lock, flags); rndis_uninit(rndis->params); spin_unlock_irqrestore(&_rndis_lock, flags); gether_disconnect(&rndis->port); usb_ep_disable(rndis->notify); Loading Loading @@ -992,6 +1054,7 @@ static struct usb_function_instance *rndis_alloc_inst(void) opts->rndis_os_desc.ext_compat_id = opts->rndis_ext_compat_id; mutex_init(&opts->lock); spin_lock_init(&_rndis_lock); opts->func_inst.free_func_inst = rndis_free_inst; INIT_LIST_HEAD(&opts->rndis_os_desc.ext_prop); Loading Loading @@ -1022,11 +1085,15 @@ static void rndis_free(struct usb_function *f) { struct f_rndis *rndis; struct f_rndis_opts *opts; unsigned long int flags; rndis = func_to_rndis(f); rndis_deregister(rndis->params); opts = container_of(f->fi, struct f_rndis_opts, func_inst); spin_lock_irqsave(&_rndis_lock, flags); kfree(rndis); __rndis = NULL; spin_unlock_irqrestore(&_rndis_lock, flags); mutex_lock(&opts->lock); opts->refcnt--; mutex_unlock(&opts->lock); Loading Loading @@ -1059,6 +1126,8 @@ static struct usb_function *rndis_alloc(struct usb_function_instance *fi) if (!rndis) return ERR_PTR(-ENOMEM); __rndis = rndis; opts = container_of(fi, struct f_rndis_opts, func_inst); mutex_lock(&opts->lock); opts->refcnt++; Loading drivers/usb/gadget/function/u_ether.c +78 −36 Original line number Diff line number Diff line Loading @@ -246,6 +246,7 @@ static void defer_kevent(struct eth_dev *dev, int flag) } static void rx_complete(struct usb_ep *ep, struct usb_request *req); static void tx_complete(struct usb_ep *ep, struct usb_request *req); static int rx_submit(struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags) Loading Loading @@ -312,7 +313,6 @@ rx_submit(struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags) req->buf = skb->data; req->length = size; req->complete = rx_complete; req->context = skb; retval = usb_ep_queue(out, req, gfp_flags); Loading Loading @@ -415,6 +415,7 @@ static int prealloc(struct list_head *list, struct usb_ep *ep, unsigned n) { unsigned i; struct usb_request *req; bool usb_in; if (!n) return -ENOMEM; Loading @@ -425,10 +426,22 @@ static int prealloc(struct list_head *list, struct usb_ep *ep, unsigned n) if (i-- == 0) goto extra; } if (ep->desc->bEndpointAddress & USB_DIR_IN) usb_in = true; else usb_in = false; while (i--) { req = usb_ep_alloc_request(ep, GFP_ATOMIC); if (!req) return list_empty(list) ? -ENOMEM : 0; /* update completion handler */ if (usb_in) req->complete = tx_complete; else req->complete = rx_complete; list_add(&req->list, list); } return 0; Loading Loading @@ -580,7 +593,7 @@ static void eth_work(struct work_struct *work) static void tx_complete(struct usb_ep *ep, struct usb_request *req) { struct sk_buff *skb = req->context; struct sk_buff *skb; struct eth_dev *dev = ep->driver_data; struct net_device *net = dev->net; struct usb_request *new_req; Loading Loading @@ -693,6 +706,7 @@ static void tx_complete(struct usb_ep *ep, struct usb_request *req) spin_unlock(&dev->req_lock); } } else { skb = req->context; /* Is aggregation already enabled and buffers allocated ? */ if (dev->port_usb->multi_pkt_xfer && dev->tx_req_bufsize) { req->buf = kzalloc(dev->tx_req_bufsize Loading Loading @@ -735,7 +749,7 @@ static int alloc_tx_buffer(struct eth_dev *dev) list_for_each(act, &dev->tx_reqs) { req = container_of(act, struct usb_request, list); if (!req->buf) req->buf = kmalloc(dev->tx_req_bufsize req->buf = kzalloc(dev->tx_req_bufsize + dev->gadget->extra_buf_alloc, GFP_ATOMIC); if (!req->buf) Loading Loading @@ -771,11 +785,15 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb, struct usb_ep *in = NULL; u16 cdc_filter = 0; bool multi_pkt_xfer = false; u32 fixed_in_len = 0; bool is_fixed = false; spin_lock_irqsave(&dev->lock, flags); if (dev->port_usb) { in = dev->port_usb->in_ep; cdc_filter = dev->port_usb->cdc_filter; is_fixed = dev->port_usb->is_fixed; fixed_in_len = dev->port_usb->fixed_in_len; multi_pkt_xfer = dev->port_usb->multi_pkt_xfer; } spin_unlock_irqrestore(&dev->lock, flags); Loading @@ -786,7 +804,8 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb, } /* apply outgoing CDC or RNDIS filters */ if (skb && !is_promisc(cdc_filter)) { if (!test_bit(RMNET_MODE_LLP_IP, &dev->flags) && !is_promisc(cdc_filter)) { u8 *dest = skb->data; if (is_multicast_ether_addr(dest)) { Loading @@ -800,6 +819,7 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb, else type = USB_CDC_PACKET_TYPE_ALL_MULTICAST; if (!(cdc_filter & type)) { dev->net->stats.tx_dropped++; dev_kfree_skb_any(skb); return NETDEV_TX_OK; } Loading @@ -808,29 +828,6 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb, } dev->tx_pkts_rcvd++; /* * no buffer copies needed, unless the network stack did it * or the hardware can't use skb buffers. * or there's not enough space for extra headers we need */ spin_lock_irqsave(&dev->lock, flags); if (dev->wrap && dev->port_usb) skb = dev->wrap(dev->port_usb, skb); spin_unlock_irqrestore(&dev->lock, flags); if (!skb) { if (dev->port_usb && dev->port_usb->supports_multi_frame) { /* * Multi frame CDC protocols may store the frame for * later which is not a dropped frame. */ } else { dev->net->stats.tx_dropped++; } /* no error code for dropped packets */ return NETDEV_TX_OK; } /* Allocate memory for tx_reqs to support multi packet transfer */ spin_lock_irqsave(&dev->req_lock, flags); Loading Loading @@ -865,13 +862,45 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb, dev->tx_throttle++; netif_stop_queue(net); } spin_unlock_irqrestore(&dev->req_lock, flags); /* no buffer copies needed, unless the network stack did it * or the hardware can't use skb buffers. * or there's not enough space for extra headers we need */ spin_lock_irqsave(&dev->lock, flags); if (dev->wrap) { if (dev->port_usb) skb = dev->wrap(dev->port_usb, skb); if (!skb) { spin_unlock_irqrestore(&dev->lock, flags); /* Multi frame CDC protocols may store the frame for * later which is not a dropped frame. */ if (dev->port_usb && dev->port_usb->supports_multi_frame) goto multiframe; goto drop; } } dev->tx_skb_hold_count++; spin_unlock_irqrestore(&dev->req_lock, flags); spin_unlock_irqrestore(&dev->lock, flags); if (multi_pkt_xfer) { pr_debug("req->length:%d header_len:%u\n" "skb->len:%d skb->data_len:%d\n", req->length, dev->header_len, skb->len, skb->data_len); /* Add RNDIS Header */ memcpy(req->buf + req->length, dev->port_usb->header, dev->header_len); /* Increment req length by header size */ req->length += dev->header_len; /* Copy received IP data from SKB */ memcpy(req->buf + req->length, skb->data, skb->len); req->length = req->length + skb->len; /* Increment req length by skb data length */ req->length += skb->len; length = req->length; dev_kfree_skb_any(skb); Loading Loading @@ -931,12 +960,8 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb, req->context = skb; } req->complete = tx_complete; /* NCM requires no zlp if transfer is dwNtbInMaxSize */ if (dev->port_usb && dev->port_usb->is_fixed && length == dev->port_usb->fixed_in_len && if (is_fixed && length == fixed_in_len && (length % in->maxpacket) == 0) req->zero = 0; else Loading Loading @@ -983,11 +1008,13 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb, dev_kfree_skb_any(skb); else req->length = 0; drop: dev->net->stats.tx_dropped++; multiframe: spin_lock_irqsave(&dev->req_lock, flags); if (list_empty(&dev->tx_reqs)) netif_start_queue(net); list_add(&req->list, &dev->tx_reqs); list_add_tail(&req->list, &dev->tx_reqs); spin_unlock_irqrestore(&dev->req_lock, flags); } success: Loading Loading @@ -1446,6 +1473,8 @@ int gether_register_netdev(struct net_device *net) else INFO(dev, "MAC %pM\n", dev->dev_mac); uether_debugfs_init(dev); return status; } EXPORT_SYMBOL_GPL(gether_register_netdev); Loading Loading @@ -1584,6 +1613,7 @@ void gether_cleanup(struct eth_dev *dev) uether_debugfs_exit(dev); unregister_netdev(dev->net); flush_work(&dev->work); cancel_work_sync(&dev->rx_work); free_netdev(dev->net); } EXPORT_SYMBOL_GPL(gether_cleanup); Loading Loading @@ -1612,6 +1642,11 @@ struct net_device *gether_connect(struct gether *link) if (!dev) return ERR_PTR(-EINVAL); /* size of rndis_packet_msg_type is 44 */ link->header = kzalloc(44, GFP_ATOMIC); if (!link->header) return ERR_PTR(-ENOMEM); if (link->in_ep) { link->in_ep->driver_data = dev; result = usb_ep_enable(link->in_ep); Loading Loading @@ -1675,8 +1710,12 @@ struct net_device *gether_connect(struct gether *link) } fail0: /* caller is responsible for cleanup on error */ if (result < 0) if (result < 0) { kfree(link->header); return ERR_PTR(result); } return dev->net; } EXPORT_SYMBOL_GPL(gether_connect); Loading Loading @@ -1729,6 +1768,9 @@ void gether_disconnect(struct gether *link) spin_lock(&dev->req_lock); } spin_unlock(&dev->req_lock); /* Free rndis header buffer memory */ kfree(link->header); link->header = NULL; link->in_ep->desc = NULL; } Loading drivers/usb/gadget/function/u_ether.h +1 −0 Original line number Diff line number Diff line Loading @@ -86,6 +86,7 @@ struct gether { /* called on network open/close */ void (*open)(struct gether *); void (*close)(struct gether *); struct rndis_packet_msg_type *header; }; #define DEFAULT_FILTER (USB_CDC_PACKET_TYPE_BROADCAST \ Loading Loading
drivers/usb/gadget/function/f_rndis.c +79 −10 Original line number Diff line number Diff line Loading @@ -93,6 +93,9 @@ struct f_rndis { atomic_t notify_count; }; static struct f_rndis *__rndis; static spinlock_t _rndis_lock; static inline struct f_rndis *func_to_rndis(struct usb_function *f) { return container_of(f, struct f_rndis, port.func); Loading Loading @@ -383,10 +386,31 @@ static struct sk_buff *rndis_add_header(struct gether *port, struct sk_buff *skb) { struct sk_buff *skb2; struct rndis_packet_msg_type *header = NULL; struct f_rndis *rndis = func_to_rndis(&port->func); if (!skb) return NULL; if (rndis->port.multi_pkt_xfer) { if (port->header) { header = port->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; } dev_kfree_skb(skb); pr_err("RNDIS header is NULL.\n"); return NULL; } skb2 = skb_realloc_headroom(skb, sizeof(struct rndis_packet_msg_type)); rndis_add_hdr(skb2); Loading Loading @@ -422,10 +446,19 @@ 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 f_rndis *rndis; struct usb_composite_dev *cdev; int status = req->status; struct usb_ep *notify_ep; spin_lock(&_rndis_lock); rndis = __rndis; if (!rndis || !rndis->notify) { spin_unlock(&_rndis_lock); return; } cdev = rndis->port.func.config->cdev; /* after TX: * - USB_CDC_GET_ENCAPSULATED_RESPONSE (ep0/control) * - RNDIS_RESPONSE_AVAILABLE (status/irq) Loading @@ -435,7 +468,7 @@ static void rndis_response_complete(struct usb_ep *ep, struct usb_request *req) case -ESHUTDOWN: /* connection gone */ atomic_set(&rndis->notify_count, 0); break; goto out; default: DBG(cdev, "RNDIS %s response error %d, %d/%d\n", ep->name, status, Loading @@ -443,29 +476,54 @@ static void rndis_response_complete(struct usb_ep *ep, struct usb_request *req) /* FALLTHROUGH */ case 0: if (ep != rndis->notify) break; goto out; /* handle multiple pending RNDIS_RESPONSE_AVAILABLE * notifications by resending until we're done */ if (atomic_dec_and_test(&rndis->notify_count)) break; status = usb_ep_queue(rndis->notify, req, GFP_ATOMIC); goto out; notify_ep = rndis->notify; spin_unlock(&_rndis_lock); status = usb_ep_queue(notify_ep, req, GFP_ATOMIC); if (status) { atomic_dec(&rndis->notify_count); spin_lock(&_rndis_lock); if (!__rndis) goto out; atomic_dec(&__rndis->notify_count); DBG(cdev, "notify/1 --> %d\n", status); spin_unlock(&_rndis_lock); } break; } return; out: spin_unlock(&_rndis_lock); } static void rndis_command_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 f_rndis *rndis; struct usb_composite_dev *cdev; int status; rndis_init_msg_type *buf; if (req->status != 0) { pr_err("%s: RNDIS command completion error:%d\n", __func__, req->status); return; } spin_lock(&_rndis_lock); rndis = __rndis; if (!rndis || !rndis->notify) { spin_unlock(&_rndis_lock); return; } cdev = rndis->port.func.config->cdev; /* received RNDIS command from USB_CDC_SEND_ENCAPSULATED_COMMAND */ // spin_lock(&dev->lock); status = rndis_msg_parser(rndis->params, (u8 *) req->buf); Loading @@ -488,6 +546,7 @@ static void rndis_command_complete(struct usb_ep *ep, struct usb_request *req) rndis->port.multi_pkt_xfer = 0; } // spin_unlock(&dev->lock); spin_unlock(&_rndis_lock); } static int Loading Loading @@ -639,13 +698,16 @@ static void rndis_disable(struct usb_function *f) { struct f_rndis *rndis = func_to_rndis(f); struct usb_composite_dev *cdev = f->config->cdev; unsigned long flags; if (!rndis->notify->enabled) return; DBG(cdev, "rndis deactivated\n"); spin_lock_irqsave(&_rndis_lock, flags); rndis_uninit(rndis->params); spin_unlock_irqrestore(&_rndis_lock, flags); gether_disconnect(&rndis->port); usb_ep_disable(rndis->notify); Loading Loading @@ -992,6 +1054,7 @@ static struct usb_function_instance *rndis_alloc_inst(void) opts->rndis_os_desc.ext_compat_id = opts->rndis_ext_compat_id; mutex_init(&opts->lock); spin_lock_init(&_rndis_lock); opts->func_inst.free_func_inst = rndis_free_inst; INIT_LIST_HEAD(&opts->rndis_os_desc.ext_prop); Loading Loading @@ -1022,11 +1085,15 @@ static void rndis_free(struct usb_function *f) { struct f_rndis *rndis; struct f_rndis_opts *opts; unsigned long int flags; rndis = func_to_rndis(f); rndis_deregister(rndis->params); opts = container_of(f->fi, struct f_rndis_opts, func_inst); spin_lock_irqsave(&_rndis_lock, flags); kfree(rndis); __rndis = NULL; spin_unlock_irqrestore(&_rndis_lock, flags); mutex_lock(&opts->lock); opts->refcnt--; mutex_unlock(&opts->lock); Loading Loading @@ -1059,6 +1126,8 @@ static struct usb_function *rndis_alloc(struct usb_function_instance *fi) if (!rndis) return ERR_PTR(-ENOMEM); __rndis = rndis; opts = container_of(fi, struct f_rndis_opts, func_inst); mutex_lock(&opts->lock); opts->refcnt++; Loading
drivers/usb/gadget/function/u_ether.c +78 −36 Original line number Diff line number Diff line Loading @@ -246,6 +246,7 @@ static void defer_kevent(struct eth_dev *dev, int flag) } static void rx_complete(struct usb_ep *ep, struct usb_request *req); static void tx_complete(struct usb_ep *ep, struct usb_request *req); static int rx_submit(struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags) Loading Loading @@ -312,7 +313,6 @@ rx_submit(struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags) req->buf = skb->data; req->length = size; req->complete = rx_complete; req->context = skb; retval = usb_ep_queue(out, req, gfp_flags); Loading Loading @@ -415,6 +415,7 @@ static int prealloc(struct list_head *list, struct usb_ep *ep, unsigned n) { unsigned i; struct usb_request *req; bool usb_in; if (!n) return -ENOMEM; Loading @@ -425,10 +426,22 @@ static int prealloc(struct list_head *list, struct usb_ep *ep, unsigned n) if (i-- == 0) goto extra; } if (ep->desc->bEndpointAddress & USB_DIR_IN) usb_in = true; else usb_in = false; while (i--) { req = usb_ep_alloc_request(ep, GFP_ATOMIC); if (!req) return list_empty(list) ? -ENOMEM : 0; /* update completion handler */ if (usb_in) req->complete = tx_complete; else req->complete = rx_complete; list_add(&req->list, list); } return 0; Loading Loading @@ -580,7 +593,7 @@ static void eth_work(struct work_struct *work) static void tx_complete(struct usb_ep *ep, struct usb_request *req) { struct sk_buff *skb = req->context; struct sk_buff *skb; struct eth_dev *dev = ep->driver_data; struct net_device *net = dev->net; struct usb_request *new_req; Loading Loading @@ -693,6 +706,7 @@ static void tx_complete(struct usb_ep *ep, struct usb_request *req) spin_unlock(&dev->req_lock); } } else { skb = req->context; /* Is aggregation already enabled and buffers allocated ? */ if (dev->port_usb->multi_pkt_xfer && dev->tx_req_bufsize) { req->buf = kzalloc(dev->tx_req_bufsize Loading Loading @@ -735,7 +749,7 @@ static int alloc_tx_buffer(struct eth_dev *dev) list_for_each(act, &dev->tx_reqs) { req = container_of(act, struct usb_request, list); if (!req->buf) req->buf = kmalloc(dev->tx_req_bufsize req->buf = kzalloc(dev->tx_req_bufsize + dev->gadget->extra_buf_alloc, GFP_ATOMIC); if (!req->buf) Loading Loading @@ -771,11 +785,15 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb, struct usb_ep *in = NULL; u16 cdc_filter = 0; bool multi_pkt_xfer = false; u32 fixed_in_len = 0; bool is_fixed = false; spin_lock_irqsave(&dev->lock, flags); if (dev->port_usb) { in = dev->port_usb->in_ep; cdc_filter = dev->port_usb->cdc_filter; is_fixed = dev->port_usb->is_fixed; fixed_in_len = dev->port_usb->fixed_in_len; multi_pkt_xfer = dev->port_usb->multi_pkt_xfer; } spin_unlock_irqrestore(&dev->lock, flags); Loading @@ -786,7 +804,8 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb, } /* apply outgoing CDC or RNDIS filters */ if (skb && !is_promisc(cdc_filter)) { if (!test_bit(RMNET_MODE_LLP_IP, &dev->flags) && !is_promisc(cdc_filter)) { u8 *dest = skb->data; if (is_multicast_ether_addr(dest)) { Loading @@ -800,6 +819,7 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb, else type = USB_CDC_PACKET_TYPE_ALL_MULTICAST; if (!(cdc_filter & type)) { dev->net->stats.tx_dropped++; dev_kfree_skb_any(skb); return NETDEV_TX_OK; } Loading @@ -808,29 +828,6 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb, } dev->tx_pkts_rcvd++; /* * no buffer copies needed, unless the network stack did it * or the hardware can't use skb buffers. * or there's not enough space for extra headers we need */ spin_lock_irqsave(&dev->lock, flags); if (dev->wrap && dev->port_usb) skb = dev->wrap(dev->port_usb, skb); spin_unlock_irqrestore(&dev->lock, flags); if (!skb) { if (dev->port_usb && dev->port_usb->supports_multi_frame) { /* * Multi frame CDC protocols may store the frame for * later which is not a dropped frame. */ } else { dev->net->stats.tx_dropped++; } /* no error code for dropped packets */ return NETDEV_TX_OK; } /* Allocate memory for tx_reqs to support multi packet transfer */ spin_lock_irqsave(&dev->req_lock, flags); Loading Loading @@ -865,13 +862,45 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb, dev->tx_throttle++; netif_stop_queue(net); } spin_unlock_irqrestore(&dev->req_lock, flags); /* no buffer copies needed, unless the network stack did it * or the hardware can't use skb buffers. * or there's not enough space for extra headers we need */ spin_lock_irqsave(&dev->lock, flags); if (dev->wrap) { if (dev->port_usb) skb = dev->wrap(dev->port_usb, skb); if (!skb) { spin_unlock_irqrestore(&dev->lock, flags); /* Multi frame CDC protocols may store the frame for * later which is not a dropped frame. */ if (dev->port_usb && dev->port_usb->supports_multi_frame) goto multiframe; goto drop; } } dev->tx_skb_hold_count++; spin_unlock_irqrestore(&dev->req_lock, flags); spin_unlock_irqrestore(&dev->lock, flags); if (multi_pkt_xfer) { pr_debug("req->length:%d header_len:%u\n" "skb->len:%d skb->data_len:%d\n", req->length, dev->header_len, skb->len, skb->data_len); /* Add RNDIS Header */ memcpy(req->buf + req->length, dev->port_usb->header, dev->header_len); /* Increment req length by header size */ req->length += dev->header_len; /* Copy received IP data from SKB */ memcpy(req->buf + req->length, skb->data, skb->len); req->length = req->length + skb->len; /* Increment req length by skb data length */ req->length += skb->len; length = req->length; dev_kfree_skb_any(skb); Loading Loading @@ -931,12 +960,8 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb, req->context = skb; } req->complete = tx_complete; /* NCM requires no zlp if transfer is dwNtbInMaxSize */ if (dev->port_usb && dev->port_usb->is_fixed && length == dev->port_usb->fixed_in_len && if (is_fixed && length == fixed_in_len && (length % in->maxpacket) == 0) req->zero = 0; else Loading Loading @@ -983,11 +1008,13 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb, dev_kfree_skb_any(skb); else req->length = 0; drop: dev->net->stats.tx_dropped++; multiframe: spin_lock_irqsave(&dev->req_lock, flags); if (list_empty(&dev->tx_reqs)) netif_start_queue(net); list_add(&req->list, &dev->tx_reqs); list_add_tail(&req->list, &dev->tx_reqs); spin_unlock_irqrestore(&dev->req_lock, flags); } success: Loading Loading @@ -1446,6 +1473,8 @@ int gether_register_netdev(struct net_device *net) else INFO(dev, "MAC %pM\n", dev->dev_mac); uether_debugfs_init(dev); return status; } EXPORT_SYMBOL_GPL(gether_register_netdev); Loading Loading @@ -1584,6 +1613,7 @@ void gether_cleanup(struct eth_dev *dev) uether_debugfs_exit(dev); unregister_netdev(dev->net); flush_work(&dev->work); cancel_work_sync(&dev->rx_work); free_netdev(dev->net); } EXPORT_SYMBOL_GPL(gether_cleanup); Loading Loading @@ -1612,6 +1642,11 @@ struct net_device *gether_connect(struct gether *link) if (!dev) return ERR_PTR(-EINVAL); /* size of rndis_packet_msg_type is 44 */ link->header = kzalloc(44, GFP_ATOMIC); if (!link->header) return ERR_PTR(-ENOMEM); if (link->in_ep) { link->in_ep->driver_data = dev; result = usb_ep_enable(link->in_ep); Loading Loading @@ -1675,8 +1710,12 @@ struct net_device *gether_connect(struct gether *link) } fail0: /* caller is responsible for cleanup on error */ if (result < 0) if (result < 0) { kfree(link->header); return ERR_PTR(result); } return dev->net; } EXPORT_SYMBOL_GPL(gether_connect); Loading Loading @@ -1729,6 +1768,9 @@ void gether_disconnect(struct gether *link) spin_lock(&dev->req_lock); } spin_unlock(&dev->req_lock); /* Free rndis header buffer memory */ kfree(link->header); link->header = NULL; link->in_ep->desc = NULL; } Loading
drivers/usb/gadget/function/u_ether.h +1 −0 Original line number Diff line number Diff line Loading @@ -86,6 +86,7 @@ struct gether { /* called on network open/close */ void (*open)(struct gether *); void (*close)(struct gether *); struct rndis_packet_msg_type *header; }; #define DEFAULT_FILTER (USB_CDC_PACKET_TYPE_BROADCAST \ Loading