From 9476f78e2dddbcf932008b5b4ebb2305d0f97157 Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Thu, 14 Jun 2018 10:11:23 +0800 Subject: [PATCH] netdev: add helper to set/unset 4ADDR property --- src/netdev.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/netdev.h | 6 ++++ 2 files changed, 90 insertions(+) diff --git a/src/netdev.c b/src/netdev.c index f9fab848..ac3d0ba1 100644 --- a/src/netdev.c +++ b/src/netdev.c @@ -106,6 +106,7 @@ struct netdev { bool rekey_offload_support : 1; bool in_ft : 1; bool cur_rssi_low : 1; + bool use_4addr : 1; }; struct netdev_preauth_state { @@ -3496,6 +3497,83 @@ static void netdev_bridge_port_event(const struct ifinfomsg *ifi, int bytes, (added ? "added to" : "removed from"), master); } +struct set_4addr_cb_data { + struct netdev *netdev; + bool value; + netdev_set_4addr_cb_t callback; + void *user_data; + netdev_destroy_func_t destroy; +}; + +static void netdev_set_4addr_cb(struct l_genl_msg *msg, void *user_data) +{ + struct set_4addr_cb_data *cb_data = user_data; + int error = l_genl_msg_get_error(msg); + + if (!cb_data) + return; + + /* cache the value that has just been set */ + if (!error) + cb_data->netdev->use_4addr = cb_data->value; + + cb_data->callback(cb_data->netdev, -error, cb_data->user_data); +} + +static void netdev_set_4addr_destroy(void *user_data) +{ + struct set_4addr_cb_data *cb_data = user_data; + + if (!cb_data) + return; + + if (cb_data->destroy) + cb_data->destroy(cb_data->user_data); + + l_free(cb_data); +} + +int netdev_set_4addr(struct netdev *netdev, bool use_4addr, + netdev_set_4addr_cb_t cb, void *user_data, + netdev_destroy_func_t destroy) +{ + struct set_4addr_cb_data *cb_data = NULL; + uint8_t attr_4addr = (use_4addr ? 1 : 0); + struct l_genl_msg *msg; + + l_debug("netdev: %d use_4addr: %d", netdev->index, use_4addr); + + msg = l_genl_msg_new_sized(NL80211_CMD_SET_INTERFACE, 32); + l_genl_msg_append_attr(msg, NL80211_ATTR_IFINDEX, 4, &netdev->index); + l_genl_msg_append_attr(msg, NL80211_ATTR_4ADDR, 1, &attr_4addr); + + if (cb) { + cb_data = l_new(struct set_4addr_cb_data, 1); + cb_data->netdev = netdev; + cb_data->value = use_4addr; + cb_data->callback = cb; + cb_data->user_data = user_data; + cb_data->destroy = destroy; + } + + if (!l_genl_family_send(nl80211, msg, netdev_set_4addr_cb, cb_data, + netdev_set_4addr_destroy)) { + l_error("CMD_SET_INTERFACE (4addr) failed"); + + l_genl_msg_unref(msg); + l_free(cb_data); + + return -EIO; + } + + return 0; +} + +bool netdev_get_4addr(struct netdev *netdev) +{ + return netdev->use_4addr; +} + static void netdev_newlink_notify(const struct ifinfomsg *ifi, int bytes) { struct netdev *netdev; @@ -3583,6 +3661,12 @@ static void netdev_initial_up_cb(struct netdev *netdev, int result, netdev_linkmode_dormant_cb, netdev); + /* + * we don't know the initial status of the 4addr property on this + * netdev, therefore we set it to zero by default. + */ + netdev_set_4addr(netdev, netdev->use_4addr, NULL, NULL, NULL); + l_debug("Interface %i initialized", netdev->index); netdev->device = device_create(netdev->wiphy, netdev); diff --git a/src/netdev.h b/src/netdev.h index ad831940..a8399d2f 100644 --- a/src/netdev.h +++ b/src/netdev.h @@ -76,6 +76,8 @@ typedef void (*netdev_watch_func_t)(struct netdev *netdev, void *user_data); typedef void (*netdev_set_powered_cb_t)(struct netdev *netdev, int result, void *user_data); +typedef void (*netdev_set_4addr_cb_t)(struct netdev *netdev, int result, + void *user_data); typedef void (*netdev_destroy_func_t)(void *user_data); typedef void (*netdev_eapol_event_func_t)(unsigned int event, const void *event_data, @@ -96,6 +98,10 @@ const uint8_t *netdev_get_address(struct netdev *netdev); uint32_t netdev_get_ifindex(struct netdev *netdev); enum netdev_iftype netdev_get_iftype(struct netdev *netdev); int netdev_set_iftype(struct netdev *netdev, enum netdev_iftype type); +int netdev_set_4addr(struct netdev *netdev, bool use_4addr, + netdev_set_4addr_cb_t cb, void *user_data, + netdev_destroy_func_t destroy); +bool netdev_get_4addr(struct netdev *netdev); const char *netdev_get_name(struct netdev *netdev); bool netdev_get_is_up(struct netdev *netdev); struct handshake_state *netdev_get_handshake(struct netdev *netdev);