mirror of
https://github.com/systemd/systemd
synced 2025-09-28 00:04:47 +02:00
Compare commits
21 Commits
df49792e01
...
537ae584c8
Author | SHA1 | Date | |
---|---|---|---|
![]() |
537ae584c8 | ||
![]() |
c33e405f20 | ||
![]() |
4bb322f58c | ||
![]() |
09db85080a | ||
![]() |
048be097d2 | ||
![]() |
7c5869530c | ||
![]() |
b3d6eb0165 | ||
![]() |
089cd8b34b | ||
![]() |
6fda02e150 | ||
![]() |
019951ec97 | ||
![]() |
361eb4125d | ||
![]() |
8b6ea477a7 | ||
![]() |
5a99444e4f | ||
![]() |
b79951fa32 | ||
![]() |
e4336c0a5d | ||
![]() |
1e270127de | ||
![]() |
ea07086285 | ||
![]() |
0d9b8913e2 | ||
![]() |
c97cad60d1 | ||
![]() |
810f29140a | ||
![]() |
ba423af6b5 |
@ -307,6 +307,14 @@ sensor:modalias:acpi:INVN6500*:dmi:*svnDell*:pnVenue10Pro5055:*
|
||||
sensor:modalias:acpi:SMO8500*:dmi:*svn*DEXP*:*pn*DEXPOEM:*
|
||||
ACCEL_MOUNT_MATRIX=0, -1, 0; -1, 0, 0; 0, 0, 1
|
||||
|
||||
#########################################
|
||||
# Digibras
|
||||
#########################################
|
||||
|
||||
# Digibras F10-30
|
||||
sensor:modalias:acpi:SMO8500*:dmi:*:svnDigibras:pnF10-30:*
|
||||
ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, 1, 0; 0, 0, 1
|
||||
|
||||
#########################################
|
||||
# DIGMA
|
||||
#########################################
|
||||
|
@ -743,6 +743,22 @@
|
||||
PAUSE configuration. When unset, the kernel's default will be used.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><varname>GenericSegmentOffloadMaxBytes=</varname></term>
|
||||
<listitem>
|
||||
<para>Specifies the maximum size of a Generic Segment Offload (GSO) packet the
|
||||
device should accept. The usual suffixes K, M, G, are supported and are
|
||||
understood to the base of 1024. An unsigned integer in the range 1—65536.
|
||||
Defaults to unset.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><varname>GenericSegmentOffloadMaxSegments=</varname></term>
|
||||
<listitem>
|
||||
<para>Specifies the maximum number of a Generic Segment Offload (GSO) segments the device should accept.
|
||||
An unsigned integer in the range 1—65535. Defaults to unset.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
@ -491,6 +491,28 @@
|
||||
like physical interfaces. When unset, the kernel's default will be used.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><varname>EgressQOSMaps=</varname></term>
|
||||
<listitem>
|
||||
<para>Defines a mapping of Linux internal packet priority (<constant>SO_PRIORITY</constant>) to VLAN header
|
||||
PCP field for outgoing frames. Takes a whitespace-separated list of unsigned integer pairs in the format
|
||||
<literal>from</literal>-<literal>to</literal>, e.g., <literal>21-7 45-5</literal> ranges 1–4294967294.
|
||||
Note that <literal>from</literal> must be greater than or equal to <literal>to</literal>. When unset,
|
||||
the kernel's default will be used.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><varname>IngressQOSMaps=</varname></term>
|
||||
<listitem>
|
||||
<para>Defines a mapping of Linux internal packet priority (<constant>SO_PRIORITY</constant>) to VLAN header
|
||||
PCP field for incoming frames. Takes a whitespace-separated list of unsigned integer pairs in the format
|
||||
<literal>from</literal>-<literal>to</literal>, e.g., <literal>21-7 45-5</literal> ranges 1–4294967294.
|
||||
Note that <literal>from</literal> must be greater than or equal to <literal>to</literal>. When unset,
|
||||
the kernel's default will be used.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
|
@ -296,9 +296,8 @@ static void tar_pull_job_on_finished(PullJob *j) {
|
||||
goto finish;
|
||||
}
|
||||
|
||||
/* This is invoked if either the download completed
|
||||
* successfully, or the download was skipped because we
|
||||
* already have the etag. */
|
||||
/* This is invoked if either the download completed successfully, or the download was skipped because
|
||||
* we already have the etag. */
|
||||
|
||||
if (!tar_pull_is_done(i))
|
||||
return;
|
||||
@ -340,6 +339,10 @@ static void tar_pull_job_on_finished(PullJob *j) {
|
||||
|
||||
tar_pull_report_progress(i, TAR_FINALIZING);
|
||||
|
||||
r = import_mangle_os_tree(i->temp_path);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
r = import_make_read_only(i->temp_path);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
const char *namespace;
|
||||
LogTarget log_target;
|
||||
Server server;
|
||||
int r;
|
||||
|
||||
@ -25,8 +26,13 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
namespace = argc > 1 ? empty_to_null(argv[1]) : NULL;
|
||||
|
||||
log_set_prohibit_ipc(true);
|
||||
log_set_target(LOG_TARGET_AUTO);
|
||||
/* So here's the deal: journald can't be considered as regular daemon when it comes to
|
||||
* logging hence LOG_TARGET_AUTO won't do the right thing for it. Hence explicitly log to
|
||||
* the console if we're started from a console or to kmsg otherwise. */
|
||||
log_target = isatty(STDERR_FILENO) > 0 ? LOG_TARGET_CONSOLE : LOG_TARGET_KMSG;
|
||||
|
||||
log_set_prohibit_ipc(true); /* better safe than sorry */
|
||||
log_set_target(log_target);
|
||||
log_set_facility(LOG_SYSLOG);
|
||||
log_parse_environment();
|
||||
log_open();
|
||||
|
@ -38,11 +38,14 @@ static int option_append(uint8_t options[], size_t size, size_t *offset,
|
||||
size_t total = 0;
|
||||
char **s;
|
||||
|
||||
if (strv_isempty((char **) optval))
|
||||
return -EINVAL;
|
||||
|
||||
STRV_FOREACH(s, (char **) optval) {
|
||||
size_t len = strlen(*s);
|
||||
|
||||
if (len > 255)
|
||||
return -ENAMETOOLONG;
|
||||
if (len > 255 || len == 0)
|
||||
return -EINVAL;
|
||||
|
||||
total += 1 + len;
|
||||
}
|
||||
@ -58,7 +61,6 @@ static int option_append(uint8_t options[], size_t size, size_t *offset,
|
||||
size_t len = strlen(*s);
|
||||
|
||||
options[*offset] = len;
|
||||
|
||||
memcpy(&options[*offset + 1], *s, len);
|
||||
*offset += 1 + len;
|
||||
}
|
||||
|
@ -99,8 +99,8 @@ int dhcp6_option_append(uint8_t **buf, size_t *buflen, uint16_t code,
|
||||
int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, const DHCP6IA *ia);
|
||||
int dhcp6_option_append_pd(uint8_t *buf, size_t len, const DHCP6IA *pd, DHCP6Address *hint_pd_prefix);
|
||||
int dhcp6_option_append_fqdn(uint8_t **buf, size_t *buflen, const char *fqdn);
|
||||
int dhcp6_option_append_user_class(uint8_t **buf, size_t *buflen, char **user_class);
|
||||
int dhcp6_option_append_vendor_class(uint8_t **buf, size_t *buflen, char **user_class);
|
||||
int dhcp6_option_append_user_class(uint8_t **buf, size_t *buflen, char * const *user_class);
|
||||
int dhcp6_option_append_vendor_class(uint8_t **buf, size_t *buflen, char * const *user_class);
|
||||
int dhcp6_option_append_vendor_option(uint8_t **buf, size_t *buflen, OrderedHashmap *vendor_options);
|
||||
int dhcp6_option_parse(uint8_t **buf, size_t *buflen, uint16_t *optcode,
|
||||
size_t *optlen, uint8_t **optvalue);
|
||||
|
@ -200,19 +200,22 @@ int dhcp6_option_append_fqdn(uint8_t **buf, size_t *buflen, const char *fqdn) {
|
||||
return r;
|
||||
}
|
||||
|
||||
int dhcp6_option_append_user_class(uint8_t **buf, size_t *buflen, char **user_class) {
|
||||
int dhcp6_option_append_user_class(uint8_t **buf, size_t *buflen, char * const *user_class) {
|
||||
_cleanup_free_ uint8_t *p = NULL;
|
||||
size_t total = 0, offset = 0;
|
||||
char **s;
|
||||
char * const *s;
|
||||
|
||||
assert_return(buf && *buf && buflen && user_class, -EINVAL);
|
||||
assert(buf);
|
||||
assert(*buf);
|
||||
assert(buflen);
|
||||
assert(!strv_isempty(user_class));
|
||||
|
||||
STRV_FOREACH(s, user_class) {
|
||||
size_t len = strlen(*s);
|
||||
uint8_t *q;
|
||||
|
||||
if (len > 0xffff)
|
||||
return -ENAMETOOLONG;
|
||||
if (len > 0xffff || len == 0)
|
||||
return -EINVAL;
|
||||
q = realloc(p, total + len + 2);
|
||||
if (!q)
|
||||
return -ENOMEM;
|
||||
@ -229,16 +232,16 @@ int dhcp6_option_append_user_class(uint8_t **buf, size_t *buflen, char **user_cl
|
||||
return dhcp6_option_append(buf, buflen, SD_DHCP6_OPTION_USER_CLASS, total, p);
|
||||
}
|
||||
|
||||
int dhcp6_option_append_vendor_class(uint8_t **buf, size_t *buflen, char **vendor_class) {
|
||||
int dhcp6_option_append_vendor_class(uint8_t **buf, size_t *buflen, char * const *vendor_class) {
|
||||
_cleanup_free_ uint8_t *p = NULL;
|
||||
uint32_t enterprise_identifier;
|
||||
size_t total, offset;
|
||||
char **s;
|
||||
char * const *s;
|
||||
|
||||
assert(buf);
|
||||
assert(*buf);
|
||||
assert(buflen);
|
||||
assert(vendor_class);
|
||||
assert(!strv_isempty(vendor_class));
|
||||
|
||||
enterprise_identifier = htobe32(SYSTEMD_PEN);
|
||||
|
||||
@ -253,6 +256,9 @@ int dhcp6_option_append_vendor_class(uint8_t **buf, size_t *buflen, char **vendo
|
||||
size_t len = strlen(*s);
|
||||
uint8_t *q;
|
||||
|
||||
if (len > UINT16_MAX || len == 0)
|
||||
return -EINVAL;
|
||||
|
||||
q = realloc(p, total + len + 2);
|
||||
if (!q)
|
||||
return -ENOMEM;
|
||||
|
@ -274,7 +274,6 @@ int sd_dhcp_client_set_request_address(
|
||||
}
|
||||
|
||||
int sd_dhcp_client_set_ifindex(sd_dhcp_client *client, int ifindex) {
|
||||
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED), -EBUSY);
|
||||
assert_return(ifindex > 0, -EINVAL);
|
||||
@ -348,13 +347,14 @@ int sd_dhcp_client_get_client_id(
|
||||
assert_return(data, -EINVAL);
|
||||
assert_return(data_len, -EINVAL);
|
||||
|
||||
*type = 0;
|
||||
*data = NULL;
|
||||
*data_len = 0;
|
||||
if (client->client_id_len) {
|
||||
*type = client->client_id.type;
|
||||
*data = client->client_id.raw.data;
|
||||
*data_len = client->client_id_len - sizeof(client->client_id.type);
|
||||
} else {
|
||||
*type = 0;
|
||||
*data = NULL;
|
||||
*data_len = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -573,22 +573,26 @@ int sd_dhcp_client_set_mud_url(
|
||||
|
||||
int sd_dhcp_client_set_user_class(
|
||||
sd_dhcp_client *client,
|
||||
const char* const* user_class) {
|
||||
char * const *user_class) {
|
||||
|
||||
_cleanup_strv_free_ char **s = NULL;
|
||||
char **p;
|
||||
char * const *p;
|
||||
char **s = NULL;
|
||||
|
||||
STRV_FOREACH(p, (char **) user_class)
|
||||
if (strlen(*p) > 255)
|
||||
return -ENAMETOOLONG;
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(!strv_isempty(user_class), -EINVAL);
|
||||
|
||||
s = strv_copy((char **) user_class);
|
||||
STRV_FOREACH(p, user_class) {
|
||||
size_t n = strlen(*p);
|
||||
|
||||
if (n > 255 || n == 0)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
s = strv_copy(user_class);
|
||||
if (!s)
|
||||
return -ENOMEM;
|
||||
|
||||
client->user_class = TAKE_PTR(s);
|
||||
|
||||
return 0;
|
||||
return strv_free_and_replace(client->user_class, s);
|
||||
}
|
||||
|
||||
int sd_dhcp_client_set_client_port(
|
||||
|
@ -157,7 +157,6 @@ int sd_dhcp6_client_set_callback(
|
||||
}
|
||||
|
||||
int sd_dhcp6_client_set_ifindex(sd_dhcp6_client *client, int ifindex) {
|
||||
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(ifindex > 0, -EINVAL);
|
||||
assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
|
||||
@ -351,6 +350,7 @@ int sd_dhcp6_client_duid_as_string(
|
||||
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(client->duid_len > 0, -ENODATA);
|
||||
assert_return(duid, -EINVAL);
|
||||
|
||||
v = dhcp6_duid_type_to_string(be16toh(client->duid.type));
|
||||
if (v) {
|
||||
@ -454,7 +454,6 @@ int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, uint16_t option)
|
||||
}
|
||||
|
||||
int sd_dhcp6_client_set_request_mud_url(sd_dhcp6_client *client, const char *mudurl) {
|
||||
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY);
|
||||
assert_return(mudurl, -EINVAL);
|
||||
@ -464,47 +463,48 @@ int sd_dhcp6_client_set_request_mud_url(sd_dhcp6_client *client, const char *mud
|
||||
return free_and_strdup(&client->mudurl, mudurl);
|
||||
}
|
||||
|
||||
int sd_dhcp6_client_set_request_user_class(sd_dhcp6_client *client, char **user_class) {
|
||||
_cleanup_strv_free_ char **s = NULL;
|
||||
char **p;
|
||||
int sd_dhcp6_client_set_request_user_class(sd_dhcp6_client *client, char * const *user_class) {
|
||||
char * const *p;
|
||||
char **s;
|
||||
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY);
|
||||
assert_return(!strv_isempty(user_class), -EINVAL);
|
||||
|
||||
assert_return(user_class, -EINVAL);
|
||||
STRV_FOREACH(p, user_class) {
|
||||
size_t len = strlen(*p);
|
||||
|
||||
STRV_FOREACH(p, user_class)
|
||||
if (strlen(*p) > UINT16_MAX)
|
||||
return -ENAMETOOLONG;
|
||||
if (len > UINT16_MAX || len == 0)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
s = strv_copy(user_class);
|
||||
if (!s)
|
||||
return -ENOMEM;
|
||||
|
||||
client->user_class = TAKE_PTR(s);
|
||||
|
||||
return 0;
|
||||
return strv_free_and_replace(client->user_class, s);
|
||||
}
|
||||
|
||||
int sd_dhcp6_client_set_request_vendor_class(sd_dhcp6_client *client, char **vendor_class) {
|
||||
_cleanup_strv_free_ char **s = NULL;
|
||||
char **p;
|
||||
int sd_dhcp6_client_set_request_vendor_class(sd_dhcp6_client *client, char * const *vendor_class) {
|
||||
char * const *p;
|
||||
char **s;
|
||||
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY);
|
||||
assert_return(vendor_class, -EINVAL);
|
||||
assert_return(!strv_isempty(vendor_class), -EINVAL);
|
||||
|
||||
STRV_FOREACH(p, vendor_class)
|
||||
if (strlen(*p) > UINT8_MAX)
|
||||
return -ENAMETOOLONG;
|
||||
STRV_FOREACH(p, vendor_class) {
|
||||
size_t len = strlen(*p);
|
||||
|
||||
if (len > UINT16_MAX || len == 0)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
s = strv_copy(vendor_class);
|
||||
if (!s)
|
||||
return -ENOMEM;
|
||||
|
||||
client->vendor_class = TAKE_PTR(s);
|
||||
|
||||
return 0;
|
||||
return strv_free_and_replace(client->vendor_class, s);
|
||||
}
|
||||
|
||||
int sd_dhcp6_client_get_prefix_delegation(sd_dhcp6_client *client, int *delegation) {
|
||||
|
@ -152,13 +152,20 @@ static const NLType rtnl_link_info_data_bridge_types[] = {
|
||||
[IFLA_BR_MCAST_IGMP_VERSION] = { .type = NETLINK_TYPE_U8 },
|
||||
};
|
||||
|
||||
static const NLType rtnl_vlan_qos_map_types[] = {
|
||||
[IFLA_VLAN_QOS_MAPPING] = { .size = sizeof(struct ifla_vlan_qos_mapping) },
|
||||
};
|
||||
|
||||
static const NLTypeSystem rtnl_vlan_qos_map_type_system = {
|
||||
.count = ELEMENTSOF(rtnl_vlan_qos_map_types),
|
||||
.types = rtnl_vlan_qos_map_types,
|
||||
};
|
||||
|
||||
static const NLType rtnl_link_info_data_vlan_types[] = {
|
||||
[IFLA_VLAN_ID] = { .type = NETLINK_TYPE_U16 },
|
||||
/*
|
||||
[IFLA_VLAN_FLAGS] = { .len = sizeof(struct ifla_vlan_flags) },
|
||||
[IFLA_VLAN_EGRESS_QOS] = { .type = NETLINK_TYPE_NESTED },
|
||||
[IFLA_VLAN_INGRESS_QOS] = { .type = NETLINK_TYPE_NESTED },
|
||||
*/
|
||||
[IFLA_VLAN_FLAGS] = { .size = sizeof(struct ifla_vlan_flags) },
|
||||
[IFLA_VLAN_EGRESS_QOS] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_vlan_qos_map_type_system },
|
||||
[IFLA_VLAN_INGRESS_QOS] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_vlan_qos_map_type_system },
|
||||
[IFLA_VLAN_PROTOCOL] = { .type = NETLINK_TYPE_U16 },
|
||||
};
|
||||
|
||||
@ -642,6 +649,8 @@ static const NLType rtnl_link_types[] = {
|
||||
[IFLA_PROMISCUITY] = { .type = NETLINK_TYPE_U32 },
|
||||
[IFLA_NUM_TX_QUEUES] = { .type = NETLINK_TYPE_U32 },
|
||||
[IFLA_NUM_RX_QUEUES] = { .type = NETLINK_TYPE_U32 },
|
||||
[IFLA_GSO_MAX_SEGS] = { .type = NETLINK_TYPE_U32 },
|
||||
[IFLA_GSO_MAX_SIZE] = { .type = NETLINK_TYPE_U32 },
|
||||
[IFLA_CARRIER] = { .type = NETLINK_TYPE_U8 },
|
||||
/*
|
||||
[IFLA_PHYS_PORT_ID] = { .type = NETLINK_TYPE_BINARY, .len = MAX_PHYS_PORT_ID_LEN },
|
||||
|
@ -58,14 +58,15 @@ int rtnl_set_link_name(sd_netlink **rtnl, int ifindex, const char *name) {
|
||||
}
|
||||
|
||||
int rtnl_set_link_properties(sd_netlink **rtnl, int ifindex, const char *alias,
|
||||
const struct ether_addr *mac, uint32_t mtu) {
|
||||
const struct ether_addr *mac, uint32_t mtu,
|
||||
uint32_t gso_max_size, size_t gso_max_segments) {
|
||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL;
|
||||
int r;
|
||||
|
||||
assert(rtnl);
|
||||
assert(ifindex > 0);
|
||||
|
||||
if (!alias && !mac && mtu == 0)
|
||||
if (!alias && !mac && mtu == 0 && gso_max_size == 0 && gso_max_segments == 0)
|
||||
return 0;
|
||||
|
||||
if (!*rtnl) {
|
||||
@ -96,6 +97,18 @@ int rtnl_set_link_properties(sd_netlink **rtnl, int ifindex, const char *alias,
|
||||
return r;
|
||||
}
|
||||
|
||||
if (gso_max_size > 0) {
|
||||
r = sd_netlink_message_append_u32(message, IFLA_GSO_MAX_SIZE, gso_max_size);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (gso_max_segments > 0) {
|
||||
r = sd_netlink_message_append_u32(message, IFLA_GSO_MAX_SEGS, gso_max_segments);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = sd_netlink_call(*rtnl, message, 0, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
@ -70,7 +70,8 @@ static inline bool rtnl_message_type_is_mdb(uint16_t type) {
|
||||
}
|
||||
|
||||
int rtnl_set_link_name(sd_netlink **rtnl, int ifindex, const char *name);
|
||||
int rtnl_set_link_properties(sd_netlink **rtnl, int ifindex, const char *alias, const struct ether_addr *mac, uint32_t mtu);
|
||||
int rtnl_set_link_properties(sd_netlink **rtnl, int ifindex, const char *alias, const struct ether_addr *mac, uint32_t mtu,
|
||||
uint32_t gso_max_size, size_t gso_max_segments);
|
||||
int rtnl_get_link_alternative_names(sd_netlink **rtnl, int ifindex, char ***ret);
|
||||
int rtnl_set_link_alternative_names(sd_netlink **rtnl, int ifindex, char * const *alternative_names);
|
||||
int rtnl_set_link_alternative_names_by_ifname(sd_netlink **rtnl, const char *ifname, char * const *alternative_names);
|
||||
|
@ -53,6 +53,8 @@ VLAN.GVRP, config_parse_tristate,
|
||||
VLAN.MVRP, config_parse_tristate, 0, offsetof(VLan, mvrp)
|
||||
VLAN.LooseBinding, config_parse_tristate, 0, offsetof(VLan, loose_binding)
|
||||
VLAN.ReorderHeader, config_parse_tristate, 0, offsetof(VLan, reorder_hdr)
|
||||
VLAN.EgressQOSMaps, config_parse_vlan_qos_maps, 0, offsetof(VLan, egress_qos_maps)
|
||||
VLAN.IngressQOSMaps, config_parse_vlan_qos_maps, 0, offsetof(VLan, ingress_qos_maps)
|
||||
MACVLAN.Mode, config_parse_macvlan_mode, 0, offsetof(MacVlan, mode)
|
||||
MACVLAN.SourceMACAddress, config_parse_hwaddrs, 0, offsetof(MacVlan, match_source_mac)
|
||||
MACVTAP.Mode, config_parse_macvlan_mode, 0, offsetof(MacVlan, mode)
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <net/if.h>
|
||||
#include <linux/if_vlan.h>
|
||||
|
||||
#include "parse-util.h"
|
||||
#include "vlan-util.h"
|
||||
#include "vlan.h"
|
||||
|
||||
@ -54,9 +55,129 @@ static int netdev_vlan_fill_message_create(NetDev *netdev, Link *link, sd_netlin
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_VLAN_FLAGS attribute: %m");
|
||||
|
||||
if (!set_isempty(v->egress_qos_maps)) {
|
||||
struct ifla_vlan_qos_mapping *m;
|
||||
|
||||
r = sd_netlink_message_open_container(req, IFLA_VLAN_EGRESS_QOS);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not open container IFLA_VLAN_EGRESS_QOS: %m");
|
||||
|
||||
SET_FOREACH(m, v->egress_qos_maps) {
|
||||
r = sd_netlink_message_append_data(req, IFLA_VLAN_QOS_MAPPING, m, sizeof(struct ifla_vlan_qos_mapping));
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_VLAN_QOS_MAPPING attribute: %m");
|
||||
}
|
||||
|
||||
r = sd_netlink_message_close_container(req);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not close container IFLA_VLAN_EGRESS_QOS: %m");
|
||||
}
|
||||
|
||||
if (!set_isempty(v->ingress_qos_maps)) {
|
||||
struct ifla_vlan_qos_mapping *m;
|
||||
|
||||
r = sd_netlink_message_open_container(req, IFLA_VLAN_INGRESS_QOS);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not open container IFLA_VLAN_INGRESS_QOS: %m");
|
||||
|
||||
SET_FOREACH(m, v->ingress_qos_maps) {
|
||||
r = sd_netlink_message_append_data(req, IFLA_VLAN_QOS_MAPPING, m, sizeof(struct ifla_vlan_qos_mapping));
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_VLAN_QOS_MAPPING attribute: %m");
|
||||
}
|
||||
|
||||
r = sd_netlink_message_close_container(req);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not close container IFLA_VLAN_INGRESS_QOS: %m");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vlan_qos_maps_hash_func(const struct ifla_vlan_qos_mapping *x, struct siphash *state) {
|
||||
siphash24_compress(&x->from, sizeof(x->from), state);
|
||||
siphash24_compress(&x->to, sizeof(x->to), state);
|
||||
}
|
||||
|
||||
static int vlan_qos_maps_compare_func(const struct ifla_vlan_qos_mapping *a, const struct ifla_vlan_qos_mapping *b) {
|
||||
int r;
|
||||
|
||||
r = CMP(a->from, b->from);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
return CMP(a->to, b->to);
|
||||
}
|
||||
|
||||
DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
|
||||
vlan_qos_maps_hash_ops,
|
||||
struct ifla_vlan_qos_mapping,
|
||||
vlan_qos_maps_hash_func,
|
||||
vlan_qos_maps_compare_func,
|
||||
free);
|
||||
|
||||
int config_parse_vlan_qos_maps(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *section,
|
||||
unsigned section_line,
|
||||
const char *lvalue,
|
||||
int ltype,
|
||||
const char *rvalue,
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
Set **s = data;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
if (isempty(rvalue)) {
|
||||
*s = set_free(*s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (const char *p = rvalue;;) {
|
||||
_cleanup_free_ struct ifla_vlan_qos_mapping *m = NULL;
|
||||
_cleanup_free_ char *w = NULL;
|
||||
|
||||
r = extract_first_word(&p, &w, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNQUOTE);
|
||||
if (r == -ENOMEM)
|
||||
return log_oom();
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse %s, ignoring: %s", lvalue, rvalue);
|
||||
return 0;
|
||||
}
|
||||
if (r == 0)
|
||||
return 0;
|
||||
|
||||
m = new0(struct ifla_vlan_qos_mapping, 1);
|
||||
if (!m)
|
||||
return log_oom();
|
||||
|
||||
r = parse_range(w, &m->from, &m->to);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse %s, ignoring: %s", lvalue, w);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (m->to > m->from || m->to == 0 || m->from == 0) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid %s, ignoring: %s", lvalue, w);
|
||||
continue;
|
||||
}
|
||||
|
||||
r = set_ensure_consume(s, &vlan_qos_maps_hash_ops, TAKE_PTR(m));
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to store %s, ignoring: %s", lvalue, w);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int netdev_vlan_verify(NetDev *netdev, const char *filename) {
|
||||
VLan *v;
|
||||
|
||||
@ -75,6 +196,17 @@ static int netdev_vlan_verify(NetDev *netdev, const char *filename) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vlan_done(NetDev *n) {
|
||||
VLan *v;
|
||||
|
||||
v = VLAN(n);
|
||||
|
||||
assert(v);
|
||||
|
||||
set_free(v->egress_qos_maps);
|
||||
set_free(v->ingress_qos_maps);
|
||||
}
|
||||
|
||||
static void vlan_init(NetDev *netdev) {
|
||||
VLan *v = VLAN(netdev);
|
||||
|
||||
@ -96,4 +228,5 @@ const NetDevVTable vlan_vtable = {
|
||||
.fill_message_create = netdev_vlan_fill_message_create,
|
||||
.create_type = NETDEV_CREATE_STACKED,
|
||||
.config_verify = netdev_vlan_verify,
|
||||
.done = vlan_done,
|
||||
};
|
||||
|
@ -4,6 +4,7 @@
|
||||
typedef struct VLan VLan;
|
||||
|
||||
#include "netdev.h"
|
||||
#include "set.h"
|
||||
|
||||
struct VLan {
|
||||
NetDev meta;
|
||||
@ -15,7 +16,12 @@ struct VLan {
|
||||
int mvrp;
|
||||
int loose_binding;
|
||||
int reorder_hdr;
|
||||
|
||||
Set *egress_qos_maps;
|
||||
Set *ingress_qos_maps;
|
||||
};
|
||||
|
||||
DEFINE_NETDEV_CAST(VLAN, VLan);
|
||||
extern const NetDevVTable vlan_vtable;
|
||||
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_vlan_qos_maps);
|
||||
|
@ -507,7 +507,7 @@ int config_parse_iaid(const char *unit,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_dhcp_user_class(
|
||||
int config_parse_dhcp_user_or_vendor_class(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
@ -525,6 +525,7 @@ int config_parse_dhcp_user_class(
|
||||
assert(l);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(IN_SET(ltype, AF_INET, AF_INET6));
|
||||
|
||||
if (isempty(rvalue)) {
|
||||
*l = strv_free(*l);
|
||||
@ -533,6 +534,7 @@ int config_parse_dhcp_user_class(
|
||||
|
||||
for (const char *p = rvalue;;) {
|
||||
_cleanup_free_ char *w = NULL;
|
||||
size_t len;
|
||||
|
||||
r = extract_first_word(&p, &w, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNQUOTE);
|
||||
if (r == -ENOMEM)
|
||||
@ -545,76 +547,24 @@ int config_parse_dhcp_user_class(
|
||||
if (r == 0)
|
||||
return 0;
|
||||
|
||||
len = strlen(w);
|
||||
if (ltype == AF_INET) {
|
||||
if (strlen(w) > UINT8_MAX) {
|
||||
if (len > UINT8_MAX || len == 0) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, 0,
|
||||
"%s length is not in the range 1-255, ignoring.", w);
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
if (strlen(w) > UINT16_MAX) {
|
||||
if (len > UINT16_MAX || len == 0) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, 0,
|
||||
"%s length is not in the range 1-65535, ignoring.", w);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
r = strv_push(l, w);
|
||||
r = strv_consume(l, TAKE_PTR(w));
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
w = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int config_parse_dhcp_vendor_class(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *section,
|
||||
unsigned section_line,
|
||||
const char *lvalue,
|
||||
int ltype,
|
||||
const char *rvalue,
|
||||
void *data,
|
||||
void *userdata) {
|
||||
char ***l = data;
|
||||
int r;
|
||||
|
||||
assert(l);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
|
||||
if (isempty(rvalue)) {
|
||||
*l = strv_free(*l);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (const char *p = rvalue;;) {
|
||||
_cleanup_free_ char *w = NULL;
|
||||
|
||||
r = extract_first_word(&p, &w, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNQUOTE);
|
||||
if (r == -ENOMEM)
|
||||
return log_oom();
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, r,
|
||||
"Failed to split vendor classes option, ignoring: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
if (r == 0)
|
||||
return 0;
|
||||
|
||||
if (strlen(w) > UINT8_MAX) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, 0,
|
||||
"%s length is not in the range 1-255, ignoring.", w);
|
||||
continue;
|
||||
}
|
||||
|
||||
r = strv_push(l, w);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
w = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -66,7 +66,6 @@ CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_use_domains);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_use_ntp);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_iaid);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_section_route_table);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_user_class);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_vendor_class);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_user_or_vendor_class);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_send_option);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_request_options);
|
||||
|
@ -1417,7 +1417,7 @@ int dhcp4_configure(Link *link) {
|
||||
}
|
||||
|
||||
if (link->network->dhcp_user_class) {
|
||||
r = sd_dhcp_client_set_user_class(link->dhcp_client, (const char **) link->network->dhcp_user_class);
|
||||
r = sd_dhcp_client_set_user_class(link->dhcp_client, link->network->dhcp_user_class);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set user class: %m");
|
||||
}
|
||||
|
@ -204,7 +204,7 @@ DHCPv4.RequestBroadcast, config_parse_bool,
|
||||
DHCPv4.VendorClassIdentifier, config_parse_string, 0, offsetof(Network, dhcp_vendor_class_identifier)
|
||||
DHCPv4.MUDURL, config_parse_dhcp_mud_url, 0, 0
|
||||
DHCPv4.MaxAttempts, config_parse_dhcp_max_attempts, 0, 0
|
||||
DHCPv4.UserClass, config_parse_dhcp_user_class, AF_INET, offsetof(Network, dhcp_user_class)
|
||||
DHCPv4.UserClass, config_parse_dhcp_user_or_vendor_class, AF_INET, offsetof(Network, dhcp_user_class)
|
||||
DHCPv4.DUIDType, config_parse_duid_type, 0, offsetof(Network, duid)
|
||||
DHCPv4.DUIDRawData, config_parse_duid_rawdata, 0, offsetof(Network, duid)
|
||||
DHCPv4.RouteMetric, config_parse_dhcp_route_metric, 0, 0
|
||||
@ -227,8 +227,8 @@ DHCPv6.UseNTP, config_parse_dhcp_use_ntp,
|
||||
DHCPv6.RapidCommit, config_parse_bool, 0, offsetof(Network, dhcp6_rapid_commit)
|
||||
DHCPv6.MUDURL, config_parse_dhcp6_mud_url, 0, 0
|
||||
DHCPv6.RequestOptions, config_parse_dhcp_request_options, AF_INET6, 0
|
||||
DHCPv6.UserClass, config_parse_dhcp_user_class, AF_INET6, offsetof(Network, dhcp6_user_class)
|
||||
DHCPv6.VendorClass, config_parse_dhcp_vendor_class, 0, offsetof(Network, dhcp6_vendor_class)
|
||||
DHCPv6.UserClass, config_parse_dhcp_user_or_vendor_class, AF_INET6, offsetof(Network, dhcp6_user_class)
|
||||
DHCPv6.VendorClass, config_parse_dhcp_user_or_vendor_class, AF_INET6, offsetof(Network, dhcp6_vendor_class)
|
||||
DHCPv6.SendVendorOption, config_parse_dhcp_send_option, AF_INET6, offsetof(Network, dhcp6_client_send_vendor_options)
|
||||
DHCPv6.ForceDHCPv6PDOtherInformation, config_parse_bool, 0, offsetof(Network, dhcp6_force_pd_other_information)
|
||||
DHCPv6.PrefixDelegationHint, config_parse_dhcp6_pd_hint, 0, 0
|
||||
@ -467,7 +467,7 @@ DHCP.Hostname, config_parse_hostname,
|
||||
DHCP.RequestBroadcast, config_parse_bool, 0, offsetof(Network, dhcp_broadcast)
|
||||
DHCP.CriticalConnection, config_parse_tristate, 0, offsetof(Network, dhcp_critical)
|
||||
DHCP.VendorClassIdentifier, config_parse_string, 0, offsetof(Network, dhcp_vendor_class_identifier)
|
||||
DHCP.UserClass, config_parse_dhcp_user_class, AF_INET, offsetof(Network, dhcp_user_class)
|
||||
DHCP.UserClass, config_parse_dhcp_user_or_vendor_class, AF_INET, offsetof(Network, dhcp_user_class)
|
||||
DHCP.DUIDType, config_parse_duid_type, 0, offsetof(Network, duid)
|
||||
DHCP.DUIDRawData, config_parse_duid_rawdata, 0, offsetof(Network, duid)
|
||||
DHCP.RouteMetric, config_parse_dhcp_route_metric, 0, 0
|
||||
|
@ -16,6 +16,8 @@
|
||||
#include "wifi-util.h"
|
||||
|
||||
int wifi_get_info(Link *link) {
|
||||
_cleanup_free_ char *ssid = NULL;
|
||||
enum nl80211_iftype iftype;
|
||||
const char *type;
|
||||
int r, s = 0;
|
||||
|
||||
@ -33,16 +35,18 @@ int wifi_get_info(Link *link) {
|
||||
if (!streq(type, "wlan"))
|
||||
return 0;
|
||||
|
||||
_cleanup_free_ char *ssid = NULL;
|
||||
r = wifi_get_interface(link->manager->genl, link->ifindex, &link->wlan_iftype, &ssid);
|
||||
r = wifi_get_interface(link->manager->genl, link->ifindex, &iftype, &ssid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r > 0 && streq_ptr(link->ssid, ssid))
|
||||
if (r > 0 && link->wlan_iftype == iftype && streq_ptr(link->ssid, ssid))
|
||||
r = 0;
|
||||
|
||||
link->wlan_iftype = iftype;
|
||||
free_and_replace(link->ssid, ssid);
|
||||
|
||||
if (link->wlan_iftype == NL80211_IFTYPE_STATION) {
|
||||
struct ether_addr old_bssid = link->bssid;
|
||||
|
||||
s = wifi_get_station(link->manager->genl, link->ifindex, &link->bssid);
|
||||
if (s < 0)
|
||||
return s;
|
||||
@ -56,7 +60,9 @@ int wifi_get_info(Link *link) {
|
||||
if (link->wlan_iftype == NL80211_IFTYPE_STATION && link->ssid)
|
||||
log_link_info(link, "Connected WiFi access point: %s (%s)",
|
||||
link->ssid, ether_addr_to_string(&link->bssid, buf));
|
||||
return 1;
|
||||
|
||||
return 1; /* Some information is updated. */
|
||||
}
|
||||
return 0;
|
||||
|
||||
return 0; /* No new information. */
|
||||
}
|
||||
|
@ -444,6 +444,8 @@ static int oci_process(const char *name, JsonVariant *v, JsonDispatchFlags flags
|
||||
}
|
||||
|
||||
static int oci_root(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
|
||||
Settings *s = userdata;
|
||||
int r;
|
||||
|
||||
static const JsonDispatch table[] = {
|
||||
{ "path", JSON_VARIANT_STRING, json_dispatch_string, offsetof(Settings, root) },
|
||||
@ -451,7 +453,21 @@ static int oci_root(const char *name, JsonVariant *v, JsonDispatchFlags flags, v
|
||||
{}
|
||||
};
|
||||
|
||||
return json_dispatch(v, table, oci_unexpected, flags, userdata);
|
||||
r = json_dispatch(v, table, oci_unexpected, flags, s);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (s->root && !path_is_absolute(s->root)) {
|
||||
char *joined;
|
||||
|
||||
joined = path_join(s->bundle, s->root);
|
||||
if (!joined)
|
||||
return log_oom();
|
||||
|
||||
free_and_replace(s->root, joined);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int oci_hostname(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
|
||||
|
@ -181,7 +181,7 @@ int sd_dhcp_client_set_mud_url(
|
||||
const char *mudurl);
|
||||
int sd_dhcp_client_set_user_class(
|
||||
sd_dhcp_client *client,
|
||||
const char* const *user_class);
|
||||
char * const *user_class);
|
||||
int sd_dhcp_client_get_lease(
|
||||
sd_dhcp_client *client,
|
||||
sd_dhcp_lease **ret);
|
||||
|
@ -133,10 +133,10 @@ int sd_dhcp6_client_set_request_mud_url(
|
||||
const char *mudurl);
|
||||
int sd_dhcp6_client_set_request_user_class(
|
||||
sd_dhcp6_client *client,
|
||||
char** user_class);
|
||||
char * const *user_class);
|
||||
int sd_dhcp6_client_set_request_vendor_class(
|
||||
sd_dhcp6_client *client,
|
||||
char** vendor_class);
|
||||
char * const *vendor_class);
|
||||
int sd_dhcp6_client_set_prefix_delegation_hint(
|
||||
sd_dhcp6_client *client,
|
||||
uint8_t prefixlen,
|
||||
|
@ -66,3 +66,5 @@ Link.TxBufferSize, config_parse_nic_buffer_size, 0,
|
||||
Link.RxFlowControl, config_parse_tristate, 0, offsetof(link_config, rx_flow_control)
|
||||
Link.TxFlowControl, config_parse_tristate, 0, offsetof(link_config, tx_flow_control)
|
||||
Link.AutoNegotiationFlowControl, config_parse_tristate, 0, offsetof(link_config, autoneg_flow_control)
|
||||
Link.GenericSegmentOffloadMaxBytes, config_parse_iec_size, 0, offsetof(link_config, gso_max_size)
|
||||
Link.GenericSegmentOffloadMaxSegments, config_parse_uint32, 0, offsetof(link_config, gso_max_segments)
|
||||
|
@ -426,7 +426,7 @@ static int link_config_apply_rtnl_settings(sd_netlink **rtnl, const link_config
|
||||
} else
|
||||
mac = config->mac;
|
||||
|
||||
r = rtnl_set_link_properties(rtnl, ifindex, config->alias, mac, config->mtu);
|
||||
r = rtnl_set_link_properties(rtnl, ifindex, config->alias, mac, config->mtu, config->gso_max_size, config->gso_max_segments);
|
||||
if (r < 0)
|
||||
log_device_warning_errno(device, r, "Could not set Alias=, MACAddress= or MTU=, ignoring: %m");
|
||||
|
||||
|
@ -47,6 +47,8 @@ struct link_config {
|
||||
char **alternative_names;
|
||||
char *alias;
|
||||
uint32_t mtu;
|
||||
uint32_t gso_max_segments;
|
||||
size_t gso_max_size;
|
||||
uint64_t speed;
|
||||
Duplex duplex;
|
||||
int autonegotiation;
|
||||
|
@ -46,3 +46,5 @@ TxBufferSize=
|
||||
RxFlowControl=
|
||||
TxFlowControl=
|
||||
AutoNegotiationFlowControl=
|
||||
GenericSegmentOffloadMaxBytes=
|
||||
GenericSegmentOffloadMaxSegments=
|
||||
|
@ -5,6 +5,8 @@ ReorderHeader=
|
||||
Id=
|
||||
GVRP=
|
||||
Protocol=
|
||||
EgressQOSMaps=
|
||||
IngressQOSMaps=
|
||||
[MACVLAN]
|
||||
Mode=
|
||||
SourceMACAddress=
|
||||
|
Loading…
x
Reference in New Issue
Block a user