/* * This component encapsulates the Ethernet link glue needed to provide * one (!) network link through the USB gadget stack, normally "usb0". * * The control and data models are handled by the function driver which * connects to this code; such as CDC Ethernet (ECM or EEM), * "CDC Subset", or RNDIS. That includes all descriptor and endpoint * management. * * Link level addressing is handled by this component using module * parameters; if no such parameters are provided, random link level * addresses are used. Each end of the link uses one address. The * host end address is exported in various ways, and is often recorded * in configuration databases. * * The driver which assembles each configuration using such a link is * responsible for ensuring that each configuration includes at most one * instance of is network link. (The network layer provides ways for * this single "physical" link to be used by multiple virtual links.)
*/
#define UETH__VERSION "29-May-2008"
/* Experiments show that both Linux and Windows hosts allow up to 16k * frame sizes. Set the max MTU size to 15k+52 to prevent allocating 32k
* blocks and still have efficient handling. */ #define GETHER_MAX_MTU_SIZE 15412 #define GETHER_MAX_ETH_FRAME_LEN (GETHER_MAX_MTU_SIZE + ETH_HLEN)
struct eth_dev { /* lock is held while accessing port_usb
*/
spinlock_t lock; struct gether *port_usb;
staticvoid defer_kevent(struct eth_dev *dev, int flag)
{ if (test_and_set_bit(flag, &dev->todo)) return; if (!schedule_work(&dev->work))
ERROR(dev, "kevent %d may have been dropped\n", flag); else
DBG(dev, "kevent %d scheduled\n", flag);
}
spin_lock_irqsave(&dev->lock, flags); if (dev->port_usb)
out = dev->port_usb->out_ep; else
out = NULL;
if (!out)
{
spin_unlock_irqrestore(&dev->lock, flags); return -ENOTCONN;
}
/* Padding up to RX_EXTRA handles minor disagreements with host. * Normally we use the USB "terminate on short read" convention; * so allow up to (N*maxpacket), since that memory is normally * already allocated. Some hardware doesn't deal well with short * reads (e.g. DMA must be N*maxpacket), so for now don't trim a * byte off the end (to force hardware errors on overflow). * * RNDIS uses internal framing, and explicitly allows senders to * pad to end-of-packet. That's potentially nice for speed, but * means receivers can't recover lost synch on their own (because * new packets don't only start after a short RX).
*/
size += sizeof(struct ethhdr) + dev->net->mtu + RX_EXTRA;
size += dev->port_usb->header_len;
if (dev->port_usb->is_fixed)
size = max_t(size_t, size, dev->port_usb->fixed_out_len);
spin_unlock_irqrestore(&dev->lock, flags);
skb = __netdev_alloc_skb(dev->net, size + NET_IP_ALIGN, gfp_flags); if (skb == NULL) {
DBG(dev, "no rx skb\n"); goto enomem;
}
/* Some platforms perform better when IP packets are aligned, * but on at least one, checksumming fails otherwise. Note: * RNDIS headers involve variable numbers of LE32 values.
*/ if (likely(!dev->no_skb_reserve))
skb_reserve(skb, NET_IP_ALIGN);
if (!in) { if (skb)
dev_kfree_skb_any(skb); return NETDEV_TX_OK;
}
/* apply outgoing CDC or RNDIS filters */ if (skb && !is_promisc(cdc_filter)) {
u8 *dest = skb->data;
if (is_multicast_ether_addr(dest)) {
u16 type;
/* ignores USB_CDC_PACKET_TYPE_MULTICAST and host * SET_ETHERNET_MULTICAST_FILTERS requests
*/ if (is_broadcast_ether_addr(dest))
type = USB_CDC_PACKET_TYPE_BROADCAST; else
type = USB_CDC_PACKET_TYPE_ALL_MULTICAST; if (!(cdc_filter & type)) {
dev_kfree_skb_any(skb); return NETDEV_TX_OK;
}
} /* ignores USB_CDC_PACKET_TYPE_DIRECTED */
}
spin_lock_irqsave(&dev->req_lock, flags); /* * this freelist can be empty if an interrupt triggered disconnect() * and reconfigured the gadget (shutting down this queue) after the * network stack decided to xmit but before we got the spinlock.
*/ if (list_empty(&dev->tx_reqs)) {
spin_unlock_irqrestore(&dev->req_lock, flags); return NETDEV_TX_BUSY;
}
/* temporarily stop TX queue when the freelist empties */ if (list_empty(&dev->tx_reqs))
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
*/ if (dev->wrap) { unsignedlong flags;
spin_lock_irqsave(&dev->lock, flags); if (dev->port_usb)
skb = dev->wrap(dev->port_usb, skb);
spin_unlock_irqrestore(&dev->lock, flags); if (!skb) { /* 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;
}
}
/* NCM requires no zlp if transfer is dwNtbInMaxSize */ if (dev->port_usb &&
dev->port_usb->is_fixed &&
length == dev->port_usb->fixed_in_len &&
(length % in->maxpacket) == 0)
req->zero = 0; else
req->zero = 1;
/* use zlp framing on tx for strict CDC-Ether conformance, * though any robust network rx path ignores extra padding. * and some hardware doesn't like to write zlps.
*/ if (req->zero && !dev->zlp && (length % in->maxpacket) == 0)
length++;
/* ensure there are no more active requests */
spin_lock_irqsave(&dev->lock, flags); if (dev->port_usb) { struct gether *link = dev->port_usb; conststruct usb_endpoint_descriptor *in; conststruct usb_endpoint_descriptor *out;
if (link->close)
link->close(link);
/* NOTE: we have no abort-queue primitive we could use * to cancel all pending I/O. Instead, we disable then * reenable the endpoints ... this idiom may leave toggle * wrong, but that's a self-correcting error. * * REVISIT: we *COULD* just let the transfers complete at * their own pace; the network stack can handle old packets. * For the moment we leave this here, since it works.
*/
in = link->in_ep->desc;
out = link->out_ep->desc;
usb_ep_disable(link->in_ep);
usb_ep_disable(link->out_ep); if (netif_carrier_ok(net)) {
DBG(dev, "host still using in/out endpoints\n");
link->in_ep->desc = in;
link->out_ep->desc = out;
usb_ep_enable(link->in_ep);
usb_ep_enable(link->out_ep);
}
}
spin_unlock_irqrestore(&dev->lock, flags);
/* * gether_setup_name - initialize one ethernet-over-usb link * @g: gadget to associated with these links * @ethaddr: NULL, or a buffer in which the ethernet address of the * host side of the link is recorded * @netname: name for network device (for example, "usb") * Context: may sleep * * This sets up the single network link that may be exported by a * gadget driver using this framework. The link layer addresses are * set up using module parameters. * * Returns an eth_dev pointer on success, or an ERR_PTR on failure.
*/ struct eth_dev *gether_setup_name(struct usb_gadget *g, constchar *dev_addr, constchar *host_addr,
u8 ethaddr[ETH_ALEN], unsigned qmult, constchar *netname)
{ struct eth_dev *dev; struct net_device *net; int status;
u8 addr[ETH_ALEN];
net = alloc_etherdev(sizeof *dev); if (!net) return ERR_PTR(-ENOMEM);
dev = netdev_priv(net);
spin_lock_init(&dev->lock);
spin_lock_init(&dev->req_lock);
INIT_WORK(&dev->work, eth_work);
INIT_LIST_HEAD(&dev->tx_reqs);
INIT_LIST_HEAD(&dev->rx_reqs);
status = register_netdev(net); if (status < 0) {
dev_dbg(&g->dev, "register_netdev failed, %d\n", status);
free_netdev(net);
dev = ERR_PTR(status);
} else {
INFO(dev, "MAC %pM\n", net->dev_addr);
INFO(dev, "HOST MAC %pM\n", dev->host_mac);
/* * two kinds of host-initiated state changes: * - iff DATA transfer is active, carrier is "on" * - tx queueing enabled if open *and* carrier is "on"
*/
netif_carrier_off(net);
}
int gether_register_netdev(struct net_device *net)
{ struct eth_dev *dev; struct usb_gadget *g; int status;
if (!net->dev.parent) return -EINVAL;
dev = netdev_priv(net);
g = dev->gadget;
eth_hw_addr_set(net, dev->dev_mac);
status = register_netdev(net); if (status < 0) {
dev_dbg(&g->dev, "register_netdev failed, %d\n", status); return status;
} else {
INFO(dev, "HOST MAC %pM\n", dev->host_mac);
INFO(dev, "MAC %pM\n", dev->dev_mac);
/* two kinds of host-initiated state changes: * - iff DATA transfer is active, carrier is "on" * - tx queueing enabled if open *and* carrier is "on"
*/
netif_carrier_off(net);
}
int gether_set_ifname(struct net_device *net, constchar *name, int len)
{ struct eth_dev *dev = netdev_priv(net); char tmp[IFNAMSIZ]; constchar *p;
if (name[len - 1] == '\n')
len--;
if (len >= sizeof(tmp)) return -E2BIG;
strscpy(tmp, name, len + 1); if (!dev_valid_name(tmp)) return -EINVAL;
/* Require exactly one %d, so binding will not fail with EEXIST. */
p = strchr(name, '%'); if (!p || p[1] != 'd' || strchr(p + 2, '%')) return -EINVAL;
if (atomic_read(&dev->tx_qlen)) { /* * There is a transfer in progress. So we trigger a remote * wakeup to inform the host.
*/ if (!ether_wakeup_host(dev->port_usb)) return;
}
spin_lock_irqsave(&dev->lock, flags);
link->is_suspend = true;
spin_unlock_irqrestore(&dev->lock, flags);
}
EXPORT_SYMBOL_GPL(gether_suspend);
/* * gether_cleanup - remove Ethernet-over-USB device * Context: may sleep * * This is called to free all resources allocated by @gether_setup().
*/ void gether_cleanup(struct eth_dev *dev)
{ if (!dev) return;
/** * gether_connect - notify network layer that USB link is active * @link: the USB link, set up with endpoints, descriptors matching * current device speed, and any framing wrapper(s) set up. * Context: irqs blocked * * This is called to activate endpoints and let the network layer know * the connection is active ("carrier detect"). It may cause the I/O * queues to open and start letting network packets flow, but will in * any case activate the endpoints so that they respond properly to the * USB host. * * Verify net_device pointer returned using IS_ERR(). If it doesn't * indicate some error code (negative errno), ep->driver_data values * have been overwritten.
*/ struct net_device *gether_connect(struct gether *link)
{ struct eth_dev *dev = link->ioport; int result = 0;
spin_lock(&dev->lock);
dev->port_usb = link; if (netif_running(dev->net)) { if (link->open)
link->open(link);
} else { if (link->close)
link->close(link);
}
spin_unlock(&dev->lock);
netif_carrier_on(dev->net); if (netif_running(dev->net))
eth_start(dev, GFP_ATOMIC);
/* on error, disable any endpoints */
} else {
(void) usb_ep_disable(link->out_ep);
fail1:
(void) usb_ep_disable(link->in_ep);
}
fail0: /* caller is responsible for cleanup on error */ if (result < 0) return ERR_PTR(result); return dev->net;
}
EXPORT_SYMBOL_GPL(gether_connect);
/** * gether_disconnect - notify network layer that USB link is inactive * @link: the USB link, on which gether_connect() was called * Context: irqs blocked * * This is called to deactivate endpoints and let the network layer know * the connection went inactive ("no carrier"). * * On return, the state is as if gether_connect() had never been called. * The endpoints are inactive, and accordingly without active USB I/O. * Pointers to endpoint descriptors and endpoint private data are nulled.
*/ void gether_disconnect(struct gether *link)
{ struct eth_dev *dev = link->ioport; struct usb_request *req;
/* disable endpoints, forcing (synchronous) completion * of all pending i/o. then free the request objects * and forget about the endpoints.
*/
usb_ep_disable(link->in_ep);
spin_lock(&dev->req_lock); while (!list_empty(&dev->tx_reqs)) {
req = list_first_entry(&dev->tx_reqs, struct usb_request, list);
list_del(&req->list);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.