linux/drivers/usb/gadget/function/f_rndis.c

// SPDX-License-Identifier: GPL-2.0+
/*
 * f_rndis.c -- RNDIS link function driver
 *
 * Copyright (C) 2003-2005,2008 David Brownell
 * Copyright (C) 2003-2004 Robert Schwebel, Benedikt Spranger
 * Copyright (C) 2008 Nokia Corporation
 * Copyright (C) 2009 Samsung Electronics
 *                    Author: Michal Nazarewicz ([email protected])
 */

/* #define VERBOSE_DEBUG */

#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/etherdevice.h>

#include <linux/atomic.h>

#include "u_ether.h"
#include "u_ether_configfs.h"
#include "u_rndis.h"
#include "rndis.h"
#include "configfs.h"

/*
 * This function is an RNDIS Ethernet port -- a Microsoft protocol that's
 * been promoted instead of the standard CDC Ethernet.  The published RNDIS
 * spec is ambiguous, incomplete, and needlessly complex.  Variants such as
 * ActiveSync have even worse status in terms of specification.
 *
 * In short:  it's a protocol controlled by (and for) Microsoft, not for an
 * Open ecosystem or markets.  Linux supports it *only* because Microsoft
 * doesn't support the CDC Ethernet standard.
 *
 * The RNDIS data transfer model is complex, with multiple Ethernet packets
 * per USB message, and out of band data.  The control model is built around
 * what's essentially an "RNDIS RPC" protocol.  It's all wrapped in a CDC ACM
 * (modem, not Ethernet) veneer, with those ACM descriptors being entirely
 * useless (they're ignored).  RNDIS expects to be the only function in its
 * configuration, so it's no real help if you need composite devices; and
 * it expects to be the first configuration too.
 *
 * There is a single technical advantage of RNDIS over CDC Ethernet, if you
 * discount the fluff that its RPC can be made to deliver: it doesn't need
 * a NOP altsetting for the data interface.  That lets it work on some of the
 * "so smart it's stupid" hardware which takes over configuration changes
 * from the software, and adds restrictions like "no altsettings".
 *
 * Unfortunately MSFT's RNDIS drivers are buggy.  They hang or oops, and
 * have all sorts of contrary-to-specification oddities that can prevent
 * them from working sanely.  Since bugfixes (or accurate specs, letting
 * Linux work around those bugs) are unlikely to ever come from MSFT, you
 * may want to avoid using RNDIS on purely operational grounds.
 *
 * Omissions from the RNDIS 1.0 specification include:
 *
 *   - Power management ... references data that's scattered around lots
 *     of other documentation, which is incorrect/incomplete there too.
 *
 *   - There are various undocumented protocol requirements, like the need
 *     to send garbage in some control-OUT messages.
 *
 *   - MS-Windows drivers sometimes emit undocumented requests.
 */

struct f_rndis {};

static inline struct f_rndis *func_to_rndis(struct usb_function *f)
{}

/*-------------------------------------------------------------------------*/

/*
 */

#define RNDIS_STATUS_INTERVAL_MS
#define STATUS_BYTECOUNT


/* interface descriptor: */

static struct usb_interface_descriptor rndis_control_intf =;

static struct usb_cdc_header_desc header_desc =;

static struct usb_cdc_call_mgmt_descriptor call_mgmt_descriptor =;

static struct usb_cdc_acm_descriptor rndis_acm_descriptor =;

static struct usb_cdc_union_desc rndis_union_desc =;

/* the data interface has two bulk endpoints */

static struct usb_interface_descriptor rndis_data_intf =;


static struct usb_interface_assoc_descriptor
rndis_iad_descriptor =;

/* full speed support: */

static struct usb_endpoint_descriptor fs_notify_desc =;

static struct usb_endpoint_descriptor fs_in_desc =;

static struct usb_endpoint_descriptor fs_out_desc =;

static struct usb_descriptor_header *eth_fs_function[] =;

/* high speed support: */

