mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2025-12-26 07:40:08 +01:00
merge: add WWAN support for IPv6 (bgo #682623)
This commit is contained in:
commit
0151df2f0a
15 changed files with 1045 additions and 137 deletions
|
|
@ -14,6 +14,11 @@
|
|||
<arg name="config" type="a{sv}" direction="in"/>
|
||||
</method>
|
||||
|
||||
<method name="SetIp6Config">
|
||||
<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_ppp_manager_set_ip6_config"/>
|
||||
<arg name="config" type="a{sv}" direction="in"/>
|
||||
</method>
|
||||
|
||||
<method name="SetState">
|
||||
<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_ppp_manager_set_state"/>
|
||||
<arg name="state" type="u" direction="in"/>
|
||||
|
|
|
|||
|
|
@ -882,8 +882,7 @@ act_stage3_ip6_config_start (NMDevice *device,
|
|||
|
||||
if (priv->bt_type == NM_BT_CAPABILITY_DUN) {
|
||||
ret = nm_modem_stage3_ip6_config_start (NM_DEVICE_BT_GET_PRIVATE (device)->modem,
|
||||
device,
|
||||
NM_DEVICE_CLASS (nm_device_bt_parent_class),
|
||||
nm_device_get_act_request (device),
|
||||
reason);
|
||||
} else
|
||||
ret = NM_DEVICE_CLASS (nm_device_bt_parent_class)->act_stage3_ip6_config_start (device, out_config, reason);
|
||||
|
|
|
|||
|
|
@ -98,4 +98,9 @@ void nm_device_set_carrier (NMDevice *device, gboolean carrier);
|
|||
void nm_device_emit_recheck_auto_activate (NMDevice *device);
|
||||
void nm_device_queue_recheck_assume (NMDevice *device);
|
||||
|
||||
void nm_device_set_wwan_ip4_config (NMDevice *device, NMIP4Config *config);
|
||||
void nm_device_set_wwan_ip6_config (NMDevice *device, NMIP6Config *config);
|
||||
|
||||
gboolean nm_device_ipv6_sysctl_set (NMDevice *self, const char *property, const char *value);
|
||||
|
||||
#endif /* NM_DEVICE_PRIVATE_H */
|
||||
|
|
|
|||
|
|
@ -237,6 +237,7 @@ typedef struct {
|
|||
IpState ip4_state;
|
||||
NMIP4Config * dev_ip4_config; /* Config from DHCP, PPP, LLv4, etc */
|
||||
NMIP4Config * ext_ip4_config; /* Stuff added outside NM */
|
||||
NMIP4Config * wwan_ip4_config; /* WWAN configuration */
|
||||
|
||||
/* DHCPv4 tracking */
|
||||
NMDHCPClient * dhcp4_client;
|
||||
|
|
@ -263,6 +264,7 @@ typedef struct {
|
|||
NMIP6Config * ip6_config;
|
||||
IpState ip6_state;
|
||||
NMIP6Config * vpn6_config; /* routes added by a VPN which uses this device */
|
||||
NMIP6Config * wwan_ip6_config;
|
||||
NMIP6Config * ext_ip6_config; /* Stuff added outside NM */
|
||||
|
||||
NMRDisc * rdisc;
|
||||
|
|
@ -445,7 +447,7 @@ reason_to_string (NMDeviceStateReason reason)
|
|||
|
||||
/***********************************************************/
|
||||
|
||||
static inline gboolean
|
||||
gboolean
|
||||
nm_device_ipv6_sysctl_set (NMDevice *self, const char *property, const char *value)
|
||||
{
|
||||
return nm_platform_sysctl_set (nm_utils_ip6_property_path (nm_device_get_ip_iface (self), property), value);
|
||||
|
|
@ -2662,6 +2664,12 @@ ip4_config_merge_and_apply (NMDevice *self,
|
|||
if (priv->ext_ip4_config)
|
||||
nm_ip4_config_merge (composite, priv->ext_ip4_config);
|
||||
|
||||
/* Merge WWAN config *last* to ensure modem-given settings overwrite
|
||||
* any external stuff set by pppd or other scripts.
|
||||
*/
|
||||
if (priv->wwan_ip4_config)
|
||||
nm_ip4_config_merge (composite, priv->wwan_ip4_config);
|
||||
|
||||
/* Merge user overrides into the composite config */
|
||||
connection = nm_device_get_connection (self);
|
||||
if (connection) {
|
||||
|
|
@ -3089,6 +3097,12 @@ ip6_config_merge_and_apply (NMDevice *self,
|
|||
if (priv->ext_ip6_config)
|
||||
nm_ip6_config_merge (composite, priv->ext_ip6_config);
|
||||
|
||||
/* Merge WWAN config *last* to ensure modem-given settings overwrite
|
||||
* any external stuff set by pppd or other scripts.
|
||||
*/
|
||||
if (priv->wwan_ip6_config)
|
||||
nm_ip6_config_merge (composite, priv->wwan_ip6_config);
|
||||
|
||||
/* Merge user overrides into the composite config */
|
||||
connection = nm_device_get_connection (self);
|
||||
if (connection) {
|
||||
|
|
@ -3141,10 +3155,17 @@ dhcp6_fail (NMDevice *device, gboolean timeout)
|
|||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device);
|
||||
|
||||
dhcp6_cleanup (device, TRUE, FALSE);
|
||||
if (timeout || (priv->ip6_state == IP_CONF))
|
||||
nm_device_activate_schedule_ip6_config_timeout (device);
|
||||
else if (priv->ip6_state == IP_FAIL)
|
||||
nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED);
|
||||
|
||||
if (priv->dhcp6_mode == NM_RDISC_DHCP_LEVEL_MANAGED) {
|
||||
if (timeout || (priv->ip6_state == IP_CONF))
|
||||
nm_device_activate_schedule_ip6_config_timeout (device);
|
||||
else if (priv->ip6_state == IP_FAIL)
|
||||
nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED);
|
||||
} else {
|
||||
/* not a hard failure; just live with the RA info */
|
||||
if (priv->ip6_state == IP_CONF)
|
||||
nm_device_activate_schedule_ip6_config_result (device);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -4623,11 +4644,11 @@ nm_device_activate_schedule_ip4_config_result (NMDevice *self, NMIP4Config *conf
|
|||
NMDevicePrivate *priv;
|
||||
|
||||
g_return_if_fail (NM_IS_DEVICE (self));
|
||||
g_return_if_fail (NM_IS_IP4_CONFIG (config));
|
||||
priv = NM_DEVICE_GET_PRIVATE (self);
|
||||
|
||||
g_clear_object (&priv->dev_ip4_config);
|
||||
priv->dev_ip4_config = g_object_ref (config);
|
||||
if (config)
|
||||
priv->dev_ip4_config = g_object_ref (config);
|
||||
|
||||
activation_source_schedule (self, nm_device_activate_ip4_config_commit, AF_INET);
|
||||
|
||||
|
|
@ -5204,6 +5225,25 @@ nm_device_set_vpn4_config (NMDevice *device, NMIP4Config *config)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
nm_device_set_wwan_ip4_config (NMDevice *device, NMIP4Config *config)
|
||||
{
|
||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device);
|
||||
|
||||
if (priv->wwan_ip4_config == config)
|
||||
return;
|
||||
|
||||
g_clear_object (&priv->wwan_ip4_config);
|
||||
if (config)
|
||||
priv->wwan_ip4_config = g_object_ref (config);
|
||||
|
||||
/* NULL to use existing configs */
|
||||
if (!ip4_config_merge_and_apply (device, NULL, TRUE, NULL)) {
|
||||
nm_log_warn (LOGD_IP4, "(%s): failed to set WWAN IPv4 configuration",
|
||||
nm_device_get_ip_iface (device));
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
nm_device_set_ip6_config (NMDevice *self,
|
||||
NMIP6Config *new_config,
|
||||
|
|
@ -5308,6 +5348,25 @@ nm_device_set_vpn6_config (NMDevice *device, NMIP6Config *config)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
nm_device_set_wwan_ip6_config (NMDevice *device, NMIP6Config *config)
|
||||
{
|
||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device);
|
||||
|
||||
if (priv->wwan_ip6_config == config)
|
||||
return;
|
||||
|
||||
g_clear_object (&priv->wwan_ip6_config);
|
||||
if (config)
|
||||
priv->wwan_ip6_config = g_object_ref (config);
|
||||
|
||||
/* NULL to use existing configs */
|
||||
if (!ip6_config_merge_and_apply (device, TRUE, NULL)) {
|
||||
nm_log_warn (LOGD_IP6, "(%s): failed to set WWAN IPv6 configuration",
|
||||
nm_device_get_ip_iface (device));
|
||||
}
|
||||
}
|
||||
|
||||
NMDHCP6Config *
|
||||
nm_device_get_dhcp6_config (NMDevice *self)
|
||||
{
|
||||
|
|
@ -5864,6 +5923,8 @@ update_ip_config (NMDevice *self, gboolean initial)
|
|||
nm_ip4_config_subtract (priv->ext_ip4_config, priv->dev_ip4_config);
|
||||
if (priv->vpn4_config)
|
||||
nm_ip4_config_subtract (priv->ext_ip4_config, priv->vpn4_config);
|
||||
if (priv->wwan_ip4_config)
|
||||
nm_ip4_config_subtract (priv->ext_ip4_config, priv->wwan_ip4_config);
|
||||
|
||||
ip4_config_merge_and_apply (self, NULL, FALSE, NULL);
|
||||
}
|
||||
|
|
@ -5881,6 +5942,8 @@ update_ip_config (NMDevice *self, gboolean initial)
|
|||
nm_ip6_config_subtract (priv->ext_ip6_config, priv->ac_ip6_config);
|
||||
if (priv->dhcp6_ip6_config)
|
||||
nm_ip6_config_subtract (priv->ext_ip6_config, priv->dhcp6_ip6_config);
|
||||
if (priv->wwan_ip6_config)
|
||||
nm_ip6_config_subtract (priv->ext_ip6_config, priv->wwan_ip6_config);
|
||||
if (priv->vpn6_config)
|
||||
nm_ip6_config_subtract (priv->ext_ip6_config, priv->vpn6_config);
|
||||
|
||||
|
|
@ -6511,11 +6574,13 @@ _cleanup_generic_post (NMDevice *self, gboolean deconfigure)
|
|||
nm_device_set_ip6_config (self, NULL, TRUE, &ignored);
|
||||
g_clear_object (&priv->dev_ip4_config);
|
||||
g_clear_object (&priv->ext_ip4_config);
|
||||
g_clear_object (&priv->wwan_ip4_config);
|
||||
g_clear_object (&priv->vpn4_config);
|
||||
g_clear_object (&priv->ip4_config);
|
||||
g_clear_object (&priv->ac_ip6_config);
|
||||
g_clear_object (&priv->ext_ip6_config);
|
||||
g_clear_object (&priv->vpn6_config);
|
||||
g_clear_object (&priv->wwan_ip6_config);
|
||||
g_clear_object (&priv->ip6_config);
|
||||
|
||||
clear_act_request (self);
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <glib.h>
|
||||
|
||||
#include "nm-device-modem.h"
|
||||
|
|
@ -30,6 +31,7 @@
|
|||
#include "nm-dbus-manager.h"
|
||||
#include "nm-settings-connection.h"
|
||||
#include "nm-modem-broadband.h"
|
||||
#include "NetworkManagerUtils.h"
|
||||
|
||||
G_DEFINE_TYPE (NMDeviceModem, nm_device_modem, NM_TYPE_DEVICE)
|
||||
|
||||
|
|
@ -153,23 +155,100 @@ modem_ip4_config_result (NMModem *self,
|
|||
g_return_if_fail (nm_device_activate_ip4_state_in_conf (device) == TRUE);
|
||||
|
||||
if (error) {
|
||||
nm_log_warn (LOGD_MB | LOGD_IP4, "retrieving IP4 configuration failed: (%d) %s",
|
||||
nm_log_warn (LOGD_MB | LOGD_IP4, "retrieving IPv4 configuration failed: (%d) %s",
|
||||
error ? error->code : -1,
|
||||
error && error->message ? error->message : "(unknown)");
|
||||
|
||||
nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE);
|
||||
} else
|
||||
nm_device_activate_schedule_ip4_config_result (device, config);
|
||||
} else {
|
||||
nm_device_set_wwan_ip4_config (device, config);
|
||||
nm_device_activate_schedule_ip4_config_result (device, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
modem_ip6_config_result (NMModem *self,
|
||||
NMIP6Config *config,
|
||||
gboolean do_slaac,
|
||||
GError *error,
|
||||
gpointer user_data)
|
||||
{
|
||||
NMDevice *device = NM_DEVICE (user_data);
|
||||
NMActStageReturn ret;
|
||||
NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE;
|
||||
NMIP6Config *ignored = NULL;
|
||||
gboolean got_config = !!config;
|
||||
|
||||
g_return_if_fail (nm_device_activate_ip6_state_in_conf (device) == TRUE);
|
||||
|
||||
if (error) {
|
||||
nm_log_warn (LOGD_MB | LOGD_IP6, "retrieving IPv6 configuration failed: (%d) %s",
|
||||
error ? error->code : -1,
|
||||
error && error->message ? error->message : "(unknown)");
|
||||
|
||||
nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Re-enable IPv6 on the interface */
|
||||
nm_device_ipv6_sysctl_set (device, "disable_ipv6", "0");
|
||||
|
||||
if (config)
|
||||
nm_device_set_wwan_ip6_config (device, config);
|
||||
|
||||
if (do_slaac == FALSE) {
|
||||
if (got_config)
|
||||
nm_device_activate_schedule_ip6_config_result (device);
|
||||
else {
|
||||
nm_log_warn (LOGD_MB | LOGD_IP6, "retrieving IPv6 configuration failed: SLAAC not requested and no addresses");
|
||||
nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Start SLAAC now that we have a link-local address from the modem */
|
||||
ret = NM_DEVICE_CLASS (nm_device_modem_parent_class)->act_stage3_ip6_config_start (device, &ignored, &reason);
|
||||
g_assert (ignored == NULL);
|
||||
switch (ret) {
|
||||
case NM_ACT_STAGE_RETURN_FAILURE:
|
||||
nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, reason);
|
||||
break;
|
||||
case NM_ACT_STAGE_RETURN_STOP:
|
||||
/* all done */
|
||||
nm_device_activate_schedule_ip6_config_result (device);
|
||||
break;
|
||||
case NM_ACT_STAGE_RETURN_POSTPONE:
|
||||
/* let SLAAC run */
|
||||
break;
|
||||
default:
|
||||
/* Should never get here since we've assured that the IPv6 method
|
||||
* will either be "auto" or "ignored" when starting IPv6 configuration.
|
||||
*/
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
data_port_changed_cb (NMModem *modem, GParamSpec *pspec, gpointer user_data)
|
||||
{
|
||||
NMDevice *self = NM_DEVICE (user_data);
|
||||
const char *old = nm_device_get_ip_iface (self);
|
||||
const char *new = nm_modem_get_data_port (modem);
|
||||
gboolean changed = FALSE;
|
||||
|
||||
if (new && g_strcmp0 (new, old))
|
||||
changed = TRUE;
|
||||
|
||||
/* We set the IP iface in the device as soon as we know it, so that we
|
||||
* properly ifup it if needed */
|
||||
nm_device_set_ip_iface (self, nm_modem_get_data_port (modem));
|
||||
nm_device_set_ip_iface (self, new);
|
||||
|
||||
/* Disable IPv6 immediately on the interface since NM handles IPv6
|
||||
* internally, and leaving it enabled could allow the kernel's IPv6
|
||||
* RA handling code to run before NM is ready.
|
||||
*/
|
||||
if (changed)
|
||||
nm_device_ipv6_sysctl_set (self, "disable_ipv6", "1");
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -394,11 +473,24 @@ act_stage3_ip6_config_start (NMDevice *device,
|
|||
NMDeviceStateReason *reason)
|
||||
{
|
||||
return nm_modem_stage3_ip6_config_start (NM_DEVICE_MODEM_GET_PRIVATE (device)->modem,
|
||||
device,
|
||||
NM_DEVICE_CLASS (nm_device_modem_parent_class),
|
||||
nm_device_get_act_request (device),
|
||||
reason);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
get_ip_iface_identifier (NMDevice *device, NMUtilsIPv6IfaceId *out_iid)
|
||||
{
|
||||
NMDeviceModem *self = NM_DEVICE_MODEM (device);
|
||||
NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (self);
|
||||
gboolean success;
|
||||
|
||||
g_return_val_if_fail (priv->modem, FALSE);
|
||||
success = nm_modem_get_iid (priv->modem, out_iid);
|
||||
if (!success)
|
||||
success = NM_DEVICE_CLASS (nm_device_modem_parent_class)->get_ip_iface_identifier (device, out_iid);
|
||||
return success;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static gboolean
|
||||
|
|
@ -486,8 +578,10 @@ nm_device_modem_new (NMModem *modem)
|
|||
|
||||
/* If the data port is known, set it as the IP interface immediately */
|
||||
data_port = nm_modem_get_data_port (modem);
|
||||
if (data_port)
|
||||
if (data_port) {
|
||||
nm_device_set_ip_iface (device, data_port);
|
||||
nm_device_ipv6_sysctl_set (device, "disable_ipv6", "1");
|
||||
}
|
||||
|
||||
return device;
|
||||
}
|
||||
|
|
@ -497,6 +591,18 @@ nm_device_modem_init (NMDeviceModem *self)
|
|||
{
|
||||
}
|
||||
|
||||
static void
|
||||
constructed (GObject *object)
|
||||
{
|
||||
G_OBJECT_CLASS (nm_device_modem_parent_class)->constructed (object);
|
||||
|
||||
/* DHCP is always done by the modem firmware, not by the network, and
|
||||
* by the time we get around to DHCP the firmware should already know
|
||||
* the IP addressing details. So the DHCP timeout can be much shorter.
|
||||
*/
|
||||
nm_device_set_dhcp_timeout (NM_DEVICE (object), 15);
|
||||
}
|
||||
|
||||
static void
|
||||
set_modem (NMDeviceModem *self, NMModem *modem)
|
||||
{
|
||||
|
|
@ -509,6 +615,7 @@ set_modem (NMDeviceModem *self, NMModem *modem)
|
|||
g_signal_connect (modem, NM_MODEM_PPP_FAILED, G_CALLBACK (ppp_failed), self);
|
||||
g_signal_connect (modem, NM_MODEM_PREPARE_RESULT, G_CALLBACK (modem_prepare_result), self);
|
||||
g_signal_connect (modem, NM_MODEM_IP4_CONFIG_RESULT, G_CALLBACK (modem_ip4_config_result), self);
|
||||
g_signal_connect (modem, NM_MODEM_IP6_CONFIG_RESULT, G_CALLBACK (modem_ip6_config_result), self);
|
||||
g_signal_connect (modem, NM_MODEM_AUTH_REQUESTED, G_CALLBACK (modem_auth_requested), self);
|
||||
g_signal_connect (modem, NM_MODEM_AUTH_RESULT, G_CALLBACK (modem_auth_result), self);
|
||||
g_signal_connect (modem, NM_MODEM_STATE_CHANGED, G_CALLBACK (modem_state_cb), self);
|
||||
|
|
@ -589,6 +696,7 @@ nm_device_modem_class_init (NMDeviceModemClass *mclass)
|
|||
object_class->dispose = dispose;
|
||||
object_class->get_property = get_property;
|
||||
object_class->set_property = set_property;
|
||||
object_class->constructed = constructed;
|
||||
|
||||
device_class->check_connection_compatible = check_connection_compatible;
|
||||
device_class->check_connection_available = check_connection_available;
|
||||
|
|
@ -603,6 +711,7 @@ nm_device_modem_class_init (NMDeviceModemClass *mclass)
|
|||
device_class->set_enabled = set_enabled;
|
||||
device_class->owns_iface = owns_iface;
|
||||
device_class->is_available = is_available;
|
||||
device_class->get_ip_iface_identifier = get_ip_iface_identifier;
|
||||
|
||||
device_class->state_changed = device_state_changed;
|
||||
|
||||
|
|
|
|||
|
|
@ -157,13 +157,29 @@ ask_for_pin (NMModemBroadband *self)
|
|||
NM_SETTING_GSM_PIN);
|
||||
}
|
||||
|
||||
static NMModemIPMethod
|
||||
get_bearer_ip_method (MMBearerIpConfig *config)
|
||||
{
|
||||
MMBearerIpMethod mm_method;
|
||||
|
||||
mm_method = mm_bearer_ip_config_get_method (config);
|
||||
if (mm_method == MM_BEARER_IP_METHOD_PPP)
|
||||
return NM_MODEM_IP_METHOD_PPP;
|
||||
else if (mm_method == MM_BEARER_IP_METHOD_STATIC)
|
||||
return NM_MODEM_IP_METHOD_STATIC;
|
||||
else if (mm_method == MM_BEARER_IP_METHOD_DHCP)
|
||||
return NM_MODEM_IP_METHOD_AUTO;
|
||||
return NM_MODEM_IP_METHOD_UNKNOWN;
|
||||
}
|
||||
|
||||
static void
|
||||
connect_ready (MMModemSimple *simple_iface,
|
||||
GAsyncResult *res,
|
||||
NMModemBroadband *self)
|
||||
{
|
||||
GError *error = NULL;
|
||||
guint ip_method;
|
||||
NMModemIPMethod ip4_method = NM_MODEM_IP_METHOD_UNKNOWN;
|
||||
NMModemIPMethod ip6_method = NM_MODEM_IP_METHOD_UNKNOWN;
|
||||
|
||||
g_clear_object (&self->priv->connect_properties);
|
||||
|
||||
|
|
@ -196,35 +212,31 @@ connect_ready (MMModemSimple *simple_iface,
|
|||
|
||||
/* Grab IP configurations */
|
||||
self->priv->ipv4_config = mm_bearer_get_ipv4_config (self->priv->bearer);
|
||||
self->priv->ipv6_config = mm_bearer_get_ipv6_config (self->priv->bearer);
|
||||
if (self->priv->ipv4_config)
|
||||
ip4_method = get_bearer_ip_method (self->priv->ipv4_config);
|
||||
|
||||
switch (mm_bearer_ip_config_get_method (self->priv->ipv4_config)) {
|
||||
case MM_BEARER_IP_METHOD_PPP:
|
||||
ip_method = MM_MODEM_IP_METHOD_PPP;
|
||||
break;
|
||||
case MM_BEARER_IP_METHOD_STATIC:
|
||||
ip_method = MM_MODEM_IP_METHOD_STATIC;
|
||||
break;
|
||||
case MM_BEARER_IP_METHOD_DHCP:
|
||||
ip_method = MM_MODEM_IP_METHOD_DHCP;
|
||||
break;
|
||||
default:
|
||||
error = g_error_new (NM_MODEM_ERROR,
|
||||
NM_MODEM_ERROR_CONNECTION_INVALID,
|
||||
"invalid IP config");
|
||||
nm_log_warn (LOGD_MB, "(%s) failed to connect modem: %s",
|
||||
nm_modem_get_uid (NM_MODEM (self)),
|
||||
error->message);
|
||||
g_signal_emit_by_name (self, NM_MODEM_PREPARE_RESULT, FALSE, translate_mm_error (error));
|
||||
self->priv->ipv6_config = mm_bearer_get_ipv6_config (self->priv->bearer);
|
||||
if (self->priv->ipv6_config)
|
||||
ip6_method = get_bearer_ip_method (self->priv->ipv6_config);
|
||||
|
||||
if (ip4_method == NM_MODEM_IP_METHOD_UNKNOWN &&
|
||||
ip6_method == NM_MODEM_IP_METHOD_UNKNOWN) {
|
||||
nm_log_warn (LOGD_MB, "(%s) failed to connect modem: invalid bearer IP configuration",
|
||||
nm_modem_get_uid (NM_MODEM (self)));
|
||||
|
||||
error = g_error_new_literal (NM_MODEM_ERROR,
|
||||
NM_MODEM_ERROR_CONNECTION_INVALID,
|
||||
"invalid bearer IP configuration");
|
||||
g_signal_emit_by_name (self, NM_MODEM_PREPARE_RESULT, FALSE, error);
|
||||
g_error_free (error);
|
||||
g_object_unref (self);
|
||||
return;
|
||||
}
|
||||
|
||||
/* IPv4 for now only */
|
||||
g_object_set (self,
|
||||
NM_MODEM_DATA_PORT, mm_bearer_get_interface (self->priv->bearer),
|
||||
NM_MODEM_IP_METHOD, ip_method,
|
||||
NM_MODEM_IP4_METHOD, ip4_method,
|
||||
NM_MODEM_IP6_METHOD, ip6_method,
|
||||
NM_MODEM_IP_TIMEOUT, mm_bearer_get_ip_timeout (self->priv->bearer),
|
||||
NULL);
|
||||
|
||||
|
|
@ -250,12 +262,15 @@ create_cdma_connect_properties (NMConnection *connection)
|
|||
}
|
||||
|
||||
static MMSimpleConnectProperties *
|
||||
create_gsm_connect_properties (NMConnection *connection)
|
||||
create_gsm_connect_properties (NMModem *modem,
|
||||
NMConnection *connection,
|
||||
GError **error)
|
||||
{
|
||||
NMSettingGsm *setting;
|
||||
NMSettingPPP *s_ppp;
|
||||
MMSimpleConnectProperties *properties;
|
||||
const gchar *str;
|
||||
NMModemIPType ip_type;
|
||||
|
||||
setting = nm_connection_get_setting_gsm (connection);
|
||||
properties = mm_simple_connect_properties_new ();
|
||||
|
|
@ -310,6 +325,22 @@ create_gsm_connect_properties (NMConnection *connection)
|
|||
mm_simple_connect_properties_set_allowed_auth (properties, allowed_auth);
|
||||
}
|
||||
|
||||
/* Determine IP types to use when connecting */
|
||||
ip_type = nm_modem_get_connection_ip_type (modem, connection, error);
|
||||
if (ip_type == NM_MODEM_IP_TYPE_UNKNOWN) {
|
||||
g_object_unref (properties);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ip_type == NM_MODEM_IP_TYPE_IPV4)
|
||||
mm_simple_connect_properties_set_ip_type (properties, MM_BEARER_IP_FAMILY_IPV4);
|
||||
else if (ip_type == NM_MODEM_IP_TYPE_IPV6)
|
||||
mm_simple_connect_properties_set_ip_type (properties, MM_BEARER_IP_FAMILY_IPV6);
|
||||
else if (ip_type == NM_MODEM_IP_TYPE_IPV4V6)
|
||||
mm_simple_connect_properties_set_ip_type (properties, MM_BEARER_IP_FAMILY_IPV4V6);
|
||||
else
|
||||
g_assert_not_reached ();
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
|
|
@ -320,17 +351,29 @@ act_stage1_prepare (NMModem *_self,
|
|||
{
|
||||
NMModemBroadband *self = NM_MODEM_BROADBAND (_self);
|
||||
MMModemCapability caps;
|
||||
GError *error = NULL;
|
||||
|
||||
g_clear_object (&self->priv->connect_properties);
|
||||
|
||||
caps = mm_modem_get_current_capabilities (self->priv->modem_iface);
|
||||
if (MODEM_CAPS_3GPP (caps))
|
||||
self->priv->connect_properties = create_gsm_connect_properties (connection);
|
||||
self->priv->connect_properties = create_gsm_connect_properties (_self, connection, &error);
|
||||
else if (MODEM_CAPS_3GPP2 (caps))
|
||||
self->priv->connect_properties = create_cdma_connect_properties (connection);
|
||||
else {
|
||||
nm_log_warn (LOGD_MB, "(%s) not a mobile broadband modem",
|
||||
nm_modem_get_uid (NM_MODEM (self)));
|
||||
*reason = NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED;
|
||||
return NM_ACT_STAGE_RETURN_FAILURE;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
nm_log_warn (LOGD_MB, "(%s): Failed to connect '%s': %s",
|
||||
nm_modem_get_uid (NM_MODEM (self)),
|
||||
nm_connection_get_id (connection),
|
||||
error->message);
|
||||
g_clear_error (&error);
|
||||
*reason = NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED;
|
||||
return NM_ACT_STAGE_RETURN_FAILURE;
|
||||
}
|
||||
|
||||
|
|
@ -591,11 +634,10 @@ set_mm_enabled (NMModem *_self,
|
|||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* IP method static */
|
||||
/* IPv4 method static */
|
||||
|
||||
static gboolean
|
||||
ip_string_to_network_address (const gchar *str,
|
||||
guint32 *out)
|
||||
ip4_string_to_num (const gchar *str, guint32 *out)
|
||||
{
|
||||
guint32 addr = 0;
|
||||
gboolean success = FALSE;
|
||||
|
|
@ -610,7 +652,7 @@ ip_string_to_network_address (const gchar *str,
|
|||
}
|
||||
|
||||
static gboolean
|
||||
static_stage3_done (NMModemBroadband *self)
|
||||
static_stage3_ip4_done (NMModemBroadband *self)
|
||||
{
|
||||
GError *error = NULL;
|
||||
NMIP4Config *config = NULL;
|
||||
|
|
@ -629,7 +671,7 @@ static_stage3_done (NMModemBroadband *self)
|
|||
|
||||
/* Fully fail if invalid IP address retrieved */
|
||||
address_string = mm_bearer_ip_config_get_address (self->priv->ipv4_config);
|
||||
if (!ip_string_to_network_address (address_string, &address_network)) {
|
||||
if (!ip4_string_to_num (address_string, &address_network)) {
|
||||
error = g_error_new (NM_MODEM_ERROR,
|
||||
NM_MODEM_ERROR_CONNECTION_INVALID,
|
||||
"(%s) retrieving IP4 configuration failed: invalid address given '%s'",
|
||||
|
|
@ -640,7 +682,7 @@ static_stage3_done (NMModemBroadband *self)
|
|||
|
||||
/* Missing gateway not a hard failure */
|
||||
gw_string = mm_bearer_ip_config_get_gateway (self->priv->ipv4_config);
|
||||
ip_string_to_network_address (gw_string, &gw);
|
||||
ip4_string_to_num (gw_string, &gw);
|
||||
|
||||
config = nm_ip4_config_new ();
|
||||
|
||||
|
|
@ -660,7 +702,7 @@ static_stage3_done (NMModemBroadband *self)
|
|||
/* DNS servers */
|
||||
dns = mm_bearer_ip_config_get_dns (self->priv->ipv4_config);
|
||||
for (i = 0; dns[i]; i++) {
|
||||
if ( ip_string_to_network_address (dns[i], &address_network)
|
||||
if ( ip4_string_to_num (dns[i], &address_network)
|
||||
&& address_network > 0) {
|
||||
nm_ip4_config_add_nameserver (config, address_network);
|
||||
nm_log_info (LOGD_MB, " DNS %s", dns[i]);
|
||||
|
|
@ -682,7 +724,110 @@ static_stage3_ip4_config_start (NMModem *_self,
|
|||
|
||||
/* We schedule it in an idle just to follow the same logic as in the
|
||||
* generic modem implementation. */
|
||||
g_idle_add ((GSourceFunc)static_stage3_done, self);
|
||||
g_idle_add ((GSourceFunc) static_stage3_ip4_done, self);
|
||||
|
||||
return NM_ACT_STAGE_RETURN_POSTPONE;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* IPv6 method static */
|
||||
|
||||
static gboolean
|
||||
stage3_ip6_done (NMModemBroadband *self)
|
||||
{
|
||||
GError *error = NULL;
|
||||
NMIP6Config *config = NULL;
|
||||
const gchar *address_string;
|
||||
NMPlatformIP6Address address;
|
||||
NMModemIPMethod ip_method;
|
||||
const gchar **dns;
|
||||
guint i;
|
||||
|
||||
g_assert (self->priv->ipv6_config);
|
||||
|
||||
memset (&address, 0, sizeof (address));
|
||||
|
||||
ip_method = get_bearer_ip_method (self->priv->ipv6_config);
|
||||
|
||||
address_string = mm_bearer_ip_config_get_address (self->priv->ipv6_config);
|
||||
if (!address_string) {
|
||||
/* DHCP/SLAAC is allowed to skip addresses; other methods require it */
|
||||
if (ip_method != NM_MODEM_IP_METHOD_AUTO) {
|
||||
error = g_error_new (NM_MODEM_ERROR,
|
||||
NM_MODEM_ERROR_CONNECTION_INVALID,
|
||||
"(%s) retrieving IPv6 configuration failed: no address given",
|
||||
nm_modem_get_uid (NM_MODEM (self)));
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Fail if invalid IP address retrieved */
|
||||
if (!inet_pton (AF_INET6, address_string, (void *) &(address.address))) {
|
||||
error = g_error_new (NM_MODEM_ERROR,
|
||||
NM_MODEM_ERROR_CONNECTION_INVALID,
|
||||
"(%s) retrieving IPv6 configuration failed: invalid address given '%s'",
|
||||
nm_modem_get_uid (NM_MODEM (self)),
|
||||
address_string);
|
||||
goto out;
|
||||
}
|
||||
|
||||
nm_log_info (LOGD_MB, "(%s): IPv6 base configuration:",
|
||||
nm_modem_get_uid (NM_MODEM (self)));
|
||||
|
||||
config = nm_ip6_config_new ();
|
||||
|
||||
address.plen = mm_bearer_ip_config_get_prefix (self->priv->ipv6_config);
|
||||
nm_ip6_config_add_address (config, &address);
|
||||
|
||||
nm_log_info (LOGD_MB, " address %s/%d", address_string, address.plen);
|
||||
|
||||
address_string = mm_bearer_ip_config_get_gateway (self->priv->ipv6_config);
|
||||
if (address_string) {
|
||||
if (!inet_pton (AF_INET6, address_string, (void *) &(address.address))) {
|
||||
error = g_error_new (NM_MODEM_ERROR,
|
||||
NM_MODEM_ERROR_CONNECTION_INVALID,
|
||||
"(%s) retrieving IPv6 configuration failed: invalid gateway given '%s'",
|
||||
nm_modem_get_uid (NM_MODEM (self)),
|
||||
address_string);
|
||||
goto out;
|
||||
}
|
||||
nm_log_info (LOGD_MB, " gateway %s", address_string);
|
||||
nm_ip6_config_set_gateway (config, &address.address);
|
||||
} else if (ip_method == NM_MODEM_IP_METHOD_STATIC) {
|
||||
/* Gateway required for the 'static' method */
|
||||
error = g_error_new (NM_MODEM_ERROR,
|
||||
NM_MODEM_ERROR_CONNECTION_INVALID,
|
||||
"(%s) retrieving IPv6 configuration failed: missing gateway",
|
||||
nm_modem_get_uid (NM_MODEM (self)));
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* DNS servers */
|
||||
dns = mm_bearer_ip_config_get_dns (self->priv->ipv6_config);
|
||||
for (i = 0; dns[i]; i++) {
|
||||
struct in6_addr addr;
|
||||
|
||||
if (inet_pton (AF_INET6, dns[i], &addr)) {
|
||||
nm_ip6_config_add_nameserver (config, &addr);
|
||||
nm_log_info (LOGD_MB, " DNS %s", dns[i]);
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
nm_modem_emit_ip6_config_result (NM_MODEM (self), config, error);
|
||||
g_clear_object (&config);
|
||||
g_clear_error (&error);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static NMActStageReturn
|
||||
stage3_ip6_config_request (NMModem *_self, NMDeviceStateReason *reason)
|
||||
{
|
||||
NMModemBroadband *self = NM_MODEM_BROADBAND (_self);
|
||||
|
||||
/* We schedule it in an idle just to follow the same logic as in the
|
||||
* generic modem implementation. */
|
||||
g_idle_add ((GSourceFunc) stage3_ip6_done, self);
|
||||
|
||||
return NM_ACT_STAGE_RETURN_POSTPONE;
|
||||
}
|
||||
|
|
@ -721,11 +866,15 @@ simple_disconnect_ready (MMModemSimple *modem_iface,
|
|||
}
|
||||
|
||||
static void
|
||||
disconnect (NMModem *self,
|
||||
disconnect (NMModem *modem,
|
||||
gboolean warn)
|
||||
{
|
||||
NMModemBroadband *self = NM_MODEM_BROADBAND (modem);
|
||||
SimpleDisconnectContext *ctx;
|
||||
|
||||
if (!self->priv->simple_iface)
|
||||
return;
|
||||
|
||||
ctx = g_slice_new (SimpleDisconnectContext);
|
||||
ctx->self = g_object_ref (self);
|
||||
|
||||
|
|
@ -807,6 +956,21 @@ modem_state_changed (MMModem *modem,
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
static NMModemIPType
|
||||
mm_ip_family_to_nm (MMBearerIpFamily family)
|
||||
{
|
||||
NMModemIPType nm_type = NM_MODEM_IP_TYPE_UNKNOWN;
|
||||
|
||||
if (family & MM_BEARER_IP_FAMILY_IPV4)
|
||||
nm_type |= NM_MODEM_IP_TYPE_IPV4;
|
||||
if (family & MM_BEARER_IP_FAMILY_IPV6)
|
||||
nm_type |= NM_MODEM_IP_TYPE_IPV6;
|
||||
if (family & MM_BEARER_IP_FAMILY_IPV4V6)
|
||||
nm_type |= MM_BEARER_IP_FAMILY_IPV4V6;
|
||||
|
||||
return nm_type;
|
||||
}
|
||||
|
||||
NMModem *
|
||||
nm_modem_broadband_new (GObject *object, GError **error)
|
||||
{
|
||||
|
|
@ -831,6 +995,7 @@ nm_modem_broadband_new (GObject *object, GError **error)
|
|||
NM_MODEM_UID, mm_modem_get_primary_port (modem_iface),
|
||||
NM_MODEM_CONTROL_PORT, mm_modem_get_primary_port (modem_iface),
|
||||
NM_MODEM_DATA_PORT, NULL, /* We don't know it until bearer created */
|
||||
NM_MODEM_IP_TYPES, mm_ip_family_to_nm (mm_modem_get_supported_ip_families (modem_iface)),
|
||||
NM_MODEM_STATE, mm_state_to_nm (mm_modem_get_state (modem_iface)),
|
||||
NM_MODEM_DEVICE_ID, mm_modem_get_device_identifier (modem_iface),
|
||||
NM_MODEM_BROADBAND_MODEM, modem_object,
|
||||
|
|
@ -968,6 +1133,7 @@ nm_modem_broadband_class_init (NMModemBroadbandClass *klass)
|
|||
|
||||
modem_class->get_capabilities = get_capabilities;
|
||||
modem_class->static_stage3_ip4_config_start = static_stage3_ip4_config_start;
|
||||
modem_class->stage3_ip6_config_request = stage3_ip6_config_request;
|
||||
modem_class->disconnect = disconnect;
|
||||
modem_class->deactivate = deactivate;
|
||||
modem_class->set_mm_enabled = set_mm_enabled;
|
||||
|
|
|
|||
|
|
@ -42,11 +42,13 @@ enum {
|
|||
PROP_PATH,
|
||||
PROP_UID,
|
||||
PROP_DRIVER,
|
||||
PROP_IP_METHOD,
|
||||
PROP_IP4_METHOD,
|
||||
PROP_IP6_METHOD,
|
||||
PROP_IP_TIMEOUT,
|
||||
PROP_STATE,
|
||||
PROP_DEVICE_ID,
|
||||
PROP_SIM_ID,
|
||||
PROP_IP_TYPES,
|
||||
|
||||
LAST_PROP
|
||||
};
|
||||
|
|
@ -58,11 +60,14 @@ typedef struct {
|
|||
char *control_port;
|
||||
char *data_port;
|
||||
char *ppp_iface;
|
||||
guint32 ip_method;
|
||||
NMModemIPMethod ip4_method;
|
||||
NMModemIPMethod ip6_method;
|
||||
NMUtilsIPv6IfaceId iid;
|
||||
NMModemState state;
|
||||
NMModemState prev_state; /* revert to this state if enable/disable fails */
|
||||
char *device_id;
|
||||
char *sim_id;
|
||||
NMModemIPType ip_types;
|
||||
|
||||
NMPPPManager *ppp_manager;
|
||||
|
||||
|
|
@ -82,6 +87,7 @@ enum {
|
|||
PPP_FAILED,
|
||||
PREPARE_RESULT,
|
||||
IP4_CONFIG_RESULT,
|
||||
IP6_CONFIG_RESULT,
|
||||
AUTH_REQUESTED,
|
||||
AUTH_RESULT,
|
||||
REMOVED,
|
||||
|
|
@ -218,6 +224,103 @@ nm_modem_emit_removed (NMModem *self)
|
|||
g_signal_emit (self, signals[REMOVED], 0);
|
||||
}
|
||||
|
||||
NMModemIPType
|
||||
nm_modem_get_supported_ip_types (NMModem *self)
|
||||
{
|
||||
return NM_MODEM_GET_PRIVATE (self)->ip_types;
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_modem_get_connection_ip_type:
|
||||
* @self: the #NMModem
|
||||
* @connection: the #NMConnection to determine IP type to use
|
||||
*
|
||||
* Given a modem and a connection, determine which NMModemIpType to use
|
||||
* when connecting.
|
||||
*
|
||||
* Returns: a single %NMModemIpType value
|
||||
*/
|
||||
NMModemIPType
|
||||
nm_modem_get_connection_ip_type (NMModem *self,
|
||||
NMConnection *connection,
|
||||
GError **error)
|
||||
{
|
||||
NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self);
|
||||
NMSettingIP4Config *s_ip4;
|
||||
NMSettingIP6Config *s_ip6;
|
||||
const char *method;
|
||||
gboolean ip4 = TRUE, ip6 = TRUE;
|
||||
gboolean ip4_may_fail = TRUE, ip6_may_fail = TRUE;
|
||||
|
||||
s_ip4 = nm_connection_get_setting_ip4_config (connection);
|
||||
if (s_ip4) {
|
||||
method = nm_setting_ip4_config_get_method (s_ip4);
|
||||
if (g_strcmp0 (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED) == 0)
|
||||
ip4 = FALSE;
|
||||
ip4_may_fail = nm_setting_ip4_config_get_may_fail (s_ip4);
|
||||
}
|
||||
|
||||
s_ip6 = nm_connection_get_setting_ip6_config (connection);
|
||||
if (s_ip6) {
|
||||
method = nm_setting_ip6_config_get_method (s_ip6);
|
||||
if (g_strcmp0 (method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE) == 0)
|
||||
ip6 = FALSE;
|
||||
ip6_may_fail = nm_setting_ip6_config_get_may_fail (s_ip6);
|
||||
}
|
||||
|
||||
if (ip4 && !ip6) {
|
||||
if (!(priv->ip_types & NM_MODEM_IP_TYPE_IPV4)) {
|
||||
g_set_error_literal (error,
|
||||
NM_MODEM_ERROR,
|
||||
NM_MODEM_ERROR_CONNECTION_INCOMPATIBLE,
|
||||
"Connection requested IPv4 but IPv4 is "
|
||||
"unsuported by the modem.");
|
||||
return NM_MODEM_IP_TYPE_UNKNOWN;
|
||||
}
|
||||
return NM_MODEM_IP_TYPE_IPV4;
|
||||
}
|
||||
|
||||
if (ip6 && !ip4) {
|
||||
if (!(priv->ip_types & NM_MODEM_IP_TYPE_IPV6)) {
|
||||
g_set_error_literal (error,
|
||||
NM_MODEM_ERROR,
|
||||
NM_MODEM_ERROR_CONNECTION_INCOMPATIBLE,
|
||||
"Connection requested IPv6 but IPv6 is "
|
||||
"unsuported by the modem.");
|
||||
return NM_MODEM_IP_TYPE_UNKNOWN;
|
||||
}
|
||||
return NM_MODEM_IP_TYPE_IPV6;
|
||||
}
|
||||
|
||||
if (ip4 && ip6) {
|
||||
/* Modem supports dual-stack */
|
||||
if (priv->ip_types & NM_MODEM_IP_TYPE_IPV4V6)
|
||||
return NM_MODEM_IP_TYPE_IPV4V6;
|
||||
|
||||
/* Both IPv4 and IPv6 requested, but modem doesn't support dual-stack;
|
||||
* if one method is marked "may-fail" then use the other.
|
||||
*/
|
||||
if (ip6_may_fail)
|
||||
return NM_MODEM_IP_TYPE_IPV4;
|
||||
else if (ip4_may_fail)
|
||||
return NM_MODEM_IP_TYPE_IPV6;
|
||||
|
||||
g_set_error_literal (error,
|
||||
NM_MODEM_ERROR,
|
||||
NM_MODEM_ERROR_CONNECTION_INCOMPATIBLE,
|
||||
"Connection requested both IPv4 and IPv6 "
|
||||
"but dual-stack addressing is unsupported "
|
||||
"by the modem.");
|
||||
return NM_MODEM_IP_TYPE_UNKNOWN;
|
||||
}
|
||||
|
||||
g_set_error_literal (error,
|
||||
NM_MODEM_ERROR,
|
||||
NM_MODEM_ERROR_CONNECTION_INCOMPATIBLE,
|
||||
"Connection specified no IP configuration!");
|
||||
return NM_MODEM_IP_TYPE_UNKNOWN;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* IP method PPP */
|
||||
|
||||
|
|
@ -236,6 +339,18 @@ ppp_state_changed (NMPPPManager *ppp_manager, NMPPPStatus status, gpointer user_
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
set_data_port (NMModem *self, const char *new_data_port)
|
||||
{
|
||||
NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self);
|
||||
|
||||
if (g_strcmp0 (priv->data_port, new_data_port) != 0) {
|
||||
g_free (priv->data_port);
|
||||
priv->data_port = g_strdup (new_data_port);
|
||||
g_object_notify (G_OBJECT (self), NM_MODEM_DATA_PORT);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ppp_ip4_config (NMPPPManager *ppp_manager,
|
||||
const char *iface,
|
||||
|
|
@ -243,7 +358,6 @@ ppp_ip4_config (NMPPPManager *ppp_manager,
|
|||
gpointer user_data)
|
||||
{
|
||||
NMModem *self = NM_MODEM (user_data);
|
||||
NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self);
|
||||
guint32 i, num;
|
||||
guint32 bad_dns1 = htonl (0x0A0B0C0D);
|
||||
guint32 good_dns1 = htonl (0x04020201); /* GTE nameserver */
|
||||
|
|
@ -252,9 +366,7 @@ ppp_ip4_config (NMPPPManager *ppp_manager,
|
|||
gboolean dns_workaround = FALSE;
|
||||
|
||||
/* Notify about the new data port to use */
|
||||
g_free (priv->ppp_iface);
|
||||
priv->ppp_iface = g_strdup (iface);
|
||||
g_object_notify (G_OBJECT (self), NM_MODEM_DATA_PORT);
|
||||
set_data_port (self, iface);
|
||||
|
||||
/* Work around a PPP bug (#1732) which causes many mobile broadband
|
||||
* providers to return 10.11.12.13 and 10.11.12.14 for the DNS servers.
|
||||
|
|
@ -295,6 +407,23 @@ ppp_ip4_config (NMPPPManager *ppp_manager,
|
|||
g_signal_emit (self, signals[IP4_CONFIG_RESULT], 0, config, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
ppp_ip6_config (NMPPPManager *ppp_manager,
|
||||
const char *iface,
|
||||
const NMUtilsIPv6IfaceId *iid,
|
||||
NMIP6Config *config,
|
||||
gpointer user_data)
|
||||
{
|
||||
NMModem *self = NM_MODEM (user_data);
|
||||
|
||||
/* Notify about the new data port to use */
|
||||
set_data_port (self, iface);
|
||||
|
||||
NM_MODEM_GET_PRIVATE (self)->iid = *iid;
|
||||
|
||||
nm_modem_emit_ip6_config_result (self, config, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
ppp_stats (NMPPPManager *ppp_manager,
|
||||
guint32 in_bytes,
|
||||
|
|
@ -313,20 +442,27 @@ ppp_stats (NMPPPManager *ppp_manager,
|
|||
}
|
||||
|
||||
static NMActStageReturn
|
||||
ppp_stage3_ip4_config_start (NMModem *self,
|
||||
NMActRequest *req,
|
||||
NMDeviceStateReason *reason)
|
||||
ppp_stage3_ip_config_start (NMModem *self,
|
||||
NMActRequest *req,
|
||||
NMDeviceStateReason *reason)
|
||||
{
|
||||
NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self);
|
||||
const char *ppp_name = NULL;
|
||||
GError *error = NULL;
|
||||
NMActStageReturn ret;
|
||||
guint ip_timeout = 20;
|
||||
guint ip_timeout = 30;
|
||||
|
||||
g_return_val_if_fail (NM_IS_MODEM (self), NM_ACT_STAGE_RETURN_FAILURE);
|
||||
g_return_val_if_fail (NM_IS_ACT_REQUEST (req), NM_ACT_STAGE_RETURN_FAILURE);
|
||||
g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE);
|
||||
|
||||
/* If we're already running PPP don't restart it; for example, if both
|
||||
* IPv4 and IPv6 are requested, IPv4 gets started first, but we use the
|
||||
* same pppd for both v4 and v6.
|
||||
*/
|
||||
if (priv->ppp_manager)
|
||||
return NM_ACT_STAGE_RETURN_POSTPONE;
|
||||
|
||||
if (NM_MODEM_GET_CLASS (self)->get_user_pass) {
|
||||
NMConnection *connection = nm_act_request_get_connection (req);
|
||||
|
||||
|
|
@ -336,7 +472,7 @@ ppp_stage3_ip4_config_start (NMModem *self,
|
|||
}
|
||||
|
||||
/* Check if ModemManager requested a specific IP timeout to be used. If 0 reported,
|
||||
* use the default one (20s) */
|
||||
* use the default one (30s) */
|
||||
if (priv->mm_ip_timeout > 0) {
|
||||
nm_log_info (LOGD_PPP, "using modem-specified IP timeout: %u seconds",
|
||||
priv->mm_ip_timeout);
|
||||
|
|
@ -351,6 +487,9 @@ ppp_stage3_ip4_config_start (NMModem *self,
|
|||
g_signal_connect (priv->ppp_manager, "ip4-config",
|
||||
G_CALLBACK (ppp_ip4_config),
|
||||
self);
|
||||
g_signal_connect (priv->ppp_manager, "ip6-config",
|
||||
G_CALLBACK (ppp_ip6_config),
|
||||
self);
|
||||
g_signal_connect (priv->ppp_manager, "stats",
|
||||
G_CALLBACK (ppp_stats),
|
||||
self);
|
||||
|
|
@ -382,6 +521,8 @@ nm_modem_stage3_ip4_config_start (NMModem *self,
|
|||
{
|
||||
NMModemPrivate *priv;
|
||||
NMActRequest *req;
|
||||
NMConnection *connection;
|
||||
const char *method;
|
||||
NMActStageReturn ret;
|
||||
|
||||
g_return_val_if_fail (NM_IS_MODEM (self), NM_ACT_STAGE_RETURN_FAILURE);
|
||||
|
|
@ -391,21 +532,36 @@ nm_modem_stage3_ip4_config_start (NMModem *self,
|
|||
|
||||
req = nm_device_get_act_request (device);
|
||||
g_assert (req);
|
||||
connection = nm_act_request_get_connection (req);
|
||||
g_assert (connection);
|
||||
method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP4_CONFIG);
|
||||
|
||||
/* Only Disabled and Auto methods make sense for WWAN */
|
||||
if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED) == 0)
|
||||
return NM_ACT_STAGE_RETURN_STOP;
|
||||
|
||||
if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO) != 0) {
|
||||
nm_log_warn (LOGD_MB | LOGD_IP4,
|
||||
"(%s): unhandled WWAN IPv4 method '%s'; will fail",
|
||||
nm_modem_get_uid (self), method);
|
||||
*reason = NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE;
|
||||
return NM_ACT_STAGE_RETURN_FAILURE;
|
||||
}
|
||||
|
||||
priv = NM_MODEM_GET_PRIVATE (self);
|
||||
switch (priv->ip_method) {
|
||||
case MM_MODEM_IP_METHOD_PPP:
|
||||
ret = ppp_stage3_ip4_config_start (self, req, reason);
|
||||
switch (priv->ip4_method) {
|
||||
case NM_MODEM_IP_METHOD_PPP:
|
||||
ret = ppp_stage3_ip_config_start (self, req, reason);
|
||||
break;
|
||||
case MM_MODEM_IP_METHOD_STATIC:
|
||||
case NM_MODEM_IP_METHOD_STATIC:
|
||||
ret = NM_MODEM_GET_CLASS (self)->static_stage3_ip4_config_start (self, req, reason);
|
||||
break;
|
||||
case MM_MODEM_IP_METHOD_DHCP:
|
||||
case NM_MODEM_IP_METHOD_AUTO:
|
||||
ret = device_class->act_stage3_ip4_config_start (device, NULL, reason);
|
||||
break;
|
||||
default:
|
||||
nm_log_err (LOGD_MB, "unknown IP method %d", priv->ip_method);
|
||||
ret = NM_ACT_STAGE_RETURN_FAILURE;
|
||||
nm_log_info (LOGD_MB, "(%s): IPv4 configuration disabled", nm_modem_get_uid (self));
|
||||
ret = NM_ACT_STAGE_RETURN_STOP;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -423,8 +579,8 @@ nm_modem_ip4_pre_commit (NMModem *modem,
|
|||
* not point-to-point) and IP config has a /32 prefix, then we assume that
|
||||
* ARP will be pointless and we turn it off.
|
||||
*/
|
||||
if ( priv->ip_method == MM_MODEM_IP_METHOD_STATIC
|
||||
|| priv->ip_method == MM_MODEM_IP_METHOD_DHCP) {
|
||||
if ( priv->ip4_method == NM_MODEM_IP_METHOD_STATIC
|
||||
|| priv->ip4_method == NM_MODEM_IP_METHOD_AUTO) {
|
||||
const NMPlatformIP4Address *address = nm_ip4_config_get_address (config, 0);
|
||||
|
||||
g_assert (address);
|
||||
|
|
@ -435,15 +591,100 @@ nm_modem_ip4_pre_commit (NMModem *modem,
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
void
|
||||
nm_modem_emit_ip6_config_result (NMModem *self,
|
||||
NMIP6Config *config,
|
||||
GError *error)
|
||||
{
|
||||
NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self);
|
||||
guint i, num;
|
||||
gboolean do_slaac = TRUE;
|
||||
|
||||
if (error) {
|
||||
g_signal_emit (self, signals[IP6_CONFIG_RESULT], 0, NULL, FALSE, error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (config) {
|
||||
/* If the IPv6 configuration only included a Link-Local address, then
|
||||
* we have to run SLAAC to get the full IPv6 configuration.
|
||||
*/
|
||||
num = nm_ip6_config_get_num_addresses (config);
|
||||
g_assert (num > 0);
|
||||
for (i = 0; i < num; i++) {
|
||||
const NMPlatformIP6Address * addr = nm_ip6_config_get_address (config, i);
|
||||
|
||||
if (IN6_IS_ADDR_LINKLOCAL (&addr->address)) {
|
||||
if (!priv->iid.id)
|
||||
priv->iid.id = ((guint64 *)(&addr->address.s6_addr))[1];
|
||||
} else
|
||||
do_slaac = FALSE;
|
||||
}
|
||||
}
|
||||
g_assert (config || do_slaac);
|
||||
|
||||
g_signal_emit (self, signals[IP6_CONFIG_RESULT], 0, config, do_slaac, NULL);
|
||||
}
|
||||
|
||||
static NMActStageReturn
|
||||
stage3_ip6_config_request (NMModem *self, NMDeviceStateReason *reason)
|
||||
{
|
||||
*reason = NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE;
|
||||
return NM_ACT_STAGE_RETURN_FAILURE;
|
||||
}
|
||||
|
||||
NMActStageReturn
|
||||
nm_modem_stage3_ip6_config_start (NMModem *self,
|
||||
NMDevice *device,
|
||||
NMDeviceClass *device_class,
|
||||
NMActRequest *req,
|
||||
NMDeviceStateReason *reason)
|
||||
{
|
||||
/* FIXME: We don't support IPv6 on modems quite yet... */
|
||||
nm_device_activate_schedule_ip6_config_timeout (device);
|
||||
return NM_ACT_STAGE_RETURN_POSTPONE;
|
||||
NMModemPrivate *priv;
|
||||
NMActStageReturn ret;
|
||||
NMConnection *connection;
|
||||
const char *method;
|
||||
|
||||
g_return_val_if_fail (self != NULL, NM_ACT_STAGE_RETURN_FAILURE);
|
||||
g_return_val_if_fail (NM_IS_MODEM (self), NM_ACT_STAGE_RETURN_FAILURE);
|
||||
g_return_val_if_fail (req != NULL, NM_ACT_STAGE_RETURN_FAILURE);
|
||||
g_return_val_if_fail (NM_IS_ACT_REQUEST (req), NM_ACT_STAGE_RETURN_FAILURE);
|
||||
g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE);
|
||||
|
||||
connection = nm_act_request_get_connection (req);
|
||||
g_assert (connection);
|
||||
method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP6_CONFIG);
|
||||
|
||||
/* Only Ignore and Auto methods make sense for WWAN */
|
||||
if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE) == 0)
|
||||
return NM_ACT_STAGE_RETURN_STOP;
|
||||
|
||||
if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO) != 0) {
|
||||
nm_log_warn (LOGD_MB | LOGD_IP6,
|
||||
"(%s): unhandled WWAN IPv6 method '%s'; will fail",
|
||||
nm_modem_get_uid (self), method);
|
||||
*reason = NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE;
|
||||
return NM_ACT_STAGE_RETURN_FAILURE;
|
||||
}
|
||||
|
||||
priv = NM_MODEM_GET_PRIVATE (self);
|
||||
switch (priv->ip6_method) {
|
||||
case NM_MODEM_IP_METHOD_PPP:
|
||||
ret = ppp_stage3_ip_config_start (self, req, reason);
|
||||
break;
|
||||
case NM_MODEM_IP_METHOD_STATIC:
|
||||
case NM_MODEM_IP_METHOD_AUTO:
|
||||
/* Both static and DHCP/Auto retrieve a base IP config from the modem
|
||||
* which in the static case is the full config, and the DHCP/Auto case
|
||||
* is just the IPv6LL address to use for SLAAC.
|
||||
*/
|
||||
ret = NM_MODEM_GET_CLASS (self)->stage3_ip6_config_request (self, reason);
|
||||
break;
|
||||
default:
|
||||
nm_log_info (LOGD_MB, "(%s): IPv6 configuration disabled", nm_modem_get_uid (self));
|
||||
ret = NM_ACT_STAGE_RETURN_STOP;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -633,22 +874,19 @@ deactivate (NMModem *self, NMDevice *device)
|
|||
priv->ppp_manager = NULL;
|
||||
}
|
||||
|
||||
switch (priv->ip_method) {
|
||||
case MM_MODEM_IP_METHOD_PPP:
|
||||
break;
|
||||
case MM_MODEM_IP_METHOD_STATIC:
|
||||
case MM_MODEM_IP_METHOD_DHCP:
|
||||
if (priv->ip4_method == NM_MODEM_IP_METHOD_STATIC ||
|
||||
priv->ip4_method == NM_MODEM_IP_METHOD_AUTO ||
|
||||
priv->ip6_method == NM_MODEM_IP_METHOD_STATIC ||
|
||||
priv->ip6_method == NM_MODEM_IP_METHOD_AUTO) {
|
||||
ifindex = nm_device_get_ip_ifindex (device);
|
||||
if (ifindex > 0) {
|
||||
nm_platform_route_flush (ifindex);
|
||||
nm_platform_address_flush (ifindex);
|
||||
nm_platform_link_set_down (ifindex);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
nm_log_err (LOGD_MB, "unknown IP method %d", priv->ip_method);
|
||||
break;
|
||||
}
|
||||
priv->ip4_method = NM_MODEM_IP_METHOD_UNKNOWN;
|
||||
priv->ip6_method = NM_MODEM_IP_METHOD_UNKNOWN;
|
||||
|
||||
g_free (priv->ppp_iface);
|
||||
priv->ppp_iface = NULL;
|
||||
|
|
@ -772,6 +1010,15 @@ nm_modem_owns_port (NMModem *self, const char *iface)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_modem_get_iid (NMModem *self, NMUtilsIPv6IfaceId *out_iid)
|
||||
{
|
||||
g_return_val_if_fail (NM_IS_MODEM (self), FALSE);
|
||||
|
||||
*out_iid = NM_MODEM_GET_PRIVATE (self)->iid;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void
|
||||
|
|
@ -846,8 +1093,11 @@ get_property (GObject *object, guint prop_id,
|
|||
case PROP_UID:
|
||||
g_value_set_string (value, priv->uid);
|
||||
break;
|
||||
case PROP_IP_METHOD:
|
||||
g_value_set_uint (value, priv->ip_method);
|
||||
case PROP_IP4_METHOD:
|
||||
g_value_set_uint (value, priv->ip4_method);
|
||||
break;
|
||||
case PROP_IP6_METHOD:
|
||||
g_value_set_uint (value, priv->ip6_method);
|
||||
break;
|
||||
case PROP_IP_TIMEOUT:
|
||||
g_value_set_uint (value, priv->mm_ip_timeout);
|
||||
|
|
@ -861,6 +1111,9 @@ get_property (GObject *object, guint prop_id,
|
|||
case PROP_SIM_ID:
|
||||
g_value_set_string (value, priv->sim_id);
|
||||
break;
|
||||
case PROP_IP_TYPES:
|
||||
g_value_set_uint (value, priv->ip_types);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
|
|
@ -892,8 +1145,11 @@ set_property (GObject *object, guint prop_id,
|
|||
/* Construct only */
|
||||
priv->uid = g_value_dup_string (value);
|
||||
break;
|
||||
case PROP_IP_METHOD:
|
||||
priv->ip_method = g_value_get_uint (value);
|
||||
case PROP_IP4_METHOD:
|
||||
priv->ip4_method = g_value_get_uint (value);
|
||||
break;
|
||||
case PROP_IP6_METHOD:
|
||||
priv->ip6_method = g_value_get_uint (value);
|
||||
break;
|
||||
case PROP_IP_TIMEOUT:
|
||||
priv->mm_ip_timeout = g_value_get_uint (value);
|
||||
|
|
@ -909,6 +1165,9 @@ set_property (GObject *object, guint prop_id,
|
|||
g_free (priv->sim_id);
|
||||
priv->sim_id = g_value_dup_string (value);
|
||||
break;
|
||||
case PROP_IP_TYPES:
|
||||
priv->ip_types = g_value_get_uint (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
|
|
@ -959,6 +1218,7 @@ nm_modem_class_init (NMModemClass *klass)
|
|||
object_class->finalize = finalize;
|
||||
|
||||
klass->act_stage1_prepare = act_stage1_prepare;
|
||||
klass->stage3_ip6_config_request = stage3_ip6_config_request;
|
||||
klass->deactivate = deactivate;
|
||||
|
||||
/* Properties */
|
||||
|
|
@ -999,12 +1259,21 @@ nm_modem_class_init (NMModemClass *klass)
|
|||
G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property
|
||||
(object_class, PROP_IP_METHOD,
|
||||
g_param_spec_uint (NM_MODEM_IP_METHOD, "", "",
|
||||
MM_MODEM_IP_METHOD_PPP,
|
||||
MM_MODEM_IP_METHOD_DHCP,
|
||||
MM_MODEM_IP_METHOD_PPP,
|
||||
G_PARAM_READWRITE |
|
||||
(object_class, PROP_IP4_METHOD,
|
||||
g_param_spec_uint (NM_MODEM_IP4_METHOD, "", "",
|
||||
NM_MODEM_IP_METHOD_UNKNOWN,
|
||||
NM_MODEM_IP_METHOD_AUTO,
|
||||
NM_MODEM_IP_METHOD_UNKNOWN,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property
|
||||
(object_class, PROP_IP6_METHOD,
|
||||
g_param_spec_uint (NM_MODEM_IP6_METHOD, "", "",
|
||||
NM_MODEM_IP_METHOD_UNKNOWN,
|
||||
NM_MODEM_IP_METHOD_AUTO,
|
||||
NM_MODEM_IP_METHOD_UNKNOWN,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property
|
||||
|
|
@ -1036,6 +1305,14 @@ nm_modem_class_init (NMModemClass *klass)
|
|||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property
|
||||
(object_class, PROP_IP_TYPES,
|
||||
g_param_spec_uint (NM_MODEM_IP_TYPES,
|
||||
"IP Types",
|
||||
"Supported IP types",
|
||||
0, G_MAXUINT32, NM_MODEM_IP_TYPE_IPV4,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
|
||||
|
||||
/* Signals */
|
||||
|
||||
signals[PPP_STATS] =
|
||||
|
|
@ -1063,6 +1340,27 @@ nm_modem_class_init (NMModemClass *klass)
|
|||
NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 2, G_TYPE_OBJECT, G_TYPE_POINTER);
|
||||
|
||||
/**
|
||||
* NMModem::ip6-config-result:
|
||||
* @modem: the #NMModem on which the signal is emitted
|
||||
* @config: the #NMIP6Config to apply to the modem's data port
|
||||
* @do_slaac: %TRUE if IPv6 SLAAC should be started
|
||||
* @error: a #GError if any error occurred during IP configuration
|
||||
*
|
||||
* This signal is emitted when IPv6 configuration has completed or failed.
|
||||
* If @error is set the configuration failed. If @config is set, then
|
||||
* the details should be applied to the data port before any further
|
||||
* configuration (like SLAAC) is done. @do_slaac indicates whether SLAAC
|
||||
* should be started after applying @config to the data port.
|
||||
*/
|
||||
signals[IP6_CONFIG_RESULT] =
|
||||
g_signal_new (NM_MODEM_IP6_CONFIG_RESULT,
|
||||
G_OBJECT_CLASS_TYPE (object_class),
|
||||
G_SIGNAL_RUN_FIRST,
|
||||
G_STRUCT_OFFSET (NMModemClass, ip6_config_result),
|
||||
NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 3, G_TYPE_OBJECT, G_TYPE_BOOLEAN, G_TYPE_POINTER);
|
||||
|
||||
signals[PREPARE_RESULT] =
|
||||
g_signal_new (NM_MODEM_PREPARE_RESULT,
|
||||
G_OBJECT_CLASS_TYPE (object_class),
|
||||
|
|
|
|||
|
|
@ -42,25 +42,50 @@ G_BEGIN_DECLS
|
|||
#define NM_MODEM_DRIVER "driver"
|
||||
#define NM_MODEM_CONTROL_PORT "control-port"
|
||||
#define NM_MODEM_DATA_PORT "data-port"
|
||||
#define NM_MODEM_IP_METHOD "ip-method"
|
||||
#define NM_MODEM_IP4_METHOD "ip4-method"
|
||||
#define NM_MODEM_IP6_METHOD "ip6-method"
|
||||
#define NM_MODEM_IP_TIMEOUT "ip-timeout"
|
||||
#define NM_MODEM_STATE "state"
|
||||
#define NM_MODEM_DEVICE_ID "device-id"
|
||||
#define NM_MODEM_SIM_ID "sim-id"
|
||||
#define NM_MODEM_IP_TYPES "ip-types" /* Supported IP types */
|
||||
|
||||
/* Signals */
|
||||
#define NM_MODEM_PPP_STATS "ppp-stats"
|
||||
#define NM_MODEM_PPP_FAILED "ppp-failed"
|
||||
#define NM_MODEM_PREPARE_RESULT "prepare-result"
|
||||
#define NM_MODEM_IP4_CONFIG_RESULT "ip4-config-result"
|
||||
#define NM_MODEM_IP6_CONFIG_RESULT "ip6-config-result"
|
||||
#define NM_MODEM_AUTH_REQUESTED "auth-requested"
|
||||
#define NM_MODEM_AUTH_RESULT "auth-result"
|
||||
#define NM_MODEM_REMOVED "removed"
|
||||
#define NM_MODEM_STATE_CHANGED "state-changed"
|
||||
|
||||
#define MM_MODEM_IP_METHOD_PPP 0
|
||||
#define MM_MODEM_IP_METHOD_STATIC 1
|
||||
#define MM_MODEM_IP_METHOD_DHCP 2
|
||||
typedef enum {
|
||||
NM_MODEM_IP_METHOD_UNKNOWN = 0,
|
||||
NM_MODEM_IP_METHOD_PPP,
|
||||
NM_MODEM_IP_METHOD_STATIC,
|
||||
NM_MODEM_IP_METHOD_AUTO, /* DHCP and/or SLAAC */
|
||||
} NMModemIPMethod;
|
||||
|
||||
/**
|
||||
* NMModemIPType:
|
||||
* @NM_MODEM_IP_TYPE_UNKNOWN: unknown or no IP support
|
||||
* @NM_MODEM_IP_TYPE_IPV4: IPv4-only bearers are supported
|
||||
* @NM_MODEM_IP_TYPE_IPV6: IPv6-only bearers are supported
|
||||
* @NM_MODEM_IP_TYPE_IPV4V6: dual-stack IPv4 + IPv6 bearers are supported
|
||||
*
|
||||
* Indicates what IP protocols the modem supports for an IP bearer. Any
|
||||
* combination of flags is possible. For example, (%NM_MODEM_IP_TYPE_IPV4 |
|
||||
* %NM_MODEM_IP_TYPE_IPV6) indicates that the modem supports IPv4 and IPv6
|
||||
* but not simultaneously on the same bearer.
|
||||
*/
|
||||
typedef enum {
|
||||
NM_MODEM_IP_TYPE_UNKNOWN = 0x0,
|
||||
NM_MODEM_IP_TYPE_IPV4 = 0x1,
|
||||
NM_MODEM_IP_TYPE_IPV6 = 0x2,
|
||||
NM_MODEM_IP_TYPE_IPV4V6 = 0x4
|
||||
} NMModemIPType;
|
||||
|
||||
typedef enum {
|
||||
NM_MODEM_ERROR_CONNECTION_NOT_GSM, /*< nick=ConnectionNotGsm >*/
|
||||
|
|
@ -68,6 +93,7 @@ typedef enum {
|
|||
NM_MODEM_ERROR_CONNECTION_INVALID, /*< nick=ConnectionInvalid >*/
|
||||
NM_MODEM_ERROR_CONNECTION_INCOMPATIBLE, /*< nick=ConnectionIncompatible >*/
|
||||
NM_MODEM_ERROR_INITIALIZATION_FAILED, /*< nick=InitializationFailed >*/
|
||||
NM_MODEM_ERROR_IP_CONFIG_INVALID, /*< nick=IpConfigInvalid >*/
|
||||
} NMModemError;
|
||||
|
||||
typedef enum { /*< underscore_name=nm_modem_state >*/
|
||||
|
|
@ -122,6 +148,12 @@ typedef struct {
|
|||
NMActRequest *req,
|
||||
NMDeviceStateReason *reason);
|
||||
|
||||
/* Request the IP6 config; when the config returns the modem
|
||||
* subclass should emit the ip6_config_result signal.
|
||||
*/
|
||||
NMActStageReturn (*stage3_ip6_config_request) (NMModem *self,
|
||||
NMDeviceStateReason *reason);
|
||||
|
||||
void (*set_mm_enabled) (NMModem *self, gboolean enabled);
|
||||
|
||||
void (*disconnect) (NMModem *self, gboolean warn);
|
||||
|
|
@ -136,6 +168,10 @@ typedef struct {
|
|||
|
||||
void (*prepare_result) (NMModem *self, gboolean success, NMDeviceStateReason reason);
|
||||
void (*ip4_config_result) (NMModem *self, NMIP4Config *config, GError *error);
|
||||
void (*ip6_config_result) (NMModem *self,
|
||||
NMIP6Config *config,
|
||||
gboolean do_slaac,
|
||||
GError *error);
|
||||
|
||||
void (*auth_requested) (NMModem *self);
|
||||
void (*auth_result) (NMModem *self, GError *error);
|
||||
|
|
@ -154,6 +190,7 @@ const char *nm_modem_get_uid (NMModem *modem);
|
|||
const char *nm_modem_get_control_port (NMModem *modem);
|
||||
const char *nm_modem_get_data_port (NMModem *modem);
|
||||
const char *nm_modem_get_driver (NMModem *modem);
|
||||
gboolean nm_modem_get_iid (NMModem *modem, NMUtilsIPv6IfaceId *out_iid);
|
||||
|
||||
gboolean nm_modem_owns_port (NMModem *modem, const char *iface);
|
||||
|
||||
|
|
@ -182,8 +219,7 @@ NMActStageReturn nm_modem_stage3_ip4_config_start (NMModem *modem,
|
|||
NMDeviceStateReason *reason);
|
||||
|
||||
NMActStageReturn nm_modem_stage3_ip6_config_start (NMModem *modem,
|
||||
NMDevice *device,
|
||||
NMDeviceClass *device_class,
|
||||
NMActRequest *req,
|
||||
NMDeviceStateReason *reason);
|
||||
|
||||
void nm_modem_ip4_pre_commit (NMModem *modem, NMDevice *device, NMIP4Config *config);
|
||||
|
|
@ -209,9 +245,20 @@ void nm_modem_set_state (NMModem *self,
|
|||
void nm_modem_set_prev_state (NMModem *self, const char *reason);
|
||||
const char * nm_modem_state_to_string (NMModemState state);
|
||||
|
||||
NMModemIPType nm_modem_get_supported_ip_types (NMModem *self);
|
||||
|
||||
/* For the modem-manager only */
|
||||
void nm_modem_emit_removed (NMModem *self);
|
||||
|
||||
NMModemIPType nm_modem_get_connection_ip_type (NMModem *self,
|
||||
NMConnection *connection,
|
||||
GError **error);
|
||||
|
||||
/* For subclasses */
|
||||
void nm_modem_emit_ip6_config_result (NMModem *self,
|
||||
NMIP6Config *config,
|
||||
GError *error);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* NM_MODEM_H */
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ global:
|
|||
nm_modem_get_control_port;
|
||||
nm_modem_get_data_port;
|
||||
nm_modem_get_driver;
|
||||
nm_modem_get_iid;
|
||||
nm_modem_get_path;
|
||||
nm_modem_get_secrets;
|
||||
nm_modem_get_state;
|
||||
|
|
|
|||
|
|
@ -1719,6 +1719,30 @@ recheck_assume_connection (NMDevice *device, gpointer user_data)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
device_ip_iface_changed (NMDevice *device,
|
||||
GParamSpec *pspec,
|
||||
NMManager *self)
|
||||
{
|
||||
const char *ip_iface = nm_device_get_ip_iface (device);
|
||||
GSList *iter;
|
||||
|
||||
/* Remove NMDevice objects that are actually child devices of others,
|
||||
* when the other device finally knows its IP interface name. For example,
|
||||
* remove the PPP interface that's a child of a WWAN device, since it's
|
||||
* not really a standalone NMDevice.
|
||||
*/
|
||||
for (iter = NM_MANAGER_GET_PRIVATE (self)->devices; iter; iter = iter->next) {
|
||||
NMDevice *candidate = NM_DEVICE (iter->data);
|
||||
|
||||
if ( candidate != device
|
||||
&& g_strcmp0 (nm_device_get_iface (candidate), ip_iface) == 0) {
|
||||
remove_device (self, candidate, FALSE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* add_device:
|
||||
* @self: the #NMManager
|
||||
|
|
@ -1774,6 +1798,10 @@ add_device (NMManager *self, NMDevice *device, gboolean generate_con)
|
|||
G_CALLBACK (device_removed_cb),
|
||||
self);
|
||||
|
||||
g_signal_connect (device, "notify::" NM_DEVICE_IP_IFACE,
|
||||
G_CALLBACK (device_ip_iface_changed),
|
||||
self);
|
||||
|
||||
if (priv->startup) {
|
||||
g_signal_connect (device, "notify::" NM_DEVICE_HAS_PENDING_ACTION,
|
||||
G_CALLBACK (device_has_pending_action_changed),
|
||||
|
|
|
|||
|
|
@ -20,8 +20,8 @@ nm_pppd_plugin_la_SOURCES = \
|
|||
nm_pppd_plugin_la_LDFLAGS = -module -avoid-version
|
||||
|
||||
nm_pppd_plugin_la_LIBADD = \
|
||||
$(top_builddir)/libnm-util/libnm-util.la \
|
||||
$(DBUS_LIBS) \
|
||||
$(GLIB_LIBS)
|
||||
$(GLIB_LIBS) \
|
||||
-ldl
|
||||
|
||||
endif
|
||||
|
|
|
|||
|
|
@ -67,6 +67,10 @@ static gboolean impl_ppp_manager_set_ip4_config (NMPPPManager *manager,
|
|||
GHashTable *config,
|
||||
GError **err);
|
||||
|
||||
static gboolean impl_ppp_manager_set_ip6_config (NMPPPManager *manager,
|
||||
GHashTable *config,
|
||||
GError **err);
|
||||
|
||||
#include "nm-ppp-manager-glue.h"
|
||||
|
||||
static void _ppp_cleanup (NMPPPManager *manager);
|
||||
|
|
@ -101,6 +105,7 @@ G_DEFINE_TYPE (NMPPPManager, nm_ppp_manager, G_TYPE_OBJECT)
|
|||
enum {
|
||||
STATE_CHANGED,
|
||||
IP4_CONFIG,
|
||||
IP6_CONFIG,
|
||||
STATS,
|
||||
|
||||
LAST_SIGNAL
|
||||
|
|
@ -132,6 +137,7 @@ nm_ppp_manager_error_quark (void)
|
|||
static void
|
||||
nm_ppp_manager_init (NMPPPManager *manager)
|
||||
{
|
||||
NM_PPP_MANAGER_GET_PRIVATE (manager)->monitor_fd = -1;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -245,6 +251,14 @@ nm_ppp_manager_class_init (NMPPPManagerClass *manager_class)
|
|||
G_TYPE_STRING,
|
||||
G_TYPE_OBJECT);
|
||||
|
||||
signals[IP6_CONFIG] =
|
||||
g_signal_new ("ip6-config",
|
||||
G_OBJECT_CLASS_TYPE (object_class),
|
||||
G_SIGNAL_RUN_FIRST,
|
||||
G_STRUCT_OFFSET (NMPPPManagerClass, ip6_config),
|
||||
NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 3, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_OBJECT);
|
||||
|
||||
signals[STATS] =
|
||||
g_signal_new ("stats",
|
||||
G_OBJECT_CLASS_TYPE (object_class),
|
||||
|
|
@ -300,8 +314,12 @@ monitor_stats (NMPPPManager *manager)
|
|||
{
|
||||
NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (manager);
|
||||
|
||||
/* already monitoring */
|
||||
if (priv->monitor_fd >= 0)
|
||||
return;
|
||||
|
||||
priv->monitor_fd = socket (AF_INET, SOCK_DGRAM, 0);
|
||||
if (priv->monitor_fd > 0) {
|
||||
if (priv->monitor_fd >= 0) {
|
||||
g_warn_if_fail (priv->monitor_id == 0);
|
||||
if (priv->monitor_id)
|
||||
g_source_remove (priv->monitor_id);
|
||||
|
|
@ -498,20 +516,52 @@ static gboolean impl_ppp_manager_set_state (NMPPPManager *manager,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
set_ip_config_common (NMPPPManager *self,
|
||||
GHashTable *hash,
|
||||
const char *iface_prop,
|
||||
guint32 *out_mtu)
|
||||
{
|
||||
NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (self);
|
||||
NMConnection *connection;
|
||||
NMSettingPPP *s_ppp;
|
||||
GValue *val;
|
||||
|
||||
val = g_hash_table_lookup (hash, iface_prop);
|
||||
if (!val || !G_VALUE_HOLDS_STRING (val)) {
|
||||
nm_log_err (LOGD_PPP, "no interface received!");
|
||||
return FALSE;
|
||||
}
|
||||
if (priv->ip_iface == NULL)
|
||||
priv->ip_iface = g_value_dup_string (val);
|
||||
|
||||
/* Got successful IP config; obviously the secrets worked */
|
||||
connection = nm_act_request_get_connection (priv->act_req);
|
||||
g_assert (connection);
|
||||
g_object_set_data (G_OBJECT (connection), PPP_MANAGER_SECRET_TRIES, NULL);
|
||||
|
||||
/* Get any custom MTU */
|
||||
s_ppp = nm_connection_get_setting_ppp (connection);
|
||||
if (s_ppp && out_mtu)
|
||||
*out_mtu = nm_setting_ppp_get_mtu (s_ppp);
|
||||
|
||||
monitor_stats (self);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
impl_ppp_manager_set_ip4_config (NMPPPManager *manager,
|
||||
GHashTable *config_hash,
|
||||
GError **err)
|
||||
{
|
||||
NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (manager);
|
||||
NMConnection *connection;
|
||||
NMSettingPPP *s_ppp;
|
||||
NMIP4Config *config;
|
||||
NMPlatformIP4Address address;
|
||||
GValue *val;
|
||||
int i;
|
||||
guint32 mtu = 0;
|
||||
|
||||
nm_log_info (LOGD_PPP, "PPP manager(IP Config Get) reply received.");
|
||||
nm_log_info (LOGD_PPP, "PPP manager (IPv4 Config Get) reply received.");
|
||||
|
||||
remove_timeout_handler (manager);
|
||||
|
||||
|
|
@ -557,35 +607,89 @@ impl_ppp_manager_set_ip4_config (NMPPPManager *manager,
|
|||
nm_ip4_config_add_wins (config, g_array_index (wins, guint, i));
|
||||
}
|
||||
|
||||
val = (GValue *) g_hash_table_lookup (config_hash, NM_PPP_IP4_CONFIG_INTERFACE);
|
||||
if (!val || !G_VALUE_HOLDS_STRING (val)) {
|
||||
nm_log_err (LOGD_PPP, "no interface received!");
|
||||
if (!set_ip_config_common (manager, config_hash, NM_PPP_IP4_CONFIG_INTERFACE, &mtu))
|
||||
goto out;
|
||||
}
|
||||
priv->ip_iface = g_value_dup_string (val);
|
||||
|
||||
/* Got successful IP4 config; obviously the secrets worked */
|
||||
connection = nm_act_request_get_connection (priv->act_req);
|
||||
g_assert (connection);
|
||||
g_object_set_data (G_OBJECT (connection), PPP_MANAGER_SECRET_TRIES, NULL);
|
||||
|
||||
/* Merge in custom MTU */
|
||||
s_ppp = nm_connection_get_setting_ppp (connection);
|
||||
if (s_ppp) {
|
||||
guint32 mtu = nm_setting_ppp_get_mtu (s_ppp);
|
||||
|
||||
if (mtu)
|
||||
nm_ip4_config_set_mtu (config, mtu);
|
||||
}
|
||||
if (mtu)
|
||||
nm_ip4_config_set_mtu (config, mtu);
|
||||
|
||||
/* Push the IP4 config up to the device */
|
||||
g_signal_emit (manager, signals[IP4_CONFIG], 0, priv->ip_iface, config);
|
||||
|
||||
monitor_stats (manager);
|
||||
|
||||
out:
|
||||
out:
|
||||
g_object_unref (config);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Converts the named Interface Identifier item to an IPv6 LL address and
|
||||
* returns the IID.
|
||||
*/
|
||||
static gboolean
|
||||
iid_value_to_ll6_addr (GHashTable *hash,
|
||||
const char *prop,
|
||||
struct in6_addr *out_addr,
|
||||
NMUtilsIPv6IfaceId *out_iid)
|
||||
{
|
||||
GValue *val;
|
||||
guint64 iid;
|
||||
|
||||
val = g_hash_table_lookup (hash, prop);
|
||||
if (!val || !G_VALUE_HOLDS (val, G_TYPE_UINT64)) {
|
||||
nm_log_dbg (LOGD_PPP, "pppd plugin property '%s' missing or not a uint64", prop);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
iid = g_value_get_uint64 (val);
|
||||
g_return_val_if_fail (iid != 0, FALSE);
|
||||
|
||||
/* Construct an IPv6 LL address from the interface identifier. See
|
||||
* http://tools.ietf.org/html/rfc4291#section-2.5.1 (IPv6) and
|
||||
* http://tools.ietf.org/html/rfc5072#section-4.1 (IPv6 over PPP).
|
||||
*/
|
||||
memset (out_addr->s6_addr, 0, sizeof (out_addr->s6_addr));
|
||||
out_addr->s6_addr16[0] = htons (0xfe80);
|
||||
memcpy (out_addr->s6_addr + 8, &iid, sizeof (iid));
|
||||
if (out_iid)
|
||||
nm_utils_ipv6_interface_identfier_get_from_addr (out_iid, out_addr);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
impl_ppp_manager_set_ip6_config (NMPPPManager *manager,
|
||||
GHashTable *hash,
|
||||
GError **err)
|
||||
{
|
||||
NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (manager);
|
||||
NMIP6Config *config;
|
||||
NMPlatformIP6Address addr;
|
||||
struct in6_addr a;
|
||||
NMUtilsIPv6IfaceId iid = NM_UTILS_IPV6_IFACE_ID_INIT;
|
||||
|
||||
nm_log_info (LOGD_PPP, "PPP manager (IPv6 Config Get) reply received.");
|
||||
|
||||
remove_timeout_handler (manager);
|
||||
|
||||
config = nm_ip6_config_new ();
|
||||
|
||||
memset (&addr, 0, sizeof (addr));
|
||||
addr.plen = 64;
|
||||
|
||||
if (iid_value_to_ll6_addr (hash, NM_PPP_IP6_CONFIG_PEER_IID, &a, NULL)) {
|
||||
nm_ip6_config_set_gateway (config, &a);
|
||||
addr.peer_address = a;
|
||||
}
|
||||
|
||||
if (iid_value_to_ll6_addr (hash, NM_PPP_IP6_CONFIG_OUR_IID, &addr.address, &iid)) {
|
||||
nm_ip6_config_add_address (config, &addr);
|
||||
|
||||
if (set_ip_config_common (manager, hash, NM_PPP_IP6_CONFIG_INTERFACE, NULL)) {
|
||||
/* Push the IPv6 config and interface identifier up to the device */
|
||||
g_signal_emit (manager, signals[IP6_CONFIG], 0, priv->ip_iface, &iid, config);
|
||||
}
|
||||
} else
|
||||
nm_log_err (LOGD_PPP, "invalid IPv6 address received!");
|
||||
|
||||
g_object_unref (config);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -1127,11 +1231,11 @@ _ppp_cleanup (NMPPPManager *manager)
|
|||
priv->monitor_id = 0;
|
||||
}
|
||||
|
||||
if (priv->monitor_fd) {
|
||||
if (priv->monitor_fd >= 0) {
|
||||
/* Get the stats one last time */
|
||||
monitor_cb (manager);
|
||||
close (priv->monitor_fd);
|
||||
priv->monitor_fd = 0;
|
||||
priv->monitor_fd = -1;
|
||||
}
|
||||
|
||||
if (priv->ppp_timeout_handler) {
|
||||
|
|
|
|||
|
|
@ -29,7 +29,9 @@
|
|||
#include "nm-activation-request.h"
|
||||
#include "nm-connection.h"
|
||||
#include "nm-ip4-config.h"
|
||||
#include "nm-ip6-config.h"
|
||||
#include "nm-pppd-plugin.h"
|
||||
#include "NetworkManagerUtils.h"
|
||||
|
||||
#define NM_TYPE_PPP_MANAGER (nm_ppp_manager_get_type ())
|
||||
#define NM_PPP_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_PPP_MANAGER, NMPPPManager))
|
||||
|
|
@ -50,6 +52,10 @@ typedef struct {
|
|||
/* Signals */
|
||||
void (*state_changed) (NMPPPManager *manager, NMPPPStatus status);
|
||||
void (*ip4_config) (NMPPPManager *manager, const char *iface, NMIP4Config *config);
|
||||
void (*ip6_config) (NMPPPManager *manager,
|
||||
const char *iface,
|
||||
const NMUtilsIPv6IfaceId *iid,
|
||||
NMIP6Config *config);
|
||||
void (*stats) (NMPPPManager *manager, guint32 in_bytes, guint32 out_bytes);
|
||||
} NMPPPManagerClass;
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
* Copyright (C) 2008 Red Hat, Inc.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <string.h>
|
||||
#include <pppd/pppd.h>
|
||||
#include <pppd/fsm.h>
|
||||
|
|
@ -26,10 +27,15 @@
|
|||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <dlfcn.h>
|
||||
#include <glib.h>
|
||||
#include <glib-object.h>
|
||||
#include <dbus/dbus-glib.h>
|
||||
|
||||
#define INET6
|
||||
#include <pppd/eui64.h>
|
||||
#include <pppd/ipv6cp.h>
|
||||
|
||||
#include "NetworkManager.h"
|
||||
#include "nm-pppd-plugin.h"
|
||||
#include "nm-ppp-status.h"
|
||||
|
|
@ -128,7 +134,6 @@ str_to_gvalue (const char *str)
|
|||
val = g_slice_new0 (GValue);
|
||||
g_value_init (val, G_TYPE_STRING);
|
||||
g_value_set_string (val, str);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
|
|
@ -140,7 +145,6 @@ uint_to_gvalue (guint32 i)
|
|||
val = g_slice_new0 (GValue);
|
||||
g_value_init (val, G_TYPE_UINT);
|
||||
g_value_set_uint (val, i);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
|
|
@ -230,7 +234,7 @@ nm_ip_up (void *data, int arg)
|
|||
g_hash_table_insert (hash, NM_PPP_IP4_CONFIG_WINS, val);
|
||||
}
|
||||
|
||||
g_message ("nm-ppp-plugin: (%s): sending Ip4Config to NetworkManager...", __func__);
|
||||
g_message ("nm-ppp-plugin: (%s): sending IPv4 config to NetworkManager...", __func__);
|
||||
|
||||
dbus_g_proxy_call_no_reply (proxy, "SetIp4Config",
|
||||
DBUS_TYPE_G_MAP_OF_VARIANT, hash, G_TYPE_INVALID,
|
||||
|
|
@ -239,6 +243,48 @@ nm_ip_up (void *data, int arg)
|
|||
g_hash_table_destroy (hash);
|
||||
}
|
||||
|
||||
static GValue *
|
||||
eui64_to_gvalue (eui64_t eui)
|
||||
{
|
||||
GValue *val;
|
||||
guint64 iid;
|
||||
|
||||
G_STATIC_ASSERT (sizeof (iid) == sizeof (eui));
|
||||
|
||||
val = g_slice_new0 (GValue);
|
||||
g_value_init (val, G_TYPE_UINT64);
|
||||
memcpy (&iid, &eui, sizeof (eui));
|
||||
g_value_set_uint64 (val, iid);
|
||||
return val;
|
||||
}
|
||||
|
||||
static void
|
||||
nm_ip6_up (void *data, int arg)
|
||||
{
|
||||
ipv6cp_options *ho = &ipv6cp_hisoptions[0];
|
||||
ipv6cp_options *go = &ipv6cp_gotoptions[0];
|
||||
GHashTable *hash;
|
||||
|
||||
g_return_if_fail (DBUS_IS_G_PROXY (proxy));
|
||||
|
||||
g_message ("nm-ppp-plugin: (%s): ip6-up event", __func__);
|
||||
|
||||
hash = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, value_destroy);
|
||||
g_hash_table_insert (hash, NM_PPP_IP6_CONFIG_INTERFACE, str_to_gvalue (ifname));
|
||||
g_hash_table_insert (hash, NM_PPP_IP6_CONFIG_OUR_IID, eui64_to_gvalue (go->ourid));
|
||||
g_hash_table_insert (hash, NM_PPP_IP6_CONFIG_PEER_IID, eui64_to_gvalue (ho->hisid));
|
||||
|
||||
/* DNS is done via DHCPv6 or router advertisements */
|
||||
|
||||
g_message ("nm-ppp-plugin: (%s): sending IPv6 config to NetworkManager...", __func__);
|
||||
|
||||
dbus_g_proxy_call_no_reply (proxy, "SetIp6Config",
|
||||
DBUS_TYPE_G_MAP_OF_VARIANT, hash, G_TYPE_INVALID,
|
||||
G_TYPE_INVALID);
|
||||
|
||||
g_hash_table_destroy (hash);
|
||||
}
|
||||
|
||||
static int
|
||||
get_chap_check (void)
|
||||
{
|
||||
|
|
@ -319,6 +365,27 @@ nm_exit_notify (void *data, int arg)
|
|||
proxy = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
add_ip6_notifier (void)
|
||||
{
|
||||
static struct notifier **notifier = NULL;
|
||||
static gsize load_once = 0;
|
||||
|
||||
if (g_once_init_enter (&load_once)) {
|
||||
void *handle = dlopen(NULL, RTLD_NOW | RTLD_GLOBAL);
|
||||
|
||||
if (handle) {
|
||||
notifier = dlsym (handle, "ipv6_up_notifier");
|
||||
dlclose (handle);
|
||||
}
|
||||
g_once_init_leave (&load_once, 1);
|
||||
}
|
||||
if (notifier)
|
||||
add_notifier (notifier, nm_ip6_up, NULL);
|
||||
else
|
||||
g_message ("nm-ppp-plugin: no IPV6CP notifier support; IPv6 not available");
|
||||
}
|
||||
|
||||
int
|
||||
plugin_init (void)
|
||||
{
|
||||
|
|
@ -356,6 +423,7 @@ plugin_init (void)
|
|||
add_notifier (&phasechange, nm_phasechange, NULL);
|
||||
add_notifier (&ip_up_notifier, nm_ip_up, NULL);
|
||||
add_notifier (&exitnotify, nm_exit_notify, proxy);
|
||||
add_ip6_notifier ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,14 +16,21 @@
|
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Copyright (C) 2008 Novell, Inc.
|
||||
* Copyright (C) 2008 Red Hat, Inc.
|
||||
* Copyright (C) 2008 - 2014 Red Hat, Inc.
|
||||
*/
|
||||
|
||||
#define NM_DBUS_INTERFACE_PPP "org.freedesktop.NetworkManager.PPP"
|
||||
|
||||
#define NM_PPP_IP4_CONFIG_INTERFACE "interface"
|
||||
#define NM_PPP_IP4_CONFIG_ADDRESS "address"
|
||||
#define NM_PPP_IP4_CONFIG_PREFIX "prefix"
|
||||
#define NM_PPP_IP4_CONFIG_GATEWAY "gateway"
|
||||
#define NM_PPP_IP4_CONFIG_DNS "dns"
|
||||
#define NM_PPP_IP4_CONFIG_WINS "wins"
|
||||
#define NM_PPP_IP4_CONFIG_ADDRESS "address"
|
||||
#define NM_PPP_IP4_CONFIG_PREFIX "prefix"
|
||||
#define NM_PPP_IP4_CONFIG_GATEWAY "gateway"
|
||||
#define NM_PPP_IP4_CONFIG_DNS "dns"
|
||||
#define NM_PPP_IP4_CONFIG_WINS "wins"
|
||||
|
||||
#define NM_PPP_IP6_CONFIG_INTERFACE "interface"
|
||||
#define NM_PPP_IP6_CONFIG_OUR_IID "our-iid"
|
||||
#define NM_PPP_IP6_CONFIG_PEER_IID "peer-iid"
|
||||
|
||||
#define DBUS_TYPE_EUI64 (dbus_g_type_get_collection ("GByteArray", G_TYPE_UINT8))
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue