reception.</para>
</listitem>
</varlistentry>
+
<varlistentry>
<term><varname>BindCarrier=</varname></term>
<listitem>
</variablelist>
</refsect1>
+ <refsect1>
+ <title>[LLDP] Section Options</title>
+ <para>The <literal>[LLDP]</literal> section manages the Link Layer Discovery Protocol (LLDP) and accepts the
+ following keys.</para>
+ <variablelist class='network-directives'>
+ <varlistentry>
+ <term><varname>MUDURL=</varname></term>
+ <listitem>
+ <para>Controls support for Ethernet LLDP packet's Manufacturer Usage Description (MUD). MUD is an embedded software
+ standard defined by the IETF that allows IoT Device makers to advertise device specifications, including the intended
+ communication patterns for their device when it connects to the network. The network can then use this intent to author
+ a context-specific access policy, so the device functions only within those parameters. Takes an URL of length up to 255
+ characters. A superficial verification that the string is a valid URL
+ will be performed. See
+ <ulink url="https://tools.ietf.org/html/rfc8520">RFC 8520</ulink> for details. The MUD URL received
+ from the LLDP packets will be saved at the state files and can be read via
+ <function>sd_lldp_neighbor_get_mud_url()</function> function.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
<refsect1>
<title>[CAN] Section Options</title>
<para>The <literal>[CAN]</literal> section manages the Controller Area Network (CAN bus) and accepts the
#include <net/if_arp.h>
#include "alloc-util.h"
+#include "escape.h"
#include "env-file.h"
#include "fd-util.h"
#include "hostname-util.h"
#include "socket-util.h"
#include "string-util.h"
#include "unaligned.h"
+#include "web-util.h"
/* The LLDP spec calls this "txFastInit", see 9.2.5.19 */
#define LLDP_TX_FAST_INIT 4U
const char *pretty_hostname,
uint16_t system_capabilities,
uint16_t enabled_capabilities,
+ char *mud,
void **ret, size_t *sz) {
- size_t machine_id_length, ifname_length, port_description_length = 0, hostname_length = 0, pretty_hostname_length = 0;
+ size_t machine_id_length, ifname_length, port_description_length = 0, hostname_length = 0,
+ pretty_hostname_length = 0, mud_length = 0;
_cleanup_free_ void *packet = NULL;
struct ether_header *h;
uint8_t *p;
if (pretty_hostname)
pretty_hostname_length = strlen(pretty_hostname);
+ if (mud)
+ mud_length = strlen(mud);
+
l = sizeof(struct ether_header) +
/* Chassis ID */
2 + 1 + machine_id_length +
if (pretty_hostname)
l += 2 + pretty_hostname_length;
+ /* MUD URL */
+ if (mud)
+ l += 2 + sizeof(SD_LLDP_OUI_MUD) + 1 + mud_length;
+
packet = malloc(l);
if (!packet)
return -ENOMEM;
p = mempcpy(p, pretty_hostname, pretty_hostname_length);
}
+ if (mud) {
+ uint8_t oui_mud[sizeof(SD_LLDP_OUI_MUD)] = {0x00, 0x00, 0x5E};
+ /*
+ * +--------+--------+----------+---------+--------------
+ * |TLV Type| len | OUI |subtype | MUDString
+ * | =127 | |= 00 00 5E| = 1 |
+ * |(7 bits)|(9 bits)|(3 octets)|(1 octet)|(1-255 octets)
+ * +--------+--------+----------+---------+--------------
+ * where:
+
+ * o TLV Type = 127 indicates a vendor-specific TLV
+ * o len = indicates the TLV string length
+ * o OUI = 00 00 5E is the organizationally unique identifier of IANA
+ * o subtype = 1 (as assigned by IANA for the MUDstring)
+ * o MUDstring = the length MUST NOT exceed 255 octets
+ */
+
+ r = lldp_write_tlv_header(&p, SD_LLDP_TYPE_PRIVATE, sizeof(SD_LLDP_OUI_MUD) + 1 + mud_length);
+ if (r < 0)
+ return r;
+
+ p = mempcpy(p, &oui_mud, sizeof(SD_LLDP_OUI_MUD));
+ *(p++) = SD_LLDP_OUI_SUBTYPE_MUD_USAGE_DESCRIPTION;
+ p = mempcpy(p, mud, mud_length);
+ }
+
r = lldp_write_tlv_header(&p, SD_LLDP_TYPE_SYSTEM_CAPABILITIES, 4);
if (r < 0)
return r;
pretty_hostname,
SD_LLDP_SYSTEM_CAPABILITIES_STATION|SD_LLDP_SYSTEM_CAPABILITIES_BRIDGE|SD_LLDP_SYSTEM_CAPABILITIES_ROUTER,
caps,
+ link->network ? link->network->lldp_mud : NULL,
&packet, &packet_size);
if (r < 0)
return r;
return 0;
}
+
+int config_parse_lldp_mud(
+ 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) {
+
+ _cleanup_free_ char *unescaped = NULL;
+ Network *n = data;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+
+ r = cunescape(rvalue, 0, &unescaped);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r,
+ "Failed to Failed to unescape LLDP MUD URL, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ if (!http_url_is_valid(unescaped) || strlen(unescaped) > 255) {
+ log_syntax(unit, LOG_ERR, filename, line, 0,
+ "Failed to parse LLDP MUD URL '%s', ignoring: %m", rvalue);
+
+ return 0;
+ }
+
+ return free_and_replace(n->lldp_mud, unescaped);
+}
IPv6Prefix.Assign, config_parse_prefix_assign, 0, 0
IPv6RoutePrefix.Route, config_parse_route_prefix, 0, 0
IPv6RoutePrefix.LifetimeSec, config_parse_route_prefix_lifetime, 0, 0
+LLDP.MUDURL, config_parse_lldp_mud, 0, 0
CAN.BitRate, config_parse_can_bitrate, 0, offsetof(Network, can_bitrate)
CAN.SamplePoint, config_parse_permille, 0, offsetof(Network, can_sample_point)
CAN.DataBitRate, config_parse_can_bitrate, 0, offsetof(Network, can_data_bitrate)