mirror of
https://github.com/linux-usb-gadgets/libusbgx.git
synced 2025-07-20 18:25:05 +03:00
libusbgx: net: Add implementation of function specific API
Implement all function-specific functions from header file Signed-off-by: Krzysztof Opasiak <k.opasiak@samsung.com>
This commit is contained in:
parent
b5288f38de
commit
5fff0aefae
1 changed files with 192 additions and 138 deletions
|
@ -12,90 +12,99 @@
|
||||||
|
|
||||||
#include "usbg/usbg.h"
|
#include "usbg/usbg.h"
|
||||||
#include "usbg/usbg_internal.h"
|
#include "usbg/usbg_internal.h"
|
||||||
|
#include "usbg/function/net.h"
|
||||||
|
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#ifdef HAS_LIBCONFIG
|
#ifdef HAS_LIBCONFIG
|
||||||
#include <libconfig.h>
|
#include <libconfig.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct usbg_f_ether {
|
struct usbg_f_net {
|
||||||
struct usbg_function func;
|
struct usbg_function func;
|
||||||
};
|
};
|
||||||
|
|
||||||
GENERIC_ALLOC_INST(ether, struct usbg_f_ether, 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, \
|
||||||
|
}
|
||||||
|
|
||||||
GENERIC_FREE_INST(ether, struct usbg_f_ether, func);
|
#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),
|
||||||
|
};
|
||||||
|
|
||||||
|
#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,
|
static int ether_set_attrs(struct usbg_function *f,
|
||||||
const usbg_function_attrs *f_attrs)
|
const usbg_function_attrs *f_attrs)
|
||||||
{
|
{
|
||||||
int ret = USBG_SUCCESS;
|
int ret = USBG_SUCCESS;
|
||||||
char addr_buf[USBG_MAX_STR_LENGTH];
|
|
||||||
const usbg_f_net_attrs *attrs = &f_attrs->attrs.net;
|
const usbg_f_net_attrs *attrs = &f_attrs->attrs.net;
|
||||||
char *addr;
|
|
||||||
|
if (f_attrs->header.attrs_type &&
|
||||||
|
f_attrs->header.attrs_type != USBG_F_ATTRS_NET)
|
||||||
|
return USBG_ERROR_INVALID_PARAM;
|
||||||
|
|
||||||
/* ifname is read only so we accept only empty string for this param */
|
/* ifname is read only so we accept only empty string for this param */
|
||||||
if (attrs->ifname && attrs->ifname[0]) {
|
if (attrs->ifname && attrs->ifname[0])
|
||||||
ret = USBG_ERROR_INVALID_PARAM;
|
return USBG_ERROR_INVALID_PARAM;
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
addr = usbg_ether_ntoa_r(&attrs->dev_addr, addr_buf);
|
return usbg_f_net_set_attrs(usbg_to_net_function(f),
|
||||||
ret = usbg_write_string(f->path, f->name, "dev_addr", addr);
|
(struct usbg_f_net_attrs *)attrs);
|
||||||
if (ret != USBG_SUCCESS)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
addr = usbg_ether_ntoa_r(&attrs->host_addr, addr_buf);
|
|
||||||
ret = usbg_write_string(f->path, f->name, "host_addr", addr);
|
|
||||||
if (ret != USBG_SUCCESS)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
ret = usbg_write_dec(f->path, f->name, "qmult", attrs->qmult);
|
|
||||||
|
|
||||||
out:
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ether_get_attrs(struct usbg_function *f,
|
static int ether_get_attrs(struct usbg_function *f,
|
||||||
usbg_function_attrs *f_attrs)
|
usbg_function_attrs *f_attrs)
|
||||||
{
|
{
|
||||||
struct ether_addr *addr;
|
int ret;
|
||||||
struct ether_addr addr_buf;
|
|
||||||
char str_addr[USBG_MAX_STR_LENGTH];
|
|
||||||
usbg_f_net_attrs *attrs = &f_attrs->attrs.net;
|
usbg_f_net_attrs *attrs = &f_attrs->attrs.net;
|
||||||
int ret = USBG_ERROR_INVALID_PARAM;
|
|
||||||
|
|
||||||
ret = usbg_read_string(f->path, f->name, "dev_addr", str_addr);
|
ret = usbg_f_net_get_attrs(usbg_to_net_function(f),
|
||||||
|
(struct usbg_f_net_attrs *)attrs);
|
||||||
if (ret != USBG_SUCCESS)
|
if (ret != USBG_SUCCESS)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
addr = ether_aton_r(str_addr, &addr_buf);
|
|
||||||
if (addr) {
|
|
||||||
attrs->dev_addr = *addr;
|
|
||||||
} else {
|
|
||||||
ret = USBG_ERROR_IO;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = usbg_read_string(f->path, f->name, "host_addr", str_addr);
|
|
||||||
if (ret != USBG_SUCCESS)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
addr = ether_aton_r(str_addr, &addr_buf);
|
|
||||||
if (addr) {
|
|
||||||
attrs->host_addr = *addr;
|
|
||||||
} else {
|
|
||||||
ret = USBG_ERROR_IO;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = usbg_read_dec(f->path, f->name, "qmult", &(attrs->qmult));
|
|
||||||
if (ret != USBG_SUCCESS)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
ret = usbg_read_string_alloc(f->path, f->name, "ifname",
|
|
||||||
&(attrs->ifname));
|
|
||||||
|
|
||||||
f_attrs->header.attrs_type = USBG_F_ATTRS_NET;
|
f_attrs->header.attrs_type = USBG_F_ATTRS_NET;
|
||||||
out:
|
out:
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -113,103 +122,52 @@ static void ether_cleanup_attrs(struct usbg_function *f,
|
||||||
static int ether_libconfig_import(struct usbg_function *f,
|
static int ether_libconfig_import(struct usbg_function *f,
|
||||||
config_setting_t *root)
|
config_setting_t *root)
|
||||||
{
|
{
|
||||||
config_setting_t *node;
|
struct usbg_f_net *nf = usbg_to_net_function(f);
|
||||||
int ret = USBG_SUCCESS;
|
union usbg_f_net_attr_val val;
|
||||||
int qmult;
|
int i;
|
||||||
struct ether_addr *addr;
|
int ret = 0;
|
||||||
struct ether_addr addr_buf;
|
|
||||||
const char *str;
|
|
||||||
|
|
||||||
#define GET_OPTIONAL_ADDR(NAME) \
|
for (i = USBG_F_NET_ATTR_MIN; i < USBG_F_NET_ATTR_MAX; ++i) {
|
||||||
do { \
|
if (net_attr[i].ro)
|
||||||
node = config_setting_get_member(root, #NAME); \
|
continue;
|
||||||
if (node) { \
|
|
||||||
str = config_setting_get_string(node); \
|
|
||||||
if (!str) { \
|
|
||||||
ret = USBG_ERROR_INVALID_TYPE; \
|
|
||||||
goto out; \
|
|
||||||
} \
|
|
||||||
\
|
|
||||||
addr = ether_aton_r(str, &addr_buf); \
|
|
||||||
if (!addr) { \
|
|
||||||
ret = USBG_ERROR_INVALID_VALUE; \
|
|
||||||
goto out; \
|
|
||||||
} \
|
|
||||||
ret = usbg_set_net_##NAME(f, addr); \
|
|
||||||
if (ret != USBG_SUCCESS) \
|
|
||||||
goto out; \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
GET_OPTIONAL_ADDR(host_addr);
|
ret = net_attr[i].import(root, net_attr[i].name, &val);
|
||||||
GET_OPTIONAL_ADDR(dev_addr);
|
/* node not found */
|
||||||
|
if (ret == 0)
|
||||||
|
continue;
|
||||||
|
/* error */
|
||||||
|
if (ret < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
#undef GET_OPTIONAL_ADDR
|
ret = usbg_f_net_set_attr_val(nf, i, val);
|
||||||
|
if (ret)
|
||||||
node = config_setting_get_member(root, "qmult");
|
break;
|
||||||
if (node) {
|
|
||||||
if (!usbg_config_is_int(node)) {
|
|
||||||
ret = USBG_ERROR_INVALID_TYPE;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
qmult = config_setting_get_int(node);
|
|
||||||
ret = usbg_set_net_qmult(f, qmult);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ether_libconfig_export(struct usbg_function *f,
|
static int ether_libconfig_export(struct usbg_function *f,
|
||||||
config_setting_t *root)
|
config_setting_t *root)
|
||||||
{
|
{
|
||||||
config_setting_t *node;
|
struct usbg_f_net *nf = usbg_to_net_function(f);
|
||||||
char *addr;
|
union usbg_f_net_attr_val val;
|
||||||
char addr_buf[USBG_MAX_STR_LENGTH];
|
int i;
|
||||||
int cfg_ret, usbg_ret;
|
int ret = 0;
|
||||||
usbg_function_attrs f_attrs;
|
|
||||||
usbg_f_net_attrs *attrs = &f_attrs.attrs.net;
|
|
||||||
int ret = USBG_ERROR_NO_MEM;
|
|
||||||
|
|
||||||
usbg_ret = ether_get_attrs(f, &f_attrs);
|
for (i = USBG_F_NET_ATTR_MIN; i < USBG_F_NET_ATTR_MAX; ++i) {
|
||||||
if (usbg_ret != USBG_SUCCESS) {
|
if (net_attr[i].ro)
|
||||||
ret = usbg_ret;
|
continue;
|
||||||
goto out;
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
node = config_setting_add(root, "dev_addr", CONFIG_TYPE_STRING);
|
|
||||||
if (!node)
|
|
||||||
goto cleanup;
|
|
||||||
|
|
||||||
addr = usbg_ether_ntoa_r(&attrs->dev_addr, addr_buf);
|
|
||||||
cfg_ret = config_setting_set_string(node, addr);
|
|
||||||
if (cfg_ret != CONFIG_TRUE) {
|
|
||||||
ret = USBG_ERROR_OTHER_ERROR;
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
node = config_setting_add(root, "host_addr", CONFIG_TYPE_STRING);
|
|
||||||
if (!node)
|
|
||||||
goto cleanup;
|
|
||||||
|
|
||||||
addr = usbg_ether_ntoa_r(&attrs->host_addr, addr_buf);
|
|
||||||
cfg_ret = config_setting_set_string(node, addr);
|
|
||||||
if (cfg_ret != CONFIG_TRUE) {
|
|
||||||
ret = USBG_ERROR_OTHER_ERROR;
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
node = config_setting_add(root, "qmult", CONFIG_TYPE_INT);
|
|
||||||
if (!node)
|
|
||||||
goto cleanup;
|
|
||||||
|
|
||||||
cfg_ret = config_setting_set_int(node, attrs->qmult);
|
|
||||||
ret = cfg_ret == CONFIG_TRUE ? 0 : USBG_ERROR_OTHER_ERROR;
|
|
||||||
|
|
||||||
/* ifname is read only so we don't export it */
|
|
||||||
cleanup:
|
|
||||||
ether_cleanup_attrs(f, &f_attrs);
|
|
||||||
out:
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -256,3 +214,99 @@ struct usbg_function_type usbg_f_type_rndis = {
|
||||||
ETHER_FUNCTION_OPTS
|
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;
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue