From c3012c1de6e6b73f691ff9e851c7ce3852849691 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Mon, 9 Sep 2019 19:48:24 +0200 Subject: [PATCH 1/8] core/connection: drop some unused parameters --- libnm-core/nm-connection.c | 60 +++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/libnm-core/nm-connection.c b/libnm-core/nm-connection.c index 2c69d2a998..c78e468d71 100644 --- a/libnm-core/nm-connection.c +++ b/libnm-core/nm-connection.c @@ -1041,7 +1041,7 @@ _normalize_ip_config (NMConnection *self, GHashTable *parameters) } static gboolean -_normalize_infiniband_mtu (NMConnection *self, GHashTable *parameters) +_normalize_infiniband_mtu (NMConnection *self) { NMSettingInfiniband *s_infini = nm_connection_get_setting_infiniband (self); @@ -1056,7 +1056,7 @@ _normalize_infiniband_mtu (NMConnection *self, GHashTable *parameters) } static gboolean -_normalize_bond_mode (NMConnection *self, GHashTable *parameters) +_normalize_bond_mode (NMConnection *self) { NMSettingBond *s_bond = nm_connection_get_setting_bond (self); @@ -1077,7 +1077,7 @@ _normalize_bond_mode (NMConnection *self, GHashTable *parameters) } static gboolean -_normalize_bond_options (NMConnection *self, GHashTable *parameters) +_normalize_bond_options (NMConnection *self) { NMSettingBond *s_bond = nm_connection_get_setting_bond (self); gboolean changed = FALSE; @@ -1107,7 +1107,7 @@ again: } static gboolean -_normalize_wireless_mac_address_randomization (NMConnection *self, GHashTable *parameters) +_normalize_wireless_mac_address_randomization (NMConnection *self) { NMSettingWireless *s_wifi = nm_connection_get_setting_wireless (self); const char *cloned_mac_address; @@ -1153,7 +1153,7 @@ _normalize_wireless_mac_address_randomization (NMConnection *self, GHashTable *p } static gboolean -_normalize_macsec (NMConnection *self, GHashTable *parameters) +_normalize_macsec (NMConnection *self) { NMSettingMacsec *s_macsec = nm_connection_get_setting_macsec (self); gboolean changed = FALSE; @@ -1176,7 +1176,7 @@ _normalize_macsec (NMConnection *self, GHashTable *parameters) } static gboolean -_normalize_team_config (NMConnection *self, GHashTable *parameters) +_normalize_team_config (NMConnection *self) { NMSettingTeam *s_team = nm_connection_get_setting_team (self); @@ -1192,7 +1192,7 @@ _normalize_team_config (NMConnection *self, GHashTable *parameters) } static gboolean -_normalize_team_port_config (NMConnection *self, GHashTable *parameters) +_normalize_team_port_config (NMConnection *self) { NMSettingTeamPort *s_team_port = nm_connection_get_setting_team_port (self); @@ -1208,7 +1208,7 @@ _normalize_team_port_config (NMConnection *self, GHashTable *parameters) } static gboolean -_normalize_bluetooth_type (NMConnection *self, GHashTable *parameters) +_normalize_bluetooth_type (NMConnection *self) { const char *type = _nm_connection_detect_bluetooth_type (self); @@ -1222,7 +1222,7 @@ _normalize_bluetooth_type (NMConnection *self, GHashTable *parameters) } static gboolean -_normalize_ovs_interface_type (NMConnection *self, GHashTable *parameters) +_normalize_ovs_interface_type (NMConnection *self) { NMSettingOvsInterface *s_ovs_interface = nm_connection_get_setting_ovs_interface (self); gboolean modified; @@ -1243,7 +1243,7 @@ _normalize_ovs_interface_type (NMConnection *self, GHashTable *parameters) } static gboolean -_normalize_ip_tunnel_wired_setting (NMConnection *self, GHashTable *parameters) +_normalize_ip_tunnel_wired_setting (NMConnection *self) { NMSettingIPTunnel *s_ip_tunnel; @@ -1263,7 +1263,7 @@ _normalize_ip_tunnel_wired_setting (NMConnection *self, GHashTable *parameters) } static gboolean -_normalize_sriov_vf_order (NMConnection *self, GHashTable *parameters) +_normalize_sriov_vf_order (NMConnection *self) { NMSettingSriov *s_sriov; @@ -1275,7 +1275,7 @@ _normalize_sriov_vf_order (NMConnection *self, GHashTable *parameters) } static gboolean -_normalize_bridge_vlan_order (NMConnection *self, GHashTable *parameters) +_normalize_bridge_vlan_order (NMConnection *self) { NMSettingBridge *s_bridge; @@ -1287,7 +1287,7 @@ _normalize_bridge_vlan_order (NMConnection *self, GHashTable *parameters) } static gboolean -_normalize_bridge_port_vlan_order (NMConnection *self, GHashTable *parameters) +_normalize_bridge_port_vlan_order (NMConnection *self) { NMSettingBridgePort *s_port; @@ -1299,7 +1299,7 @@ _normalize_bridge_port_vlan_order (NMConnection *self, GHashTable *parameters) } static gboolean -_normalize_required_settings (NMConnection *self, GHashTable *parameters) +_normalize_required_settings (NMConnection *self) { NMSettingBluetooth *s_bt = nm_connection_get_setting_bluetooth (self); NMSetting *s_bridge; @@ -1323,7 +1323,7 @@ _normalize_required_settings (NMConnection *self, GHashTable *parameters) } static gboolean -_normalize_invalid_slave_port_settings (NMConnection *self, GHashTable *parameters) +_normalize_invalid_slave_port_settings (NMConnection *self) { NMSettingConnection *s_con = nm_connection_get_setting_connection (self); const char *slave_type; @@ -1597,23 +1597,23 @@ _connection_normalize (NMConnection *connection, was_modified |= _normalize_connection_uuid (connection); was_modified |= _normalize_connection_type (connection); was_modified |= _normalize_connection_slave_type (connection); - was_modified |= _normalize_required_settings (connection, parameters); - was_modified |= _normalize_invalid_slave_port_settings (connection, parameters); + was_modified |= _normalize_required_settings (connection); + was_modified |= _normalize_invalid_slave_port_settings (connection); was_modified |= _normalize_ip_config (connection, parameters); was_modified |= _normalize_ethernet_link_neg (connection); - was_modified |= _normalize_infiniband_mtu (connection, parameters); - was_modified |= _normalize_bond_mode (connection, parameters); - was_modified |= _normalize_bond_options (connection, parameters); - was_modified |= _normalize_wireless_mac_address_randomization (connection, parameters); - was_modified |= _normalize_macsec (connection, parameters); - was_modified |= _normalize_team_config (connection, parameters); - was_modified |= _normalize_team_port_config (connection, parameters); - was_modified |= _normalize_bluetooth_type (connection, parameters); - was_modified |= _normalize_ovs_interface_type (connection, parameters); - was_modified |= _normalize_ip_tunnel_wired_setting (connection, parameters); - was_modified |= _normalize_sriov_vf_order (connection, parameters); - was_modified |= _normalize_bridge_vlan_order (connection, parameters); - was_modified |= _normalize_bridge_port_vlan_order (connection, parameters); + was_modified |= _normalize_infiniband_mtu (connection); + was_modified |= _normalize_bond_mode (connection); + was_modified |= _normalize_bond_options (connection); + was_modified |= _normalize_wireless_mac_address_randomization (connection); + was_modified |= _normalize_macsec (connection); + was_modified |= _normalize_team_config (connection); + was_modified |= _normalize_team_port_config (connection); + was_modified |= _normalize_bluetooth_type (connection); + was_modified |= _normalize_ovs_interface_type (connection); + was_modified |= _normalize_ip_tunnel_wired_setting (connection); + was_modified |= _normalize_sriov_vf_order (connection); + was_modified |= _normalize_bridge_vlan_order (connection); + was_modified |= _normalize_bridge_port_vlan_order (connection); was_modified = !!was_modified; From 0eb4a5dfa7afeba706649a2b6f6cd579fc30a683 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Mon, 9 Sep 2019 20:22:19 +0200 Subject: [PATCH 2/8] setting-gsm: add auto-config property This will make NetworkManager look up APN, username, and password in the Mobile Broadband Provider database. It is mutually exclusive with the apn, username and password properties. If that is the case, the connection will be normalized to auto-config=false. This makes it convenient for the user to turn off the automatism by just setting the apn. --- clients/common/nm-meta-setting-desc.c | 3 ++ clients/common/settings-docs.h.in | 1 + .../test_003.expected | 10 ++-- libnm-core/nm-connection.c | 24 +++++++++ libnm-core/nm-setting-gsm.c | 50 +++++++++++++++++++ libnm-core/nm-setting-gsm.h | 5 ++ libnm/libnm.ver | 5 ++ 7 files changed, 94 insertions(+), 4 deletions(-) diff --git a/clients/common/nm-meta-setting-desc.c b/clients/common/nm-meta-setting-desc.c index 6451fe3378..40faa485ed 100644 --- a/clients/common/nm-meta-setting-desc.c +++ b/clients/common/nm-meta-setting-desc.c @@ -5365,6 +5365,9 @@ static const NMMetaPropertyInfo *const property_infos_ETHTOOL[] = { #undef _CURRENT_NM_META_SETTING_TYPE #define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_GSM static const NMMetaPropertyInfo *const property_infos_GSM[] = { + PROPERTY_INFO_WITH_DESC (NM_SETTING_GSM_AUTO_CONFIG, + .property_type = &_pt_gobject_bool, + ), PROPERTY_INFO_WITH_DESC (NM_SETTING_GSM_NUMBER, .property_type = &_pt_gobject_string, ), diff --git a/clients/common/settings-docs.h.in b/clients/common/settings-docs.h.in index d49331993b..518381077b 100644 --- a/clients/common/settings-docs.h.in +++ b/clients/common/settings-docs.h.in @@ -170,6 +170,7 @@ #define DESCRIBE_DOC_NM_SETTING_DCB_PRIORITY_STRICT_BANDWIDTH N_("An array of 8 boolean values, where the array index corresponds to the User Priority (0 - 7) and the value indicates whether or not the priority may use all of the bandwidth allocated to its assigned group.") #define DESCRIBE_DOC_NM_SETTING_DCB_PRIORITY_TRAFFIC_CLASS N_("An array of 8 uint values, where the array index corresponds to the User Priority (0 - 7) and the value indicates the traffic class (0 - 7) to which the priority is mapped.") #define DESCRIBE_DOC_NM_SETTING_GSM_APN N_("The GPRS Access Point Name specifying the APN used when establishing a data session with the GSM-based network. The APN often determines how the user will be billed for their network usage and whether the user has access to the Internet or just a provider-specific walled-garden, so it is important to use the correct APN for the user's mobile broadband plan. The APN may only be composed of the characters a-z, 0-9, ., and - per GSM 03.60 Section 14.9.") +#define DESCRIBE_DOC_NM_SETTING_GSM_AUTO_CONFIG N_("When TRUE, the settings such as APN, username, or password will default to values that match the network the modem will register to in the Mobile Broadband Provider database.") #define DESCRIBE_DOC_NM_SETTING_GSM_DEVICE_ID N_("The device unique identifier (as given by the WWAN management service) which this connection applies to. If given, the connection will only apply to the specified device.") #define DESCRIBE_DOC_NM_SETTING_GSM_HOME_ONLY N_("When TRUE, only connections to the home network will be allowed. Connections to roaming networks will not be made.") #define DESCRIBE_DOC_NM_SETTING_GSM_MTU N_("If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple frames.") diff --git a/clients/tests/test-client.check-on-disk/test_003.expected b/clients/tests/test-client.check-on-disk/test_003.expected index c8cb4903b5..8bffc5b126 100644 --- a/clients/tests/test-client.check-on-disk/test_003.expected +++ b/clients/tests/test-client.check-on-disk/test_003.expected @@ -150,12 +150,12 @@ id path uuid <<< -size: 4116 +size: 4159 location: clients/tests/test-client.py:911:test_003()/12 cmd: $NMCLI con s con-gsm1 lang: C returncode: 0 -stdout: 3982 bytes +stdout: 4025 bytes >>> connection.id: con-gsm1 connection.uuid: UUID-con-gsm1-REPLACED-REPLACED-REPL @@ -228,6 +228,7 @@ serial.bits: 8 serial.parity: even serial.stopbits: 1 serial.send-delay: 100 +gsm.auto-config: no gsm.number: -- gsm.username: -- gsm.password: @@ -247,12 +248,12 @@ proxy.pac-url: -- proxy.pac-script: -- <<< -size: 4145 +size: 4189 location: clients/tests/test-client.py:911:test_003()/13 cmd: $NMCLI con s con-gsm1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 4001 bytes +stdout: 4045 bytes >>> connection.id: con-gsm1 connection.uuid: UUID-con-gsm1-REPLACED-REPLACED-REPL @@ -325,6 +326,7 @@ serial.bits: 8 serial.parity: even serial.stopbits: 1 serial.send-delay: 100 +gsm.auto-config: nie gsm.number: -- gsm.username: -- gsm.password: diff --git a/libnm-core/nm-connection.c b/libnm-core/nm-connection.c index c78e468d71..36600a89c4 100644 --- a/libnm-core/nm-connection.c +++ b/libnm-core/nm-connection.c @@ -1298,6 +1298,29 @@ _normalize_bridge_port_vlan_order (NMConnection *self) return _nm_setting_bridge_port_sort_vlans (s_port); } +static gboolean +_normalize_gsm_auto_config (NMConnection *self) +{ + NMSettingGsm *s_gsm; + + s_gsm = nm_connection_get_setting_gsm (self); + if (!s_gsm) + return FALSE; + + if (!nm_setting_gsm_get_auto_config (s_gsm)) + return FALSE; + + if ( !nm_setting_gsm_get_apn (s_gsm) + && !nm_setting_gsm_get_username (s_gsm) + && !nm_setting_gsm_get_password (s_gsm)) + return FALSE; + + g_object_set (s_gsm, + NM_SETTING_GSM_AUTO_CONFIG, FALSE, + NULL); + return TRUE; +} + static gboolean _normalize_required_settings (NMConnection *self) { @@ -1614,6 +1637,7 @@ _connection_normalize (NMConnection *connection, was_modified |= _normalize_sriov_vf_order (connection); was_modified |= _normalize_bridge_vlan_order (connection); was_modified |= _normalize_bridge_port_vlan_order (connection); + was_modified |= _normalize_gsm_auto_config (connection); was_modified = !!was_modified; diff --git a/libnm-core/nm-setting-gsm.c b/libnm-core/nm-setting-gsm.c index dd5e5ee37a..973120af86 100644 --- a/libnm-core/nm-setting-gsm.c +++ b/libnm-core/nm-setting-gsm.c @@ -24,6 +24,7 @@ /*****************************************************************************/ NM_GOBJECT_PROPERTIES_DEFINE_BASE ( + PROP_AUTO_CONFIG, PROP_NUMBER, PROP_USERNAME, PROP_PASSWORD, @@ -40,6 +41,8 @@ NM_GOBJECT_PROPERTIES_DEFINE_BASE ( ); typedef struct { + gboolean auto_config; + char *number; /* For dialing, duh */ char *username; char *password; @@ -66,6 +69,22 @@ G_DEFINE_TYPE (NMSettingGsm, nm_setting_gsm, NM_TYPE_SETTING) /*****************************************************************************/ +/** + * nm_setting_gsm_get_auto_config: + * @setting: the #NMSettingGsm + * + * Returns: the #NMSettingGsm:auto-config property of the setting + * + * Since: 1.22 + **/ +gboolean +nm_setting_gsm_get_auto_config (NMSettingGsm *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_GSM (setting), FALSE); + + return NM_SETTING_GSM_GET_PRIVATE (setting)->auto_config; +} + /** * nm_setting_gsm_get_number: * @setting: the #NMSettingGsm @@ -400,6 +419,16 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) } } + if ( priv->auto_config + && (priv->apn || priv->username || priv->password)) { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("can't be enabled when manual configuration is present")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_GSM_SETTING_NAME, NM_SETTING_GSM_AUTO_CONFIG); + return NM_SETTING_VERIFY_NORMALIZABLE_ERROR; + } + return TRUE; } @@ -440,6 +469,9 @@ get_property (GObject *object, guint prop_id, NMSettingGsm *setting = NM_SETTING_GSM (object); switch (prop_id) { + case PROP_AUTO_CONFIG: + g_value_set_boolean (value, nm_setting_gsm_get_auto_config (setting)); + break; case PROP_NUMBER: g_value_set_string (value, nm_setting_gsm_get_number (setting)); break; @@ -493,6 +525,9 @@ set_property (GObject *object, guint prop_id, char *tmp; switch (prop_id) { + case PROP_AUTO_CONFIG: + priv->auto_config = g_value_get_boolean (value); + break; case PROP_NUMBER: g_free (priv->number); priv->number = g_value_dup_string (value); @@ -608,6 +643,21 @@ nm_setting_gsm_class_init (NMSettingGsmClass *klass) setting_class->verify_secrets = verify_secrets; setting_class->need_secrets = need_secrets; + /** + * NMSettingGsm:auto-config: + * + * When %TRUE, the settings such as APN, username, or password will + * default to values that match the network the modem will register + * to in the Mobile Broadband Provider database. + * + * Since: 1.22 + **/ + obj_properties[PROP_AUTO_CONFIG] = + g_param_spec_boolean (NM_SETTING_GSM_AUTO_CONFIG, "", "", + FALSE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS); + /** * NMSettingGsm:number: * diff --git a/libnm-core/nm-setting-gsm.h b/libnm-core/nm-setting-gsm.h index 057ccf9e75..8a6fabd7f8 100644 --- a/libnm-core/nm-setting-gsm.h +++ b/libnm-core/nm-setting-gsm.h @@ -24,6 +24,7 @@ G_BEGIN_DECLS #define NM_SETTING_GSM_SETTING_NAME "gsm" +#define NM_SETTING_GSM_AUTO_CONFIG "auto-config" #define NM_SETTING_GSM_USERNAME "username" #define NM_SETTING_GSM_PASSWORD "password" #define NM_SETTING_GSM_PASSWORD_FLAGS "password-flags" @@ -59,6 +60,10 @@ typedef struct { GType nm_setting_gsm_get_type (void); NMSetting *nm_setting_gsm_new (void); + +NM_AVAILABLE_IN_1_22 +gboolean nm_setting_gsm_get_auto_config (NMSettingGsm *setting); + const char *nm_setting_gsm_get_username (NMSettingGsm *setting); const char *nm_setting_gsm_get_password (NMSettingGsm *setting); const char *nm_setting_gsm_get_apn (NMSettingGsm *setting); diff --git a/libnm/libnm.ver b/libnm/libnm.ver index 51e0d87241..68eaf745e9 100644 --- a/libnm/libnm.ver +++ b/libnm/libnm.ver @@ -1628,3 +1628,8 @@ global: nm_setting_wireguard_get_ip6_auto_default_route; nm_settings_add_connection2_flags_get_type; } libnm_1_18_0; + +libnm_1_22_0 { +global: + nm_setting_gsm_get_auto_config; +} libnm_1_20_0; From b92193236ae989aca3baf1208f0684d7b432218e Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sun, 25 Aug 2019 15:27:30 +0200 Subject: [PATCH 3/8] setting-gsm: use size_t variable for strlen() result --- libnm-core/nm-setting-gsm.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/libnm-core/nm-setting-gsm.c b/libnm-core/nm-setting-gsm.c index 973120af86..cb482095e5 100644 --- a/libnm-core/nm-setting-gsm.c +++ b/libnm-core/nm-setting-gsm.c @@ -292,8 +292,8 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) } if (priv->apn) { - guint32 apn_len = strlen (priv->apn); - guint32 i; + gsize apn_len = strlen (priv->apn); + gsize i; if (apn_len < 1 || apn_len > 64) { g_set_error (error, @@ -339,7 +339,8 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) } } - if (priv->username && !strlen (priv->username)) { + if ( priv->username + && priv->username[0] == '\0') { g_set_error_literal (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, @@ -349,8 +350,8 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) } if (priv->network_id) { - guint32 nid_len = strlen (priv->network_id); - guint32 i; + gsize nid_len = strlen (priv->network_id); + gsize i; /* Accept both 5 and 6 digit MCC/MNC codes */ if ((nid_len < 5) || (nid_len > 6)) { From adf02543693c49357631f746e562f5ab30968c42 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sun, 25 Aug 2019 15:27:37 +0200 Subject: [PATCH 4/8] setting-gsm: allow empty apn property in verify() NetworkManager treats "gsm.apn" %NULL as setting an empty APN (""). At least with ModemManager. With oFono, a %NULL APN means not to set the "AccessPointName", so oFono implementation treats %NULL different from "". Soon the meaning will change to allow %NULL to automatically obtain the APN from the mobile-broadband-provider-info. That will be a change in behavior how to treat %NULL. Anyway, since %NULL is accepted and in fact means to actually use "", the empty word should be also accepted to explicitly choose this behavior. This is especially important in combination with changing the meaning of %NULL. --- libnm-core/nm-setting-gsm.c | 2 +- libnm-core/tests/test-general.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libnm-core/nm-setting-gsm.c b/libnm-core/nm-setting-gsm.c index cb482095e5..b4ca97e6d8 100644 --- a/libnm-core/nm-setting-gsm.c +++ b/libnm-core/nm-setting-gsm.c @@ -295,7 +295,7 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) gsize apn_len = strlen (priv->apn); gsize i; - if (apn_len < 1 || apn_len > 64) { + if (apn_len > 64) { g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, diff --git a/libnm-core/tests/test-general.c b/libnm-core/tests/test-general.c index 4df97b3469..c477844c55 100644 --- a/libnm-core/tests/test-general.c +++ b/libnm-core/tests/test-general.c @@ -1747,7 +1747,7 @@ test_setting_gsm_apn_bad_chars (void) /* 0 characters long */ g_object_set (s_gsm, NM_SETTING_GSM_APN, "", NULL); - g_assert (!nm_setting_verify (NM_SETTING (s_gsm), NULL, NULL)); + g_assert (nm_setting_verify (NM_SETTING (s_gsm), NULL, NULL)); /* 65-character long */ g_object_set (s_gsm, NM_SETTING_GSM_APN, "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkl1", NULL); From 6632c7709492182c795895c7d32ce2542a8d9e9a Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Mon, 18 Mar 2019 10:53:20 +0100 Subject: [PATCH 5/8] wwan: add service-providers.xml parser This allows up to look up a default APN if the user doesn't pick one. --- Makefile.am | 5 +- src/devices/wwan/meson.build | 1 + src/devices/wwan/nm-service-providers.c | 460 ++++++++++++++++++++++++ src/devices/wwan/nm-service-providers.h | 24 ++ 4 files changed, 489 insertions(+), 1 deletion(-) create mode 100644 src/devices/wwan/nm-service-providers.c create mode 100644 src/devices/wwan/nm-service-providers.h diff --git a/Makefile.am b/Makefile.am index ef275bb440..aea13af505 100644 --- a/Makefile.am +++ b/Makefile.am @@ -3315,7 +3315,10 @@ src_devices_wwan_libnm_wwan_la_SOURCES = \ src/devices/wwan/nm-modem-manager.c \ src/devices/wwan/nm-modem-manager.h \ src/devices/wwan/nm-modem.c \ - src/devices/wwan/nm-modem.h + src/devices/wwan/nm-modem.h \ + src/devices/wwan/nm-service-providers.c \ + src/devices/wwan/nm-service-providers.h \ + $(NULL) if WITH_OFONO src_devices_wwan_libnm_wwan_la_SOURCES += \ diff --git a/src/devices/wwan/meson.build b/src/devices/wwan/meson.build index 482dc205fa..7f28265f81 100644 --- a/src/devices/wwan/meson.build +++ b/src/devices/wwan/meson.build @@ -2,6 +2,7 @@ sources = files( 'nm-modem-broadband.c', 'nm-modem.c', 'nm-modem-manager.c', + 'nm-service-providers.c', ) deps = [ diff --git a/src/devices/wwan/nm-service-providers.c b/src/devices/wwan/nm-service-providers.c new file mode 100644 index 0000000000..f363ebe506 --- /dev/null +++ b/src/devices/wwan/nm-service-providers.c @@ -0,0 +1,460 @@ +// SPDX-License-Identifier: LGPL-2.1+ +/* + * Copyright (C) 2009 Novell, Inc. + * Author: Tambet Ingo (tambet@gmail.com). + * + * Copyright (C) 2009 - 2019 Red Hat, Inc. + * Copyright (C) 2012 Lanedo GmbH + */ + +#include "nm-default.h" + +#include "nm-service-providers.h" + +typedef enum { + PARSER_TOPLEVEL = 0, + PARSER_COUNTRY, + PARSER_PROVIDER, + PARSER_METHOD_GSM, + PARSER_METHOD_GSM_APN, + PARSER_METHOD_CDMA, + PARSER_DONE, + PARSER_ERROR +} ParseContextState; + +typedef struct { + char *mccmnc; + NMServiceProvidersGsmApnCallback callback; + gpointer user_data; + GCancellable *cancellable; + GMarkupParseContext *ctx; + char buffer[4096]; + + char *text_buffer; + ParseContextState state; + + gboolean mccmnc_matched; + gboolean found_internet_apn; + char *apn; + char *username; + char *password; + char *gateway; + char *auth_method; + GSList *dns; +} ParseContext; + +/*****************************************************************************/ + +static void +parser_toplevel_start (ParseContext *parse_context, + const char *name, + const char **attribute_names, + const char **attribute_values) +{ + int i; + + if (strcmp (name, "serviceproviders") == 0) { + for (i = 0; attribute_names && attribute_names[i]; i++) { + if (strcmp (attribute_names[i], "format") == 0) { + if (strcmp (attribute_values[i], "2.0")) { + g_warning ("%s: mobile broadband provider database format '%s'" + " not supported.", __func__, attribute_values[i]); + parse_context->state = PARSER_ERROR; + break; + } + } + } + } else if (strcmp (name, "country") == 0) { + parse_context->state = PARSER_COUNTRY; + } +} + +static void +parser_country_start (ParseContext *parse_context, + const char *name, + const char **attribute_names, + const char **attribute_values) +{ + if (strcmp (name, "provider") == 0) + parse_context->state = PARSER_PROVIDER; +} + +static void +parser_provider_start (ParseContext *parse_context, + const char *name, + const char **attribute_names, + const char **attribute_values) +{ + parse_context->mccmnc_matched = FALSE; + if (strcmp (name, "gsm") == 0) + parse_context->state = PARSER_METHOD_GSM; + else if (strcmp (name, "cdma") == 0) + parse_context->state = PARSER_METHOD_CDMA; +} + +static void +parser_gsm_start (ParseContext *parse_context, + const char *name, + const char **attribute_names, + const char **attribute_values) +{ + int i; + + if (strcmp (name, "network-id") == 0) { + const char *mcc = NULL, *mnc = NULL; + + for (i = 0; attribute_names && attribute_names[i]; i++) { + if (strcmp (attribute_names[i], "mcc") == 0) + mcc = attribute_values[i]; + else if (strcmp (attribute_names[i], "mnc") == 0) + mnc = attribute_values[i]; + if (mcc && strlen (mcc) && mnc && strlen (mnc)) { + char *mccmnc = g_strdup_printf ("%s%s", mcc, mnc); + + if (strcmp (mccmnc, parse_context->mccmnc) == 0) + parse_context->mccmnc_matched = TRUE; + g_free (mccmnc); + break; + } + } + } else if (strcmp (name, "apn") == 0) { + parse_context->found_internet_apn = FALSE; + g_clear_pointer (&parse_context->apn, g_free); + g_clear_pointer (&parse_context->username, g_free); + g_clear_pointer (&parse_context->password, g_free); + g_clear_pointer (&parse_context->gateway, g_free); + g_clear_pointer (&parse_context->auth_method, g_free); + g_slist_free_full (parse_context->dns, g_free); + parse_context->dns = NULL; + + for (i = 0; attribute_names && attribute_names[i]; i++) { + if (strcmp (attribute_names[i], "value") == 0) { + parse_context->state = PARSER_METHOD_GSM_APN; + parse_context->apn = g_strstrip (g_strdup (attribute_values[i])); + break; + } + } + } +} + +static void +parser_gsm_apn_start (ParseContext *parse_context, + const char *name, + const char **attribute_names, + const char **attribute_values) +{ + int i; + + if (strcmp (name, "usage") == 0) { + for (i = 0; attribute_names && attribute_names[i]; i++) { + if ( (strcmp (attribute_names[i], "type") == 0) + && (strcmp (attribute_values[i], "internet") == 0)) { + parse_context->found_internet_apn = TRUE; + break; + } + } + } else if (strcmp (name, "authentication") == 0) { + for (i = 0; attribute_names && attribute_names[i]; i++) { + if (strcmp (attribute_names[i], "method") == 0) { + g_clear_pointer (&parse_context->auth_method, g_free); + parse_context->auth_method = g_strstrip (g_strdup (attribute_values[i])); + break; + } + } + } +} + +static void +parser_start_element (GMarkupParseContext *context, + const char *element_name, + const char **attribute_names, + const char **attribute_values, + gpointer user_data, + GError **error) +{ + ParseContext *parse_context = user_data; + + g_clear_pointer (&parse_context->text_buffer, g_free); + + switch (parse_context->state) { + case PARSER_TOPLEVEL: + parser_toplevel_start (parse_context, element_name, attribute_names, attribute_values); + break; + case PARSER_COUNTRY: + parser_country_start (parse_context, element_name, attribute_names, attribute_values); + break; + case PARSER_PROVIDER: + parser_provider_start (parse_context, element_name, attribute_names, attribute_values); + break; + case PARSER_METHOD_GSM: + parser_gsm_start (parse_context, element_name, attribute_names, attribute_values); + break; + case PARSER_METHOD_GSM_APN: + parser_gsm_apn_start (parse_context, element_name, attribute_names, attribute_values); + break; + case PARSER_METHOD_CDMA: + break; + case PARSER_ERROR: + break; + case PARSER_DONE: + break; + } +} + +static void +parser_country_end (ParseContext *parse_context, + const char *name) +{ + if (strcmp (name, "country") == 0) { + g_clear_pointer (&parse_context->text_buffer, g_free); + parse_context->state = PARSER_TOPLEVEL; + } +} + +static void +parser_provider_end (ParseContext *parse_context, + const char *name) +{ + if (strcmp (name, "provider") == 0) { + g_clear_pointer (&parse_context->text_buffer, g_free); + parse_context->state = PARSER_COUNTRY; + } +} + +static void +parser_gsm_end (ParseContext *parse_context, + const char *name) +{ + if (strcmp (name, "gsm") == 0) { + g_clear_pointer (&parse_context->text_buffer, g_free); + parse_context->state = PARSER_PROVIDER; + } +} + +static void +parser_gsm_apn_end (ParseContext *parse_context, + const char *name) +{ + if (strcmp (name, "username") == 0) { + g_clear_pointer (&parse_context->username, g_free); + parse_context->username = g_steal_pointer (&parse_context->text_buffer); + } else if (strcmp (name, "password") == 0) { + g_clear_pointer (&parse_context->password, g_free); + parse_context->password = g_steal_pointer (&parse_context->text_buffer); + } else if (strcmp (name, "dns") == 0) { + parse_context->dns = g_slist_prepend (parse_context->dns, + g_steal_pointer (&parse_context->text_buffer)); + } else if (strcmp (name, "gateway") == 0) { + g_clear_pointer (&parse_context->gateway, g_free); + parse_context->gateway = g_steal_pointer (&parse_context->text_buffer); + } else if (strcmp (name, "apn") == 0) { + g_clear_pointer (&parse_context->text_buffer, g_free); + + if (parse_context->mccmnc_matched && parse_context->found_internet_apn) + parse_context->state = PARSER_DONE; + else + parse_context->state = PARSER_METHOD_GSM; + + } +} + +static void +parser_cdma_end (ParseContext *parse_context, + const char *name) +{ + if (strcmp (name, "cdma") == 0) { + g_clear_pointer (&parse_context->text_buffer, g_free); + parse_context->state = PARSER_PROVIDER; + } +} + +static void +parser_end_element (GMarkupParseContext *context, + const char *element_name, + gpointer user_data, + GError **error) +{ + ParseContext *parse_context = user_data; + + switch (parse_context->state) { + case PARSER_TOPLEVEL: + break; + case PARSER_COUNTRY: + parser_country_end (parse_context, element_name); + break; + case PARSER_PROVIDER: + parser_provider_end (parse_context, element_name); + break; + case PARSER_METHOD_GSM: + parser_gsm_end (parse_context, element_name); + break; + case PARSER_METHOD_GSM_APN: + parser_gsm_apn_end (parse_context, element_name); + break; + case PARSER_METHOD_CDMA: + parser_cdma_end (parse_context, element_name); + break; + case PARSER_ERROR: + break; + case PARSER_DONE: + break; + } +} + +static void +parser_text (GMarkupParseContext *context, + const char *text, + gsize text_len, + gpointer user_data, + GError **error) +{ + ParseContext *parse_context = user_data; + + g_free (parse_context->text_buffer); + parse_context->text_buffer = g_strdup (text); +} + +static const GMarkupParser parser = { + .start_element = parser_start_element, + .end_element = parser_end_element, + .text = parser_text, + .passthrough = NULL, + .error = NULL, +}; + +/*****************************************************************************/ + +static void +finish_parse_context (ParseContext *parse_context, GError *error) +{ + if (parse_context->callback) { + if (error) { + parse_context->callback (NULL, NULL, NULL, NULL, NULL, + NULL, error, + parse_context->user_data); + } else { + parse_context->callback (parse_context->apn, + parse_context->username, + parse_context->password, + parse_context->gateway, + parse_context->auth_method, + parse_context->dns, + error, + parse_context->user_data); + } + } + + g_free (parse_context->mccmnc); + g_markup_parse_context_free (parse_context->ctx); + + g_free (parse_context->text_buffer); + g_free (parse_context->apn); + g_free (parse_context->username); + g_free (parse_context->password); + g_free (parse_context->gateway); + g_free (parse_context->auth_method); + g_slist_free_full (parse_context->dns, g_free); + + g_slice_free (ParseContext, parse_context); +} + +static void +read_next_chunk (GInputStream *stream, ParseContext *parse_context); + +static void +stream_read_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) +{ + GInputStream *stream = G_INPUT_STREAM (source_object); + ParseContext *parse_context = user_data; + gssize len; + GError *error = NULL; + + len = g_input_stream_read_finish (stream, res, &error); + if (len == -1) { + g_prefix_error (&error, "Error reading service provider database: "); + finish_parse_context (parse_context, error); + g_clear_error (&error); + return; + } + + if (len == 0) { + g_set_error (&error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, + "Operator ID '%s' not found in service provider database", + parse_context->mccmnc); + finish_parse_context (parse_context, error); + g_clear_error (&error); + return; + } + + if (!g_markup_parse_context_parse (parse_context->ctx, parse_context->buffer, len, &error)) { + g_prefix_error (&error, "Error parsing service provider database: "); + finish_parse_context (parse_context, error); + g_clear_error (&error); + return; + } + + if (parse_context->state == PARSER_DONE) { + finish_parse_context (parse_context, NULL); + return; + } + + read_next_chunk (stream, parse_context); +} + +static void +read_next_chunk (GInputStream *stream, ParseContext *parse_context) +{ + g_input_stream_read_async (stream, + parse_context->buffer, + sizeof (parse_context->buffer), + G_PRIORITY_DEFAULT, + parse_context->cancellable, + stream_read_cb, + parse_context); +} + +static void +file_read_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) +{ + GFile *file = G_FILE (source_object); + ParseContext *parse_context = user_data; + GFileInputStream *stream; + gs_free_error GError *error = NULL; + + stream = g_file_read_finish (file, res, &error); + if (!stream) { + g_prefix_error (&error, "Error opening service provider database: "); + finish_parse_context (parse_context, error); + return; + } + + read_next_chunk (G_INPUT_STREAM (stream), parse_context); + + g_object_unref (stream); +} + +/*****************************************************************************/ + +void +nm_service_providers_find_gsm_apn (const char *service_providers, + const char *mccmnc, + GCancellable *cancellable, + NMServiceProvidersGsmApnCallback callback, + gpointer user_data) +{ + GFile *file; + ParseContext *parse_context; + + parse_context = g_slice_new0 (ParseContext); + parse_context->mccmnc = g_strdup (mccmnc); + parse_context->cancellable = cancellable; + parse_context->callback = callback; + parse_context->user_data = user_data; + parse_context->ctx = g_markup_parse_context_new (&parser, 0, parse_context, NULL); + + file = g_file_new_for_path (service_providers); + + g_file_read_async (file, G_PRIORITY_DEFAULT, cancellable, file_read_cb, parse_context); + + g_object_unref (file); +} diff --git a/src/devices/wwan/nm-service-providers.h b/src/devices/wwan/nm-service-providers.h new file mode 100644 index 0000000000..35ad2fc120 --- /dev/null +++ b/src/devices/wwan/nm-service-providers.h @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: LGPL-2.1+ +/* + * Copyright (C) 2019 Red Hat, Inc. + */ + +#ifndef __NETWORKMANAGER_SERVICE_PROVIDERS_H__ +#define __NETWORKMANAGER_SERVICE_PROVIDERS_H__ + +typedef void (*NMServiceProvidersGsmApnCallback) (const char *apn, + const char *username, + const char *password, + const char *gateway, + const char *auth_method, + const GSList *dns, + GError *error, + gpointer user_data); + +void nm_service_providers_find_gsm_apn (const char *service_providers, + const char *mccmnc, + GCancellable *cancellable, + NMServiceProvidersGsmApnCallback callback, + gpointer user_data); + +#endif /* __NETWORKMANAGER_SERVICE_PROVIDERS_H__ */ From 6e5385a4ebba29d17446239030a1ca1d0dd51898 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Mon, 12 Aug 2019 12:42:10 +0200 Subject: [PATCH 6/8] wwan/tests: test service-providers.xml parser Just a handful of unit tests. --- .gitignore | 1 + Makefile.am | 26 +++- src/devices/wwan/meson.build | 8 +- src/devices/wwan/tests/meson.build | 13 ++ .../wwan/tests/test-service-providers.c | 124 ++++++++++++++++++ .../wwan/tests/test-service-providers.xml | 73 +++++++++++ 6 files changed, 243 insertions(+), 2 deletions(-) create mode 100644 src/devices/wwan/tests/meson.build create mode 100644 src/devices/wwan/tests/test-service-providers.c create mode 100644 src/devices/wwan/tests/test-service-providers.xml diff --git a/.gitignore b/.gitignore index d74b40c08d..55e8317e31 100644 --- a/.gitignore +++ b/.gitignore @@ -209,6 +209,7 @@ test-*.trs /src/devices/tests/test-acd /src/devices/tests/test-lldp /src/devices/wifi/tests/test-devices-wifi +/src/devices/wwan/tests/test-service-providers /src/dhcp/nm-dhcp-helper /src/dhcp/tests/test-dhcp-dhclient /src/dhcp/tests/test-dhcp-options diff --git a/Makefile.am b/Makefile.am index aea13af505..7eb6a82674 100644 --- a/Makefile.am +++ b/Makefile.am @@ -3367,11 +3367,35 @@ check-local-devices-wwan: src/devices/wwan/libnm-device-plugin-wwan.la src/devic check_local += check-local-devices-wwan +src_devices_wwan_tests_test_service_providers_SOURCES = \ + src/devices/wwan/tests/test-service-providers.c \ + src/devices/wwan/nm-service-providers.c \ + src/devices/wwan/nm-service-providers.h \ + $(NULL) + +src_devices_wwan_tests_test_service_providers_CPPFLAGS = \ + $(src_cppflags_base_test) \ + -I$(srcdir)/src/devices/wwan \ + $(NULL) + +src_devices_wwan_tests_test_service_providers_LDFLAGS = \ + $(SANITIZER_EXEC_LDFLAGS) \ + $(NULL) + +src_devices_wwan_tests_test_service_providers_LDADD = \ + src/libNetworkManagerTest.la \ + $(GLIB_LIBS) \ + $(NULL) + +check_programs += src/devices/wwan/tests/test-service-providers + endif EXTRA_DIST += \ src/devices/wwan/libnm-wwan.ver \ - src/devices/wwan/meson.build + src/devices/wwan/meson.build \ + src/devices/wwan/tests/test-service-providers.xml \ + $(NULL) ############################################################################### # src/devices/bluetooth diff --git a/src/devices/wwan/meson.build b/src/devices/wwan/meson.build index 7f28265f81..363e522bf1 100644 --- a/src/devices/wwan/meson.build +++ b/src/devices/wwan/meson.build @@ -29,8 +29,10 @@ libnm_wwan = shared_module( install_dir: nm_plugindir, ) +wwan_inc = include_directories('.') + libnm_wwan_dep = declare_dependency( - include_directories: include_directories('.'), + include_directories: wwan_inc, link_with: libnm_wwan, ) @@ -75,3 +77,7 @@ check-local-devices-wwan: src/devices/wwan/libnm-device-plugin-wwan.la src/devic $(srcdir)/tools/check-exports.sh $(builddir)/src/devices/wwan/.libs/libnm-wwan.so "$(srcdir)/src/devices/wwan/libnm-wwan.ver" $(call check_so_symbols,$(builddir)/src/devices/wwan/.libs/libnm-wwan.so) ''' + +if enable_tests + subdir('tests') +endif diff --git a/src/devices/wwan/tests/meson.build b/src/devices/wwan/tests/meson.build new file mode 100644 index 0000000000..64dd76742a --- /dev/null +++ b/src/devices/wwan/tests/meson.build @@ -0,0 +1,13 @@ +exe = executable( + 'test-service-providers', + sources: files('test-service-providers.c', + '../nm-service-providers.c'), + dependencies: test_nm_dep, + include_directories: wwan_inc, +) +test( + 'wwan/test-service-providers', + test_script, + timeout: default_test_timeout, + args: test_args + [exe.full_path()], +) diff --git a/src/devices/wwan/tests/test-service-providers.c b/src/devices/wwan/tests/test-service-providers.c new file mode 100644 index 0000000000..33402cd52c --- /dev/null +++ b/src/devices/wwan/tests/test-service-providers.c @@ -0,0 +1,124 @@ +// SPDX-License-Identifier: LGPL-2.1+ +/* + * Copyright (C) 2019 Red Hat + */ + +#include "nm-default.h" + +#include "nm-service-providers.h" + +#include "nm-test-utils-core.h" + +static void +test_positive_cb (const char *apn, + const char *username, + const char *password, + const char *gateway, + const char *auth_method, + const GSList *dns, + GError *error, + gpointer user_data) +{ + GMainLoop *loop = user_data; + + g_main_loop_quit (loop); + g_assert_no_error (error); + g_assert_cmpstr (apn, ==, "gprs.example.com"); + g_assert_cmpstr (username, ==, "praise"); + g_assert_cmpstr (password, ==, "santa"); + g_assert_cmpstr (gateway, ==, "192.0.2.3"); + g_assert_cmpstr (auth_method, ==, "pap"); + + g_assert_nonnull (dns); + g_assert_cmpstr (dns->data, ==, "192.0.2.2"); + dns = dns->next; + g_assert_nonnull (dns); + g_assert_cmpstr (dns->data, ==, "192.0.2.1"); + g_assert_null (dns->next); +} + +static void +test_positive (void) +{ + GMainLoop *loop = g_main_loop_new (NULL, FALSE); + + nm_service_providers_find_gsm_apn (NM_BUILD_SRCDIR"/src/devices/wwan/tests/test-service-providers.xml", + "13337", NULL, test_positive_cb, loop); + g_main_loop_run (loop); + g_main_loop_unref (loop); +} + +/*****************************************************************************/ + +static void +test_negative_cb (const char *apn, + const char *username, + const char *password, + const char *gateway, + const char *auth_method, + const GSList *dns, + GError *error, + gpointer user_data) +{ + GMainLoop *loop = user_data; + + g_main_loop_quit (loop); + g_assert_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN); +} + +static void +test_negative (void) +{ + GMainLoop *loop = g_main_loop_new (NULL, FALSE); + + nm_service_providers_find_gsm_apn (NM_BUILD_SRCDIR"/src/devices/wwan/tests/test-service-providers.xml", + "78130", NULL, test_negative_cb, loop); + g_main_loop_run (loop); + g_main_loop_unref (loop); +} + +/*****************************************************************************/ + +static void +test_nonexistent_cb (const char *apn, + const char *username, + const char *password, + const char *gateway, + const char *auth_method, + const GSList *dns, + GError *error, + gpointer user_data) +{ + GMainLoop *loop = user_data; + + g_main_loop_quit (loop); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_AGAIN); +} + +static void +test_nonexistent (void) +{ + GMainLoop *loop = g_main_loop_new (NULL, FALSE); + + nm_service_providers_find_gsm_apn ("nonexistent.xml", "13337", NULL, + test_nonexistent_cb, loop); + g_main_loop_run (loop); + g_main_loop_unref (loop); +} + +/*****************************************************************************/ + +NMTST_DEFINE (); + +int +main (int argc, char **argv) +{ + nmtst_init_assert_logging (&argc, &argv, "INFO", "DEFAULT"); + + g_test_add_func ("/service-providers/positive", test_positive); + g_test_add_func ("/service-providers/negative", test_negative); + g_test_add_func ("/service-providers/nonexistent", test_nonexistent); + + return g_test_run (); +} + diff --git a/src/devices/wwan/tests/test-service-providers.xml b/src/devices/wwan/tests/test-service-providers.xml new file mode 100644 index 0000000000..f0ca2debce --- /dev/null +++ b/src/devices/wwan/tests/test-service-providers.xml @@ -0,0 +1,73 @@ + + + + + + + + Sophia + + + + + + APN + 192.0.2.1 + 192.0.2.2 + + + + + + + + Demiurge + + + + + + Unsolicited Nudes MMS + mms + mms + http://mms.example.com/ + 192.0.2.1:8080 + + + + + GPRS + praise + santa + 192.0.2.1 + 192.0.2.2 + 192.0.2.3 + + + + + + Second + worship + doom + + + + + + Personal + + + + + + APN + 192.0.2.1 + 192.0.2.2 + + + + + + + From 0d44b640fcd120c0661f8fbaf98a5b80c0490b60 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Tue, 25 Jun 2019 10:42:52 +0200 Subject: [PATCH 7/8] wwan/modem-broadband: get rid of g_assert*() Though there is no known way to reach these, it may well happen that this is going to prevent some hard crashes. --- src/devices/wwan/nm-modem-broadband.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/devices/wwan/nm-modem-broadband.c b/src/devices/wwan/nm-modem-broadband.c index 056d302e96..a9239fca34 100644 --- a/src/devices/wwan/nm-modem-broadband.c +++ b/src/devices/wwan/nm-modem-broadband.c @@ -487,9 +487,9 @@ connect_context_step (NMModemBroadband *self) if (mm_modem_get_state (self->_priv.modem_iface) <= MM_MODEM_STATE_LOCKED) break; - /* Create core connect properties based on the modem capabilities */ - g_assert (!ctx->connect_properties); + g_return_if_fail (!ctx->connect_properties); + /* Create core connect properties based on the modem capabilities */ if (MODEM_CAPS_3GPP (ctx->caps)) ctx->connect_properties = create_gsm_connect_properties (ctx->connection); else if (MODEM_CAPS_3GPP2 (ctx->caps)) @@ -502,7 +502,8 @@ connect_context_step (NMModemBroadband *self) connect_context_clear (self); break; } - g_assert (ctx->connect_properties); + + g_return_if_fail (ctx->connect_properties); /* Build up list of IP types that we need to use in the retries */ ctx->ip_types = nm_modem_get_connection_ip_type (NM_MODEM (self), ctx->connection, &error); @@ -533,7 +534,7 @@ connect_context_step (NMModemBroadband *self) else if (current == NM_MODEM_IP_TYPE_IPV4V6) mm_simple_connect_properties_set_ip_type (ctx->connect_properties, MM_BEARER_IP_FAMILY_IPV4V6); else - g_assert_not_reached (); + g_return_if_reached (); _nm_modem_set_apn (NM_MODEM (self), mm_simple_connect_properties_get_apn (ctx->connect_properties)); @@ -863,8 +864,8 @@ static_stage3_ip4_done (NMModemBroadband *self) guint32 ip4_route_table, ip4_route_metric; NMPlatformIP4Route *r; - g_assert (self->_priv.ipv4_config); - g_assert (self->_priv.bearer); + g_return_val_if_fail (self->_priv.ipv4_config, FALSE); + g_return_val_if_fail (self->_priv.bearer, FALSE); self->_priv.idle_id_ip4 = 0; @@ -895,7 +896,7 @@ static_stage3_ip4_done (NMModemBroadband *self) } data_port = mm_bearer_get_interface (self->_priv.bearer); - g_assert (data_port); + g_return_val_if_fail (data_port, FALSE); config = nm_ip4_config_new (nm_platform_get_multi_idx (NM_PLATFORM_GET), nm_platform_link_get_ifindex (NM_PLATFORM_GET, data_port)); @@ -970,7 +971,7 @@ stage3_ip6_done (NMModemBroadband *self) const char **dns; guint i; - g_assert (self->_priv.ipv6_config); + g_return_val_if_fail (self->_priv.ipv6_config, FALSE); self->_priv.idle_id_ip6 = 0; memset (&address, 0, sizeof (address)); @@ -1002,7 +1003,8 @@ stage3_ip6_done (NMModemBroadband *self) _LOGI ("IPv6 base configuration:"); data_port = mm_bearer_get_interface (self->_priv.bearer); - g_assert (data_port); + g_return_val_if_fail (data_port, FALSE); + config = nm_ip6_config_new (nm_platform_get_multi_idx (NM_PLATFORM_GET), nm_platform_link_get_ifindex (NM_PLATFORM_GET, data_port)); @@ -1370,8 +1372,9 @@ set_property (GObject *object, /* construct-only */ self->_priv.modem_object = g_value_dup_object (value); self->_priv.modem_iface = mm_object_get_modem (self->_priv.modem_object); + g_return_if_fail (self->_priv.modem_iface); self->_priv.modem_3gpp_iface = mm_object_get_modem_3gpp (self->_priv.modem_object); - g_assert (self->_priv.modem_iface != NULL); + g_signal_connect (self->_priv.modem_iface, "state-changed", G_CALLBACK (modem_state_changed), From 7c53930ceb1561182deb8f47dd9927e049fc396d Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Mon, 18 Mar 2019 15:01:38 +0100 Subject: [PATCH 8/8] wwan/modem-broadband: add capability to look up default APN/username/password This allows the GSM connection to Just Work most of the time, as in: "nmcli d connect ttyUSB0". --- config.h.meson | 3 + configure.ac | 10 ++ contrib/fedora/REQUIRED_PACKAGES | 1 + contrib/fedora/rpm/NetworkManager.spec | 3 + meson.build | 3 + src/devices/wwan/nm-modem-broadband.c | 135 ++++++++++++++++++++----- 6 files changed, 127 insertions(+), 28 deletions(-) diff --git a/config.h.meson b/config.h.meson index a8c694011f..7ba9f9af56 100644 --- a/config.h.meson +++ b/config.h.meson @@ -73,6 +73,9 @@ /* Define to path of the kernel firmware directory */ #mesondefine KERNEL_FIRMWARE_DIR +/* Mobile Broadband Service Provider Information Database location */ +#mesondefine MOBILE_BROADBAND_PROVIDER_INFO_DATABASE + /* Path to netconfig */ #mesondefine NETCONFIG_PATH diff --git a/configure.ac b/configure.ac index 951f51b9a0..68507e2884 100644 --- a/configure.ac +++ b/configure.ac @@ -747,10 +747,20 @@ if (test "${with_modem_manager_1}" != "no"); then fi else with_modem_manager_1="yes" + + PKG_CHECK_MODULES(MOBILE_BROADBAND_PROVIDER_INFO, [mobile-broadband-provider-info], + [MOBILE_BROADBAND_PROVIDER_INFO_DATABASE=`$PKG_CONFIG --variable=database mobile-broadband-provider-info`], + [MOBILE_BROADBAND_PROVIDER_INFO_DATABASE="$prefix/share/mobile-broadband-provider-info/serviceproviders.xml"]) + AC_DEFINE_UNQUOTED([MOBILE_BROADBAND_PROVIDER_INFO_DATABASE], + ["$MOBILE_BROADBAND_PROVIDER_INFO_DATABASE"], + [Mobile Broadband Service Provider Information Database location]) fi fi AM_CONDITIONAL(WITH_MODEM_MANAGER_1, test "${with_modem_manager_1}" = "yes") + + + # Bluez5 DUN support PKG_CHECK_MODULES(BLUEZ5, [bluez >= 5], [have_bluez5=yes],[have_bluez5=no]) AC_ARG_ENABLE(bluez5-dun, diff --git a/contrib/fedora/REQUIRED_PACKAGES b/contrib/fedora/REQUIRED_PACKAGES index 00164cc669..7579e9a983 100755 --- a/contrib/fedora/REQUIRED_PACKAGES +++ b/contrib/fedora/REQUIRED_PACKAGES @@ -22,6 +22,7 @@ install \ \ ModemManager-devel \ ModemManager-glib-devel \ + mobile-broadband-provider-info-devel \ audit-libs-devel \ bash-completion \ bluez-libs-devel \ diff --git a/contrib/fedora/rpm/NetworkManager.spec b/contrib/fedora/rpm/NetworkManager.spec index b7957d602c..4eddef793a 100644 --- a/contrib/fedora/rpm/NetworkManager.spec +++ b/contrib/fedora/rpm/NetworkManager.spec @@ -219,6 +219,9 @@ BuildRequires: libndp-devel >= 1.0 %if 0%{?with_modem_manager_1} BuildRequires: ModemManager-glib-devel >= 1.0 %endif +%if %{with wwan} +BuildRequires: mobile-broadband-provider-info-devel +%endif %if %{with nmtui} BuildRequires: newt-devel %endif diff --git a/meson.build b/meson.build index 9fc9ad2684..db0fcbd29f 100644 --- a/meson.build +++ b/meson.build @@ -502,6 +502,9 @@ config_h.set10('WITH_PPP', enable_ppp) enable_modem_manager = get_option('modem_manager') if enable_modem_manager mm_glib_dep = dependency('mm-glib', version: '>= 0.7.991') + + service_provider_db = dependency('mobile-broadband-provider-info').get_pkgconfig_variable('database') + config_h.set_quoted('MOBILE_BROADBAND_PROVIDER_INFO_DATABASE', service_provider_db) endif # Bluez5 DUN support diff --git a/src/devices/wwan/nm-modem-broadband.c b/src/devices/wwan/nm-modem-broadband.c index a9239fca34..820c343a31 100644 --- a/src/devices/wwan/nm-modem-broadband.c +++ b/src/devices/wwan/nm-modem-broadband.c @@ -7,6 +7,7 @@ #include "nm-default.h" #include "nm-modem-broadband.h" +#include "nm-service-providers.h" #include #include @@ -261,7 +262,10 @@ create_cdma_connect_properties (NMConnection *connection) } static MMSimpleConnectProperties * -create_gsm_connect_properties (NMConnection *connection) +create_gsm_connect_properties (NMConnection *connection, + const char *apn, + const char *username, + const char *password) { NMSettingGsm *setting; NMSettingPpp *s_ppp; @@ -269,11 +273,14 @@ create_gsm_connect_properties (NMConnection *connection) const char *str; setting = nm_connection_get_setting_gsm (connection); + properties = mm_simple_connect_properties_new (); - /* Blank APN ("") means the default subscription APN */ - str = nm_setting_gsm_get_apn (setting); - mm_simple_connect_properties_set_apn (properties, str ?: ""); + mm_simple_connect_properties_set_apn (properties, apn ?: ""); + if (username) + mm_simple_connect_properties_set_user (properties, username); + if (password) + mm_simple_connect_properties_set_password (properties, password); str = nm_setting_gsm_get_network_id (setting); if (str) @@ -283,14 +290,6 @@ create_gsm_connect_properties (NMConnection *connection) if (str) mm_simple_connect_properties_set_pin (properties, str); - str = nm_setting_gsm_get_username (setting); - if (str) - mm_simple_connect_properties_set_user (properties, str); - - str = nm_setting_gsm_get_password (setting); - if (str) - mm_simple_connect_properties_set_password (properties, str); - /* Roaming */ if (nm_setting_gsm_get_home_only (setting)) mm_simple_connect_properties_set_allow_roaming (properties, FALSE); @@ -443,6 +442,95 @@ send_pin_ready (MMSim *sim, GAsyncResult *result, NMModemBroadband *self) connect_context_step (self); } +static void +find_gsm_apn_cb (const char *apn, + const char *username, + const char *password, + const char *gateway, + const char *auth_method, + const GSList *dns, + GError *error, + gpointer user_data) +{ + NMModemBroadband *self = user_data; + NMModemBroadbandPrivate *priv = NM_MODEM_BROADBAND_GET_PRIVATE (self); + ConnectContext *ctx = priv->ctx; + + if (error) { + _LOGW ("failed to connect '%s': APN not found: %s", + nm_connection_get_id (ctx->connection), error->message); + + nm_modem_emit_prepare_result (NM_MODEM (self), FALSE, NM_DEVICE_STATE_REASON_GSM_APN_FAILED); + connect_context_clear (self); + return; + } + + /* Blank APN ("") means the default subscription APN */ + ctx->connect_properties = create_gsm_connect_properties (ctx->connection, + apn, + username, + password); + g_return_if_fail (ctx->connect_properties); + connect_context_step (self); +} + +static gboolean +try_create_connect_properties (NMModemBroadband *self) +{ + NMModemBroadbandPrivate *priv = NM_MODEM_BROADBAND_GET_PRIVATE (self); + ConnectContext *ctx = priv->ctx; + + if (MODEM_CAPS_3GPP (ctx->caps)) { + NMSettingGsm *s_gsm = nm_connection_get_setting_gsm (ctx->connection); + + if (!s_gsm || nm_setting_gsm_get_auto_config (s_gsm)) { + gs_unref_object MMModem3gpp *modem_3gpp = NULL; + const char *network_id = NULL; + + s_gsm = nm_connection_get_setting_gsm (ctx->connection); + if (s_gsm) + network_id = nm_setting_gsm_get_network_id (s_gsm); + if (!network_id) { + if (mm_modem_get_state (self->_priv.modem_iface) < MM_MODEM_STATE_REGISTERED) + return FALSE; + modem_3gpp = mm_object_get_modem_3gpp (priv->modem_object); + network_id = mm_modem_3gpp_get_operator_code (modem_3gpp); + } + if (!network_id) { + _LOGW ("failed to connect '%s': unable to determine the network id", + nm_connection_get_id (ctx->connection)); + goto out; + } + + nm_service_providers_find_gsm_apn (MOBILE_BROADBAND_PROVIDER_INFO_DATABASE, + network_id, + ctx->cancellable, + find_gsm_apn_cb, + self); + } else { + ctx->connect_properties = create_gsm_connect_properties (ctx->connection, + nm_setting_gsm_get_apn (s_gsm), + nm_setting_gsm_get_username (s_gsm), + nm_setting_gsm_get_password (s_gsm)); + g_return_val_if_fail (ctx->connect_properties, TRUE); + } + + return TRUE; + } else if (MODEM_CAPS_3GPP2 (ctx->caps)) { + ctx->connect_properties = create_cdma_connect_properties (ctx->connection); + g_return_val_if_fail (ctx->connect_properties, FALSE); + return TRUE; + } else { + _LOGW ("failed to connect '%s': not a mobile broadband modem", + nm_connection_get_id (ctx->connection)); + } + +out: + nm_modem_emit_prepare_result (NM_MODEM (self), FALSE, NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED); + connect_context_clear (self); + return TRUE; +} + static void connect_context_step (NMModemBroadband *self) { @@ -487,23 +575,8 @@ connect_context_step (NMModemBroadband *self) if (mm_modem_get_state (self->_priv.modem_iface) <= MM_MODEM_STATE_LOCKED) break; - g_return_if_fail (!ctx->connect_properties); - - /* Create core connect properties based on the modem capabilities */ - if (MODEM_CAPS_3GPP (ctx->caps)) - ctx->connect_properties = create_gsm_connect_properties (ctx->connection); - else if (MODEM_CAPS_3GPP2 (ctx->caps)) - ctx->connect_properties = create_cdma_connect_properties (ctx->connection); - else { - _LOGW ("failed to connect '%s': not a mobile broadband modem", - nm_connection_get_id (ctx->connection)); - - nm_modem_emit_prepare_result (NM_MODEM (self), FALSE, NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED); - connect_context_clear (self); + if (!try_create_connect_properties (self)) break; - } - - g_return_if_fail (ctx->connect_properties); /* Build up list of IP types that we need to use in the retries */ ctx->ip_types = nm_modem_get_connection_ip_type (NM_MODEM (self), ctx->connection, &error); @@ -522,6 +595,9 @@ connect_context_step (NMModemBroadband *self) } /* fall through */ case CONNECT_STEP_CONNECT: + if (!ctx->connect_properties) + break; + if (ctx->ip_types_i < ctx->ip_types->len) { NMModemIPType current; @@ -677,6 +753,9 @@ complete_connection (NMModem *modem, if (!s_gsm) { s_gsm = (NMSettingGsm *) nm_setting_gsm_new (); nm_connection_add_setting (connection, NM_SETTING (s_gsm)); + g_object_set (G_OBJECT (s_gsm), + NM_SETTING_GSM_AUTO_CONFIG, TRUE, + NULL); } if (!nm_setting_gsm_get_device_id (s_gsm)) {