+ "Tunnel is invalid, ignoring assignment: %s", rvalue);
+ return 0;
+ }
+
+ if (netdev->kind != NETDEV_KIND_IPIP &&
+ netdev->kind != NETDEV_KIND_SIT &&
+ netdev->kind != NETDEV_KIND_GRE &&
+ netdev->kind != NETDEV_KIND_GRETAP &&
+ netdev->kind != NETDEV_KIND_IP6GRE &&
+ netdev->kind != NETDEV_KIND_IP6GRETAP &&
+ netdev->kind != NETDEV_KIND_VTI &&
+ netdev->kind != NETDEV_KIND_IP6TNL
+ ) {
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+ "NetDev is not a tunnel, ignoring assignment: %s", rvalue);
+ return 0;
+ }
+
+ r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+ "Can not add VLAN '%s' to network: %s",
+ rvalue, strerror(-r));
+ return 0;
+ }
+
+ netdev_ref(netdev);
+
+ return 0;
+}
+
+int config_parse_ipv4ll(
+ 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) {
+
+ AddressFamilyBoolean *link_local = data;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ /* Note that this is mostly like
+ * config_parse_address_family_boolean(), except that it
+ * applies only to IPv4 */
+
+ if (parse_boolean(rvalue))
+ *link_local |= ADDRESS_FAMILY_IPV4;
+ else
+ *link_local &= ~ADDRESS_FAMILY_IPV4;
+
+ return 0;
+}
+
+int config_parse_dhcp(
+ 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) {
+
+ AddressFamilyBoolean *dhcp = data, s;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ /* Note that this is mostly like
+ * config_parse_address_family_boolean(), except that it
+ * understands some old names for the enum values */
+
+ s = address_family_boolean_from_string(rvalue);
+ if (s < 0) {
+
+ /* Previously, we had a slightly different enum here,
+ * support its values for compatbility. */
+
+ if (streq(rvalue, "none"))
+ s = ADDRESS_FAMILY_NO;
+ else if (streq(rvalue, "v4"))
+ s = ADDRESS_FAMILY_IPV4;
+ else if (streq(rvalue, "v6"))
+ s = ADDRESS_FAMILY_IPV6;
+ else if (streq(rvalue, "both"))
+ s = ADDRESS_FAMILY_YES;
+ else {
+ log_syntax(unit, LOG_ERR, filename, line, s, "Failed to parse DHCP option, ignoring: %s", rvalue);
+ return 0;
+ }
+ }
+
+ *dhcp = s;
+ return 0;
+}
+
+static const char* const dhcp_client_identifier_table[_DHCP_CLIENT_ID_MAX] = {
+ [DHCP_CLIENT_ID_MAC] = "mac",
+ [DHCP_CLIENT_ID_DUID] = "duid"
+};
+
+DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_client_identifier, DCHPClientIdentifier);
+DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_client_identifier, dhcp_client_identifier, DCHPClientIdentifier, "Failed to parse client identifier type");
+
+static const char* const llmnr_support_table[_LLMNR_SUPPORT_MAX] = {
+ [LLMNR_SUPPORT_NO] = "no",
+ [LLMNR_SUPPORT_YES] = "yes",
+ [LLMNR_SUPPORT_RESOLVE] = "resolve",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(llmnr_support, LLMNRSupport);
+
+int config_parse_llmnr(
+ 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) {
+
+ LLMNRSupport *llmnr = data;
+ int k;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(llmnr);
+
+ /* Our enum shall be a superset of booleans, hence first try
+ * to parse as boolean, and then as enum */
+
+ k = parse_boolean(rvalue);
+ if (k > 0)
+ *llmnr = LLMNR_SUPPORT_YES;
+ else if (k == 0)
+ *llmnr = LLMNR_SUPPORT_NO;
+ else {
+ LLMNRSupport s;
+
+ s = llmnr_support_from_string(rvalue);
+ if (s < 0){
+ log_syntax(unit, LOG_ERR, filename, line, -s, "Failed to parse LLMNR option, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ *llmnr = s;
+ }
+
+ return 0;
+}
+
+int config_parse_ipv6token(
+ 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) {
+
+ union in_addr_union buffer;
+ struct in6_addr *token = data;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(token);
+
+ r = in_addr_from_string(AF_INET6, rvalue, &buffer);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to parse IPv6 token, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ r = in_addr_is_null(AF_INET6, &buffer);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, -r, "IPv6 token can not be the ANY address, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ if ((buffer.in6.s6_addr32[0] | buffer.in6.s6_addr32[1]) != 0) {
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL, "IPv6 token can not be longer than 64 bits, ignoring: %s", rvalue);