From: Oleksandr Andrushchenko Date: Mon, 2 Mar 2026 15:01:31 +0000 (+0200) Subject: network: Rename ModemManager .network section WRT tech, not project... X-Git-Tag: v260-rc2~5 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=899992bc1e1fd2a7983caa174744281a4ee81e77;p=thirdparty%2Fsystemd.git network: Rename ModemManager .network section WRT tech, not project... and use dedicated knobs for every option used in former SimpleConnectProperties. New section is [MobileNetwork] with the following configuration options: APN= AllowedAuthenticationMechanisms== User= Password= IPFamily= AllowRoaming= PIN= OperatorId= --- diff --git a/NEWS b/NEWS index 792aee47617..2862a224350 100644 --- a/NEWS +++ b/NEWS @@ -241,11 +241,11 @@ CHANGES WITH 260 in spe: * MultiPathRoute= option now supports interface-bound ECMP routes. * systemd-networkd gained integration with ModemManager via the "simple - connect" protocol. A new [ModemManager] section has been added with - SimpleConnectProperties= (currently apn=, allowed-auth=, user=, - password=, ip-type=, allow-roaming=, pin=, and operator-id=), - RouteMetric=, and UseGateway= settings. This allows systemd-networkd - to establish a cellular modem connection to a broadband network. + connect" protocol. A new [MobileNetwork] section has been added with + APN=, AllowedAuthenticationMechanisms=, User=, Password=, IPFamily=, + AllowRoaming=, PIN=, OperatorId=, RouteMetric=, and UseGateway= + settings. This allows systemd-networkd to establish a cellular modem + connection to a broadband network. * systemd-networkd gained a pair of varlink methods io.systemd.Network.Link.Up()/Down(). 'networkctl up/down' now diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 3b08a292e0d..58dae4f948c 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -6445,12 +6445,12 @@ ServerAddress=192.168.0.1/24 - [ModemManager] Section Options + [MobileNetwork] Section Options This section configures the default setting of the ModemManager integration. See for more information about ModemManager. - Regardless of the [ModemManager] section settings consider using the following for LTE modems (take into account + Regardless of the [MobileNetwork] section settings consider using the following for LTE modems (take into account that LTE modems do not typically support LLDP because LLDP is a Layer 2 protocol for Ethernet networks and an LTE modem connects to a cellular network, not a local Ethernet LAN): [Network] @@ -6460,75 +6460,89 @@ IPv6AcceptRA=no - The following options are available in the [ModemManager] section: + The following options are available in the [MobileNetwork] section: - SimpleConnectProperties= + APN= - Specifies the white-space separated list of simple connect properties used to connect a modem. See - for more - information about simple connect. If no properties provided then the connection is not initiated. + An Access Point Name (APN) is the name of a gateway between a mobile network + (GSM, GPRS, 3G, 4G and 5G) and another computer network. Required in 3GPP. + Defaults to unset and no attempt to establish the connection is made. - - =NAME - An Access Point Name (APN) is the name of a gateway between a mobile network - (GSM, GPRS, 3G, 4G and 5G) and another computer network. Required in 3GPP. - - - - - - =METHOD - Authentication method to use. Takes one of "none", "pap", "chap", "mschap", "mschapv2" or "eap". - Optional in 3GPP. + + + - - + + AllowedAuthenticationMechanisms= + + Authentication method to use. Specifies the white-space separated list of + none, pap, chap, + mschap, mschapv2, or eap + methods. Optional in 3GPP. Defaults to unset and an automatically picked + authentication method will be used. - - =NAME - User name (if any) required by the network. Optional in 3GPP. + + + - - + + User= + + User name (if any) required by the network. Optional in 3GPP. + Defaults to unset. - - =PASSWORD - Password (if any) required by the network. Optional in 3GPP. + + + - - + + Password= + + Password (if any) required by the network. Optional in 3GPP. + Defaults to unset. - - =TYPE - Addressing type. Takes one of "none", "ipv4", "ipv6", "ipv4v6" or "any". - Optional in 3GPP and CDMA. + + + - - + + IPFamily= + + Addressing type. Takes one of ipv4, ipv6, + both, or any. Optional in 3GPP and CDMA. + Defaults to unset and automatically selected. - - =BOOL - A boolean. When true, connection is allowed during roaming. When false, - connection is not allowed during roaming. Optional in 3GPP. + + + - - + + AllowRoaming= + + A boolean. When true, connection is allowed during roaming. When false, + connection is not allowed during roaming. + Optional in 3GPP. Defaults to yes. - - =PIN - SIM-PIN unlock code. + + + - - + + PIN= + + SIM-PIN unlock code. Defaults to unset. - - =ID - ETSI MCC-MNC of a network to force registration. + + + - - + + OperatorId= + + ETSI MCC-MNC of a network to force registration. Defaults to unset. + @@ -6896,14 +6910,23 @@ LLDP=no LinkLocalAddressing=no IPv6AcceptRA=no -[ModemManager] -SimpleConnectProperties=apn=internet pin=1111 +[MobileNetwork] +APN=internet +AllowedAuthenticationMechanisms=none pap chap +User=user +Password=pass +IPFamily=both +AllowRoaming=no +PIN=1111 +OperatorId=25503 RouteMetric=30 UseGateway=yes This connects a cellular modem to a broadband network matched with the network interface wwan0, - with APN name internet, SIM card pin unlock code 1111 and sets up a default - gateway with route metric of 30. + with APN name internet, allowed authentication none, pcap, or + chap, user name user, their password pass, allows both IPv4 and IPv6, + does not allow roaming, SIM card pin unlock code 1111, only allows connecting to operator with + MCC 25503, and sets up a default gateway with route metric of 30. diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 10566b7a4ed..f1049cc7cc2 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -493,9 +493,16 @@ CAN.ClassicDataLengthCode, config_parse_can_control_mode, CAN.Termination, config_parse_can_termination, 0, 0 IPoIB.Mode, config_parse_ipoib_mode, 0, offsetof(Network, ipoib_mode) IPoIB.IgnoreUserspaceMulticastGroups, config_parse_tristate, 0, offsetof(Network, ipoib_umcast) -ModemManager.SimpleConnectProperties, config_parse_strv, 0, offsetof(Network, mm_simple_connect_props) -ModemManager.RouteMetric, config_parse_mm_route_metric, 0, 0 -ModemManager.UseGateway, config_parse_tristate, 0, offsetof(Network, mm_use_gateway) +MobileNetwork.APN, config_parse_string, CONFIG_PARSE_STRING_SAFE_AND_ASCII, offsetof(Network, mm_apn) +MobileNetwork.AllowRoaming, config_parse_bool, 0, offsetof(Network, mm_allow_roaming) +MobileNetwork.AllowedAuthenticationMechanisms, config_parse_mm_allowed_auth, 0, offsetof(Network, mm_allowed_auth) +MobileNetwork.IPFamily, config_parse_mm_ip_family, 0, offsetof(Network, mm_ip_family) +MobileNetwork.OperatorId, config_parse_string, CONFIG_PARSE_STRING_SAFE_AND_ASCII, offsetof(Network, mm_operator_id) +MobileNetwork.User, config_parse_string, CONFIG_PARSE_STRING_SAFE_AND_ASCII, offsetof(Network, mm_user) +MobileNetwork.Password, config_parse_string, CONFIG_PARSE_STRING_SAFE_AND_ASCII, offsetof(Network, mm_password) +MobileNetwork.PIN, config_parse_string, CONFIG_PARSE_STRING_SAFE_AND_ASCII, offsetof(Network, mm_pin) +MobileNetwork.RouteMetric, config_parse_mm_route_metric, 0, 0 +MobileNetwork.UseGateway, config_parse_tristate, 0, offsetof(Network, mm_use_gateway) QDisc.Parent, config_parse_qdisc_parent, _QDISC_KIND_INVALID, 0 QDisc.Handle, config_parse_qdisc_handle, _QDISC_KIND_INVALID, 0 BFIFO.Parent, config_parse_qdisc_parent, QDISC_KIND_BFIFO, 0 diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index 8141a45432e..1e159fa3102 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -513,6 +513,9 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi .ipoib_mode = _IP_OVER_INFINIBAND_MODE_INVALID, .ipoib_umcast = -1, + .mm_allow_roaming = true, + .mm_allowed_auth = MM_BEARER_ALLOWED_AUTH_UNKNOWN, + .mm_ip_family = MM_BEARER_IP_FAMILY_NONE, .mm_use_gateway = -1, }; @@ -553,7 +556,7 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi "LLDP\0" "TrafficControlQueueingDiscipline\0" "CAN\0" - "ModemManager\0" + "MobileNetwork\0" "QDisc\0" "BFIFO\0" "CAKE\0" @@ -851,7 +854,11 @@ static Network *network_free(Network *network) { hashmap_free(network->tclasses_by_section); /* ModemManager */ - strv_free(network->mm_simple_connect_props); + free(network->mm_apn); + free(network->mm_operator_id); + free(network->mm_user); + free(network->mm_password); + free(network->mm_pin); return mfree(network); } diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index dcd9f68e781..923828b2ea1 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -21,6 +21,7 @@ #include "networkd-ndisc.h" #include "networkd-radv.h" #include "networkd-sysctl.h" +#include "networkd-wwan-bus.h" #include "resolve-util.h" typedef enum KeepConfiguration { @@ -416,7 +417,14 @@ typedef struct Network { char **ntp; /* ModemManager support */ - char **mm_simple_connect_props; + char *mm_apn; + bool mm_allow_roaming; + MMBearerAllowedAuth mm_allowed_auth; + MMBearerIpFamily mm_ip_family; + char *mm_operator_id; + char *mm_user; + char *mm_password; + char *mm_pin; int mm_use_gateway; uint32_t mm_route_metric; bool mm_route_metric_set; diff --git a/src/network/networkd-wwan-bus.c b/src/network/networkd-wwan-bus.c index d87cdd34411..5d981898752 100644 --- a/src/network/networkd-wwan-bus.c +++ b/src/network/networkd-wwan-bus.c @@ -59,7 +59,6 @@ #include "networkd-manager.h" #include "networkd-wwan.h" #include "networkd-wwan-bus.h" -#include "parse-util.h" #include "string-util.h" #include "strv.h" @@ -507,78 +506,6 @@ static int modem_connect_handler(sd_bus_message *message, void *userdata, sd_bus return 0; } -static MMBearerIpFamily prop_iptype_lookup(const char *key) { - static const struct { - MMBearerIpFamily family; - const char *str; - } table[] = { - { MM_BEARER_IP_FAMILY_NONE, "none" }, - { MM_BEARER_IP_FAMILY_IPV4, "ipv4" }, - { MM_BEARER_IP_FAMILY_IPV6, "ipv6" }, - { MM_BEARER_IP_FAMILY_IPV4V6, "ipv4v6" }, - { MM_BEARER_IP_FAMILY_ANY, "any" }, - {} - }; - - assert(key); - - FOREACH_ELEMENT(item, table) - if (streq(item->str, key)) - return item->family; - - log_warning("ModemManager: ignoring unknown ip-type: %s, using any", key); - return MM_BEARER_IP_FAMILY_ANY; -} - -static MMBearerAllowedAuth prop_auth_lookup(const char *key) { - static const struct { - MMBearerAllowedAuth auth; - const char *str; - } table[] = { - { MM_BEARER_ALLOWED_AUTH_NONE, "none" }, - { MM_BEARER_ALLOWED_AUTH_PAP, "pap" }, - { MM_BEARER_ALLOWED_AUTH_CHAP, "chap" }, - { MM_BEARER_ALLOWED_AUTH_MSCHAP, "mschap" }, - { MM_BEARER_ALLOWED_AUTH_MSCHAPV2, "mschapv2" }, - { MM_BEARER_ALLOWED_AUTH_EAP, "eap" }, - {} - }; - - assert(key); - - FOREACH_ELEMENT(item, table) - if (streq(item->str, key)) - return item->auth; - - log_warning("ModemManager: ignoring unknown allowed-auth: %s, using none", key); - return MM_BEARER_ALLOWED_AUTH_NONE; -} - -static const char* prop_type_lookup(const char *key) { - static const struct { - const char *prop; - const char *type; - } table[] = { - { "apn", "s" }, - { "allowed-auth", "u" }, - { "user", "s" }, - { "password", "s" }, - { "ip-type", "u" }, - { "allow-roaming", "b" }, - { "pin", "s" }, - { "operator-id", "s" }, - {} - }; - - if (!key) - return NULL; - - FOREACH_ELEMENT(item, table) - if (streq(item->prop, key)) - return item->type; - return NULL; -} - static int bus_call_method_async_props( sd_bus *bus, sd_bus_slot **slot, @@ -591,6 +518,7 @@ static int bus_call_method_async_props( Link *link) { _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; + Network *network = ASSERT_PTR(ASSERT_PTR(link)->network); int r; assert(bus); @@ -603,38 +531,48 @@ static int bus_call_method_async_props( if (r < 0) return bus_log_create_error(r); - STRV_FOREACH(prop, link->network->mm_simple_connect_props) { - const char *type; - _cleanup_free_ char *left = NULL, *right = NULL; + if (network->mm_apn) { + r = sd_bus_message_append(m, "{sv}", "apn", "s", network->mm_apn); + if (r < 0) + return bus_log_create_error(r); + } - r = split_pair(*prop, "=", &left, &right); + r = sd_bus_message_append(m, "{sv}", "allow-roaming", "b", network->mm_allow_roaming); + if (r < 0) + return bus_log_create_error(r); + + if (network->mm_allowed_auth != MM_BEARER_ALLOWED_AUTH_UNKNOWN) { + r = sd_bus_message_append(m, "{sv}", "allowed-auth", "u", (uint32_t) network->mm_allowed_auth); if (r < 0) - return log_warning_errno(SYNTHETIC_ERRNO(r), - "ModemManager: failed to parse simple connect option: %s, file: %s", - *prop, link->network->filename); - - type = prop_type_lookup(left); - if (!type) - return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), - "ModemManager: unknown simple connect option: %s, file: %s", - *prop, link->network->filename); - - if (streq(left, "ip-type")) { - MMBearerIpFamily ip_type = prop_iptype_lookup(right); - - r = sd_bus_message_append(m, "{sv}", left, type, (uint32_t)ip_type); - } if (streq(left, "allowed-auth")) { - MMBearerAllowedAuth auth = prop_auth_lookup(right); - - r = sd_bus_message_append(m, "{sv}", left, type, (uint32_t)auth); - } else if (streq(type, "b")) { - r = parse_boolean(right); - if (r < 0) - return -EINVAL; - r = sd_bus_message_append(m, "{sv}", left, type, r); - } else if (streq(type, "s")) - r = sd_bus_message_append(m, "{sv}", left, type, right); + return bus_log_create_error(r); + } + + if (network->mm_ip_family != MM_BEARER_IP_FAMILY_NONE) { + r = sd_bus_message_append(m, "{sv}", "ip-type", "u", (uint32_t) network->mm_ip_family); + if (r < 0) + return bus_log_create_error(r); + } + + if (network->mm_operator_id) { + r = sd_bus_message_append(m, "{sv}", "operator-id", "s", network->mm_operator_id); + if (r < 0) + return bus_log_create_error(r); + } + + if (network->mm_user) { + r = sd_bus_message_append(m, "{sv}", "user", "s", network->mm_user); + if (r < 0) + return bus_log_create_error(r); + } + + if (network->mm_password) { + r = sd_bus_message_append(m, "{sv}", "password", "s", network->mm_password); + if (r < 0) + return bus_log_create_error(r); + } + if (network->mm_pin) { + r = sd_bus_message_append(m, "{sv}", "pin", "s", network->mm_pin); if (r < 0) return bus_log_create_error(r); } @@ -675,9 +613,9 @@ static void modem_simple_connect(Modem *modem) { return (void) log_debug("ModemManager: no .network file provided for %s", modem->port_name); - /* Check if we are provided with simple connection properties */ - if (!link->network->mm_simple_connect_props) - return (void) log_debug("ModemManager: no simple connect properties provided for %s", + /* Check if we are provided with at least APN which is required. */ + if (!link->network->mm_apn) + return (void) log_debug("ModemManager: not enough simple connect properties provided for %s", modem->port_name); log_info("ModemManager: starting simple connect on %s %s interface %s", diff --git a/src/network/networkd-wwan.c b/src/network/networkd-wwan.c index 2b10eb3e4ee..ccd72d0ee31 100644 --- a/src/network/networkd-wwan.c +++ b/src/network/networkd-wwan.c @@ -2,6 +2,7 @@ #include "alloc-util.h" #include "bus-util.h" +#include "extract-word.h" #include "hashmap.h" #include "networkd-address.h" #include "networkd-dhcp4.h" @@ -620,7 +621,7 @@ int config_parse_mm_route_metric( void *data, void *userdata) { - Network *network = userdata; + Network *network = ASSERT_PTR(userdata); int r; assert(filename); @@ -639,3 +640,102 @@ int config_parse_mm_route_metric( network->mm_route_metric_set = true; return 0; } + +int config_parse_mm_allowed_auth( + 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) { + + static const struct { + MMBearerAllowedAuth auth; + const char *str; + } allowed_auth_map[] = { + { MM_BEARER_ALLOWED_AUTH_NONE, "none" }, + { MM_BEARER_ALLOWED_AUTH_PAP, "pap" }, + { MM_BEARER_ALLOWED_AUTH_CHAP, "chap" }, + { MM_BEARER_ALLOWED_AUTH_MSCHAP, "mschap" }, + { MM_BEARER_ALLOWED_AUTH_MSCHAPV2, "mschapv2" }, + { MM_BEARER_ALLOWED_AUTH_EAP, "eap" }, + }; + MMBearerAllowedAuth *allowed_auth = ASSERT_PTR(data); + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + + if (isempty(rvalue)) { + *allowed_auth = MM_BEARER_ALLOWED_AUTH_UNKNOWN; + return 0; + } + + for (const char *p = rvalue;;) { + _cleanup_free_ char *auth = NULL; + + r = extract_first_word(&p, &auth, /* separators */ NULL, /* flags */ 0); + if (r < 0) + return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue); + if (r == 0) + return 0; + + bool found = false; + FOREACH_ELEMENT(i, allowed_auth_map) + if (streq(auth, i->str)) { + *allowed_auth |= i->auth; + found = true; + break; + } + + if (!found) + log_syntax(unit, LOG_WARNING, filename, line, -EINVAL, + "Unknown auth value '%s', ignoring", auth); + } +} + +int config_parse_mm_ip_family( + 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) { + + static const struct { + MMBearerIpFamily family; + const char *str; + } ip_family_map[] = { + { MM_BEARER_IP_FAMILY_IPV4, "ipv4" }, + { MM_BEARER_IP_FAMILY_IPV6, "ipv6" }, + { MM_BEARER_IP_FAMILY_IPV4V6, "both" }, + { MM_BEARER_IP_FAMILY_ANY, "any" }, + }; + MMBearerIpFamily *ip_family = ASSERT_PTR(data); + + assert(filename); + assert(lvalue); + assert(rvalue); + + if (isempty(rvalue)) { + *ip_family = MM_BEARER_IP_FAMILY_NONE; + return 0; + } + + FOREACH_ELEMENT(i, ip_family_map) + if (streq(rvalue, i->str)) { + *ip_family = i->family; + return 0; + } + + return log_syntax_parse_error(unit, filename, line, -EINVAL, lvalue, rvalue); +} diff --git a/src/network/networkd-wwan.h b/src/network/networkd-wwan.h index 962f76be2ec..0542ac174d2 100644 --- a/src/network/networkd-wwan.h +++ b/src/network/networkd-wwan.h @@ -77,4 +77,6 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(Modem*, modem_free); int modem_get_by_path(Manager *m, const char *path, Modem **ret); int link_get_modem(Link *link, Modem **ret); +CONFIG_PARSER_PROTOTYPE(config_parse_mm_allowed_auth); +CONFIG_PARSER_PROTOTYPE(config_parse_mm_ip_family); CONFIG_PARSER_PROTOTYPE(config_parse_mm_route_metric);