Skip to content
Closed
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,47 @@ fun getAllAIGeneratedValidators(): Map<Validator, OptionValueInformation> {
Validator("config_parse_socket_service", "0") to ConfigParseSocketServiceOptionValue() as OptionValueInformation,
Validator("config_parse_service_sockets", "0") to ConfigParseServiceSocketsOptionValue() as OptionValueInformation,

// Batch 2026-10: network-dhcp-misc
Validator("config_parse_dhcp_option_tlv", "0") to ConfigParseDhcpOptionTlvOptionValue() as OptionValueInformation,
Validator("config_parse_dhcp_option", "true") to ConfigParseDhcpOptionTypedOptionValue() as OptionValueInformation,
Validator("config_parse_dhcp6_send_option", "0") to ConfigParseDhcp6SendOptionOptionValue() as OptionValueInformation,
Validator("config_parse_uplink", "0") to ConfigParseUplinkOptionValue() as OptionValueInformation,
Validator("config_parse_fdb_interface", "0") to ConfigParseFdbInterfaceOptionValue() as OptionValueInformation,
Validator("config_parse_mud_url", "0") to ConfigParseMudUrlOptionValue() as OptionValueInformation,
Validator("config_parse_resolve_support", "0") to ConfigParseResolveSupportOptionValue() as OptionValueInformation,
Validator("config_parse_dns_over_tls_mode", "0") to ConfigParseDnsOverTlsModeOptionValue() as OptionValueInformation,
Validator("config_parse_dhcp_pd_prefix_route_type", "0") to ConfigParseDhcpPdPrefixRouteTypeOptionValue() as OptionValueInformation,
Validator("config_parse_lldp_multicast_mode", "0") to ConfigParseLldpMulticastModeOptionValue() as OptionValueInformation,
Validator("config_parse_activation_policy", "0") to ConfigParseActivationPolicyOptionValue() as OptionValueInformation,
Validator("config_parse_dhcp_relay_interface_mode", "0") to ConfigParseDhcpRelayInterfaceModeOptionValue() as OptionValueInformation,
Validator("config_parse_dhcp_fallback_lease_lifetime", "0") to ConfigParseDhcpFallbackLeaseLifetimeOptionValue() as OptionValueInformation,
Validator("config_parse_ipv4ll", "0") to ConfigParseIpv4llOptionValue() as OptionValueInformation,
Validator("config_parse_ignore_carrier_loss", "0") to ConfigParseIgnoreCarrierLossOptionValue() as OptionValueInformation,
Validator("config_parse_dhcp_server_ipv6_only_preferred", "0") to ConfigParseDhcpServerIpv6OnlyPreferredOptionValue() as OptionValueInformation,
Validator("config_parse_bridge_vlan_id", "0") to ConfigParseBridgeVlanIdOptionValue() as OptionValueInformation,
Validator("config_parse_link_group", "0") to ConfigParseLinkGroupOptionValue() as OptionValueInformation,
Validator("config_parse_dhcp_pd_subnet_id", "0") to ConfigParseDhcpPdSubnetIdOptionValue() as OptionValueInformation,
Validator("config_parse_required_for_online", "0") to ConfigParseRequiredForOnlineOptionValue() as OptionValueInformation,
Validator("config_parse_dhcp_server_address", "0") to ConfigParseDhcpServerAddressOptionValue() as OptionValueInformation,
Validator("config_parse_ipv4ll_address", "0") to ConfigParseIpv4llAddressOptionValue() as OptionValueInformation,
Validator("config_parse_dhcp_label", "0") to ConfigParseDhcpLabelOptionValue() as OptionValueInformation,
Validator("config_parse_dhcp_static_lease_hostname", "0") to ConfigParseDhcpStaticLeaseHostnameOptionValue() as OptionValueInformation,
Validator("config_parse_domains", "0") to ConfigParseDomainsOptionValue() as OptionValueInformation,
Validator("config_parse_dnssec_negative_trust_anchors", "0") to ConfigParseDnssecNegativeTrustAnchorsOptionValue() as OptionValueInformation,
Validator("config_parse_ntp", "0") to ConfigParseNtpOptionValue() as OptionValueInformation,
Validator("config_parse_radv_dns", "0") to ConfigParseRadvDnsOptionValue() as OptionValueInformation,
Validator("config_parse_dhcp_request_options", "AF_INET") to ConfigParseDhcpRequestOptionsOptionValue() as OptionValueInformation,
Validator("config_parse_dhcp_request_options", "AF_INET6") to ConfigParseDhcpRequestOptionsOptionValue() as OptionValueInformation,
Validator("config_parse_dhcp4_user_class", "0") to ConfigParseDhcp4UserClassOptionValue() as OptionValueInformation,
Validator("config_parse_dhcp6_user_or_vendor_class", "0") to ConfigParseDhcp6UserOrVendorClassOptionValue() as OptionValueInformation,
Validator("config_parse_duid_type", "0") to ConfigParseDuidTypeOptionValue("config_parse_duid_type") as OptionValueInformation,
Validator("config_parse_network_duid_type", "0") to ConfigParseDuidTypeOptionValue("config_parse_network_duid_type") as OptionValueInformation,
Validator("config_parse_duid_rawdata", "0") to ConfigParseDuidRawdataOptionValue("config_parse_duid_rawdata") as OptionValueInformation,
Validator("config_parse_network_duid_rawdata", "0") to ConfigParseDuidRawdataOptionValue("config_parse_network_duid_rawdata") as OptionValueInformation,
Validator("config_parse_dhcp_or_ra_route_table", "NETWORK_CONFIG_SOURCE_DHCP4") to ConfigParseDhcpOrRaRouteTableOptionValue() as OptionValueInformation,
Validator("config_parse_dhcp_or_ra_route_table", "NETWORK_CONFIG_SOURCE_DHCP6") to ConfigParseDhcpOrRaRouteTableOptionValue() as OptionValueInformation,
Validator("config_parse_dhcp_or_ra_route_table", "NETWORK_CONFIG_SOURCE_NDISC") to ConfigParseDhcpOrRaRouteTableOptionValue() as OptionValueInformation,

)

