cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

f_obex.c (12593B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * f_obex.c -- USB CDC OBEX function driver
      4 *
      5 * Copyright (C) 2008 Nokia Corporation
      6 * Contact: Felipe Balbi <felipe.balbi@nokia.com>
      7 *
      8 * Based on f_acm.c by Al Borchers and David Brownell.
      9 */
     10
     11/* #define VERBOSE_DEBUG */
     12
     13#include <linux/slab.h>
     14#include <linux/kernel.h>
     15#include <linux/device.h>
     16#include <linux/module.h>
     17
     18#include "u_serial.h"
     19
     20
     21/*
     22 * This CDC OBEX function support just packages a TTY-ish byte stream.
     23 * A user mode server will put it into "raw" mode and handle all the
     24 * relevant protocol details ... this is just a kernel passthrough.
     25 * When possible, we prevent gadget enumeration until that server is
     26 * ready to handle the commands.
     27 */
     28
     29struct f_obex {
     30	struct gserial			port;
     31	u8				ctrl_id;
     32	u8				data_id;
     33	u8				cur_alt;
     34	u8				port_num;
     35};
     36
     37static inline struct f_obex *func_to_obex(struct usb_function *f)
     38{
     39	return container_of(f, struct f_obex, port.func);
     40}
     41
     42static inline struct f_obex *port_to_obex(struct gserial *p)
     43{
     44	return container_of(p, struct f_obex, port);
     45}
     46
     47/*-------------------------------------------------------------------------*/
     48
     49#define OBEX_CTRL_IDX	0
     50#define OBEX_DATA_IDX	1
     51
     52static struct usb_string obex_string_defs[] = {
     53	[OBEX_CTRL_IDX].s	= "CDC Object Exchange (OBEX)",
     54	[OBEX_DATA_IDX].s	= "CDC OBEX Data",
     55	{  },	/* end of list */
     56};
     57
     58static struct usb_gadget_strings obex_string_table = {
     59	.language		= 0x0409,	/* en-US */
     60	.strings		= obex_string_defs,
     61};
     62
     63static struct usb_gadget_strings *obex_strings[] = {
     64	&obex_string_table,
     65	NULL,
     66};
     67
     68/*-------------------------------------------------------------------------*/
     69
     70static struct usb_interface_descriptor obex_control_intf = {
     71	.bLength		= sizeof(obex_control_intf),
     72	.bDescriptorType	= USB_DT_INTERFACE,
     73	.bInterfaceNumber	= 0,
     74
     75	.bAlternateSetting	= 0,
     76	.bNumEndpoints		= 0,
     77	.bInterfaceClass	= USB_CLASS_COMM,
     78	.bInterfaceSubClass	= USB_CDC_SUBCLASS_OBEX,
     79};
     80
     81static struct usb_interface_descriptor obex_data_nop_intf = {
     82	.bLength		= sizeof(obex_data_nop_intf),
     83	.bDescriptorType	= USB_DT_INTERFACE,
     84	.bInterfaceNumber	= 1,
     85
     86	.bAlternateSetting	= 0,
     87	.bNumEndpoints		= 0,
     88	.bInterfaceClass	= USB_CLASS_CDC_DATA,
     89};
     90
     91static struct usb_interface_descriptor obex_data_intf = {
     92	.bLength		= sizeof(obex_data_intf),
     93	.bDescriptorType	= USB_DT_INTERFACE,
     94	.bInterfaceNumber	= 2,
     95
     96	.bAlternateSetting	= 1,
     97	.bNumEndpoints		= 2,
     98	.bInterfaceClass	= USB_CLASS_CDC_DATA,
     99};
    100
    101static struct usb_cdc_header_desc obex_cdc_header_desc = {
    102	.bLength		= sizeof(obex_cdc_header_desc),
    103	.bDescriptorType	= USB_DT_CS_INTERFACE,
    104	.bDescriptorSubType	= USB_CDC_HEADER_TYPE,
    105	.bcdCDC			= cpu_to_le16(0x0120),
    106};
    107
    108static struct usb_cdc_union_desc obex_cdc_union_desc = {
    109	.bLength		= sizeof(obex_cdc_union_desc),
    110	.bDescriptorType	= USB_DT_CS_INTERFACE,
    111	.bDescriptorSubType	= USB_CDC_UNION_TYPE,
    112	.bMasterInterface0	= 1,
    113	.bSlaveInterface0	= 2,
    114};
    115
    116static struct usb_cdc_obex_desc obex_desc = {
    117	.bLength		= sizeof(obex_desc),
    118	.bDescriptorType	= USB_DT_CS_INTERFACE,
    119	.bDescriptorSubType	= USB_CDC_OBEX_TYPE,
    120	.bcdVersion		= cpu_to_le16(0x0100),
    121};
    122
    123/* High-Speed Support */
    124
    125static struct usb_endpoint_descriptor obex_hs_ep_out_desc = {
    126	.bLength		= USB_DT_ENDPOINT_SIZE,
    127	.bDescriptorType	= USB_DT_ENDPOINT,
    128
    129	.bEndpointAddress	= USB_DIR_OUT,
    130	.bmAttributes		= USB_ENDPOINT_XFER_BULK,
    131	.wMaxPacketSize		= cpu_to_le16(512),
    132};
    133
    134static struct usb_endpoint_descriptor obex_hs_ep_in_desc = {
    135	.bLength		= USB_DT_ENDPOINT_SIZE,
    136	.bDescriptorType	= USB_DT_ENDPOINT,
    137
    138	.bEndpointAddress	= USB_DIR_IN,
    139	.bmAttributes		= USB_ENDPOINT_XFER_BULK,
    140	.wMaxPacketSize		= cpu_to_le16(512),
    141};
    142
    143static struct usb_descriptor_header *hs_function[] = {
    144	(struct usb_descriptor_header *) &obex_control_intf,
    145	(struct usb_descriptor_header *) &obex_cdc_header_desc,
    146	(struct usb_descriptor_header *) &obex_desc,
    147	(struct usb_descriptor_header *) &obex_cdc_union_desc,
    148
    149	(struct usb_descriptor_header *) &obex_data_nop_intf,
    150	(struct usb_descriptor_header *) &obex_data_intf,
    151	(struct usb_descriptor_header *) &obex_hs_ep_in_desc,
    152	(struct usb_descriptor_header *) &obex_hs_ep_out_desc,
    153	NULL,
    154};
    155
    156/* Full-Speed Support */
    157
    158static struct usb_endpoint_descriptor obex_fs_ep_in_desc = {
    159	.bLength		= USB_DT_ENDPOINT_SIZE,
    160	.bDescriptorType	= USB_DT_ENDPOINT,
    161
    162	.bEndpointAddress	= USB_DIR_IN,
    163	.bmAttributes		= USB_ENDPOINT_XFER_BULK,
    164};
    165
    166static struct usb_endpoint_descriptor obex_fs_ep_out_desc = {
    167	.bLength		= USB_DT_ENDPOINT_SIZE,
    168	.bDescriptorType	= USB_DT_ENDPOINT,
    169
    170	.bEndpointAddress	= USB_DIR_OUT,
    171	.bmAttributes		= USB_ENDPOINT_XFER_BULK,
    172};
    173
    174static struct usb_descriptor_header *fs_function[] = {
    175	(struct usb_descriptor_header *) &obex_control_intf,
    176	(struct usb_descriptor_header *) &obex_cdc_header_desc,
    177	(struct usb_descriptor_header *) &obex_desc,
    178	(struct usb_descriptor_header *) &obex_cdc_union_desc,
    179
    180	(struct usb_descriptor_header *) &obex_data_nop_intf,
    181	(struct usb_descriptor_header *) &obex_data_intf,
    182	(struct usb_descriptor_header *) &obex_fs_ep_in_desc,
    183	(struct usb_descriptor_header *) &obex_fs_ep_out_desc,
    184	NULL,
    185};
    186
    187/*-------------------------------------------------------------------------*/
    188
    189static int obex_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
    190{
    191	struct f_obex		*obex = func_to_obex(f);
    192	struct usb_composite_dev *cdev = f->config->cdev;
    193
    194	if (intf == obex->ctrl_id) {
    195		if (alt != 0)
    196			goto fail;
    197		/* NOP */
    198		dev_dbg(&cdev->gadget->dev,
    199			"reset obex ttyGS%d control\n", obex->port_num);
    200
    201	} else if (intf == obex->data_id) {
    202		if (alt > 1)
    203			goto fail;
    204
    205		if (obex->port.in->enabled) {
    206			dev_dbg(&cdev->gadget->dev,
    207				"reset obex ttyGS%d\n", obex->port_num);
    208			gserial_disconnect(&obex->port);
    209		}
    210
    211		if (!obex->port.in->desc || !obex->port.out->desc) {
    212			dev_dbg(&cdev->gadget->dev,
    213				"init obex ttyGS%d\n", obex->port_num);
    214			if (config_ep_by_speed(cdev->gadget, f,
    215					       obex->port.in) ||
    216			    config_ep_by_speed(cdev->gadget, f,
    217					       obex->port.out)) {
    218				obex->port.out->desc = NULL;
    219				obex->port.in->desc = NULL;
    220				goto fail;
    221			}
    222		}
    223
    224		if (alt == 1) {
    225			dev_dbg(&cdev->gadget->dev,
    226				"activate obex ttyGS%d\n", obex->port_num);
    227			gserial_connect(&obex->port, obex->port_num);
    228		}
    229
    230	} else
    231		goto fail;
    232
    233	obex->cur_alt = alt;
    234
    235	return 0;
    236
    237fail:
    238	return -EINVAL;
    239}
    240
    241static int obex_get_alt(struct usb_function *f, unsigned intf)
    242{
    243	struct f_obex		*obex = func_to_obex(f);
    244
    245	return obex->cur_alt;
    246}
    247
    248static void obex_disable(struct usb_function *f)
    249{
    250	struct f_obex	*obex = func_to_obex(f);
    251	struct usb_composite_dev *cdev = f->config->cdev;
    252
    253	dev_dbg(&cdev->gadget->dev, "obex ttyGS%d disable\n", obex->port_num);
    254	gserial_disconnect(&obex->port);
    255}
    256
    257/*-------------------------------------------------------------------------*/
    258
    259static void obex_connect(struct gserial *g)
    260{
    261	struct f_obex		*obex = port_to_obex(g);
    262	struct usb_composite_dev *cdev = g->func.config->cdev;
    263	int			status;
    264
    265	status = usb_function_activate(&g->func);
    266	if (status)
    267		dev_dbg(&cdev->gadget->dev,
    268			"obex ttyGS%d function activate --> %d\n",
    269			obex->port_num, status);
    270}
    271
    272static void obex_disconnect(struct gserial *g)
    273{
    274	struct f_obex		*obex = port_to_obex(g);
    275	struct usb_composite_dev *cdev = g->func.config->cdev;
    276	int			status;
    277
    278	status = usb_function_deactivate(&g->func);
    279	if (status)
    280		dev_dbg(&cdev->gadget->dev,
    281			"obex ttyGS%d function deactivate --> %d\n",
    282			obex->port_num, status);
    283}
    284
    285/*-------------------------------------------------------------------------*/
    286
    287/* Some controllers can't support CDC OBEX ... */
    288static inline bool can_support_obex(struct usb_configuration *c)
    289{
    290	/* Since the first interface is a NOP, we can ignore the
    291	 * issue of multi-interface support on most controllers.
    292	 *
    293	 * Altsettings are mandatory, however...
    294	 */
    295	if (!gadget_is_altset_supported(c->cdev->gadget))
    296		return false;
    297
    298	/* everything else is *probably* fine ... */
    299	return true;
    300}
    301
    302static int obex_bind(struct usb_configuration *c, struct usb_function *f)
    303{
    304	struct usb_composite_dev *cdev = c->cdev;
    305	struct f_obex		*obex = func_to_obex(f);
    306	struct usb_string	*us;
    307	int			status;
    308	struct usb_ep		*ep;
    309
    310	if (!can_support_obex(c))
    311		return -EINVAL;
    312
    313	us = usb_gstrings_attach(cdev, obex_strings,
    314				 ARRAY_SIZE(obex_string_defs));
    315	if (IS_ERR(us))
    316		return PTR_ERR(us);
    317	obex_control_intf.iInterface = us[OBEX_CTRL_IDX].id;
    318	obex_data_nop_intf.iInterface = us[OBEX_DATA_IDX].id;
    319	obex_data_intf.iInterface = us[OBEX_DATA_IDX].id;
    320
    321	/* allocate instance-specific interface IDs, and patch descriptors */
    322
    323	status = usb_interface_id(c, f);
    324	if (status < 0)
    325		goto fail;
    326	obex->ctrl_id = status;
    327
    328	obex_control_intf.bInterfaceNumber = status;
    329	obex_cdc_union_desc.bMasterInterface0 = status;
    330
    331	status = usb_interface_id(c, f);
    332	if (status < 0)
    333		goto fail;
    334	obex->data_id = status;
    335
    336	obex_data_nop_intf.bInterfaceNumber = status;
    337	obex_data_intf.bInterfaceNumber = status;
    338	obex_cdc_union_desc.bSlaveInterface0 = status;
    339
    340	/* allocate instance-specific endpoints */
    341
    342	status = -ENODEV;
    343	ep = usb_ep_autoconfig(cdev->gadget, &obex_fs_ep_in_desc);
    344	if (!ep)
    345		goto fail;
    346	obex->port.in = ep;
    347
    348	ep = usb_ep_autoconfig(cdev->gadget, &obex_fs_ep_out_desc);
    349	if (!ep)
    350		goto fail;
    351	obex->port.out = ep;
    352
    353	/* support all relevant hardware speeds... we expect that when
    354	 * hardware is dual speed, all bulk-capable endpoints work at
    355	 * both speeds
    356	 */
    357
    358	obex_hs_ep_in_desc.bEndpointAddress =
    359		obex_fs_ep_in_desc.bEndpointAddress;
    360	obex_hs_ep_out_desc.bEndpointAddress =
    361		obex_fs_ep_out_desc.bEndpointAddress;
    362
    363	status = usb_assign_descriptors(f, fs_function, hs_function, NULL,
    364					NULL);
    365	if (status)
    366		goto fail;
    367
    368	dev_dbg(&cdev->gadget->dev, "obex ttyGS%d: %s speed IN/%s OUT/%s\n",
    369		obex->port_num,
    370		gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
    371		obex->port.in->name, obex->port.out->name);
    372
    373	return 0;
    374
    375fail:
    376	ERROR(cdev, "%s/%p: can't bind, err %d\n", f->name, f, status);
    377
    378	return status;
    379}
    380
    381static inline struct f_serial_opts *to_f_serial_opts(struct config_item *item)
    382{
    383	return container_of(to_config_group(item), struct f_serial_opts,
    384			    func_inst.group);
    385}
    386
    387static void obex_attr_release(struct config_item *item)
    388{
    389	struct f_serial_opts *opts = to_f_serial_opts(item);
    390
    391	usb_put_function_instance(&opts->func_inst);
    392}
    393
    394static struct configfs_item_operations obex_item_ops = {
    395	.release	= obex_attr_release,
    396};
    397
    398static ssize_t f_obex_port_num_show(struct config_item *item, char *page)
    399{
    400	return sprintf(page, "%u\n", to_f_serial_opts(item)->port_num);
    401}
    402
    403CONFIGFS_ATTR_RO(f_obex_, port_num);
    404
    405static struct configfs_attribute *acm_attrs[] = {
    406	&f_obex_attr_port_num,
    407	NULL,
    408};
    409
    410static const struct config_item_type obex_func_type = {
    411	.ct_item_ops	= &obex_item_ops,
    412	.ct_attrs	= acm_attrs,
    413	.ct_owner	= THIS_MODULE,
    414};
    415
    416static void obex_free_inst(struct usb_function_instance *f)
    417{
    418	struct f_serial_opts *opts;
    419
    420	opts = container_of(f, struct f_serial_opts, func_inst);
    421	gserial_free_line(opts->port_num);
    422	kfree(opts);
    423}
    424
    425static struct usb_function_instance *obex_alloc_inst(void)
    426{
    427	struct f_serial_opts *opts;
    428	int ret;
    429
    430	opts = kzalloc(sizeof(*opts), GFP_KERNEL);
    431	if (!opts)
    432		return ERR_PTR(-ENOMEM);
    433
    434	opts->func_inst.free_func_inst = obex_free_inst;
    435	ret = gserial_alloc_line_no_console(&opts->port_num);
    436	if (ret) {
    437		kfree(opts);
    438		return ERR_PTR(ret);
    439	}
    440	config_group_init_type_name(&opts->func_inst.group, "",
    441				    &obex_func_type);
    442
    443	return &opts->func_inst;
    444}
    445
    446static void obex_free(struct usb_function *f)
    447{
    448	struct f_obex *obex;
    449
    450	obex = func_to_obex(f);
    451	kfree(obex);
    452}
    453
    454static void obex_unbind(struct usb_configuration *c, struct usb_function *f)
    455{
    456	usb_free_all_descriptors(f);
    457}
    458
    459static struct usb_function *obex_alloc(struct usb_function_instance *fi)
    460{
    461	struct f_obex	*obex;
    462	struct f_serial_opts *opts;
    463
    464	/* allocate and initialize one new instance */
    465	obex = kzalloc(sizeof(*obex), GFP_KERNEL);
    466	if (!obex)
    467		return ERR_PTR(-ENOMEM);
    468
    469	opts = container_of(fi, struct f_serial_opts, func_inst);
    470
    471	obex->port_num = opts->port_num;
    472
    473	obex->port.connect = obex_connect;
    474	obex->port.disconnect = obex_disconnect;
    475
    476	obex->port.func.name = "obex";
    477	/* descriptors are per-instance copies */
    478	obex->port.func.bind = obex_bind;
    479	obex->port.func.unbind = obex_unbind;
    480	obex->port.func.set_alt = obex_set_alt;
    481	obex->port.func.get_alt = obex_get_alt;
    482	obex->port.func.disable = obex_disable;
    483	obex->port.func.free_func = obex_free;
    484	obex->port.func.bind_deactivated = true;
    485
    486	return &obex->port.func;
    487}
    488
    489DECLARE_USB_FUNCTION_INIT(obex, obex_alloc_inst, obex_alloc);
    490MODULE_AUTHOR("Felipe Balbi");
    491MODULE_LICENSE("GPL");