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 if (!device_is_devtype(link
->dev
, "wlan"))
124 r
= sd_device_new_child(&phy
, link
->dev
, "phy80211");
128 r
= sd_device_get_sysname(phy
, &s
);
133 * Maybe, it is better to cache the found Wiphy object in the Link object.
134 * To support that, we need to investigate what happens when the _phy_ is renamed. */
136 return wiphy_get_by_name(link
->manager
, s
, ret
);
139 static int rfkill_get_state(sd_device
*dev
) {
144 /* The previous values may be outdated. Let's clear cache and re-read the values. */
145 device_clear_sysattr_cache(dev
);
147 r
= device_get_sysattr_bool(dev
, "soft");
148 if (r
< 0 && r
!= -ENOENT
)
153 r
= device_get_sysattr_bool(dev
, "hard");
154 if (r
< 0 && r
!= -ENOENT
)
159 return RFKILL_UNBLOCKED
;
162 static int wiphy_rfkilled(Wiphy
*w
) {
167 if (!udev_available()) {
168 if (w
->rfkill_state
!= RFKILL_UNBLOCKED
) {
169 log_wiphy_debug(w
, "Running in container, assuming the radio transmitter is unblocked.");
170 w
->rfkill_state
= RFKILL_UNBLOCKED
; /* To suppress the above log message, cache the state. */
176 if (w
->rfkill_state
!= RFKILL_UNBLOCKED
) {
177 log_wiphy_debug(w
, "No rfkill device found, assuming the radio transmitter is unblocked.");
178 w
->rfkill_state
= RFKILL_UNBLOCKED
; /* To suppress the above log message, cache the state. */
183 r
= rfkill_get_state(w
->rfkill
);
185 return log_wiphy_debug_errno(w
, r
, "Could not get rfkill state: %m");
187 if (w
->rfkill_state
!= r
)
189 case RFKILL_UNBLOCKED
:
190 log_wiphy_debug(w
, "The radio transmitter is unblocked.");
193 log_wiphy_debug(w
, "The radio transmitter is turned off by software.");
196 log_wiphy_debug(w
, "The radio transmitter is forced off by something outside of the driver's control.");
199 assert_not_reached();
202 w
->rfkill_state
= r
; /* Cache the state to suppress the above log messages. */
203 return r
!= RFKILL_UNBLOCKED
;
206 int link_rfkilled(Link
*link
) {
212 r
= link_get_wiphy(link
, &w
);
213 if (ERRNO_IS_NEG_NOT_SUPPORTED(r
) || ERRNO_IS_NEG_DEVICE_ABSENT(r
))
214 return false; /* Typically, non-wifi interface or running in container */
216 return log_link_debug_errno(link
, r
, "Could not get phy: %m");
218 return wiphy_rfkilled(w
);
221 static int wiphy_update_name(Wiphy
*w
, sd_netlink_message
*message
) {
229 r
= sd_netlink_message_read_string(message
, NL80211_ATTR_WIPHY_NAME
, &name
);
235 if (streq(w
->name
, name
))
238 log_wiphy_debug(w
, "Wiphy name change detected, renamed to %s.", name
);
240 hashmap_remove_value(w
->manager
->wiphy_by_name
, w
->name
, w
);
242 r
= free_and_strdup(&w
->name
, name
);
246 r
= hashmap_ensure_put(&w
->manager
->wiphy_by_name
, &string_hash_ops
, w
->name
, w
);
250 return 1; /* updated */
253 static int wiphy_update_device(Wiphy
*w
) {
254 _cleanup_(sd_device_unrefp
) sd_device
*dev
= NULL
;
260 if (!udev_available())
263 w
->dev
= sd_device_unref(w
->dev
);
265 r
= sd_device_new_from_subsystem_sysname(&dev
, "ieee80211", w
->name
);
270 const char *s
= NULL
;
272 (void) sd_device_get_syspath(dev
, &s
);
273 log_wiphy_debug(w
, "Found device: %s", strna(s
));
276 w
->dev
= TAKE_PTR(dev
);
280 static int wiphy_update_rfkill(Wiphy
*w
) {
281 _cleanup_(sd_device_enumerator_unrefp
) sd_device_enumerator
*e
= NULL
;
287 if (!udev_available())
290 w
->rfkill
= sd_device_unref(w
->rfkill
);
295 r
= sd_device_enumerator_new(&e
);
299 r
= sd_device_enumerator_allow_uninitialized(e
);
303 r
= sd_device_enumerator_add_match_subsystem(e
, "rfkill", true);
307 r
= sd_device_enumerator_add_match_parent(e
, w
->dev
);
311 rfkill
= sd_device_enumerator_get_device_first(e
);
313 /* rfkill device may not detected by the kernel yet, and may appear later. */
316 if (sd_device_enumerator_get_device_next(e
))
317 return -ENXIO
; /* multiple devices found */
319 w
->rfkill
= sd_device_ref(rfkill
);
322 const char *s
= NULL
;
324 (void) sd_device_get_syspath(rfkill
, &s
);
325 log_wiphy_debug(w
, "Found rfkill device: %s", strna(s
));
331 static int wiphy_update(Wiphy
*w
) {
336 r
= wiphy_update_device(w
);
337 if (ERRNO_IS_NEG_DEVICE_ABSENT(r
))
338 log_wiphy_debug_errno(w
, r
, "Failed to update wiphy device, ignoring: %m");
340 return log_wiphy_warning_errno(w
, r
, "Failed to update wiphy device: %m");
342 r
= wiphy_update_rfkill(w
);
343 if (ERRNO_IS_NEG_DEVICE_ABSENT(r
))
344 log_wiphy_debug_errno(w
, r
, "Failed to update rfkill device, ignoring: %m");
346 return log_wiphy_warning_errno(w
, r
, "Failed to update rfkill device: %m");
351 int manager_genl_process_nl80211_wiphy(sd_netlink
*genl
, sd_netlink_message
*message
, Manager
*manager
) {
362 if (sd_netlink_message_is_error(message
)) {
363 r
= sd_netlink_message_get_errno(message
);
365 log_message_warning_errno(message
, r
, "nl80211: received error message, ignoring");
370 r
= sd_genl_message_get_family_name(genl
, message
, &family
);
372 log_debug_errno(r
, "nl80211: failed to determine genl family, ignoring: %m");
375 if (!streq(family
, NL80211_GENL_NAME
)) {
376 log_debug("nl80211: Received message of unexpected genl family '%s', ignoring.", family
);
380 r
= sd_genl_message_get_command(genl
, message
, &cmd
);
382 log_debug_errno(r
, "nl80211: failed to determine genl message command, ignoring: %m");
386 r
= sd_netlink_message_read_u32(message
, NL80211_ATTR_WIPHY
, &index
);
388 log_debug_errno(r
, "nl80211: received %s(%u) message without valid index, ignoring: %m",
389 strna(nl80211_cmd_to_string(cmd
)), cmd
);
393 (void) wiphy_get_by_index(manager
, index
, &w
);
396 case NL80211_CMD_NEW_WIPHY
: {
399 r
= wiphy_new(manager
, message
, &w
);
401 log_warning_errno(r
, "Failed to save new wiphy, ignoring: %m");
405 r
= wiphy_update_name(w
, message
);
407 log_wiphy_warning_errno(w
, r
, "Failed to update wiphy name, ignoring: %m");
416 log_wiphy_warning_errno(w
, r
, "Failed to update wiphy, ignoring: %m");
420 case NL80211_CMD_DEL_WIPHY
:
423 log_debug("The kernel removes wiphy we do not know, ignoring: %m");
427 log_wiphy_debug(w
, "Removed.");
432 log_wiphy_debug(w
, "nl80211: received %s(%u) message.",
433 strna(nl80211_cmd_to_string(cmd
)), cmd
);
439 int manager_udev_process_wiphy(Manager
*m
, sd_device
*device
, sd_device_action_t action
) {
447 r
= sd_device_get_sysname(device
, &name
);
449 return log_device_debug_errno(device
, r
, "Failed to get sysname: %m");
451 r
= wiphy_get_by_name(m
, name
, &w
);
453 /* This error is not critical, as the corresponding genl message may be received later. */
454 log_device_debug_errno(device
, r
, "Failed to get Wiphy object, ignoring: %m");
458 return device_unref_and_replace(w
->dev
, action
== SD_DEVICE_REMOVE
? NULL
: device
);
461 int manager_udev_process_rfkill(Manager
*m
, sd_device
*device
, sd_device_action_t action
) {
462 _cleanup_free_
char *parent_path
= NULL
, *parent_name
= NULL
;
470 r
= sd_device_get_syspath(device
, &s
);
472 return log_device_debug_errno(device
, r
, "Failed to get syspath: %m");
474 /* Do not use sd_device_get_parent() here, as this might be a 'remove' uevent. */
475 r
= path_extract_directory(s
, &parent_path
);
477 return log_device_debug_errno(device
, r
, "Failed to get parent syspath: %m");
479 r
= path_extract_filename(parent_path
, &parent_name
);
481 return log_device_debug_errno(device
, r
, "Failed to get parent name: %m");
483 r
= wiphy_get_by_name(m
, parent_name
, &w
);
485 /* This error is not critical, as the corresponding genl message may be received later. */
486 log_device_debug_errno(device
, r
, "Failed to get Wiphy object: %m");
490 return device_unref_and_replace(w
->rfkill
, action
== SD_DEVICE_REMOVE
? NULL
: device
);