core: consolidate reading device hardware addresses

Instead of using a mix of netlink and SIOCGIFHWADDR and doing it
in every device, create a utility function for this and have
everywhere else call that.
This commit is contained in:
Dan Williams 2012-06-13 11:32:47 -05:00
parent ff15a5e8fb
commit b584446837
8 changed files with 118 additions and 189 deletions

View file

@ -94,7 +94,7 @@ struct _NMDeviceOlpcMeshPrivate
{
gboolean dispose_has_run;
struct ether_addr hw_addr;
guint8 hw_addr[ETH_ALEN];
GByteArray * ssid;
@ -139,7 +139,7 @@ nm_device_olpc_mesh_init (NMDeviceOlpcMesh * self)
priv->companion = NULL;
priv->stage1_waiting = FALSE;
memset (&(priv->hw_addr), 0, sizeof (struct ether_addr));
memset (&priv->hw_addr, 0, sizeof (priv->hw_addr));
}
static GObject*
@ -297,23 +297,6 @@ complete_connection (NMDevice *device,
return TRUE;
}
/*
* nm_device_olpc_mesh_get_address
*
* Get a device's hardware address
*
*/
static void
nm_device_olpc_mesh_get_address (NMDeviceOlpcMesh *self,
struct ether_addr *addr)
{
NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self);
g_return_if_fail (self != NULL);
g_return_if_fail (addr != NULL);
memcpy (addr, &(priv->hw_addr), sizeof (struct ether_addr));
}
/****************************************************************************/
static void
@ -321,31 +304,15 @@ update_hw_address (NMDevice *dev)
{
NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (dev);
NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self);
struct ifreq req;
int ret, fd;
gsize addrlen;
gboolean changed = FALSE;
fd = socket (PF_INET, SOCK_DGRAM, 0);
if (fd < 0) {
nm_log_warn (LOGD_OLPC_MESH, "could not open control socket.");
return;
addrlen = nm_device_read_hwaddr (dev, priv->hw_addr, sizeof (priv->hw_addr), &changed);
if (addrlen) {
g_return_if_fail (addrlen == ETH_ALEN);
if (changed)
g_object_notify (G_OBJECT (dev), NM_DEVICE_OLPC_MESH_HW_ADDRESS);
}
memset (&req, 0, sizeof (struct ifreq));
strncpy (req.ifr_name, nm_device_get_iface (dev), IFNAMSIZ);
ret = ioctl (fd, SIOCGIFHWADDR, &req);
if (ret) {
nm_log_warn (LOGD_OLPC_MESH, "(%s): error getting hardware address: %d",
nm_device_get_iface (dev), errno);
goto out;
}
if (memcmp (&priv->hw_addr, &req.ifr_hwaddr.sa_data, sizeof (struct ether_addr))) {
memcpy (&priv->hw_addr, &req.ifr_hwaddr.sa_data, sizeof (struct ether_addr));
g_object_notify (G_OBJECT (dev), NM_DEVICE_OLPC_MESH_HW_ADDRESS);
}
out:
close (fd);
}
@ -488,12 +455,10 @@ get_property (GObject *object, guint prop_id,
{
NMDeviceOlpcMesh *device = NM_DEVICE_OLPC_MESH (object);
NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (device);
struct ether_addr hw_addr;
switch (prop_id) {
case PROP_HW_ADDRESS:
nm_device_olpc_mesh_get_address (device, &hw_addr);
g_value_take_string (value, nm_utils_hwaddr_ntoa (&hw_addr, ARPHRD_ETHER));
g_value_take_string (value, nm_utils_hwaddr_ntoa (priv->hw_addr, ARPHRD_ETHER));
break;
case PROP_COMPANION:
if (priv->companion)
@ -659,10 +624,8 @@ is_companion (NMDeviceOlpcMesh *self, NMDevice *other)
nm_device_wifi_get_address (NM_DEVICE_WIFI (other), &their_addr);
if (memcmp (priv->hw_addr.ether_addr_octet,
their_addr.ether_addr_octet, ETH_ALEN) != 0) {
if (memcmp (priv->hw_addr, their_addr.ether_addr_octet, ETH_ALEN) != 0)
return FALSE;
}
priv->companion = other;

View file

@ -46,6 +46,8 @@ gboolean nm_device_hw_bring_up (NMDevice *self, gboolean wait, gboolean *no_firm
void nm_device_hw_take_down (NMDevice *self, gboolean block);
gsize nm_device_read_hwaddr (NMDevice *dev, guint8 *out_buf, gsize buf_len, gboolean *out_changed);
gboolean nm_device_ip_config_should_fail (NMDevice *self, gboolean ip6);
void nm_device_set_firmware_missing (NMDevice *self, gboolean missing);

View file

@ -161,39 +161,15 @@ update_hw_address (NMDevice *dev)
{
NMDeviceVlan *self = NM_DEVICE_VLAN (dev);
NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (self);
struct rtnl_link *rtnl;
struct nl_addr *addr;
gsize addrlen;
gboolean changed = FALSE;
rtnl = nm_netlink_index_to_rtnl_link (nm_device_get_ip_ifindex (dev));
if (!rtnl) {
nm_log_err (LOGD_HW | LOGD_VLAN,
"(%s) failed to read hardware address (error %d)",
nm_device_get_iface (dev), errno);
return;
addrlen = nm_device_read_hwaddr (dev, priv->hw_addr, sizeof (priv->hw_addr), &changed);
if (addrlen) {
priv->hw_addr_len = addrlen;
if (changed)
g_object_notify (G_OBJECT (self), NM_DEVICE_VLAN_HW_ADDRESS);
}
addr = rtnl_link_get_addr (rtnl);
if (!addr) {
nm_log_err (LOGD_HW | LOGD_VLAN,
"(%s) no hardware address?",
nm_device_get_iface (dev));
goto out;
}
if (nl_addr_get_len (addr) > sizeof (priv->hw_addr)) {
nm_log_err (LOGD_HW | LOGD_VLAN,
"(%s) hardware address is wrong length (got %d max %zd)",
nm_device_get_iface (dev),
nl_addr_get_len (addr),
sizeof (priv->hw_addr));
} else {
priv->hw_addr_len = nl_addr_get_len (addr);
memcpy (&priv->hw_addr, nl_addr_get_binary_addr (addr), priv->hw_addr_len);
g_object_notify (G_OBJECT (self), NM_DEVICE_VLAN_HW_ADDRESS);
}
out:
rtnl_link_put (rtnl);
}
static gboolean

View file

@ -203,6 +203,8 @@ static void schedule_scanlist_cull (NMDeviceWifi *self);
static gboolean request_wireless_scan (gpointer user_data);
static void update_hw_address (NMDevice *dev);
/*****************************************************************/
#define NM_WIFI_ERROR (nm_wifi_error_quark ())
@ -831,19 +833,6 @@ bring_up (NMDevice *dev)
return TRUE;
}
static void
_update_hw_addr (NMDeviceWifi *self, const guint8 *addr)
{
NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
g_return_if_fail (addr != NULL);
if (memcmp (&priv->hw_addr, addr, ETH_ALEN)) {
memcpy (&priv->hw_addr, addr, ETH_ALEN);
g_object_notify (G_OBJECT (self), NM_DEVICE_WIFI_HW_ADDRESS);
}
}
static gboolean
_set_hw_addr (NMDeviceWifi *self, const guint8 *addr, const char *detail)
{
@ -873,7 +862,7 @@ _set_hw_addr (NMDeviceWifi *self, const guint8 *addr, const char *detail)
success = nm_system_iface_set_mac (nm_device_get_ip_ifindex (dev), (struct ether_addr *) addr);
if (success) {
/* MAC address succesfully changed; update the current MAC to match */
_update_hw_addr (self, addr);
update_hw_address (dev);
nm_log_info (LOGD_DEVICE | LOGD_ETHER, "(%s): %s MAC address to %s",
iface, detail, mac_str);
} else {
@ -2866,26 +2855,16 @@ error:
static void
update_hw_address (NMDevice *dev)
{
NMDeviceWifi *self = NM_DEVICE_WIFI (dev);
struct ifreq req;
int fd;
NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (dev);
gsize addrlen;
gboolean changed = FALSE;
fd = socket (PF_INET, SOCK_DGRAM, 0);
if (fd < 0) {
nm_log_err (LOGD_HW, "could not open control socket.");
return;
addrlen = nm_device_read_hwaddr (dev, priv->hw_addr, sizeof (priv->hw_addr), &changed);
if (addrlen) {
g_return_if_fail (addrlen == ETH_ALEN);
if (changed)
g_object_notify (G_OBJECT (dev), NM_DEVICE_WIFI_HW_ADDRESS);
}
memset (&req, 0, sizeof (struct ifreq));
strncpy (req.ifr_name, nm_device_get_iface (dev), IFNAMSIZ);
errno = 0;
if (ioctl (fd, SIOCGIFHWADDR, &req) < 0) {
nm_log_err (LOGD_HW | LOGD_WIFI, "(%s): unable to read hardware address (error %d)",
nm_device_get_iface (dev), errno);
} else
_update_hw_addr (self, (const guint8 *) &req.ifr_hwaddr.sa_data);
close (fd);
}
static void

View file

@ -378,37 +378,13 @@ update_hw_address (NMDevice *dev)
{
NMDeviceWired *self = NM_DEVICE_WIRED (dev);
NMDeviceWiredPrivate *priv = NM_DEVICE_WIRED_GET_PRIVATE (self);
struct rtnl_link *rtnl;
struct nl_addr *addr;
gsize addrlen;
rtnl = nm_netlink_index_to_rtnl_link (nm_device_get_ip_ifindex (dev));
if (!rtnl) {
nm_log_err (LOGD_HW | NM_DEVICE_WIRED_LOG_LEVEL (dev),
"(%s) failed to read hardware address (error %d)",
nm_device_get_iface (dev), errno);
return;
addrlen = nm_device_read_hwaddr (dev, priv->hw_addr, sizeof (priv->hw_addr), NULL);
if (addrlen) {
g_warn_if_fail (addrlen == priv->hw_addr_len);
priv->hw_addr_len = addrlen;
}
addr = rtnl_link_get_addr (rtnl);
if (!addr) {
nm_log_err (LOGD_HW | NM_DEVICE_WIRED_LOG_LEVEL (dev),
"(%s) no hardware address?",
nm_device_get_iface (dev));
rtnl_link_put (rtnl);
return;
}
if (nl_addr_get_len (addr) != priv->hw_addr_len) {
nm_log_err (LOGD_HW | NM_DEVICE_WIRED_LOG_LEVEL (dev),
"(%s) hardware address is wrong length (expected %d got %d)",
nm_device_get_iface (dev),
priv->hw_addr_len, nl_addr_get_len (addr));
} else {
memcpy (&priv->hw_addr, nl_addr_get_binary_addr (addr),
priv->hw_addr_len);
}
rtnl_link_put (rtnl);
}
static gboolean

View file

@ -5358,3 +5358,70 @@ nm_device_supports_vlans (NMDevice *device)
/* At the moment, NM's VLAN code assumes all VLANs are over ethernet. */
return NM_IS_DEVICE_ETHERNET (device);
}
/**
* nm_device_read_hwaddr:
* @dev: the device
* @buf: an allocated buffer which on success holds the device's hardware
* address
* @buf_len: the size of @buf
* @out_changed: on success, %TRUE if the contents of @buf are different from
* the original contents of @buf when this function was called
*
* Reads the device's hardware address from the kernel and copies it into
* @buf, returning the size of the data copied into @buf. On failure
* @buf is not modified.
*
* Returns: the size of the hardware address in bytes on success, 0 on failure
*/
gsize
nm_device_read_hwaddr (NMDevice *dev,
guint8 *buf,
gsize buf_len,
gboolean *out_changed)
{
struct rtnl_link *rtnl;
struct nl_addr *addr;
int idx;
gsize addrlen = 0;
const guint8 *binaddr;
g_return_val_if_fail (dev != NULL, 0);
g_return_val_if_fail (buf != NULL, 0);
g_return_val_if_fail (buf_len > 0, 0);
idx = nm_device_get_ip_ifindex (dev);
g_return_val_if_fail (idx > 0, 0);
rtnl = nm_netlink_index_to_rtnl_link (idx);
if (!rtnl) {
nm_log_err (LOGD_HW | LOGD_DEVICE,
"(%s): failed to read hardware address (error %d)",
nm_device_get_iface (dev), errno);
return 0;
}
addr = rtnl_link_get_addr (rtnl);
if (!addr) {
nm_log_err (LOGD_HW | LOGD_DEVICE,
"(%s): no hardware address?",
nm_device_get_iface (dev));
goto out;
}
addrlen = nl_addr_get_len (addr);
if (addrlen > buf_len) {
nm_log_err (LOGD_HW | LOGD_DEVICE,
"(%s): hardware address is wrong length (got %zd max %zd)",
nm_device_get_iface (dev), addrlen, buf_len);
} else {
binaddr = nl_addr_get_binary_addr (addr);
if (out_changed)
*out_changed = memcmp (buf, binaddr, addrlen) ? TRUE : FALSE;
memcpy (buf, binaddr, addrlen);
}
out:
rtnl_link_put (rtnl);
return addrlen;
}

View file

@ -87,7 +87,7 @@ typedef struct {
gboolean enabled;
gboolean wimaxd_enabled;
struct ether_addr hw_addr;
guint8 hw_addr[ETH_ALEN];
guint activation_timeout_id;
/* Track whether stage1 (Prepare) is completed yet or not */
@ -124,18 +124,6 @@ nm_wimax_error_quark (void)
/***********************************************************/
void
nm_device_wimax_get_hw_address (NMDeviceWimax *self, struct ether_addr *addr)
{
NMDeviceWimaxPrivate *priv;
g_return_if_fail (NM_IS_DEVICE_WIMAX (self));
g_return_if_fail (addr != NULL);
priv = NM_DEVICE_WIMAX_GET_PRIVATE (self);
memcpy (addr, &(priv->hw_addr), sizeof (struct ether_addr));
}
guint32
nm_device_wimax_get_center_frequency (NMDeviceWimax *self)
{
@ -371,32 +359,15 @@ update_hw_address (NMDevice *dev)
{
NMDeviceWimax *self = NM_DEVICE_WIMAX (dev);
NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self);
struct ifreq req;
int fd;
const char *iface;
gboolean changed = FALSE;
gsize addrlen;
iface = nm_device_get_iface (dev);
fd = socket (PF_INET, SOCK_DGRAM, 0);
if (fd < 0) {
nm_log_warn (LOGD_HW, "(%s): couldn't open control socket.", iface);
return;
addrlen = nm_device_read_hwaddr (dev, priv->hw_addr, sizeof (priv->hw_addr), &changed);
if (addrlen) {
g_return_if_fail (addrlen == ETH_ALEN);
if (changed)
g_object_notify (G_OBJECT (self), NM_DEVICE_WIMAX_HW_ADDRESS);
}
memset (&req, 0, sizeof (struct ifreq));
strncpy (req.ifr_name, nm_device_get_iface (dev), IFNAMSIZ);
errno = 0;
if (ioctl (fd, SIOCGIFHWADDR, &req) < 0) {
nm_log_err (LOGD_HW | LOGD_WIMAX,
"(%s): failed to read hardware address (error %d)",
iface, errno);
} else {
memcpy (&priv->hw_addr, &req.ifr_hwaddr.sa_data, ETH_ALEN);
g_object_notify (G_OBJECT (self), NM_DEVICE_WIMAX_HW_ADDRESS);
}
close (fd);
}
static gboolean
@ -420,7 +391,7 @@ hwaddr_matches (NMDevice *device,
g_return_val_if_fail (other_hwaddr_len == ETH_ALEN, FALSE);
if (memcmp (mac->data, other_hwaddr, mac->len) == 0)
return TRUE;
} else if (memcmp (mac->data, priv->hw_addr.ether_addr_octet, mac->len) == 0)
} else if (memcmp (mac->data, priv->hw_addr, mac->len) == 0)
return TRUE;
} else if (fail_if_no_hwaddr == FALSE)
return TRUE;
@ -459,7 +430,7 @@ check_connection_compatible (NMDevice *device,
}
mac = nm_setting_wimax_get_mac_address (s_wimax);
if (mac && memcmp (mac->data, &(priv->hw_addr.ether_addr_octet), ETH_ALEN)) {
if (mac && memcmp (mac->data, &priv->hw_addr, ETH_ALEN)) {
g_set_error (error,
NM_WIMAX_ERROR, NM_WIMAX_ERROR_CONNECTION_INCOMPATIBLE,
"The connection's MAC address did not match this device.");
@ -573,7 +544,7 @@ complete_connection (NMDevice *device,
setting_mac = nm_setting_wimax_get_mac_address (s_wimax);
if (setting_mac) {
/* Make sure the setting MAC (if any) matches the device's permanent MAC */
if (memcmp (setting_mac->data, &priv->hw_addr.ether_addr_octet, ETH_ALEN)) {
if (memcmp (setting_mac->data, &priv->hw_addr, ETH_ALEN)) {
g_set_error (error,
NM_SETTING_WIMAX_ERROR,
NM_SETTING_WIMAX_ERROR_INVALID_PROPERTY,
@ -585,9 +556,9 @@ complete_connection (NMDevice *device,
const guint8 null_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
/* Lock the connection to this device by default */
if (memcmp (&priv->hw_addr.ether_addr_octet, null_mac, ETH_ALEN)) {
if (memcmp (&priv->hw_addr, null_mac, ETH_ALEN)) {
mac = g_byte_array_sized_new (ETH_ALEN);
g_byte_array_append (mac, priv->hw_addr.ether_addr_octet, ETH_ALEN);
g_byte_array_append (mac, priv->hw_addr, ETH_ALEN);
g_object_set (G_OBJECT (s_wimax), NM_SETTING_WIMAX_MAC_ADDRESS, mac, NULL);
g_byte_array_free (mac, TRUE);
}
@ -626,7 +597,7 @@ get_best_auto_connection (NMDevice *device,
continue;
mac = nm_setting_wimax_get_mac_address (s_wimax);
if (mac && memcmp (mac->data, priv->hw_addr.ether_addr_octet, ETH_ALEN))
if (mac && memcmp (mac->data, priv->hw_addr, ETH_ALEN))
continue;
for (iter = priv->nsp_list; iter; iter = iter->next) {
@ -1421,12 +1392,10 @@ get_property (GObject *object, guint prop_id,
{
NMDeviceWimax *self = NM_DEVICE_WIMAX (object);
NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self);
struct ether_addr hw_addr;
switch (prop_id) {
case PROP_HW_ADDRESS:
nm_device_wimax_get_hw_address (self, &hw_addr);
g_value_take_string (value, nm_utils_hwaddr_ntoa (&hw_addr, ARPHRD_ETHER));
g_value_take_string (value, nm_utils_hwaddr_ntoa (priv->hw_addr, ARPHRD_ETHER));
break;
case PROP_ACTIVE_NSP:
if (priv->current_nsp)

View file

@ -70,9 +70,6 @@ NMDevice *nm_device_wimax_new (const char *udi,
const char *iface,
const char *driver);
void nm_device_wimax_get_hw_address (NMDeviceWimax *self,
struct ether_addr *addr);
NMWimaxNsp *nm_device_wimax_get_active_nsp (NMDeviceWimax *self);
guint nm_device_wimax_get_center_frequency (NMDeviceWimax *self);