network: add ModemManager support
[Match] Name=wwan* [Network] LLDP=no LinkLocalAddressing=no IPv6AcceptRA=no [ModemManager] SimpleConnectPropertie]s=apn=internet ip-type=ipv4 allow-roaming=no pin=1111 operator-id=25503 RouteMetric=200 UseGateway=yes Co-authored-by: Yu Watanabe <watanabe.yu+github@gmail.com>
This commit is contained in:
committed by
Yu Watanabe
co-authored by
Yu Watanabe
parent
4ed1e2ea17
commit
f8a4c3d375
@@ -6444,6 +6444,117 @@ ServerAddress=192.168.0.1/24</programlisting>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>[ModemManager] Section Options</title>
|
||||
|
||||
<para>This section configures the default setting of the ModemManager integration. See
|
||||
<ulink url="https://modemmanager.org/docs/modemmanager/" /> for more information about ModemManager.</para>
|
||||
|
||||
<para>Regardless of the [ModemManager] 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):
|
||||
<programlisting>[Network]
|
||||
LLDP=no
|
||||
LinkLocalAddressing=no
|
||||
IPv6AcceptRA=no
|
||||
</programlisting>
|
||||
</para>
|
||||
|
||||
<para>The following options are available in the [ModemManager] section:</para>
|
||||
<variablelist class='network-directives'>
|
||||
<varlistentry>
|
||||
<term><varname>SimpleConnectProperties=</varname></term>
|
||||
<listitem>
|
||||
<para>Specifies the white-space separated list of simple connect properties used to connect a modem. See
|
||||
<ulink url="https://www.freedesktop.org/software/ModemManager/man/latest/mmcli.1.html" /> for more
|
||||
information about simple connect. If no properties provided then the connection is not initiated.</para>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>apn</option>=<replaceable>NAME</replaceable></term>
|
||||
<listitem><para>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.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v260"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>allowed-auth</option>=<replaceable>METHOD</replaceable></term>
|
||||
<listitem><para>Authentication method to use. Takes one of "none", "pap", "chap", "mschap", "mschapv2" or "eap".
|
||||
Optional in 3GPP.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v260"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>user</option>=<replaceable>NAME</replaceable></term>
|
||||
<listitem><para>User name (if any) required by the network. Optional in 3GPP.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v260"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>password</option>=<replaceable>PASSWORD</replaceable></term>
|
||||
<listitem><para>Password (if any) required by the network. Optional in 3GPP.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v260"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>ip-type</option>=<replaceable>TYPE</replaceable></term>
|
||||
<listitem><para>Addressing type. Takes one of "none", "ipv4", "ipv6", "ipv4v6" or "any".
|
||||
Optional in 3GPP and CDMA.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v260"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>allow-roaming</option>=<replaceable>BOOL</replaceable></term>
|
||||
<listitem><para>A boolean. When true, connection is allowed during roaming. When false,
|
||||
connection is not allowed during roaming. Optional in 3GPP.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v260"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>pin</option>=<replaceable>PIN</replaceable></term>
|
||||
<listitem><para>SIM-PIN unlock code.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v260"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>operator-id</option>=<replaceable>ID</replaceable></term>
|
||||
<listitem><para>ETSI MCC-MNC of a network to force registration.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v260"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>RouteMetric=</varname></term>
|
||||
<listitem>
|
||||
<para>Set the routing metric for routes specified by the mobile network (including the prefix route
|
||||
added for the specified prefix). Takes an unsigned integer in the range 0…4294967295.
|
||||
When unset or set to 0, the kernel's default value will be used.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v260"/>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>UseGateway=</varname></term>
|
||||
<listitem>
|
||||
<para>When true (the default), the router address will be configured as the default gateway.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v260"/>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Examples</title>
|
||||
<example>
|
||||
@@ -6771,6 +6882,29 @@ Xfrm=xfrm0</programlisting>
|
||||
This allows hardware based ipsec offloading to the <literal>eth0</literal> nic.
|
||||
If offloading is not needed, xfrm interfaces can be assigned to the <literal>lo</literal> device.
|
||||
</para>
|
||||
|
||||
</example>
|
||||
|
||||
<example>
|
||||
<title>Connecting to a cellular network with ModemManager</title>
|
||||
<programlisting># /etc/systemd/network/27-wwan0.network
|
||||
[Match]
|
||||
Name=wwan0
|
||||
|
||||
[Network]
|
||||
LLDP=no
|
||||
LinkLocalAddressing=no
|
||||
IPv6AcceptRA=no
|
||||
|
||||
[ModemManager]
|
||||
SimpleConnectProperties=apn=internet pin=1111
|
||||
RouteMetric=30
|
||||
UseGateway=yes</programlisting>
|
||||
|
||||
<para>This connects a cellular modem to a broadband network matched with the network interface <literal>wwan0</literal>,
|
||||
with APN name <literal>internet</literal>, SIM card pin unlock code <literal>1111</literal> and sets up a default
|
||||
gateway with route metric of 30.
|
||||
</para>
|
||||
</example>
|
||||
</refsect1>
|
||||
|
||||
|
||||
@@ -89,6 +89,8 @@ systemd_networkd_extract_sources = files(
|
||||
'networkd-util.c',
|
||||
'networkd-wifi.c',
|
||||
'networkd-wiphy.c',
|
||||
'networkd-wwan.c',
|
||||
'networkd-wwan-bus.c',
|
||||
'tc/cake.c',
|
||||
'tc/codel.c',
|
||||
'tc/drr.c',
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "networkd-route.h"
|
||||
#include "networkd-setlink.h"
|
||||
#include "networkd-state-file.h"
|
||||
#include "networkd-wwan.h"
|
||||
#include "parse-util.h"
|
||||
#include "set.h"
|
||||
#include "socket-util.h"
|
||||
@@ -1770,6 +1771,9 @@ int dhcp4_start_full(Link *link, bool set_ipv6_connectivity) {
|
||||
if (!link->dhcp_client)
|
||||
return 0;
|
||||
|
||||
if (link_dhcp_enabled_by_bearer(link, AF_INET) == 0)
|
||||
return 0;
|
||||
|
||||
if (!link_has_carrier(link))
|
||||
return 0;
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "networkd-queue.h"
|
||||
#include "networkd-route.h"
|
||||
#include "networkd-state-file.h"
|
||||
#include "networkd-wwan.h"
|
||||
#include "set.h"
|
||||
#include "string-table.h"
|
||||
#include "string-util.h"
|
||||
@@ -494,6 +495,9 @@ int dhcp6_start(Link *link) {
|
||||
if (!link_dhcp6_enabled(link))
|
||||
return 0;
|
||||
|
||||
if (link_dhcp_enabled_by_bearer(link, AF_INET6) == 0)
|
||||
return 0;
|
||||
|
||||
if (!link_has_carrier(link))
|
||||
return 0;
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "networkd-route.h"
|
||||
#include "networkd-route-util.h"
|
||||
#include "networkd-routing-policy-rule.h"
|
||||
#include "networkd-wwan.h"
|
||||
#include "ordered-set.h"
|
||||
#include "set.h"
|
||||
#include "string-util.h"
|
||||
@@ -541,6 +542,15 @@ static int dns_append_json(Link *link, sd_json_variant **v) {
|
||||
return r;
|
||||
}
|
||||
|
||||
Bearer *b;
|
||||
|
||||
if (link_get_bearer(link, &b) >= 0)
|
||||
FOREACH_ARRAY(dns, b->dns, b->n_dns) {
|
||||
r = dns_append_json_one(link, *dns, NETWORK_CONFIG_SOURCE_MODEM_MANAGER, NULL, &array);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (link->dhcp_lease && link_get_use_dns(link, NETWORK_CONFIG_SOURCE_DHCP4)) {
|
||||
const struct in_addr *dns;
|
||||
union in_addr_union s;
|
||||
|
||||
@@ -63,6 +63,7 @@
|
||||
#include "networkd-state-file.h"
|
||||
#include "networkd-sysctl.h"
|
||||
#include "networkd-wifi.h"
|
||||
#include "networkd-wwan-bus.h"
|
||||
#include "ordered-set.h"
|
||||
#include "parse-util.h"
|
||||
#include "set.h"
|
||||
@@ -529,6 +530,9 @@ void link_check_ready(Link *link) {
|
||||
if (!link->sr_iov_configured)
|
||||
return (void) log_link_debug(link, "%s(): SR-IOV is not configured.", __func__);
|
||||
|
||||
if (!link->bearer_configured)
|
||||
return (void) log_link_debug(link, "%s(): Bearer has not been applied.", __func__);
|
||||
|
||||
/* IPv6LL is assigned after the link gains its carrier. */
|
||||
if (!link->network->configure_without_carrier &&
|
||||
link_ipv6ll_enabled(link) &&
|
||||
@@ -538,7 +542,7 @@ void link_check_ready(Link *link) {
|
||||
/* All static addresses must be ready. */
|
||||
bool has_static_address = false;
|
||||
SET_FOREACH(a, link->addresses) {
|
||||
if (a->source != NETWORK_CONFIG_SOURCE_STATIC)
|
||||
if (!IN_SET(a->source, NETWORK_CONFIG_SOURCE_STATIC, NETWORK_CONFIG_SOURCE_MODEM_MANAGER))
|
||||
continue;
|
||||
if (!address_is_ready(a))
|
||||
return (void) log_link_debug(link, "%s(): static address %s is not ready.", __func__,
|
||||
@@ -1293,6 +1297,10 @@ static int link_configure(Link *link) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = link_modem_reconfigure(link);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!link_has_carrier(link))
|
||||
return 0;
|
||||
|
||||
|
||||
@@ -108,6 +108,7 @@ typedef struct Link {
|
||||
unsigned set_link_messages;
|
||||
unsigned set_flags_messages;
|
||||
unsigned create_stacked_netdev_messages;
|
||||
unsigned bearer_messages;
|
||||
|
||||
Set *addresses;
|
||||
Set *neighbors;
|
||||
@@ -141,6 +142,7 @@ typedef struct Link {
|
||||
bool master_set:1;
|
||||
bool stacked_netdevs_created:1;
|
||||
bool bridge_vlan_set:1;
|
||||
bool bearer_configured:1;
|
||||
|
||||
sd_dhcp_server *dhcp_server;
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
#include "networkd-state-file.h"
|
||||
#include "networkd-wifi.h"
|
||||
#include "networkd-wiphy.h"
|
||||
#include "networkd-wwan-bus.h"
|
||||
#include "ordered-set.h"
|
||||
#include "qdisc.h"
|
||||
#include "set.h"
|
||||
@@ -96,6 +97,8 @@ static int on_connected(sd_bus_message *message, void *userdata, sd_bus_error *r
|
||||
if (m->product_uuid_requested)
|
||||
(void) manager_request_product_uuid(m);
|
||||
|
||||
(void) manager_notify_mm_bus_connected(m);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -145,6 +148,8 @@ static int manager_connect_bus(Manager *m) {
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to request match for PrepareForSleep, ignoring: %m");
|
||||
|
||||
(void) manager_match_mm_signals(m);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -733,6 +738,9 @@ Manager* manager_free(Manager *m) {
|
||||
|
||||
set_free(m->rules);
|
||||
|
||||
sd_bus_slot_unref(m->slot_mm);
|
||||
hashmap_free(m->modems_by_path);
|
||||
|
||||
sd_netlink_unref(m->rtnl);
|
||||
sd_netlink_unref(m->genl);
|
||||
sd_netlink_unref(m->nfnl);
|
||||
|
||||
@@ -99,6 +99,10 @@ typedef struct Manager {
|
||||
Hashmap *wiphy_by_index;
|
||||
Hashmap *wiphy_by_name;
|
||||
|
||||
/* ModemManager support */
|
||||
sd_bus_slot *slot_mm;
|
||||
Hashmap *modems_by_path;
|
||||
|
||||
/* For link speed meter */
|
||||
bool use_speed_meter;
|
||||
sd_event_source *speed_meter_event_source;
|
||||
|
||||
@@ -40,6 +40,7 @@ _Pragma("GCC diagnostic ignored \"-Wzero-as-null-pointer-constant\"")
|
||||
#include "networkd-radv.h"
|
||||
#include "networkd-route.h"
|
||||
#include "networkd-routing-policy-rule.h"
|
||||
#include "networkd-wwan.h"
|
||||
#include "qdisc.h"
|
||||
#include "socket-util.h"
|
||||
#include "tclass.h"
|
||||
@@ -492,6 +493,9 @@ 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)
|
||||
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
|
||||
|
||||
@@ -512,6 +512,8 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
|
||||
|
||||
.ipoib_mode = _IP_OVER_INFINIBAND_MODE_INVALID,
|
||||
.ipoib_umcast = -1,
|
||||
|
||||
.mm_use_gateway = -1,
|
||||
};
|
||||
|
||||
r = config_parse_many_full(
|
||||
@@ -551,6 +553,7 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
|
||||
"LLDP\0"
|
||||
"TrafficControlQueueingDiscipline\0"
|
||||
"CAN\0"
|
||||
"ModemManager\0"
|
||||
"QDisc\0"
|
||||
"BFIFO\0"
|
||||
"CAKE\0"
|
||||
@@ -847,6 +850,9 @@ static Network *network_free(Network *network) {
|
||||
hashmap_free(network->qdiscs_by_section);
|
||||
hashmap_free(network->tclasses_by_section);
|
||||
|
||||
/* ModemManager */
|
||||
strv_free(network->mm_simple_connect_props);
|
||||
|
||||
return mfree(network);
|
||||
}
|
||||
|
||||
|
||||
@@ -414,6 +414,12 @@ typedef struct Network {
|
||||
|
||||
/* NTP */
|
||||
char **ntp;
|
||||
|
||||
/* ModemManager support */
|
||||
char **mm_simple_connect_props;
|
||||
int mm_use_gateway;
|
||||
uint32_t mm_route_metric;
|
||||
bool mm_route_metric_set;
|
||||
} Network;
|
||||
|
||||
DECLARE_TRIVIAL_REF_UNREF_FUNC(Network, network);
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "networkd-network.h"
|
||||
#include "networkd-ntp.h"
|
||||
#include "networkd-state-file.h"
|
||||
#include "networkd-wwan.h"
|
||||
#include "ordered-set.h"
|
||||
#include "set.h"
|
||||
#include "string-util.h"
|
||||
@@ -109,6 +110,14 @@ static int link_put_dns(Link *link, OrderedSet **s) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
Bearer *b;
|
||||
|
||||
if (link_get_bearer(link, &b) >= 0) {
|
||||
r = ordered_set_put_dns_servers(s, link->ifindex, b->dns, b->n_dns);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (link->dhcp_lease && link_get_use_dns(link, NETWORK_CONFIG_SOURCE_DHCP4)) {
|
||||
const struct in_addr *addresses;
|
||||
|
||||
@@ -801,6 +810,11 @@ static int link_save(Link *link) {
|
||||
space = false;
|
||||
link_save_dns(link, f, link->network->dns, link->network->n_dns, &space);
|
||||
|
||||
Bearer *b;
|
||||
|
||||
if (link_get_bearer(link, &b) >= 0)
|
||||
link_save_dns(link, f, b->dns, b->n_dns, &space);
|
||||
|
||||
/* DNR resolvers are not required to provide Do53 service, however resolved doesn't
|
||||
* know how to handle such a server so for now Do53 service is required, and
|
||||
* assumed. */
|
||||
|
||||
@@ -17,14 +17,15 @@
|
||||
|
||||
/* This is used in log messages, and never used in parsing settings. So, upper cases are OK. */
|
||||
static const char * const network_config_source_table[_NETWORK_CONFIG_SOURCE_MAX] = {
|
||||
[NETWORK_CONFIG_SOURCE_FOREIGN] = "foreign",
|
||||
[NETWORK_CONFIG_SOURCE_STATIC] = "static",
|
||||
[NETWORK_CONFIG_SOURCE_IPV4LL] = "IPv4LL",
|
||||
[NETWORK_CONFIG_SOURCE_DHCP4] = "DHCPv4",
|
||||
[NETWORK_CONFIG_SOURCE_DHCP6] = "DHCPv6",
|
||||
[NETWORK_CONFIG_SOURCE_DHCP_PD] = "DHCP-PD",
|
||||
[NETWORK_CONFIG_SOURCE_NDISC] = "NDisc",
|
||||
[NETWORK_CONFIG_SOURCE_RUNTIME] = "runtime",
|
||||
[NETWORK_CONFIG_SOURCE_FOREIGN] = "foreign",
|
||||
[NETWORK_CONFIG_SOURCE_STATIC] = "static",
|
||||
[NETWORK_CONFIG_SOURCE_IPV4LL] = "IPv4LL",
|
||||
[NETWORK_CONFIG_SOURCE_DHCP4] = "DHCPv4",
|
||||
[NETWORK_CONFIG_SOURCE_DHCP6] = "DHCPv6",
|
||||
[NETWORK_CONFIG_SOURCE_DHCP_PD] = "DHCP-PD",
|
||||
[NETWORK_CONFIG_SOURCE_NDISC] = "NDisc",
|
||||
[NETWORK_CONFIG_SOURCE_RUNTIME] = "runtime",
|
||||
[NETWORK_CONFIG_SOURCE_MODEM_MANAGER] = "ModemManager",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(network_config_source, NetworkConfigSource);
|
||||
|
||||
@@ -14,6 +14,7 @@ typedef enum NetworkConfigSource {
|
||||
NETWORK_CONFIG_SOURCE_DHCP_PD,
|
||||
NETWORK_CONFIG_SOURCE_NDISC,
|
||||
NETWORK_CONFIG_SOURCE_RUNTIME, /* through D-Bus method */
|
||||
NETWORK_CONFIG_SOURCE_MODEM_MANAGER,
|
||||
_NETWORK_CONFIG_SOURCE_MAX,
|
||||
_NETWORK_CONFIG_SOURCE_INVALID = -EINVAL,
|
||||
} NetworkConfigSource;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,88 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
typedef struct Manager Manager;
|
||||
typedef struct Link Link;
|
||||
|
||||
/* From ModemManager-enums.h */
|
||||
typedef enum {
|
||||
MM_BEARER_IP_FAMILY_NONE = 0,
|
||||
MM_BEARER_IP_FAMILY_IPV4 = 1 << 0,
|
||||
MM_BEARER_IP_FAMILY_IPV6 = 1 << 1,
|
||||
MM_BEARER_IP_FAMILY_IPV4V6 = 1 << 2,
|
||||
MM_BEARER_IP_FAMILY_ANY = 0xFFFFFFFF,
|
||||
} MMBearerIpFamily;
|
||||
|
||||
typedef enum {
|
||||
MM_BEARER_TYPE_UNKNOWN = 0,
|
||||
MM_BEARER_TYPE_DEFAULT = 1,
|
||||
MM_BEARER_TYPE_DEFAULT_ATTACH = 2,
|
||||
MM_BEARER_TYPE_DEDICATED = 3,
|
||||
} MMBearerType;
|
||||
|
||||
typedef enum {
|
||||
MM_MODEM_STATE_FAILED = -1,
|
||||
MM_MODEM_STATE_UNKNOWN = 0,
|
||||
MM_MODEM_STATE_INITIALIZING = 1,
|
||||
MM_MODEM_STATE_LOCKED = 2,
|
||||
MM_MODEM_STATE_DISABLED = 3,
|
||||
MM_MODEM_STATE_DISABLING = 4,
|
||||
MM_MODEM_STATE_ENABLING = 5,
|
||||
MM_MODEM_STATE_ENABLED = 6,
|
||||
MM_MODEM_STATE_SEARCHING = 7,
|
||||
MM_MODEM_STATE_REGISTERED = 8,
|
||||
MM_MODEM_STATE_DISCONNECTING = 9,
|
||||
MM_MODEM_STATE_CONNECTING = 10,
|
||||
MM_MODEM_STATE_CONNECTED = 11,
|
||||
} MMModemState;
|
||||
|
||||
typedef enum { /*< underscore_name=mm_modem_state_failed_reason >*/
|
||||
MM_MODEM_STATE_FAILED_REASON_NONE = 0,
|
||||
MM_MODEM_STATE_FAILED_REASON_UNKNOWN = 1,
|
||||
MM_MODEM_STATE_FAILED_REASON_SIM_MISSING = 2,
|
||||
MM_MODEM_STATE_FAILED_REASON_SIM_ERROR = 3,
|
||||
MM_MODEM_STATE_FAILED_REASON_UNKNOWN_CAPABILITIES = 4,
|
||||
MM_MODEM_STATE_FAILED_REASON_ESIM_WITHOUT_PROFILES = 5,
|
||||
__MM_MODEM_STATE_FAILED_REASON_MAX = 6,
|
||||
} MMModemStateFailedReason;
|
||||
|
||||
typedef enum {
|
||||
MM_BEARER_IP_METHOD_UNKNOWN = 0,
|
||||
MM_BEARER_IP_METHOD_PPP = 1,
|
||||
MM_BEARER_IP_METHOD_STATIC = 2,
|
||||
MM_BEARER_IP_METHOD_DHCP = 3,
|
||||
} MMBearerIpMethod;
|
||||
|
||||
typedef enum { /*< underscore_name=mm_modem_port_type >*/
|
||||
MM_MODEM_PORT_TYPE_UNKNOWN = 1,
|
||||
MM_MODEM_PORT_TYPE_NET = 2,
|
||||
MM_MODEM_PORT_TYPE_AT = 3,
|
||||
MM_MODEM_PORT_TYPE_QCDM = 4,
|
||||
MM_MODEM_PORT_TYPE_GPS = 5,
|
||||
MM_MODEM_PORT_TYPE_QMI = 6,
|
||||
MM_MODEM_PORT_TYPE_MBIM = 7,
|
||||
MM_MODEM_PORT_TYPE_AUDIO = 8,
|
||||
MM_MODEM_PORT_TYPE_IGNORED = 9,
|
||||
MM_MODEM_PORT_TYPE_XMMRPC = 10,
|
||||
} MMModemPortType;
|
||||
|
||||
typedef enum { /*< underscore_name=mm_bearer_allowed_auth >*/
|
||||
MM_BEARER_ALLOWED_AUTH_UNKNOWN = 0,
|
||||
/* bits 0..4 order match Ericsson device bitmap */
|
||||
MM_BEARER_ALLOWED_AUTH_NONE = 1 << 0,
|
||||
MM_BEARER_ALLOWED_AUTH_PAP = 1 << 1,
|
||||
MM_BEARER_ALLOWED_AUTH_CHAP = 1 << 2,
|
||||
MM_BEARER_ALLOWED_AUTH_MSCHAP = 1 << 3,
|
||||
MM_BEARER_ALLOWED_AUTH_MSCHAPV2 = 1 << 4,
|
||||
MM_BEARER_ALLOWED_AUTH_EAP = 1 << 5,
|
||||
} MMBearerAllowedAuth;
|
||||
|
||||
typedef enum {
|
||||
MODEM_RECONNECT_DONE, /* No reconnect is required, e.g. connected. */
|
||||
MODEM_RECONNECT_SCHEDULED, /* Reconnect is in progress. */
|
||||
MODEM_RECONNECT_WAITING, /* Waiting for modem to recover. */
|
||||
} ModemReconnectState;
|
||||
|
||||
int manager_notify_mm_bus_connected(Manager *manager);
|
||||
int manager_match_mm_signals(Manager *manager);
|
||||
int link_modem_reconfigure(Link *link);
|
||||
@@ -0,0 +1,641 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "bus-util.h"
|
||||
#include "hashmap.h"
|
||||
#include "networkd-address.h"
|
||||
#include "networkd-dhcp4.h"
|
||||
#include "networkd-dhcp6.h"
|
||||
#include "networkd-link.h"
|
||||
#include "networkd-setlink.h"
|
||||
#include "networkd-manager.h"
|
||||
#include "networkd-ndisc.h"
|
||||
#include "networkd-route.h"
|
||||
#include "networkd-wwan.h"
|
||||
#include "parse-util.h"
|
||||
#include "sd-dhcp-client.h"
|
||||
#include "sd-dhcp6-client.h"
|
||||
#include "sd-ndisc.h"
|
||||
#include "set.h"
|
||||
#include "string-util.h"
|
||||
|
||||
Bearer* bearer_free(Bearer *b) {
|
||||
if (!b)
|
||||
return NULL;
|
||||
|
||||
if (b->modem) {
|
||||
if (b->path)
|
||||
hashmap_remove_value(b->modem->bearers_by_path, b->path, b);
|
||||
if (b->name)
|
||||
hashmap_remove_value(b->modem->bearers_by_name, b->name, b);
|
||||
}
|
||||
|
||||
sd_bus_slot_unref(b->slot_getall);
|
||||
|
||||
free(b->path);
|
||||
free(b->name);
|
||||
free(b->apn);
|
||||
|
||||
in_addr_full_array_free(b->dns, b->n_dns);
|
||||
|
||||
return mfree(b);
|
||||
}
|
||||
|
||||
DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
|
||||
bearer_hash_ops,
|
||||
char,
|
||||
string_hash_func,
|
||||
string_compare_func,
|
||||
Bearer,
|
||||
bearer_free);
|
||||
|
||||
int bearer_new(Modem *modem, const char *path, Bearer **ret) {
|
||||
_cleanup_(bearer_freep) Bearer *b = NULL;
|
||||
_cleanup_free_ char *p = NULL;
|
||||
int r;
|
||||
|
||||
assert(modem);
|
||||
assert(path);
|
||||
|
||||
if (hashmap_contains(modem->bearers_by_path, path))
|
||||
return -EEXIST;
|
||||
|
||||
p = strdup(path);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
b = new(Bearer, 1);
|
||||
if (!b)
|
||||
return -ENOMEM;
|
||||
|
||||
*b = (Bearer) {
|
||||
.modem = modem,
|
||||
.path = TAKE_PTR(p),
|
||||
};
|
||||
|
||||
r = hashmap_ensure_put(&modem->bearers_by_path, &bearer_hash_ops, b->path, b);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (ret)
|
||||
*ret = b;
|
||||
TAKE_PTR(b);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bearer_set_name(Bearer *b, const char *name) {
|
||||
Bearer *old;
|
||||
int r;
|
||||
|
||||
assert(b);
|
||||
assert(b->modem);
|
||||
assert(name);
|
||||
|
||||
if (streq_ptr(b->name, name))
|
||||
return 0;
|
||||
|
||||
if (b->name)
|
||||
hashmap_remove_value(b->modem->bearers_by_name, b->name, b);
|
||||
|
||||
if (isempty(name)) {
|
||||
b->name = mfree(b->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = free_and_strdup(&b->name, name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/*
|
||||
* FIXME: it is possible during reconnect that an interface is already
|
||||
* registered in the hash map: if simple connect options
|
||||
* are changed, e.g. externally modified .network file and then
|
||||
* reloaded with 'networkctl reload'. This may create a new bearer
|
||||
* attached to the same inerface name, e.g. "wwan0". The order in which
|
||||
* we parse the bearer properties is undetermined and it can be that we
|
||||
* need to raplce the old one with the new one now, so only one bearer
|
||||
* with the given interface name exists.
|
||||
*/
|
||||
old = hashmap_get(b->modem->bearers_by_name, name);
|
||||
if (old) {
|
||||
hashmap_remove_value(old->modem->bearers_by_name, name, old);
|
||||
old->name = mfree(old->name);
|
||||
}
|
||||
|
||||
return hashmap_ensure_put(&b->modem->bearers_by_name, &bearer_hash_ops, b->name, b);
|
||||
}
|
||||
|
||||
int bearer_get_by_path(Manager *manager, const char *path, Modem **ret_modem, Bearer **ret_bearer) {
|
||||
Modem *modem;
|
||||
Bearer *b;
|
||||
|
||||
assert(manager);
|
||||
assert(path);
|
||||
|
||||
HASHMAP_FOREACH(modem, manager->modems_by_path) {
|
||||
b = hashmap_get(modem->bearers_by_path, path);
|
||||
if (!b)
|
||||
continue;
|
||||
|
||||
if (ret_bearer)
|
||||
*ret_bearer = b;
|
||||
if (ret_modem)
|
||||
*ret_modem = modem;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
Modem* modem_free(Modem *modem) {
|
||||
if (!modem)
|
||||
return NULL;
|
||||
|
||||
if (modem->bearers_by_name)
|
||||
hashmap_free(modem->bearers_by_name);
|
||||
|
||||
if (modem->bearers_by_path)
|
||||
hashmap_free(modem->bearers_by_path);
|
||||
|
||||
if (modem->manager)
|
||||
hashmap_remove_value(modem->manager->modems_by_path, modem->path, modem);
|
||||
|
||||
sd_bus_slot_unref(modem->slot_propertieschanged);
|
||||
sd_bus_slot_unref(modem->slot_statechanged);
|
||||
sd_bus_slot_unref(modem->slot_connect);
|
||||
|
||||
free(modem->path);
|
||||
free(modem->manufacturer);
|
||||
free(modem->model);
|
||||
free(modem->port_name);
|
||||
|
||||
return mfree(modem);
|
||||
}
|
||||
|
||||
DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
|
||||
modems_hash_ops,
|
||||
char,
|
||||
string_hash_func,
|
||||
string_compare_func,
|
||||
Modem,
|
||||
modem_free);
|
||||
|
||||
int modem_new(Manager *m, const char *path, Modem **ret) {
|
||||
_cleanup_(modem_freep) Modem *modem = NULL;
|
||||
_cleanup_free_ char *p = NULL;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(path);
|
||||
|
||||
if (hashmap_contains(m->modems_by_path, path))
|
||||
return -EEXIST;
|
||||
|
||||
p = strdup(path);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
modem = new(Modem, 1);
|
||||
if (!modem)
|
||||
return -ENOMEM;
|
||||
|
||||
*modem = (Modem) {
|
||||
.manager = m,
|
||||
.path = TAKE_PTR(p),
|
||||
};
|
||||
|
||||
r = hashmap_ensure_put(&m->modems_by_path, &modems_hash_ops, modem->path, modem);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (ret)
|
||||
*ret = modem;
|
||||
|
||||
TAKE_PTR(modem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int modem_get_by_path(Manager *m, const char *path, Modem **ret) {
|
||||
Modem *modem;
|
||||
|
||||
assert(m);
|
||||
assert(path);
|
||||
|
||||
modem = hashmap_get(m->modems_by_path, path);
|
||||
if (!modem)
|
||||
return -ENOENT;
|
||||
|
||||
if (ret)
|
||||
*ret = modem;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int link_get_modem(Link *link, Modem **ret) {
|
||||
Modem *modem;
|
||||
|
||||
assert(link);
|
||||
assert(link->manager);
|
||||
assert(link->ifname);
|
||||
|
||||
HASHMAP_FOREACH(modem, link->manager->modems_by_path)
|
||||
if (modem->port_name && streq(modem->port_name, link->ifname)) {
|
||||
*ret = modem;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
int link_get_bearer(Link *link, Bearer **ret) {
|
||||
Modem *modem;
|
||||
|
||||
assert(link);
|
||||
assert(link->manager);
|
||||
assert(link->ifname);
|
||||
|
||||
HASHMAP_FOREACH(modem, link->manager->modems_by_path) {
|
||||
Bearer *b;
|
||||
|
||||
b = hashmap_get(modem->bearers_by_name, link->ifname);
|
||||
if (!b)
|
||||
continue;
|
||||
|
||||
if (ret)
|
||||
*ret = b;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
int link_dhcp_enabled_by_bearer(Link *link, int family) {
|
||||
Bearer *b;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(IN_SET(family, AF_INET, AF_INET6));
|
||||
|
||||
r = link_get_bearer(link, &b);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!b->connected)
|
||||
return false;
|
||||
|
||||
if (!FLAGS_SET(b->ip_type, family == AF_INET ? ADDRESS_FAMILY_IPV4 : ADDRESS_FAMILY_IPV6))
|
||||
return false;
|
||||
|
||||
return (family == AF_INET ? b->ip4_method : b->ip6_method) == MM_BEARER_IP_METHOD_DHCP;
|
||||
}
|
||||
|
||||
static int bearer_address_handler(
|
||||
sd_netlink *rtnl,
|
||||
sd_netlink_message *m,
|
||||
Request *req,
|
||||
Link *link,
|
||||
Address *address) {
|
||||
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
|
||||
r = address_configure_handler_internal(m, link, address);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
if (link->bearer_messages == 0) {
|
||||
link->bearer_configured = true;
|
||||
link_check_ready(link);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int link_request_bearer_address(
|
||||
Link *link,
|
||||
int family,
|
||||
const union in_addr_union *addr,
|
||||
unsigned prefixlen) {
|
||||
|
||||
_cleanup_(address_unrefp) Address *address = NULL;
|
||||
Address *existing;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(IN_SET(family, AF_INET, AF_INET6));
|
||||
assert(addr);
|
||||
|
||||
if (!in_addr_is_set(family, addr))
|
||||
return 0;
|
||||
|
||||
r = address_new(&address);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
address->source = NETWORK_CONFIG_SOURCE_MODEM_MANAGER;
|
||||
address->family = family;
|
||||
address->in_addr = *addr;
|
||||
address->prefixlen = prefixlen;
|
||||
|
||||
if (address_get(link, address, &existing) < 0) /* The address is new. */
|
||||
link->bearer_configured = false;
|
||||
else
|
||||
address_unmark(existing);
|
||||
|
||||
r = link_request_address(link, address, &link->bearer_messages,
|
||||
bearer_address_handler, /* ret = */ NULL);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "Failed to request address provided by bearer: %m");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bearer_route_handler(
|
||||
sd_netlink *rtnl,
|
||||
sd_netlink_message *m,
|
||||
Request *req,
|
||||
Link *link,
|
||||
Route *route) {
|
||||
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
|
||||
r = route_configure_handler_internal(m, req, route);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
if (link->bearer_messages == 0) {
|
||||
link->bearer_configured = true;
|
||||
link_check_ready(link);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int link_request_bearer_route(
|
||||
Link *link,
|
||||
int family,
|
||||
const union in_addr_union *gw,
|
||||
const union in_addr_union *prefsrc) {
|
||||
|
||||
_cleanup_(route_unrefp) Route *route = NULL;
|
||||
Route *existing;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(IN_SET(family, AF_INET, AF_INET6));
|
||||
assert(gw);
|
||||
assert(prefsrc);
|
||||
|
||||
if (!in_addr_is_set(family, gw))
|
||||
return 0;
|
||||
|
||||
if (link->network->mm_use_gateway == 0)
|
||||
return 0;
|
||||
|
||||
r = route_new(&route);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
route->source = NETWORK_CONFIG_SOURCE_MODEM_MANAGER;
|
||||
route->family = family;
|
||||
route->nexthop.family = family;
|
||||
route->nexthop.gw = *gw;
|
||||
if (link->network->mm_route_metric_set) {
|
||||
route->priority = link->network->mm_route_metric;
|
||||
route->priority_set = true;
|
||||
}
|
||||
|
||||
if (prefsrc)
|
||||
route->prefsrc = *prefsrc;
|
||||
|
||||
if (route_get(link->manager, route, &existing) < 0) /* This is a new route. */
|
||||
link->bearer_configured = false;
|
||||
else
|
||||
route_unmark(existing);
|
||||
|
||||
r = link_request_route(link, route, &link->bearer_messages, bearer_route_handler);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "Failed to request gateway provided by bearer: %m");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int link_apply_bearer_impl(Link *link, Bearer *b) {
|
||||
Address *address;
|
||||
Route *route;
|
||||
int r, ret = 0;
|
||||
|
||||
assert(link);
|
||||
|
||||
if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
|
||||
return 0;
|
||||
|
||||
/* First, mark bearer configs. */
|
||||
SET_FOREACH(address, link->addresses) {
|
||||
if (address->source != NETWORK_CONFIG_SOURCE_MODEM_MANAGER)
|
||||
continue;
|
||||
|
||||
address_mark(address);
|
||||
}
|
||||
|
||||
SET_FOREACH(route, link->manager->routes) {
|
||||
if (route->source != NETWORK_CONFIG_SOURCE_MODEM_MANAGER)
|
||||
continue;
|
||||
|
||||
route_mark(route);
|
||||
}
|
||||
|
||||
if (b && FLAGS_SET(b->ip_type, ADDRESS_FAMILY_IPV4)) {
|
||||
if (b->connected && b->ip4_method == MM_BEARER_IP_METHOD_STATIC) {
|
||||
r = link_request_bearer_address(link, AF_INET, &b->ip4_address, b->ip4_prefixlen);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = link_request_bearer_route(link, AF_INET, &b->ip4_gateway, &b->ip4_address);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (b->connected && b->ip4_method == MM_BEARER_IP_METHOD_DHCP) {
|
||||
if (!link_dhcp4_enabled(link))
|
||||
log_link_notice(link, "The WWAN connection requested DHCPv4 client, but it is disabled.");
|
||||
|
||||
r = dhcp4_start(link);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "Failed to start DHCPv4 client: %m");
|
||||
} else {
|
||||
r = sd_dhcp_client_stop(link->dhcp_client);
|
||||
if (r < 0)
|
||||
ret = log_link_warning_errno(link, r, "Could not stop DHCPv4 client: %m");
|
||||
}
|
||||
}
|
||||
|
||||
if (b && FLAGS_SET(b->ip_type, ADDRESS_FAMILY_IPV6)) {
|
||||
if (b->connected && b->ip6_method == MM_BEARER_IP_METHOD_STATIC) {
|
||||
r = link_request_bearer_address(link, AF_INET6, &b->ip6_address, b->ip6_prefixlen);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = link_request_bearer_route(link, AF_INET6, &b->ip6_gateway, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (b->connected && b->ip6_method == MM_BEARER_IP_METHOD_DHCP) {
|
||||
if (!link_ndisc_enabled(link) && !link_dhcp6_enabled(link))
|
||||
log_link_notice(link,
|
||||
"The WWAN connection requested IPv6 dynamic address configuration,"
|
||||
"but both IPv6 Router Discovery and DHCPv6 client are disabled.");
|
||||
|
||||
r = ndisc_start(link);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "Failed to start IPv6 Router Discovery: %m");
|
||||
|
||||
r = dhcp6_start(link);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "Failed to start DHCPv6 client: %m");
|
||||
} else {
|
||||
r = sd_dhcp6_client_stop(link->dhcp6_client);
|
||||
if (r < 0)
|
||||
ret = log_link_warning_errno(link, r, "Could not stop DHCPv6 client: %m");
|
||||
|
||||
r = sd_ndisc_stop(link->ndisc);
|
||||
if (r < 0)
|
||||
ret = log_link_warning_errno(link, r, "Could not stop IPv6 Router Discovery: %m");
|
||||
}
|
||||
}
|
||||
|
||||
/* Finally, remove all marked configs. */
|
||||
SET_FOREACH(address, link->addresses) {
|
||||
if (address->source != NETWORK_CONFIG_SOURCE_MODEM_MANAGER)
|
||||
continue;
|
||||
|
||||
if (!address_is_marked(address))
|
||||
continue;
|
||||
|
||||
r = address_remove(address, link);
|
||||
if (r < 0)
|
||||
ret = r;
|
||||
}
|
||||
|
||||
SET_FOREACH(route, link->manager->routes) {
|
||||
if (route->source != NETWORK_CONFIG_SOURCE_MODEM_MANAGER)
|
||||
continue;
|
||||
|
||||
if (!route_is_marked(route))
|
||||
continue;
|
||||
|
||||
r = route_remove(route, link->manager);
|
||||
if (ret)
|
||||
ret = r;
|
||||
}
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (link->bearer_messages == 0)
|
||||
link->bearer_configured = true;
|
||||
|
||||
if (!link->bearer_configured)
|
||||
link_set_state(link, LINK_STATE_CONFIGURING);
|
||||
|
||||
link_check_ready(link);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int link_apply_bearer(Link *link) {
|
||||
Bearer *b = NULL;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
|
||||
(void) link_get_bearer(link, &b);
|
||||
|
||||
r = link_apply_bearer_impl(link, b);
|
||||
if (r < 0)
|
||||
link_enter_failed(link);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int bearer_update_link(Bearer *b) {
|
||||
Link *link;
|
||||
int r;
|
||||
|
||||
assert(b);
|
||||
assert(b->modem);
|
||||
assert(b->modem->manager);
|
||||
|
||||
if (!b->name)
|
||||
return 0;
|
||||
|
||||
if (link_get_by_name(b->modem->manager, b->name, &link) < 0)
|
||||
return 0;
|
||||
|
||||
r = link_apply_bearer_impl(link, b);
|
||||
if (r < 0)
|
||||
link_enter_failed(link);
|
||||
|
||||
/*
|
||||
* Need to bring up the interface after the modem has connected.
|
||||
* This is because ModemManger does the following while connecting:
|
||||
* <msg> [1755871777.322239] [modem2] state changed (registered -> connecting)
|
||||
* <dbg> [1755871777.325012] [modem2/bearer5] launching connection with QMI port (cdc-wdm0) and data port (wwan0) (multiplex none)
|
||||
* <dbg> [1755871777.327665] [cdc-wdm0/qmi] bringing down data interface 'wwan0'
|
||||
* <dbg> [1755871777.330108] [modem2/wwan0/net] interface index: 9
|
||||
* <dbg> [1755871777.335265] [cdc-wdm0/qmi] deleting all links in data interface 'wwan0'
|
||||
*/
|
||||
|
||||
r = link_request_to_bring_up_or_down(link, b->connected);
|
||||
if (r < 0)
|
||||
link_enter_failed(link);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void bearer_drop(Bearer *b) {
|
||||
assert(b);
|
||||
|
||||
b->connected = false;
|
||||
b->apn = mfree(b->apn);
|
||||
|
||||
(void) bearer_update_link(b);
|
||||
|
||||
bearer_free(b);
|
||||
}
|
||||
|
||||
int config_parse_mm_route_metric(
|
||||
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) {
|
||||
|
||||
Network *network = userdata;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
|
||||
if (isempty(rvalue)) {
|
||||
network->mm_route_metric_set = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = safe_atou32(rvalue, &network->mm_route_metric);
|
||||
if (r < 0)
|
||||
return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
|
||||
|
||||
network->mm_route_metric_set = true;
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include "conf-parser-forward.h"
|
||||
#include "in-addr-util.h"
|
||||
#include "network-util.h"
|
||||
#include "networkd-wwan-bus.h"
|
||||
|
||||
typedef struct Modem Modem;
|
||||
|
||||
typedef struct Bearer {
|
||||
Modem *modem;
|
||||
|
||||
sd_bus_slot *slot_getall; /* for GetAll method */
|
||||
|
||||
char *path; /* DBus path e.g /org/freedesktop/ModemManager/Bearer/0 */
|
||||
char *name; /* Interface property, e.g. wwan0 */
|
||||
char *apn; /* "apn" field in Properties */
|
||||
AddressFamily ip_type; /* "ip-type" field in Properties */
|
||||
|
||||
/* Ip4Config or IP6Config property */
|
||||
MMBearerIpMethod ip4_method;
|
||||
MMBearerIpMethod ip6_method;
|
||||
unsigned ip4_prefixlen;
|
||||
unsigned ip6_prefixlen;
|
||||
union in_addr_union ip4_address;
|
||||
union in_addr_union ip6_address;
|
||||
union in_addr_union ip4_gateway;
|
||||
union in_addr_union ip6_gateway;
|
||||
struct in_addr_full **dns;
|
||||
size_t n_dns;
|
||||
uint32_t ip4_mtu;
|
||||
uint32_t ip6_mtu;
|
||||
|
||||
bool connected; /* Connected property */
|
||||
} Bearer;
|
||||
|
||||
typedef struct Modem {
|
||||
Manager *manager;
|
||||
|
||||
sd_bus_slot *slot_propertieschanged;
|
||||
sd_bus_slot *slot_statechanged;
|
||||
sd_bus_slot *slot_connect;
|
||||
|
||||
char *path; /* DBus path e.g /org/freedesktop/ModemManager/Modem/0 */
|
||||
char *manufacturer; /* The "Manufacturer" property */
|
||||
char *model; /* The "Model" property */
|
||||
char *port_name; /* MM_MODEM_PORT_TYPE_NET of Ports property */
|
||||
|
||||
Hashmap *bearers_by_path;
|
||||
Hashmap *bearers_by_name;
|
||||
|
||||
MMModemState state;
|
||||
MMModemStateFailedReason state_fail_reason;
|
||||
ModemReconnectState reconnect_state;
|
||||
} Modem;
|
||||
|
||||
int bearer_new(Modem *modem, const char *path, Bearer **ret);
|
||||
Bearer* bearer_free(Bearer *b);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(Bearer*, bearer_free);
|
||||
|
||||
int bearer_set_name(Bearer *b, const char *name);
|
||||
|
||||
int bearer_get_by_path(Manager *manager, const char *path, Modem **ret_modem, Bearer **ret_bearer);
|
||||
int link_get_bearer(Link *link, Bearer **ret);
|
||||
|
||||
int link_dhcp_enabled_by_bearer(Link *link, int family);
|
||||
|
||||
int link_apply_bearer(Link *link);
|
||||
int bearer_update_link(Bearer *b);
|
||||
void bearer_drop(Bearer *b);
|
||||
|
||||
int modem_new(Manager *m, const char *path, Modem **ret);
|
||||
Modem* modem_free(Modem *modem);
|
||||
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_route_metric);
|
||||
@@ -573,3 +573,4 @@ loader.conf.xml ./refsect1[title="Options"]/variablelist/varlistentry[term="rebo
|
||||
loader.conf.xml ./refsect1[title="Options"]/variablelist/varlistentry[term="secure-boot-enroll-action"]/listitem/variablelist/varlistentry[term="reboot"]
|
||||
loader.conf.xml ./refsect1[title="Options"]/variablelist/varlistentry[term="secure-boot-enroll-action"]/listitem/variablelist/varlistentry[term="shutdown"]
|
||||
varlinkctl.xml ./refsect1[title="Options"]/variablelist/varlistentry[term="--system"]
|
||||
systemd.network.xml ./refsect1[title="[ModemManager] Section Options"]/variablelist/varlistentry[term="SimpleConnectProperties="]
|
||||
|
||||
Reference in New Issue
Block a user