about summary refs log tree commit diff
path: root/src/ip6-manager/nm-ip6-manager.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ip6-manager/nm-ip6-manager.c')
-rw-r--r--src/ip6-manager/nm-ip6-manager.c56
1 files changed, 24 insertions, 32 deletions
diff --git a/src/ip6-manager/nm-ip6-manager.c b/src/ip6-manager/nm-ip6-manager.c
index 490e9574..c2871e4a 100644
--- a/src/ip6-manager/nm-ip6-manager.c
+++ b/src/ip6-manager/nm-ip6-manager.c
@@ -93,6 +93,11 @@ typedef struct {
 	NMIP6Manager *manager;
 	char *iface;
 	int ifindex;
+	/* +7 since this field is used directly by stuff that expects
+	 * padding to multiples of 8 bytes.
+	 */
+	guint8 hwaddr[NM_UTILS_HWADDR_LEN_MAX + 7];
+	guint hwaddr_len;
 
 	gboolean has_linklocal;
 	gboolean has_nonlinklocal;
@@ -164,12 +169,18 @@ nm_ip6_device_destroy (NMIP6Device *device)
 }
 
 static NMIP6Device *
-nm_ip6_device_new (NMIP6Manager *manager, int ifindex)
+nm_ip6_device_new (NMIP6Manager *manager,
+                   int ifindex,
+                   const guint8 *hwaddr,
+                   guint hwaddr_len)
 {
 	NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
 	NMIP6Device *device;
 
 	g_return_val_if_fail (ifindex > 0, NULL);
+	g_return_val_if_fail (hwaddr != NULL, NULL);
+	g_return_val_if_fail (hwaddr_len > 0, NULL);
+	g_return_val_if_fail (hwaddr_len <= NM_UTILS_HWADDR_LEN_MAX, NULL);
 
 	device = g_slice_new0 (NMIP6Device);
 	if (!device) {
@@ -186,6 +197,9 @@ nm_ip6_device_new (NMIP6Manager *manager, int ifindex)
 		goto error;
 	}
 
+	memcpy (device->hwaddr, hwaddr, hwaddr_len);
+	device->hwaddr_len = hwaddr_len;
+
 	device->manager = manager;
 
 	device->rdnss_servers = g_array_new (FALSE, FALSE, sizeof (NMIP6RDNSS));
@@ -222,28 +236,6 @@ nm_ip6_manager_get_device (NMIP6Manager *manager, int ifindex)
 	return g_hash_table_lookup (priv->devices, GINT_TO_POINTER (ifindex));
 }
 
-static int
-get_hwaddr (int ifindex, guint8 *buf)
-{
-	struct rtnl_link *lk;
-	struct nl_addr *addr;
-	int len;
-
-	lk = nm_netlink_index_to_rtnl_link (ifindex);
-	if (!lk)
-		return -1;
-
-	addr = rtnl_link_get_addr (lk);
-	len = nl_addr_get_len (addr);
-	if (len > NM_UTILS_HWADDR_LEN_MAX)
-		len = -1;
-	else
-		memcpy (buf, nl_addr_get_binary_addr (addr), len);
-
-	rtnl_link_put (lk);
-	return len;
-}
-
 static void
 device_send_router_solicitation (NMIP6Device *device, const char *why)
 {
@@ -251,8 +243,6 @@ device_send_router_solicitation (NMIP6Device *device, const char *why)
 	struct sockaddr_in6 sin6;
 	struct nd_router_solicit rs;
 	struct nd_opt_hdr lladdr_hdr;
-	guint8 hwaddr[NM_UTILS_HWADDR_LEN_MAX + 7];
-	int hwaddr_len;
 	static const guint8 local_routers_addr[] =
 		{ 0xFF, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 		  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 };
@@ -301,18 +291,15 @@ device_send_router_solicitation (NMIP6Device *device, const char *why)
 	iov[0].iov_len  = sizeof (rs);
 	iov[0].iov_base = &rs;
 
-	memset (hwaddr, 0, sizeof (hwaddr));
-	hwaddr_len = get_hwaddr (device->ifindex, hwaddr);
-
-	if (hwaddr_len > 0) {
+	if (device->hwaddr_len > 0) {
 		memset (&lladdr_hdr, 0, sizeof (lladdr_hdr));
 		lladdr_hdr.nd_opt_type = ND_OPT_SOURCE_LINKADDR;
-		lladdr_hdr.nd_opt_len = (sizeof (lladdr_hdr) + hwaddr_len + 7) % 8;
+		lladdr_hdr.nd_opt_len = (sizeof (lladdr_hdr) + device->hwaddr_len + 7) % 8;
 		iov[1].iov_len  = sizeof (lladdr_hdr);
 		iov[1].iov_base = &lladdr_hdr;
 
 		iov[2].iov_len  = (lladdr_hdr.nd_opt_len * 8) - 2;
-		iov[2].iov_base = hwaddr;
+		iov[2].iov_base = device->hwaddr;
 
 		mhdr.msg_iovlen = 3;
 	} else
@@ -1372,6 +1359,8 @@ netlink_notification (NMNetlinkMonitor *monitor, struct nl_msg *msg, gpointer us
 gboolean
 nm_ip6_manager_prepare_interface (NMIP6Manager *manager,
                                   int ifindex,
+                                  const guint8 *hwaddr,
+                                  guint hwaddr_len,
                                   NMSettingIP6Config *s_ip6,
                                   const char *accept_ra_path)
 {
@@ -1381,10 +1370,13 @@ nm_ip6_manager_prepare_interface (NMIP6Manager *manager,
 
 	g_return_val_if_fail (NM_IS_IP6_MANAGER (manager), FALSE);
 	g_return_val_if_fail (ifindex > 0, FALSE);
+	g_return_val_if_fail (hwaddr != NULL, FALSE);
+	g_return_val_if_fail (hwaddr_len > 0, FALSE);
+	g_return_val_if_fail (hwaddr_len <= NM_UTILS_HWADDR_LEN_MAX, FALSE);
 
 	priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
 
-	device = nm_ip6_device_new (manager, ifindex);
+	device = nm_ip6_device_new (manager, ifindex, hwaddr, hwaddr_len);
 	g_return_val_if_fail (device != NULL, FALSE);
 	g_return_val_if_fail (   strchr (device->iface, '/') == NULL
 	                      && strcmp (device->iface, "all") != 0