1
0
Fork 0
mirror of https://github.com/linux-usb-gadgets/libusbgx.git synced 2025-07-13 14:49:43 +03:00
libusbgx/src/function/ether.c
Ming Liu 4f3f2ad08e libusbgx: Add interface name for NCM Feature Descriptors
In commit: abf422bffc
[
Author: Stefan Agner <stefan.agner@toradex.com>
Date:   Tue Jan 24 14:22:25 2017 -0800

    libusbgx: Add interface name for Feature Descriptors

    This adds interface name required for "Feature Descriptors". If
    specified, we can assume that a Feature Descriptor with the
    interface name of the specified string is understood by the
    kernel (e.g. interface.rndis).
]

it only added Feature Descriptors for RNDIS, NCM also needs that, or
else it could not be recognized by Windows systems.

Add Feature Descriptors interface name for NCM.

Signed-off-by: Ming Liu <liu.ming50@gmail.com>
2022-12-11 16:06:08 +01:00

309 lines
7 KiB
C

/*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#include "usbg/usbg.h"
#include "usbg/usbg_internal.h"
#include "usbg/function/net.h"
#include <malloc.h>
#ifdef HAS_GADGET_SCHEMES
#include <libconfig.h>
#endif
struct usbg_f_net {
struct usbg_function func;
};
#define NET_DEC_ATTR(_name) \
{ \
.name = #_name, \
.ro = false, \
.offset = offsetof(struct usbg_f_net_attrs, _name), \
.get = usbg_get_dec, \
.set = usbg_set_dec, \
.import = usbg_get_config_node_int, \
.export = usbg_set_config_node_int, \
}
#define NET_RO_STRING_ATTR(_name) \
{ \
.name = #_name, \
.ro = true, \
.offset = offsetof(struct usbg_f_net_attrs, _name), \
.get = usbg_get_string, \
.export = usbg_set_config_node_string, \
}
#define NET_ETHER_ADDR_ATTR(_name) \
{ \
.name = #_name, \
.ro = false, \
.offset = offsetof(struct usbg_f_net_attrs, _name), \
.get = usbg_get_ether_addr, \
.set = usbg_set_ether_addr, \
.import = usbg_get_config_node_ether_addr, \
.export = usbg_set_config_node_ether_addr, \
}
static struct {
const char *name;
bool ro;
size_t offset;
usbg_attr_get_func get;
usbg_attr_set_func set;
usbg_import_node_func import;
usbg_export_node_func export;
} net_attr[USBG_F_NET_ATTR_MAX] = {
[USBG_F_NET_DEV_ADDR] = NET_ETHER_ADDR_ATTR(dev_addr),
[USBG_F_NET_HOST_ADDR] = NET_ETHER_ADDR_ATTR(host_addr),
[USBG_F_NET_IFNAME] = NET_RO_STRING_ATTR(ifname),
[USBG_F_NET_QMULT] = NET_DEC_ATTR(qmult),
[USBG_F_NET_CLASS] = NET_DEC_ATTR(class_),
[USBG_F_NET_SUBCLASS] = NET_DEC_ATTR(subclass),
[USBG_F_NET_PROTOCOL] = NET_DEC_ATTR(protocol)
};
#undef NET_DEC_ATTR
#undef NET_STRING_ATTR
GENERIC_ALLOC_INST(ether, struct usbg_f_net, func);
GENERIC_FREE_INST(ether, struct usbg_f_net, func);
static int ether_set_attrs(struct usbg_function *f, void *f_attrs)
{
const struct usbg_f_net_attrs *attrs = f_attrs;
/* ifname is read only so we accept only empty string for this param */
if (attrs->ifname && attrs->ifname[0])
return USBG_ERROR_INVALID_PARAM;
return usbg_f_net_set_attrs(usbg_to_net_function(f), attrs);
}
static int ether_get_attrs(struct usbg_function *f, void *f_attrs)
{
struct usbg_f_net_attrs *attrs = f_attrs;
return usbg_f_net_get_attrs(usbg_to_net_function(f), attrs);
}
static void ether_cleanup_attrs(struct usbg_function *f, void *f_attrs)
{
usbg_f_net_cleanup_attrs(f_attrs);
}
#ifdef HAS_GADGET_SCHEMES
static int ether_libconfig_import(struct usbg_function *f,
config_setting_t *root)
{
struct usbg_f_net *nf = usbg_to_net_function(f);
union usbg_f_net_attr_val val;
int i;
int ret = 0;
for (i = USBG_F_NET_ATTR_MIN; i < USBG_F_NET_ATTR_MAX; ++i) {
if (net_attr[i].ro)
continue;
ret = net_attr[i].import(root, net_attr[i].name, &val);
/* node not found */
if (ret == 0)
continue;
/* error */
if (ret < 0)
break;
ret = usbg_f_net_set_attr_val(nf, i, val);
if (ret)
break;
}
return ret;
}
static int ether_libconfig_export(struct usbg_function *f,
config_setting_t *root)
{
struct usbg_f_net *nf = usbg_to_net_function(f);
union usbg_f_net_attr_val val;
int i;
int ret = 0;
for (i = USBG_F_NET_ATTR_MIN; i < USBG_F_NET_ATTR_MAX; ++i) {
if (net_attr[i].ro)
continue;
ret = usbg_f_net_get_attr_val(nf, i, &val);
if (ret)
break;
ret = net_attr[i].export(root, net_attr[i].name, &val);
if (ret)
break;
}
return ret;
}
#define ETHER_LIBCONFIG_DEP_OPS \
.import = ether_libconfig_import, \
.export = ether_libconfig_export
#else
#define ETHER_LIBCONFIG_DEP_OPS
#endif /* HAS_GADGET_SCHEMES */
#define ETHER_FUNCTION_OPTS \
.alloc_inst = ether_alloc_inst, \
.free_inst = ether_free_inst, \
.set_attrs = ether_set_attrs, \
.get_attrs = ether_get_attrs, \
.cleanup_attrs = ether_cleanup_attrs, \
ETHER_LIBCONFIG_DEP_OPS
struct usbg_function_type usbg_f_type_ecm = {
.name = "ecm",
ETHER_FUNCTION_OPTS
};
struct usbg_function_type usbg_f_type_subset = {
.name = "geth",
ETHER_FUNCTION_OPTS
};
static char *ncm_os_desc_ifnames[] = {
"ncm",
NULL
};
struct usbg_function_type usbg_f_type_ncm = {
.name = "ncm",
.os_desc_iname = ncm_os_desc_ifnames,
ETHER_FUNCTION_OPTS
};
struct usbg_function_type usbg_f_type_eem = {
.name = "eem",
ETHER_FUNCTION_OPTS
};
static char *rndis_os_desc_ifnames[] = {
"rndis",
NULL
};
struct usbg_function_type usbg_f_type_rndis = {
.name = "rndis",
.os_desc_iname = rndis_os_desc_ifnames,
ETHER_FUNCTION_OPTS
};
/* API implementation */
usbg_f_net *usbg_to_net_function(usbg_function *f)
{
return f->ops == &usbg_f_type_ecm
|| f->ops == &usbg_f_type_subset
|| f->ops == &usbg_f_type_ncm
|| f->ops == &usbg_f_type_eem
|| f->ops == &usbg_f_type_rndis ?
container_of(f, struct usbg_f_net, func) : NULL;
}
usbg_function *usbg_from_net_function(usbg_f_net *nf)
{
return &nf->func;
}
int usbg_f_net_get_attrs(usbg_f_net *nf,
struct usbg_f_net_attrs *attrs)
{
int i;
int ret = 0;
for (i = USBG_F_NET_ATTR_MIN; i < USBG_F_NET_ATTR_MAX; ++i) {
ret = usbg_f_net_get_attr_val(nf, i,
(union usbg_f_net_attr_val *)
((char *)attrs
+ net_attr[i].offset));
if (ret)
break;
}
return ret;
}
int usbg_f_net_set_attrs(usbg_f_net *nf,
const struct usbg_f_net_attrs *attrs)
{
int i;
int ret = 0;
for (i = USBG_F_NET_ATTR_MIN; i < USBG_F_NET_ATTR_MAX; ++i) {
if (net_attr[i].ro)
continue;
ret = usbg_f_net_set_attr_val(nf, i,
*(union usbg_f_net_attr_val *)
((char *)attrs
+ net_attr[i].offset));
if (ret)
break;
}
return ret;
}
int usbg_f_net_get_attr_val(usbg_f_net *nf, enum usbg_f_net_attr attr,
union usbg_f_net_attr_val *val)
{
return net_attr[attr].get(nf->func.path, nf->func.name,
net_attr[attr].name, val);
}
int usbg_f_net_set_attr_val(usbg_f_net *nf, enum usbg_f_net_attr attr,
union usbg_f_net_attr_val val)
{
return net_attr[attr].ro ?
USBG_ERROR_INVALID_PARAM :
net_attr[attr].set(nf->func.path, nf->func.name,
net_attr[attr].name, &val);
}
int usbg_f_net_get_ifname_s(usbg_f_net *nf, char *buf, int len)
{
struct usbg_function *f;
int ret;
if (!nf || !buf)
return USBG_ERROR_INVALID_PARAM;
f = &nf->func;
/*
* TODO:
* Rework usbg_common to make this function consistent with doc.
* This below is only an ugly hack
*/
ret = usbg_read_string_limited(f->path, f->name, "ifname", buf, len);
if (ret)
goto out;
ret = strlen(buf);
out:
return ret;
}