1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include <net/if_arp.h>
4 #include <linux/nl80211.h>
6 #include "device-private.h"
7 #include "device-util.h"
8 #include "networkd-manager.h"
9 #include "networkd-wiphy.h"
10 #include "parse-util.h"
11 #include "path-util.h"
12 #include "udev-util.h"
13 #include "wifi-util.h"
15 Wiphy
*wiphy_free(Wiphy
*w
) {
20 hashmap_remove_value(w
->manager
->wiphy_by_index
, UINT32_TO_PTR(w
->index
), w
);
22 hashmap_remove_value(w
->manager
->wiphy_by_name
, w
->name
, w
);
25 sd_device_unref(w
->dev
);
26 sd_device_unref(w
->rfkill
);
32 static int wiphy_new(Manager
*manager
, sd_netlink_message
*message
, Wiphy
**ret
) {
33 _cleanup_(wiphy_freep
) Wiphy
*w
= NULL
;
34 _cleanup_free_
char *name
= NULL
;
41 r
= sd_netlink_message_read_u32(message
, NL80211_ATTR_WIPHY
, &index
);
45 r
= sd_netlink_message_read_string_strdup(message
, NL80211_ATTR_WIPHY_NAME
, &name
);
56 .name
= TAKE_PTR(name
),
59 r
= hashmap_ensure_put(&manager
->wiphy_by_index
, NULL
, UINT32_TO_PTR(w
->index
), w
);
63 r
= hashmap_ensure_put(&w
->manager
->wiphy_by_name
, &string_hash_ops
, w
->name
, w
);
67 log_wiphy_debug(w
, "Saved new wiphy: index=%"PRIu32
, w
->index
);
76 int wiphy_get_by_index(Manager
*manager
, uint32_t index
, Wiphy
**ret
) {
81 w
= hashmap_get(manager
->wiphy_by_index
, UINT32_TO_PTR(index
));
91 int wiphy_get_by_name(Manager
*manager
, const char *name
, Wiphy
**ret
) {
97 w
= hashmap_get(manager
->wiphy_by_name
, name
);
107 static int link_get_wiphy(Link
*link
, Wiphy
**ret
) {
108 _cleanup_(sd_device_unrefp
) sd_device
*phy
= NULL
;
113 assert(link
->manager
);
115 if (link
->iftype
!= ARPHRD_ETHER
)
121 r
= sd_device_get_devtype(link
->dev
, &s
);
125 if (!streq_ptr(s
, "wlan"))
128 r
= sd_device_get_syspath(link
->dev
, &s
);
132 s
= strjoina(s
, "/phy80211");
133 r
= sd_device_new_from_syspath(&phy
, s
);
137 r
= sd_device_get_sysname(phy
, &s
);
142 * Maybe, it is better to cache the found Wiphy object in the Link object.
143 * To support that, we need to investigate what happens when the _phy_ is renamed. */
145 return wiphy_get_by_name(link
->manager
, s
, ret
);
148 static int rfkill_get_state(sd_device
*dev
) {
153 /* The previous values may be outdated. Let's clear cache and re-read the values. */
154 device_clear_sysattr_cache(dev
);
156 r
= device_get_sysattr_bool(dev
, "soft");
157 if (r
< 0 && r
!= -ENOENT
)
162 r
= device_get_sysattr_bool(dev
, "hard");
163 if (r
< 0 && r
!= -ENOENT
)
168 return RFKILL_UNBLOCKED
;
171 static int wiphy_rfkilled(Wiphy
*w
) {
176 if (!udev_available()) {
177 if (w
->rfkill_state
!= RFKILL_UNBLOCKED
) {
178 log_wiphy_debug(w
, "Running in container, assuming the radio transmitter is unblocked.");
179 w
->rfkill_state
= RFKILL_UNBLOCKED
; /* To suppress the above log message, cache the state. */
185 if (w
->rfkill_state
!= RFKILL_UNBLOCKED
) {
186 log_wiphy_debug(w
, "No rfkill device found, assuming the radio transmitter is unblocked.");
187 w
->rfkill_state
= RFKILL_UNBLOCKED
; /* To suppress the above log message, cache the state. */
192 r
= rfkill_get_state(w
->rfkill
);
194 return log_wiphy_debug_errno(w
, r
, "Could not get rfkill state: %m");
196 if (w
->rfkill_state
!= r
)
198 case RFKILL_UNBLOCKED
:
199 log_wiphy_debug(w
, "The radio transmitter is unblocked.");
202 log_wiphy_debug(w
, "The radio transmitter is turned off by software.");
205 log_wiphy_debug(w
, "The radio transmitter is forced off by something outside of the driver's control.");
208 assert_not_reached();
211 w
->rfkill_state
= r
; /* Cache the state to suppress the above log messages. */
212 return r
!= RFKILL_UNBLOCKED
;
215 int link_rfkilled(Link
*link
) {
221 r
= link_get_wiphy(link
, &w
);
222 if (IN_SET(r
, -EOPNOTSUPP
, -ENODEV
))
223 return false; /* Typically, non-wifi interface or running in container */
225 return log_link_debug_errno(link
, r
, "Could not get phy: %m");
227 return wiphy_rfkilled(w
);
230 static int wiphy_update_name(Wiphy
*w
, sd_netlink_message
*message
) {
238 r
= sd_netlink_message_read_string(message
, NL80211_ATTR_WIPHY_NAME
, &name
);
244 if (streq(w
->name
, name
))
247 log_wiphy_debug(w
, "Wiphy name change detected, renamed to %s.", name
);
249 hashmap_remove_value(w
->manager
->wiphy_by_name
, w
->name
, w
);
251 r
= free_and_strdup(&w
->name
, name
);
255 r
= hashmap_ensure_put(&w
->manager
->wiphy_by_name
, &string_hash_ops
, w
->name
, w
);
259 return 1; /* updated */
262 static int wiphy_update_device(Wiphy
*w
) {
263 _cleanup_(sd_device_unrefp
) sd_device
*dev
= NULL
;
269 if (!udev_available())
272 w
->dev
= sd_device_unref(w
->dev
);
274 r
= sd_device_new_from_subsystem_sysname(&dev
, "ieee80211", w
->name
);
276 /* The corresponding syspath may not exist yet, and may appear later. */
277 log_wiphy_debug_errno(w
, r
, "Failed to get wiphy device, ignoring: %m");
282 const char *s
= NULL
;
284 (void) sd_device_get_syspath(dev
, &s
);
285 log_wiphy_debug(w
, "Found device: %s", strna(s
));
288 w
->dev
= TAKE_PTR(dev
);
292 static int wiphy_update_rfkill(Wiphy
*w
) {
293 _cleanup_(sd_device_enumerator_unrefp
) sd_device_enumerator
*e
= NULL
;
299 if (!udev_available())
302 w
->rfkill
= sd_device_unref(w
->rfkill
);
307 r
= sd_device_enumerator_new(&e
);
311 r
= sd_device_enumerator_allow_uninitialized(e
);
315 r
= sd_device_enumerator_add_match_subsystem(e
, "rfkill", true);
319 r
= sd_device_enumerator_add_match_parent(e
, w
->dev
);
323 rfkill
= sd_device_enumerator_get_device_first(e
);
325 /* rfkill device may not detected by the kernel yet, and may appear later. */
326 log_wiphy_debug_errno(w
, SYNTHETIC_ERRNO(ENODEV
), "No rfkill device found, ignoring.");
330 if (sd_device_enumerator_get_device_next(e
))
331 return log_wiphy_debug_errno(w
, SYNTHETIC_ERRNO(EEXIST
), "Multiple rfkill devices found.");
333 w
->rfkill
= sd_device_ref(rfkill
);
336 const char *s
= NULL
;
338 (void) sd_device_get_syspath(rfkill
, &s
);
339 log_wiphy_debug(w
, "Found rfkill device: %s", strna(s
));
345 static int wiphy_update(Wiphy
*w
) {
350 r
= wiphy_update_device(w
);
352 return log_wiphy_debug_errno(w
, r
, "Failed to update wiphy device: %m");
354 r
= wiphy_update_rfkill(w
);
356 return log_wiphy_debug_errno(w
, r
, "Failed to update rfkill device: %m");
361 int manager_genl_process_nl80211_wiphy(sd_netlink
*genl
, sd_netlink_message
*message
, Manager
*manager
) {
372 if (sd_netlink_message_is_error(message
)) {
373 r
= sd_netlink_message_get_errno(message
);
375 log_message_warning_errno(message
, r
, "nl80211: received error message, ignoring");
380 r
= sd_genl_message_get_family_name(genl
, message
, &family
);
382 log_debug_errno(r
, "nl80211: failed to determine genl family, ignoring: %m");
385 if (!streq(family
, NL80211_GENL_NAME
)) {
386 log_debug("nl80211: Received message of unexpected genl family '%s', ignoring.", family
);
390 r
= sd_genl_message_get_command(genl
, message
, &cmd
);
392 log_debug_errno(r
, "nl80211: failed to determine genl message command, ignoring: %m");
396 r
= sd_netlink_message_read_u32(message
, NL80211_ATTR_WIPHY
, &index
);
398 log_debug_errno(r
, "nl80211: received %s(%u) message without valid index, ignoring: %m",
399 strna(nl80211_cmd_to_string(cmd
)), cmd
);
403 (void) wiphy_get_by_index(manager
, index
, &w
);
406 case NL80211_CMD_NEW_WIPHY
: {
409 r
= wiphy_new(manager
, message
, &w
);
411 log_warning_errno(r
, "Failed to save new wiphy, ignoring: %m");
415 r
= wiphy_update_name(w
, message
);
417 log_wiphy_warning_errno(w
, r
, "Failed to update wiphy name, ignoring: %m");
426 log_wiphy_warning_errno(w
, r
, "Failed to update wiphy, ignoring: %m");
430 case NL80211_CMD_DEL_WIPHY
:
433 log_debug("The kernel removes wiphy we do not know, ignoring: %m");
437 log_wiphy_debug(w
, "Removed.");
442 log_wiphy_debug(w
, "nl80211: received %s(%u) message.",
443 strna(nl80211_cmd_to_string(cmd
)), cmd
);
449 int manager_udev_process_wiphy(Manager
*m
, sd_device
*device
, sd_device_action_t action
) {
457 r
= sd_device_get_sysname(device
, &name
);
459 return log_device_debug_errno(device
, r
, "Failed to get sysname: %m");
461 r
= wiphy_get_by_name(m
, name
, &w
);
463 /* This error is not critical, as the corresponding genl message may be received later. */
464 log_device_debug_errno(device
, r
, "Failed to get Wiphy object, ignoring: %m");
468 return device_unref_and_replace(w
->dev
, action
== SD_DEVICE_REMOVE
? NULL
: device
);
471 int manager_udev_process_rfkill(Manager
*m
, sd_device
*device
, sd_device_action_t action
) {
472 _cleanup_free_
char *parent_path
= NULL
, *parent_name
= NULL
;
480 r
= sd_device_get_syspath(device
, &s
);
482 return log_device_debug_errno(device
, r
, "Failed to get syspath: %m");
484 /* Do not use sd_device_get_parent() here, as this might be a 'remove' uevent. */
485 r
= path_extract_directory(s
, &parent_path
);
487 return log_device_debug_errno(device
, r
, "Failed to get parent syspath: %m");
489 r
= path_extract_filename(parent_path
, &parent_name
);
491 return log_device_debug_errno(device
, r
, "Failed to get parent name: %m");
493 r
= wiphy_get_by_name(m
, parent_name
, &w
);
495 /* This error is not critical, as the corresponding genl message may be received later. */
496 log_device_debug_errno(device
, r
, "Failed to get Wiphy object: %m");
500 return device_unref_and_replace(w
->rfkill
, action
== SD_DEVICE_REMOVE
? NULL
: device
);