diff --git a/src/platform/nm-fake-platform.c b/src/platform/nm-fake-platform.c index 246090e15..bef451819 100644 --- a/src/platform/nm-fake-platform.c +++ b/src/platform/nm-fake-platform.c @@ -40,6 +40,7 @@ typedef struct { typedef struct { NMPlatformLink link; + GBytes *address; int vlan_parent; int vlan_id; } NMFakePlatformLink; @@ -123,6 +124,7 @@ link_init (NMFakePlatformLink *device, int ifindex, int type, const char *name) default: device->link.arp = TRUE; } + device->address = NULL; } static NMFakePlatformLink * @@ -354,6 +356,35 @@ link_uses_arp (NMPlatform *platform, int ifindex) return device ? device->link.arp : FALSE; } +static gboolean +link_set_address (NMPlatform *platform, int ifindex, gconstpointer addr, size_t len) +{ + NMFakePlatformLink *device = link_get (platform, ifindex); + + if (device->address) + g_bytes_unref (device->address); + + device->address = g_bytes_new (addr, len); + + link_changed (platform, link_get (platform, ifindex)); + + return TRUE; +} + +static gconstpointer +link_get_address (NMPlatform *platform, int ifindex, size_t *length) +{ + NMFakePlatformLink *device = link_get (platform, ifindex); + + if (!device || !device->address) { + if (length) + *length = 0; + return NULL; + } + + return g_bytes_get_data (device->address, length); +} + static gboolean link_supports_carrier_detect (NMPlatform *platform, int ifindex) { @@ -896,8 +927,14 @@ static void nm_fake_platform_finalize (GObject *object) { NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (object); + int i; g_hash_table_unref (priv->options); + for (i = 0; i < priv->links->len; i++) { + NMFakePlatformLink *device = &g_array_index (priv->links, NMFakePlatformLink, i); + + g_bytes_unref (device->address); + } g_array_unref (priv->links); g_array_unref (priv->ip4_addresses); g_array_unref (priv->ip6_addresses); @@ -939,6 +976,9 @@ nm_fake_platform_class_init (NMFakePlatformClass *klass) platform_class->link_is_connected = link_is_connected; platform_class->link_uses_arp = link_uses_arp; + platform_class->link_set_address = link_set_address; + platform_class->link_get_address = link_get_address; + platform_class->link_supports_carrier_detect = link_supports_carrier_detect; platform_class->link_supports_vlans = link_supports_vlans; diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 00c748de4..86eaa59cc 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -1108,6 +1108,37 @@ link_supports_vlans (NMPlatform *platform, int ifindex) return !(features->features[block].active & (1 << bit)); } +static gboolean +link_set_address (NMPlatform *platform, int ifindex, gconstpointer address, size_t length) +{ + auto_nl_object struct rtnl_link *change = NULL; + auto_nl_addr struct nl_addr *nladdr = NULL; + + change = rtnl_link_alloc (); + g_return_val_if_fail (change, FALSE); + + nladdr = nl_addr_build (AF_LLC, address, length); + g_return_val_if_fail (nladdr, FALSE); + + rtnl_link_set_addr (change, nladdr); + + return link_change (platform, ifindex, change); +} + +static gconstpointer +link_get_address (NMPlatform *platform, int ifindex, size_t *length) +{ + auto_nl_object struct rtnl_link *rtnllink = link_get (platform, ifindex); + struct nl_addr *nladdr; + + nladdr = rtnllink ? rtnl_link_get_addr (rtnllink) : NULL; + + if (length) + *length = nladdr ? nl_addr_get_len (nladdr) : 0; + + return nladdr ? nl_addr_get_binary_addr (nladdr) : NULL; +} + static int vlan_add (NMPlatform *platform, const char *name, int parent, int vlan_id, guint32 vlan_flags) { @@ -1740,6 +1771,9 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass) platform_class->link_is_connected = link_is_connected; platform_class->link_uses_arp = link_uses_arp; + platform_class->link_get_address = link_get_address; + platform_class->link_set_address = link_set_address; + platform_class->link_supports_carrier_detect = link_supports_carrier_detect; platform_class->link_supports_vlans = link_supports_vlans; diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 4ddab10b1..a580820d6 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -493,6 +493,48 @@ nm_platform_link_uses_arp (int ifindex) return klass->link_uses_arp (platform, ifindex); } +/** + * nm_platform_link_set_address: + * @ifindex: Interface index + * @address: The new MAC address + * + * Set interface MAC address. + */ +gboolean +nm_platform_link_set_address (int ifindex, gconstpointer address, size_t length) +{ + reset_error (); + + g_return_val_if_fail (ifindex > 0, FALSE); + g_return_val_if_fail (address, FALSE); + g_return_val_if_fail (length > 0, FALSE); + g_return_val_if_fail (klass->link_set_address, FALSE); + + debug ("link: setting '%s' (%d) hardware address", nm_platform_link_get_name (ifindex), ifindex); + return klass->link_set_address (platform, ifindex, address, length); +} + +/** + * nm_platform_link_get_address: + * @ifindex: Interface index + * @length: Pointer to a variable to store address length + * + * Saves interface hardware address to @address. + */ +gconstpointer +nm_platform_link_get_address (int ifindex, size_t *length) +{ + reset_error (); + + if (length) + *length = 0; + + g_return_val_if_fail (ifindex > 0, NULL); + g_return_val_if_fail (klass->link_get_address, NULL); + + return klass->link_get_address (platform, ifindex, length); +} + gboolean nm_platform_link_supports_carrier_detect (int ifindex) { diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index 3e353e452..1abcacf9c 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -159,6 +159,9 @@ typedef struct { gboolean (*link_is_connected) (NMPlatform *, int ifindex); gboolean (*link_uses_arp) (NMPlatform *, int ifindex); + gconstpointer (*link_get_address) (NMPlatform *, int ifindex, size_t *length); + gboolean (*link_set_address) (NMPlatform *, int ifindex, gconstpointer address, size_t length); + gboolean (*link_supports_carrier_detect) (NMPlatform *, int ifindex); gboolean (*link_supports_vlans) (NMPlatform *, int ifindex); @@ -261,6 +264,9 @@ gboolean nm_platform_link_is_up (int ifindex); gboolean nm_platform_link_is_connected (int ifindex); gboolean nm_platform_link_uses_arp (int ifindex); +gconstpointer nm_platform_link_get_address (int ifindex, size_t *length); +gboolean nm_platform_link_set_address (int ifindex, const void *address, size_t length); + gboolean nm_platform_link_supports_carrier_detect (int ifindex); gboolean nm_platform_link_supports_vlans (int ifindex); diff --git a/src/platform/tests/dump.c b/src/platform/tests/dump.c index d45d0be5c..333931c61 100644 --- a/src/platform/tests/dump.c +++ b/src/platform/tests/dump.c @@ -21,6 +21,8 @@ dump_interface (NMPlatformLink *link) char networkstr[INET6_ADDRSTRLEN]; char gatewaystr[INET6_ADDRSTRLEN]; int vlan_id, vlan_parent; + const char *address; + size_t addrlen; int i; g_assert (link->up || !link->connected); @@ -44,6 +46,14 @@ dump_interface (NMPlatformLink *link) if (nm_platform_link_supports_vlans (link->ifindex)) printf (" feature vlans\n"); + address = nm_platform_link_get_address (link->ifindex, &addrlen); + if (address) { + printf (" link-address "); + for (i = 0; i < addrlen; i++) + printf ("%s%02hhx", i ? ":" : "", address[i]); + printf ("\n"); + } + ip4_addresses = nm_platform_ip4_address_get_all (link->ifindex); ip6_addresses = nm_platform_ip6_address_get_all (link->ifindex); diff --git a/src/platform/tests/platform.c b/src/platform/tests/platform.c index 92fb35104..3bc31b512 100644 --- a/src/platform/tests/platform.c +++ b/src/platform/tests/platform.c @@ -184,6 +184,52 @@ LINK_CMD_GET (is_up, boolean) LINK_CMD_GET (is_connected, boolean) LINK_CMD_GET (uses_arp, boolean) +static gboolean +do_link_set_address (char **argv) +{ + int ifindex = parse_ifindex (*argv++); + char *hex = *argv++; + int hexlen = strlen (hex); + char address[hexlen/2]; + char *endptr; + int i; + + g_assert (!(hexlen % 2)); + + for (i = 0; i < sizeof (address); i++) { + char digit[3]; + + digit[0] = hex[2*i]; + digit[1] = hex[2*i+1]; + digit[2] = '\0'; + + address[i] = strtoul (digit, &endptr, 16); + g_assert (!*endptr); + } + + return nm_platform_link_set_address (ifindex, address, sizeof (address)); +} + +static gboolean +do_link_get_address (char **argv) +{ + int ifindex = parse_ifindex (*argv++); + const char *address; + size_t length; + int i; + + address = nm_platform_link_get_address (ifindex, &length); + + if (!address || length <= 0) + return FALSE; + + for (i = 0; i < length; i++) + printf ("%02x", address[i]); + printf ("\n"); + + return TRUE; +} + LINK_CMD_GET (supports_carrier_detect, boolean) LINK_CMD_GET (supports_vlans, boolean) @@ -546,6 +592,8 @@ static const command_t commands[] = { { "link-is-up", "check if interface is up", do_link_is_up, 1, "" }, { "link-is-connected", "check interface carrier", do_link_is_connected, 1, "" }, { "link-uses-arp", "check whether interface uses arp", do_link_uses_arp, 1, "" }, + { "link-get-address", "print link address", do_link_get_address, 1, "" }, + { "link-set-address", "set link address", do_link_set_address, 2, " " }, { "link-supports-carrier-detect", "check whether interface supports carrier detect", do_link_supports_carrier_detect, 1, "" }, { "link-supports-vlans", "check whether interface supports VLANs", diff --git a/src/platform/tests/test-link.c b/src/platform/tests/test-link.c index ad7407c66..cb0251a6e 100644 --- a/src/platform/tests/test-link.c +++ b/src/platform/tests/test-link.c @@ -58,6 +58,8 @@ link_callback (NMPlatform *platform, int ifindex, NMPlatformLink *received, Sign static void test_bogus(void) { + size_t addrlen; + g_assert (!nm_platform_link_exists (BOGUS_NAME)); no_error (); g_assert (!nm_platform_link_delete (BOGUS_IFINDEX)); @@ -88,6 +90,12 @@ test_bogus(void) g_assert (!nm_platform_link_uses_arp (BOGUS_IFINDEX)); error (NM_PLATFORM_ERROR_NOT_FOUND); + g_assert (!nm_platform_link_get_address (BOGUS_IFINDEX, &addrlen)); + g_assert (!addrlen); + error (NM_PLATFORM_ERROR_NOT_FOUND); + g_assert (!nm_platform_link_get_address (BOGUS_IFINDEX, NULL)); + error (NM_PLATFORM_ERROR_NOT_FOUND); + g_assert (!nm_platform_link_supports_carrier_detect (BOGUS_IFINDEX)); error (NM_PLATFORM_ERROR_NOT_FOUND); g_assert (!nm_platform_link_supports_vlans (BOGUS_IFINDEX)); @@ -382,6 +390,9 @@ test_internal (void) SignalData *link_added = add_signal (NM_PLATFORM_LINK_ADDED, link_callback); SignalData *link_changed = add_signal (NM_PLATFORM_LINK_CHANGED, link_callback); SignalData *link_removed = add_signal (NM_PLATFORM_LINK_REMOVED, link_callback); + const char mac[6] = { 0x00, 0xff, 0x11, 0xee, 0x22, 0xdd }; + const char *address; + size_t addrlen; int ifindex; /* Check the functions for non-existent devices */ @@ -430,6 +441,15 @@ test_internal (void) g_assert (!nm_platform_link_supports_carrier_detect (ifindex)); g_assert (nm_platform_link_supports_vlans (ifindex)); + /* Set MAC address */ + g_assert (nm_platform_link_set_address (ifindex, mac, sizeof (mac))); + address = nm_platform_link_get_address (ifindex, &addrlen); + g_assert (addrlen == sizeof(mac)); + g_assert (!memcmp (address, mac, addrlen)); + address = nm_platform_link_get_address (ifindex, NULL); + g_assert (!memcmp (address, mac, addrlen)); + accept_signal (link_changed); + /* Delete device */ g_assert (nm_platform_link_delete (ifindex)); no_error ();