static struct usb_endpoint_descriptor hs_notify_desc =;

static struct usb_endpoint_descriptor hs_in_desc =;

static struct usb_endpoint_descriptor hs_out_desc =;

static struct usb_descriptor_header *eth_hs_function[] =;

/* super speed support: */

static struct usb_endpoint_descriptor ss_notify_desc =;

static struct usb_ss_ep_comp_descriptor ss_intr_comp_desc =;

static struct usb_endpoint_descriptor ss_in_desc =;

static struct usb_endpoint_descriptor ss_out_desc =;

static struct usb_ss_ep_comp_descriptor ss_bulk_comp_desc =;

static struct usb_descriptor_header *eth_ss_function[] =;

/* string descriptors: */

static struct usb_string rndis_string_defs[] =;

static struct usb_gadget_strings rndis_string_table =;

static struct usb_gadget_strings *rndis_strings[] =;

/*-------------------------------------------------------------------------*/

static struct sk_buff *rndis_add_header(struct gether *port,
					struct sk_buff *skb)
{}

static void rndis_response_available(void *_rndis)
{}

static void rndis_response_complete(struct usb_ep *ep, struct usb_request *req)
{}

static void rndis_command_complete(struct usb_ep *ep, struct usb_request *req)
{}

static int
rndis_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
{}


static int rndis_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
{}

static void rndis_disable(struct usb_function *f)
{}

/*-------------------------------------------------------------------------*/

/*
 * This isn't quite the same mechanism as CDC Ethernet, since the
 * notification scheme passes less data, but the same set of link
 * states must be tested.  A key difference is that altsettings are
 * not used to tell whether the link should send packets or not.
 */

static void rndis_open(struct gether *geth)
{}

static void rndis_close(struct gether *geth)
{}

/*-------------------------------------------------------------------------*/

/* Some controllers can't support RNDIS ... */
static inline bool can_support_rndis(struct usb_configuration *c)
{}

/* ethernet function driver setup/binding */

static int
rndis_bind(struct usb_configuration *c, struct usb_function *f)
{}

void rndis_borrow_net(struct usb_function_instance *f, struct net_device *net)
{}
EXPORT_SYMBOL_GPL();

static inline struct f_rndis_opts *to_f_rndis_opts(struct config_item *item)
{}

/* f_rndis_item_ops */
USB_ETHERNET_CONFIGFS_ITEM();

/* f_rndis_opts_dev_addr */
USB_ETHERNET_CONFIGFS_ITEM_ATTR_DEV_ADDR();

/* f_rndis_opts_host_addr */
USB_ETHERNET_CONFIGFS_ITEM_ATTR_HOST_ADDR();

/* f_rndis_opts_qmult */
USB_ETHERNET_CONFIGFS_ITEM_ATTR_QMULT();

/* f_rndis_opts_ifname */
USB_ETHERNET_CONFIGFS_ITEM_ATTR_IFNAME();

/* f_rndis_opts_class */
USB_ETHER_CONFIGFS_ITEM_ATTR_U8_RW();

/* f_rndis_opts_subclass */
USB_ETHER_CONFIGFS_ITEM_ATTR_U8_RW();

/* f_rndis_opts_protocol */
USB_ETHER_CONFIGFS_ITEM_ATTR_U8_RW();

static struct configfs_attribute *rndis_attrs[] =;

static const struct config_item_type rndis_func_type =;

static void rndis_free_inst(struct usb_function_instance *f)
{}

static struct usb_function_instance *rndis_alloc_inst(void)
{}

static void rndis_free(struct usb_function *f)
{}

static void rndis_unbind(struct usb_configuration *c, struct usb_function *f)
{}

static struct usb_function *rndis_alloc(struct usb_function_instance *fi)
{}

DECLARE_USB_FUNCTION_INIT(rndis, rndis_alloc_inst, rndis_alloc);
MODULE_DESCRIPTION();
MODULE_LICENSE();
MODULE_AUTHOR();