return allValidators
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.ai

import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.SimpleGrammarOptionValues
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.EOF
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.FlexibleLiteralChoiceTerminal
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.SequenceCombinator

/*
* [Link] ActivationPolicy= (.network).
*
* man https://www.freedesktop.org/software/systemd/man/latest/systemd.network.html#ActivationPolicy=
* parser https://github.com/systemd/systemd/blob/0f0682b773/src/network/networkd-network.c#L1201 config_parse_activation_policy (0), DEFINE_CONFIG_PARSE_ENUM
* leaf https://github.com/systemd/systemd/blob/0f0682b773/src/network/networkd-network.c#L1191-L1198 activation_policy_table
* tests https://github.com/systemd/systemd/blob/0f0682b773/test/test-network/conf/25-activation-policy.network.d/always-down.conf#L2
*/

/**
* Validator for `[Link] ActivationPolicy=`: exactly one of `up`, `always-up`, `manual`, `always-down`,
* `down`, `bound` (plain DEFINE_STRING_TABLE_LOOKUP — case-sensitive, no boolean).
*/
class ConfigParseActivationPolicyOptionValue : SimpleGrammarOptionValues(
"config_parse_activation_policy",
SequenceCombinator(
FlexibleLiteralChoiceTerminal("up", "always-up", "manual", "always-down", "down", "bound"),
EOF(),
)
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.ai

import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.SimpleGrammarOptionValues
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.AlternativeCombinator
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.BOOLEAN_FALSE
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.EOF
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.SafeAtoTerminal
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.SequenceCombinator

/*
* [BridgeVLAN] PVID= (.network).
*
* man https://www.freedesktop.org/software/systemd/man/latest/systemd.network.html#PVID=
* parser https://github.com/systemd/systemd/blob/0f0682b773/src/network/networkd-bridge-vlan.c#L341-L381 config_parse_bridge_vlan_id (0)
* leaf https://github.com/systemd/systemd/blob/0f0682b773/src/shared/vlan-util.c#L8-L23 parse_vlanid (safe_atou16, <= VLANID_MAX = 4094)
* leaf https://github.com/systemd/systemd/blob/0f0682b773/src/basic/parse-util.c#L23-L46 parse_boolean
* tests https://github.com/systemd/systemd/blob/0f0682b773/test/test-network/conf/26-bridge-vlan-master.network.d/30-override.conf#L3
* https://github.com/systemd/systemd/blob/0f0682b773/test/test-network/conf/26-bridge-vlan-master.network#L9
*/

/**
* Validator for `[BridgeVLAN] PVID=` (config_parse_bridge_vlan_id): a *false* boolean (removes the PVID;
* a true one falls through to parse_vlanid and is refused), or a VLAN id 0…4094 read by safe_atou16
* (base 0, so `0x10` is legal).
*/
class ConfigParseBridgeVlanIdOptionValue : SimpleGrammarOptionValues(
"config_parse_bridge_vlan_id",
AlternativeCombinator(
SequenceCombinator(
SafeAtoTerminal(
signed = false,
base = 0,
flags = emptySet(),
minInclusive = 0L,
maxInclusive = 4_094L,
acceptsWhitespace = true,
acceptsMinus = true,
),
EOF(),
),
SequenceCombinator(BOOLEAN_FALSE, EOF()),
)
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.ai

import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.SimpleGrammarOptionValues
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.CUNESCAPE_UNQUOTE_WORD
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.NETWORK_DHCP_MISC_NONEMPTY_UNQUOTE_WORD
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.EOF
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.SequenceCombinator
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.wordList

/*
* [DHCPv4] UserClass= (and the old [DHCP] UserClass=) (.network).
*
* Note: the plugin reports the deprecated [DHCP] section as not allowed in .network files, so this
* validator never actually runs for keys there; they are listed only because the gperf shares the parser.
*
* man https://www.freedesktop.org/software/systemd/man/latest/systemd.network.html#UserClass=
* parser https://github.com/systemd/systemd/blob/0f0682b773/src/network/networkd-dhcp-common.c#L655-L698 config_parse_dhcp4_user_class (0)
* leaf https://github.com/systemd/systemd/blob/0f0682b773/src/basic/extract-word.c#L10-L188 extract_first_word (EXTRACT_CUNESCAPE|EXTRACT_UNQUOTE)
* leaf https://github.com/systemd/systemd/blob/0f0682b773/src/basic/escape.c#L104-L296 cunescape_one
*/

/**
* Validator for `[DHCPv4] UserClass=`: a whitespace-separated list of user-class strings, split by
* extract_first_word with EXTRACT_CUNESCAPE|EXTRACT_UNQUOTE — so a class may be quoted to contain spaces
* and may use C escapes ([CUNESCAPE_UNQUOTE_WORD]). An unknown escape, a trailing backslash or an
* unterminated quote fails the assignment.
*
* Each class must also be 1…255 bytes long once unquoted/unescaped. An empty one (`""`, `''`) is
* dropped with a warning and flagged ([NETWORK_DHCP_MISC_NONEMPTY_UNQUOTE_WORD]); the upper bound is not
* modelled (lenient).
*/
class ConfigParseDhcp4UserClassOptionValue : SimpleGrammarOptionValues(
"config_parse_dhcp4_user_class",
SequenceCombinator(wordList(NETWORK_DHCP_MISC_NONEMPTY_UNQUOTE_WORD), EOF())
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.ai

import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.SimpleGrammarOptionValues
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.AlternativeCombinator
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.NETWORK_DHCP_MISC_COALESCED_COLONS
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.COLON
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.EOF
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.KeyOrSectionDispatchingGrammarOptionValue
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.SafeAtoTerminal
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.SequenceCombinator
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.ZeroOrMore
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.dhcpOptionTypedData
import java.math.BigInteger

/*
* [DHCPv6] SendOption= / SendVendorOption= (.network).
*
* man https://www.freedesktop.org/software/systemd/man/latest/systemd.network.html#SendOption=
* https://www.freedesktop.org/software/systemd/man/latest/systemd.network.html#SendVendorOption=
* parser https://github.com/systemd/systemd/blob/0f0682b773/src/network/networkd-dhcp-common.c#L745-L942 config_parse_dhcp6_send_option (0)
* leaf https://github.com/systemd/systemd/blob/0f0682b773/src/network/networkd-dhcp-common.c#L781 streq(lvalue, "SendVendorOption") — the key decides the shape
* leaf https://github.com/systemd/systemd/blob/0f0682b773/src/network/networkd-dhcp-common.c#L1176-L1183 dhcp_option_data_type_table
* leaf https://github.com/systemd/systemd/blob/0f0682b773/src/basic/extract-word.c#L10-L188 extract_first_word (":" separator, coalescing)
* leaf https://github.com/systemd/systemd/blob/0f0682b773/src/basic/parse-util.c#L599-L613 safe_atou16_full (base 0)
* leaf https://github.com/systemd/systemd/blob/0f0682b773/src/basic/parse-util.c#L429-L478 safe_atou_full (safe_atou32, base 0)
* leaf https://github.com/systemd/systemd/blob/0f0682b773/src/basic/in-addr-util.c#L517-L529 in_addr_from_string (inet_pton)
* leaf https://github.com/systemd/systemd/blob/0f0682b773/src/basic/escape.c#L104-L296 cunescape_one
* linux https://man7.org/linux/man-pages/man3/inet_pton.3.html
*/

// safe_atou16/safe_atou32 skip leading whitespace, and extract_first_word(…, ":", 0) leaves any that
// follows a colon inside the next word, so `123: 1:string:x` is fine: hence acceptsWhitespace = true.
// CODE is safe_atou16 with `u16 < 1 || u16 >= UINT16_MAX` refused, so 1…65534.
private val CODE_TYPE_DATA = SequenceCombinator(
SafeAtoTerminal(
signed = false,
base = 0,
flags = emptySet(),
minInclusive = 1L,
maxInclusive = 65_534L,
acceptsWhitespace = true,
acceptsMinus = true,
),
NETWORK_DHCP_MISC_COALESCED_COLONS,
dhcpOptionTypedData(),
EOF(),
)

private val SEND_OPTION = SequenceCombinator(ZeroOrMore(COLON), CODE_TYPE_DATA)

private val SEND_VENDOR_OPTION = SequenceCombinator(
ZeroOrMore(COLON),
SafeAtoTerminal(
signed = false,
base = 0,
flags = emptySet(),
minInclusive = BigInteger.ZERO,
maxInclusive = SafeAtoTerminal.UINT32_MAX,
acceptsWhitespace = true,
acceptsMinus = true,
),
NETWORK_DHCP_MISC_COALESCED_COLONS,
CODE_TYPE_DATA,
)

/**
* Validator for `[DHCPv6] SendOption=` (`CODE:TYPE:DATA`) and `[DHCPv6] SendVendorOption=`
* (`ENTERPRISE:CODE:TYPE:DATA`), both parsed by config_parse_dhcp6_send_option.
*
* The parser branches on the *key name*: only for SendVendorOption= does it first read an enterprise
* identifier (safe_atou32, any uint32 — the man page says 1…4294967294 but C accepts 0 and 4294967295
* too). The validator is registered per (parser, ltype) but dispatches on the key it is checking, so
* `SendOption=` takes exactly the three-field form and `SendVendorOption=` exactly the four-field one
* (`SendVendorOption=12:string:x` is refused, as systemd's safe_atou16("string") refuses it).
*
* CODE is safe_atou16 in 1…65534 — the C check is `u16 < 1 || u16 >= UINT16_MAX`, so 65535 is refused
* although the man page says "1…65536". The TYPE:DATA tail is [dhcpOptionTypedData]; all six types are
* accepted. Every separator coalesces, so leading and doubled colons are harmless.
*/
class ConfigParseDhcp6SendOptionOptionValue : KeyOrSectionDispatchingGrammarOptionValue(
VALIDATOR_NAME,
AlternativeCombinator(SEND_VENDOR_OPTION, SEND_OPTION),
{ key, _ -> if (key == "SendVendorOption") VENDOR else PLAIN },
) {
private companion object {
const val VALIDATOR_NAME = "config_parse_dhcp6_send_option"
val PLAIN = SimpleGrammarOptionValues(VALIDATOR_NAME, SEND_OPTION)
val VENDOR = SimpleGrammarOptionValues(VALIDATOR_NAME, SEND_VENDOR_OPTION)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.ai

import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.SimpleGrammarOptionValues
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.NETWORK_DHCP_MISC_NONEMPTY_UNQUOTE_WORD
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.EOF
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.SequenceCombinator
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.wordList

/*
* [DHCPv6] UserClass= / VendorClass= (.network).
*
* man https://www.freedesktop.org/software/systemd/man/latest/systemd.network.html#UserClass=
* https://www.freedesktop.org/software/systemd/man/latest/systemd.network.html#VendorClass=
* parser https://github.com/systemd/systemd/blob/0f0682b773/src/network/networkd-dhcp-common.c#L700-L743 config_parse_dhcp6_user_or_vendor_class (0)
* leaf https://github.com/systemd/systemd/blob/0f0682b773/src/basic/extract-word.c#L10-L188 extract_first_word (EXTRACT_CUNESCAPE|EXTRACT_UNQUOTE)
* leaf https://github.com/systemd/systemd/blob/0f0682b773/src/basic/escape.c#L104-L296 cunescape_one
*/

/**
* Validator for `[DHCPv6] UserClass=` and `[DHCPv6] VendorClass=`: the same quoted/escaped word list as
* [ConfigParseDhcp4UserClassOptionValue], with a 1…65535-byte length limit per entry: empty
* entries are flagged, the upper bound is not modelled.
*/
class ConfigParseDhcp6UserOrVendorClassOptionValue : SimpleGrammarOptionValues(
"config_parse_dhcp6_user_or_vendor_class",
SequenceCombinator(wordList(NETWORK_DHCP_MISC_NONEMPTY_UNQUOTE_WORD), EOF())
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.ai

import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.SimpleGrammarOptionValues
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.EOF
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.FlexibleLiteralChoiceTerminal
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.SequenceCombinator

/*
* [DHCPv4] FallbackLeaseLifetimeSec= (.network).
*
* man https://www.freedesktop.org/software/systemd/man/latest/systemd.network.html#FallbackLeaseLifetimeSec=
* parser https://github.com/systemd/systemd/blob/0f0682b773/src/network/networkd-dhcp4.c#L2098-L2133 config_parse_dhcp_fallback_lease_lifetime (0)
*/

/**
* Validator for `[DHCPv4] FallbackLeaseLifetimeSec=`. Despite the `Sec` suffix this is not a time span:
* the parser accepts only `forever` or `infinity` (STR_IN_SET, case-sensitive), as the man page says.
*/
class ConfigParseDhcpFallbackLeaseLifetimeOptionValue : SimpleGrammarOptionValues(
"config_parse_dhcp_fallback_lease_lifetime",
SequenceCombinator(FlexibleLiteralChoiceTerminal("forever", "infinity"), EOF())
)
Loading
Loading