Merge pull request #24020 from yuwata/network-rfkill

network: fix wlan interface handling when its RF is killed
This commit is contained in:
Yu Watanabe
2022-07-24 13:01:50 +09:00
committed by GitHub
13 changed files with 456 additions and 75 deletions
+11
View File
@@ -63,6 +63,17 @@ typedef void* (*mfree_func_t)(void *p);
#define free_and_replace(a, b) \
free_and_replace_full(a, b, free)
/* This is similar to free_and_replace_full(), but NULL is not assigned to 'b', and its reference counter is
* increased. */
#define unref_and_replace_full(a, b, ref_func, unref_func) \
({ \
typeof(a)* _a = &(a); \
typeof(b) _b = ref_func(b); \
unref_func(*_a); \
*_a = _b; \
0; \
})
void* memdup(const void *p, size_t l) _alloc_(2);
void* memdup_suffix0(const void *p, size_t l); /* We can't use _alloc_() here, since we return a buffer one byte larger than the specified size */
@@ -18,6 +18,7 @@ static inline int device_new_from_watch_handle(sd_device **ret, int wd) {
}
int device_get_property_bool(sd_device *device, const char *key);
int device_get_sysattr_bool(sd_device *device, const char *sysattr);
int device_get_device_id(sd_device *device, const char **ret);
int device_get_devlink_priority(sd_device *device, int *ret);
int device_get_watch_handle(sd_device *device);
@@ -25,6 +26,7 @@ int device_get_devnode_mode(sd_device *device, mode_t *ret);
int device_get_devnode_uid(sd_device *device, uid_t *ret);
int device_get_devnode_gid(sd_device *device, gid_t *ret);
void device_clear_sysattr_cache(sd_device *device);
int device_cache_sysattr_value(sd_device *device, const char *key, char *value);
int device_get_cached_sysattr_value(sd_device *device, const char *key, const char **ret_value);
+3
View File
@@ -10,6 +10,9 @@
#include "macro.h"
#include "set.h"
#define device_unref_and_replace(a, b) \
unref_and_replace_full(a, b, sd_device_ref, sd_device_unref)
#define FOREACH_DEVICE_PROPERTY(device, key, value) \
for (key = sd_device_get_property_first(device, &(value)); \
key; \
+18
View File
@@ -2044,6 +2044,10 @@ _public_ int sd_device_get_trigger_uuid(sd_device *device, sd_id128_t *ret) {
return 0;
}
void device_clear_sysattr_cache(sd_device *device) {
device->sysattr_values = hashmap_free(device->sysattr_values);
}
int device_cache_sysattr_value(sd_device *device, const char *key, char *value) {
_unused_ _cleanup_free_ char *old_value = NULL;
_cleanup_free_ char *new_key = NULL;
@@ -2166,6 +2170,20 @@ _public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr,
return 0;
}
int device_get_sysattr_bool(sd_device *device, const char *sysattr) {
const char *value;
int r;
assert(device);
assert(sysattr);
r = sd_device_get_sysattr_value(device, sysattr, &value);
if (r < 0)
return r;
return parse_boolean(value);
}
static void device_remove_cached_sysattr_value(sd_device *device, const char *_key) {
_cleanup_free_ char *key = NULL;
+1 -1
View File
@@ -1324,7 +1324,7 @@ static bool link_needs_dhcp_broadcast(Link *link) {
* If neither is set or a failure occurs, return false, which is the default for this flag.
*/
r = link->network->dhcp_broadcast;
if (r < 0 && link->sd_device && sd_device_get_property_value(link->sd_device, "ID_NET_DHCP_BROADCAST", &val) >= 0) {
if (r < 0 && link->dev && sd_device_get_property_value(link->dev, "ID_NET_DHCP_BROADCAST", &val) >= 0) {
r = parse_boolean(val);
if (r < 0)
log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to parse ID_NET_DHCP_BROADCAST, ignoring: %m");
+2 -2
View File
@@ -187,8 +187,8 @@ int ipv4ll_configure(Link *link) {
if (r < 0)
return r;
if (link->sd_device &&
net_get_unique_predictable_data(link->sd_device, true, &seed) >= 0) {
if (link->dev &&
net_get_unique_predictable_data(link->dev, true, &seed) >= 0) {
r = sd_ipv4ll_set_address_seed(link->ipv4ll, seed);
if (r < 0)
return r;
+2 -2
View File
@@ -1158,7 +1158,7 @@ int link_build_json(Link *link, JsonVariant **ret) {
assert(link);
assert(ret);
r = net_get_type_string(link->sd_device, link->iftype, &type);
r = net_get_type_string(link->dev, link->iftype, &type);
if (r == -ENOMEM)
return r;
@@ -1215,7 +1215,7 @@ int link_build_json(Link *link, JsonVariant **ret) {
w = json_variant_unref(w);
r = device_build_json(link->sd_device, &w);
r = device_build_json(link->dev, &w);
if (r < 0)
return r;
+24 -35
View File
@@ -229,7 +229,7 @@ static Link *link_free(Link *link) {
unlink_and_free(link->lldp_file);
unlink_and_free(link->state_file);
sd_device_unref(link->sd_device);
sd_device_unref(link->dev);
netdev_unref(link->netdev);
hashmap_free(link->bound_to_links);
@@ -1164,7 +1164,7 @@ static int link_get_network(Link *link, Network **ret) {
r = net_match_config(
&network->match,
link->sd_device,
link->dev,
&link->hw_addr,
&link->permanent_hw_addr,
link->driver,
@@ -1180,11 +1180,11 @@ static int link_get_network(Link *link, Network **ret) {
if (r == 0)
continue;
if (network->match.ifname && link->sd_device) {
if (network->match.ifname && link->dev) {
uint8_t name_assign_type = NET_NAME_UNKNOWN;
const char *attr;
if (sd_device_get_sysattr_value(link->sd_device, "name_assign_type", &attr) >= 0)
if (sd_device_get_sysattr_value(link->dev, "name_assign_type", &attr) >= 0)
(void) safe_atou8(attr, &name_assign_type);
warn = name_assign_type == NET_NAME_ENUM;
@@ -1433,9 +1433,7 @@ static int link_initialized(Link *link, sd_device *device) {
/* Always replace with the new sd_device object. As the sysname (and possibly other properties
* or sysattrs) may be outdated. */
sd_device_ref(device);
sd_device_unref(link->sd_device);
link->sd_device = device;
device_unref_and_replace(link->dev, device);
/* Do not ignore unamanaged state case here. If an interface is renamed after being once
* configured, and the corresponding .network file has Name= in [Match] section, then the
@@ -1490,48 +1488,39 @@ static int link_check_initialized(Link *link) {
return link_initialized(link, device);
}
int manager_udev_process_link(sd_device_monitor *monitor, sd_device *device, void *userdata) {
sd_device_action_t action;
Manager *m = userdata;
Link *link = NULL;
int manager_udev_process_link(Manager *m, sd_device *device, sd_device_action_t action) {
int r, ifindex;
Link *link;
assert(m);
assert(device);
r = sd_device_get_action(device, &action);
r = sd_device_get_ifindex(device, &ifindex);
if (r < 0)
return log_device_debug_errno(device, r, "Failed to get ifindex: %m");
r = link_get_by_index(m, ifindex, &link);
if (r < 0) {
log_device_debug_errno(device, r, "Failed to get udev action, ignoring device: %m");
/* This error is not critical, as the corresponding rtnl message may be received later. */
log_device_debug_errno(device, r, "Failed to get link from ifindex %i, ignoring: %m", ifindex);
return 0;
}
/* Ignore the "remove" uevent — let's remove a device only if rtnetlink says so. All other uevents
* are "positive" events in some form, i.e. inform us about a changed or new network interface, that
* still exists — and we are interested in that. */
if (action == SD_DEVICE_REMOVE)
return 0;
r = sd_device_get_ifindex(device, &ifindex);
if (r < 0) {
log_device_debug_errno(device, r, "Ignoring udev %s event for device without ifindex or with invalid ifindex: %m",
device_action_to_string(action));
/* Let's unref the sd-device object assigned to the corresponding Link object, but keep the Link
* object here. It will be removed only when rtnetlink says so. */
if (action == SD_DEVICE_REMOVE) {
link->dev = sd_device_unref(link->dev);
return 0;
}
r = device_is_renaming(device);
if (r < 0) {
log_device_debug_errno(device, r, "Failed to determine the device is renamed or not, ignoring '%s' uevent: %m",
device_action_to_string(action));
return 0;
}
if (r < 0)
return log_device_debug_errno(device, r, "Failed to determine if the device is renaming or not: %m");
if (r > 0) {
log_device_debug(device, "Interface is under renaming, wait for the interface to be renamed.");
return 0;
}
r = link_get_by_index(m, ifindex, &link);
if (r < 0) {
log_device_debug_errno(device, r, "Failed to get link from ifindex %i, ignoring: %m", ifindex);
log_device_debug(device, "Device is renaming, waiting for the interface to be renamed.");
/* TODO:
* What happens when a device is initialized, then soon renamed after that? When we detect
* such, maybe we should cancel or postpone all queued requests for the interface. */
return 0;
}
+2 -2
View File
@@ -66,7 +66,7 @@ typedef struct Link {
uint32_t min_mtu;
uint32_t max_mtu;
uint32_t original_mtu;
sd_device *sd_device;
sd_device *dev;
char *driver;
/* link-local addressing */
@@ -235,7 +235,7 @@ LinkState link_state_from_string(const char *s) _pure_;
int link_reconfigure(Link *link, bool force);
int link_reconfigure_after_sleep(Link *link);
int manager_udev_process_link(sd_device_monitor *monitor, sd_device *device, void *userdata);
int manager_udev_process_link(Manager *m, sd_device *device, sd_device_action_t action);
int manager_rtnl_process_link(sd_netlink *rtnl, sd_netlink_message *message, Manager *m);
int link_flags_to_string_alloc(uint32_t flags, char **ret);
+45 -2
View File
@@ -18,6 +18,8 @@
#include "bus-util.h"
#include "conf-parser.h"
#include "def.h"
#include "device-private.h"
#include "device-util.h"
#include "dns-domain.h"
#include "fd-util.h"
#include "fileio.h"
@@ -168,6 +170,39 @@ static int manager_connect_bus(Manager *m) {
return 0;
}
static int manager_process_uevent(sd_device_monitor *monitor, sd_device *device, void *userdata) {
Manager *m = ASSERT_PTR(userdata);
sd_device_action_t action;
const char *s;
int r;
assert(device);
r = sd_device_get_action(device, &action);
if (r < 0)
return log_device_warning_errno(device, r, "Failed to get udev action, ignoring: %m");
r = sd_device_get_subsystem(device, &s);
if (r < 0)
return log_device_warning_errno(device, r, "Failed to get subsystem, ignoring: %m");
if (streq(s, "net"))
r = manager_udev_process_link(m, device, action);
else if (streq(s, "ieee80211"))
r = manager_udev_process_wiphy(m, device, action);
else if (streq(s, "rfkill"))
r = manager_udev_process_rfkill(m, device, action);
else {
log_device_debug(device, "Received device with unexpected subsystem \"%s\", ignoring.", s);
return 0;
}
if (r < 0)
log_device_warning_errno(device, r, "Failed to process \"%s\" uevent, ignoring: %m",
device_action_to_string(action));
return 0;
}
static int manager_connect_udev(Manager *m) {
int r;
@@ -186,13 +221,21 @@ static int manager_connect_udev(Manager *m) {
r = sd_device_monitor_filter_add_match_subsystem_devtype(m->device_monitor, "net", NULL);
if (r < 0)
return log_error_errno(r, "Could not add device monitor filter: %m");
return log_error_errno(r, "Could not add device monitor filter for net subsystem: %m");
r = sd_device_monitor_filter_add_match_subsystem_devtype(m->device_monitor, "ieee80211", NULL);
if (r < 0)
return log_error_errno(r, "Could not add device monitor filter for ieee80211 subsystem: %m");
r = sd_device_monitor_filter_add_match_subsystem_devtype(m->device_monitor, "rfkill", NULL);
if (r < 0)
return log_error_errno(r, "Could not add device monitor filter for rfkill subsystem: %m");
r = sd_device_monitor_attach_event(m->device_monitor, m->event);
if (r < 0)
return log_error_errno(r, "Failed to attach event to device monitor: %m");
r = sd_device_monitor_start(m->device_monitor, manager_udev_process_link, m);
r = sd_device_monitor_start(m->device_monitor, manager_process_uevent, m);
if (r < 0)
return log_error_errno(r, "Failed to start device monitor: %m");
+13 -13
View File
@@ -14,6 +14,7 @@
#include "networkd-manager.h"
#include "networkd-queue.h"
#include "networkd-setlink.h"
#include "networkd-wiphy.h"
static int get_link_default_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
return link_getlink_handler_internal(rtnl, m, link, "Failed to sync link information");
@@ -951,17 +952,10 @@ static int link_up_or_down_handler(sd_netlink *rtnl, sd_netlink_message *m, Requ
r = sd_netlink_message_get_errno(m);
if (r == -ENETDOWN && up && link_up_dsa_slave(link) > 0)
log_link_message_debug_errno(link, m, r, "Could not bring up dsa slave, retrying again after dsa master becomes up");
else if (r < 0) {
const char *error_msg;
error_msg = up ?
(on_activate ? "Could not bring up interface" : "Could not bring up interface, ignoring") :
(on_activate ? "Could not bring down interface" : "Could not bring down interface, ignoring");
log_link_message_warning_errno(link, m, r, error_msg);
if (on_activate)
return 0;
}
else if (r < 0)
log_link_message_warning_errno(link, m, r, up ?
"Could not bring up interface, ignoring" :
"Could not bring down interface, ignoring");
r = link_call_getlink(link, get_link_update_flag_handler);
if (r < 0) {
@@ -1005,7 +999,7 @@ static int link_up_or_down(Link *link, bool up, Request *req) {
return request_call_netlink_async(link->manager->rtnl, m, req);
}
static bool link_is_ready_to_activate(Link *link) {
static bool link_is_ready_to_activate(Link *link, bool up) {
assert(link);
if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
@@ -1014,6 +1008,9 @@ static bool link_is_ready_to_activate(Link *link) {
if (link->set_link_messages > 0)
return false;
if (up && link_rfkilled(link) > 0)
return false;
return true;
}
@@ -1024,7 +1021,7 @@ static int link_process_activation(Request *req, Link *link, void *userdata) {
assert(req);
assert(link);
if (!link_is_ready_to_activate(link))
if (!link_is_ready_to_activate(link, up))
return 0;
r = link_up_or_down(link, up, req);
@@ -1104,6 +1101,9 @@ static bool link_is_ready_to_bring_up_or_down(Link *link, bool up) {
if (!link->activated)
return false;
if (up && link_rfkilled(link) > 0)
return false;
return true;
}
+314 -18
View File
@@ -1,11 +1,15 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <net/if_arp.h>
#include <linux/nl80211.h>
#include "device-private.h"
#include "device-util.h"
#include "networkd-manager.h"
#include "networkd-wiphy.h"
#include "parse-util.h"
#include "path-util.h"
#include "udev-util.h"
#include "wifi-util.h"
Wiphy *wiphy_free(Wiphy *w) {
@@ -18,29 +22,49 @@ Wiphy *wiphy_free(Wiphy *w) {
hashmap_remove_value(w->manager->wiphy_by_name, w->name, w);
}
sd_device_unref(w->dev);
sd_device_unref(w->rfkill);
free(w->name);
return mfree(w);
}
static int wiphy_new(Manager *manager, uint32_t index, Wiphy **ret) {
static int wiphy_new(Manager *manager, sd_netlink_message *message, Wiphy **ret) {
_cleanup_(wiphy_freep) Wiphy *w = NULL;
_cleanup_free_ char *name = NULL;
uint32_t index;
int r;
assert(manager);
assert(message);
r = sd_netlink_message_read_u32(message, NL80211_ATTR_WIPHY, &index);
if (r < 0)
return r;
r = sd_netlink_message_read_string_strdup(message, NL80211_ATTR_WIPHY_NAME, &name);
if (r < 0)
return r;
w = new(Wiphy, 1);
if (!w)
return -ENOMEM;
*w = (Wiphy) {
.manager = manager,
.index = index,
.name = TAKE_PTR(name),
};
r = hashmap_ensure_put(&manager->wiphy_by_index, NULL, UINT32_TO_PTR(w->index), w);
if (r < 0)
return r;
w->manager = manager;
r = hashmap_ensure_put(&w->manager->wiphy_by_name, &string_hash_ops, w->name, w);
if (r < 0)
return r;
log_wiphy_debug(w, "Saved new wiphy: index=%"PRIu32, w->index);
if (ret)
*ret = w;
@@ -80,6 +104,129 @@ int wiphy_get_by_name(Manager *manager, const char *name, Wiphy **ret) {
return 0;
}
static int link_get_wiphy(Link *link, Wiphy **ret) {
_cleanup_(sd_device_unrefp) sd_device *phy = NULL;
const char *s;
int r;
assert(link);
assert(link->manager);
if (link->iftype != ARPHRD_ETHER)
return -EOPNOTSUPP;
if (!link->dev)
return -EOPNOTSUPP;
r = sd_device_get_devtype(link->dev, &s);
if (r < 0)
return r;
if (!streq_ptr(s, "wlan"))
return -EOPNOTSUPP;
r = sd_device_get_syspath(link->dev, &s);
if (r < 0)
return r;
s = strjoina(s, "/phy80211");
r = sd_device_new_from_syspath(&phy, s);
if (r < 0)
return r;
r = sd_device_get_sysname(phy, &s);
if (r < 0)
return r;
/* TODO:
* Maybe, it is better to cache the found Wiphy object in the Link object.
* To support that, we need to investigate what happens when the _phy_ is renamed. */
return wiphy_get_by_name(link->manager, s, ret);
}
static int rfkill_get_state(sd_device *dev) {
int r;
assert(dev);
/* The previous values may be outdated. Let's clear cache and re-read the values. */
device_clear_sysattr_cache(dev);
r = device_get_sysattr_bool(dev, "soft");
if (r < 0 && r != -ENOENT)
return r;
if (r > 0)
return RFKILL_SOFT;
r = device_get_sysattr_bool(dev, "hard");
if (r < 0 && r != -ENOENT)
return r;
if (r > 0)
return RFKILL_HARD;
return RFKILL_UNBLOCKED;
}
static int wiphy_rfkilled(Wiphy *w) {
int r;
assert(w);
if (!udev_available()) {
if (w->rfkill_state != RFKILL_UNBLOCKED) {
log_wiphy_debug(w, "Running in container, assuming the radio transmitter is unblocked.");
w->rfkill_state = RFKILL_UNBLOCKED; /* To suppress the above log message, cache the state. */
}
return false;
}
if (!w->rfkill) {
if (w->rfkill_state != RFKILL_UNBLOCKED) {
log_wiphy_debug(w, "No rfkill device found, assuming the radio transmitter is unblocked.");
w->rfkill_state = RFKILL_UNBLOCKED; /* To suppress the above log message, cache the state. */
}
return false;
}
r = rfkill_get_state(w->rfkill);
if (r < 0)
return log_wiphy_debug_errno(w, r, "Could not get rfkill state: %m");
if (w->rfkill_state != r)
switch (r) {
case RFKILL_UNBLOCKED:
log_wiphy_debug(w, "The radio transmitter is unblocked.");
break;
case RFKILL_SOFT:
log_wiphy_debug(w, "The radio transmitter is turned off by software.");
break;
case RFKILL_HARD:
log_wiphy_debug(w, "The radio transmitter is forced off by something outside of the driver's control.");
break;
default:
assert_not_reached();
}
w->rfkill_state = r; /* Cache the state to suppress the above log messages. */
return r != RFKILL_UNBLOCKED;
}
int link_rfkilled(Link *link) {
Wiphy *w;
int r;
assert(link);
r = link_get_wiphy(link, &w);
if (IN_SET(r, -EOPNOTSUPP, -ENODEV))
return false; /* Typically, non-wifi interface or running in container */
if (r < 0)
return log_link_debug_errno(link, r, "Could not get phy: %m");
return wiphy_rfkilled(w);
}
static int wiphy_update_name(Wiphy *w, sd_netlink_message *message) {
const char *name;
int r;
@@ -94,28 +241,119 @@ static int wiphy_update_name(Wiphy *w, sd_netlink_message *message) {
if (r < 0)
return r;
if (streq_ptr(w->name, name))
if (streq(w->name, name))
return 0;
if (w->name)
hashmap_remove_value(w->manager->wiphy_by_name, w->name, w);
log_wiphy_debug(w, "Wiphy name change detected, renamed to %s.", name);
hashmap_remove_value(w->manager->wiphy_by_name, w->name, w);
r = free_and_strdup(&w->name, name);
if (r < 0)
return r;
return hashmap_ensure_put(&w->manager->wiphy_by_name, &string_hash_ops, w->name, w);
r = hashmap_ensure_put(&w->manager->wiphy_by_name, &string_hash_ops, w->name, w);
if (r < 0)
return r;
return 1; /* updated */
}
static int wiphy_update(Wiphy *w, sd_netlink_message *message) {
static int wiphy_update_device(Wiphy *w) {
_cleanup_(sd_device_unrefp) sd_device *dev = NULL;
int r;
assert(w);
assert(message);
assert(w->name);
r = wiphy_update_name(w, message);
if (!udev_available())
return 0;
w->dev = sd_device_unref(w->dev);
r = sd_device_new_from_subsystem_sysname(&dev, "ieee80211", w->name);
if (r < 0) {
/* The corresponding syspath may not exist yet, and may appear later. */
log_wiphy_debug_errno(w, r, "Failed to get wiphy device, ignoring: %m");
return 0;
}
if (DEBUG_LOGGING) {
const char *s = NULL;
(void) sd_device_get_syspath(dev, &s);
log_wiphy_debug(w, "Found device: %s", strna(s));
}
w->dev = TAKE_PTR(dev);
return 0;
}
static int wiphy_update_rfkill(Wiphy *w) {
_cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
sd_device *rfkill;
int r;
assert(w);
if (!udev_available())
return 0;
w->rfkill = sd_device_unref(w->rfkill);
if (!w->dev)
return 0;
r = sd_device_enumerator_new(&e);
if (r < 0)
return log_wiphy_debug_errno(w, r, "Failed to update wiphy name: %m");
return r;
r = sd_device_enumerator_allow_uninitialized(e);
if (r < 0)
return r;
r = sd_device_enumerator_add_match_subsystem(e, "rfkill", true);
if (r < 0)
return r;
r = sd_device_enumerator_add_match_parent(e, w->dev);
if (r < 0)
return r;
rfkill = sd_device_enumerator_get_device_first(e);
if (!rfkill) {
/* rfkill device may not detected by the kernel yet, and may appear later. */
log_wiphy_debug_errno(w, SYNTHETIC_ERRNO(ENODEV), "No rfkill device found, ignoring.");
return 0;
}
if (sd_device_enumerator_get_device_next(e))
return log_wiphy_debug_errno(w, SYNTHETIC_ERRNO(EEXIST), "Multiple rfkill devices found.");
w->rfkill = sd_device_ref(rfkill);
if (DEBUG_LOGGING) {
const char *s = NULL;
(void) sd_device_get_syspath(rfkill, &s);
log_wiphy_debug(w, "Found rfkill device: %s", strna(s));
}
return 0;
}
static int wiphy_update(Wiphy *w) {
int r;
assert(w);
r = wiphy_update_device(w);
if (r < 0)
return log_wiphy_debug_errno(w, r, "Failed to update wiphy device: %m");
r = wiphy_update_rfkill(w);
if (r < 0)
return log_wiphy_debug_errno(w, r, "Failed to update rfkill device: %m");
return 0;
}
@@ -166,23 +404,27 @@ int manager_genl_process_nl80211_wiphy(sd_netlink *genl, sd_netlink_message *mes
switch (cmd) {
case NL80211_CMD_NEW_WIPHY: {
bool is_new = !w;
if (!w) {
r = wiphy_new(manager, index, &w);
r = wiphy_new(manager, message, &w);
if (r < 0) {
log_warning_errno(r, "Failed to allocate wiphy, ignoring: %m");
log_warning_errno(r, "Failed to save new wiphy, ignoring: %m");
return 0;
}
} else {
r = wiphy_update_name(w, message);
if (r < 0) {
log_wiphy_warning_errno(w, r, "Failed to update wiphy name, ignoring: %m");
return 0;
}
if (r == 0)
return 0;
}
r = wiphy_update(w, message);
if (r < 0) {
r = wiphy_update(w);
if (r < 0)
log_wiphy_warning_errno(w, r, "Failed to update wiphy, ignoring: %m");
return 0;
}
log_wiphy_debug(w, "Received %s phy.", is_new ? "new" : "updated");
break;
}
case NL80211_CMD_DEL_WIPHY:
@@ -203,3 +445,57 @@ int manager_genl_process_nl80211_wiphy(sd_netlink *genl, sd_netlink_message *mes
return 0;
}
int manager_udev_process_wiphy(Manager *m, sd_device *device, sd_device_action_t action) {
const char *name;
Wiphy *w;
int r;
assert(m);
assert(device);
r = sd_device_get_sysname(device, &name);
if (r < 0)
return log_device_debug_errno(device, r, "Failed to get sysname: %m");
r = wiphy_get_by_name(m, name, &w);
if (r < 0) {
/* This error is not critical, as the corresponding genl message may be received later. */
log_device_debug_errno(device, r, "Failed to get Wiphy object, ignoring: %m");
return 0;
}
return device_unref_and_replace(w->dev, action == SD_DEVICE_REMOVE ? NULL : device);
}
int manager_udev_process_rfkill(Manager *m, sd_device *device, sd_device_action_t action) {
_cleanup_free_ char *parent_path = NULL, *parent_name = NULL;
const char *s;
Wiphy *w;
int r;
assert(m);
assert(device);
r = sd_device_get_syspath(device, &s);
if (r < 0)
return log_device_debug_errno(device, r, "Failed to get syspath: %m");
/* Do not use sd_device_get_parent() here, as this might be a 'remove' uevent. */
r = path_extract_directory(s, &parent_path);
if (r < 0)
return log_device_debug_errno(device, r, "Failed to get parent syspath: %m");
r = path_extract_filename(parent_path, &parent_name);
if (r < 0)
return log_device_debug_errno(device, r, "Failed to get parent name: %m");
r = wiphy_get_by_name(m, parent_name, &w);
if (r < 0) {
/* This error is not critical, as the corresponding genl message may be received later. */
log_device_debug_errno(device, r, "Failed to get Wiphy object: %m");
return 0;
}
return device_unref_and_replace(w->rfkill, action == SD_DEVICE_REMOVE ? NULL : device);
}
+19
View File
@@ -7,13 +7,28 @@
#include "macro.h"
typedef struct Link Link;
typedef struct Manager Manager;
/* The following values are different from the ones defined in linux/rfkill.h. */
typedef enum RFKillState {
RFKILL_UNKNOWN,
RFKILL_UNBLOCKED,
RFKILL_SOFT,
RFKILL_HARD,
_RFKILL_STATE_MAX,
_RFKILL_STATE_INVALID = -EINVAL,
} RFKillState;
typedef struct Wiphy {
Manager *manager;
uint32_t index;
char *name;
sd_device *dev;
sd_device *rfkill;
RFKillState rfkill_state;
} Wiphy;
Wiphy *wiphy_free(Wiphy *w);
@@ -22,7 +37,11 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(Wiphy*, wiphy_free);
int wiphy_get_by_index(Manager *manager, uint32_t index, Wiphy **ret);
int wiphy_get_by_name(Manager *manager, const char *name, Wiphy **ret);
int link_rfkilled(Link *link);
int manager_genl_process_nl80211_wiphy(sd_netlink *genl, sd_netlink_message *message, Manager *manager);
int manager_udev_process_wiphy(Manager *m, sd_device *device, sd_device_action_t action);
int manager_udev_process_rfkill(Manager *m, sd_device *device, sd_device_action_t action);
#define log_wiphy_full_errno_zerook(w, level, error, ...) \
({ \