]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-wiphy.c
various: use _NEG_ macros to reduce indentation
[thirdparty/systemd.git] / src / network / networkd-wiphy.c
CommitLineData
edb69db2
YW
1/* SPDX-License-Identifier: LGPL-2.1-or-later */
2
a9d2d037 3#include <net/if_arp.h>
edb69db2
YW
4#include <linux/nl80211.h>
5
c49d5362 6#include "device-private.h"
edb69db2
YW
7#include "device-util.h"
8#include "networkd-manager.h"
9#include "networkd-wiphy.h"
10#include "parse-util.h"
8642e04b 11#include "path-util.h"
c49d5362 12#include "udev-util.h"
edb69db2
YW
13#include "wifi-util.h"
14
15Wiphy *wiphy_free(Wiphy *w) {
16 if (!w)
17 return NULL;
18
19 if (w->manager) {
20 hashmap_remove_value(w->manager->wiphy_by_index, UINT32_TO_PTR(w->index), w);
21 if (w->name)
22 hashmap_remove_value(w->manager->wiphy_by_name, w->name, w);
23 }
24
c49d5362 25 sd_device_unref(w->dev);
8642e04b 26 sd_device_unref(w->rfkill);
c49d5362 27
edb69db2
YW
28 free(w->name);
29 return mfree(w);
30}
31
fc85b323 32static int wiphy_new(Manager *manager, sd_netlink_message *message, Wiphy **ret) {
edb69db2 33 _cleanup_(wiphy_freep) Wiphy *w = NULL;
fc85b323
YW
34 _cleanup_free_ char *name = NULL;
35 uint32_t index;
edb69db2
YW
36 int r;
37
38 assert(manager);
fc85b323
YW
39 assert(message);
40
41 r = sd_netlink_message_read_u32(message, NL80211_ATTR_WIPHY, &index);
42 if (r < 0)
43 return r;
44
45 r = sd_netlink_message_read_string_strdup(message, NL80211_ATTR_WIPHY_NAME, &name);
46 if (r < 0)
47 return r;
edb69db2
YW
48
49 w = new(Wiphy, 1);
50 if (!w)
51 return -ENOMEM;
52
53 *w = (Wiphy) {
fc85b323 54 .manager = manager,
edb69db2 55 .index = index,
fc85b323 56 .name = TAKE_PTR(name),
edb69db2
YW
57 };
58
59 r = hashmap_ensure_put(&manager->wiphy_by_index, NULL, UINT32_TO_PTR(w->index), w);
60 if (r < 0)
61 return r;
62
fc85b323
YW
63 r = hashmap_ensure_put(&w->manager->wiphy_by_name, &string_hash_ops, w->name, w);
64 if (r < 0)
65 return r;
66
67 log_wiphy_debug(w, "Saved new wiphy: index=%"PRIu32, w->index);
edb69db2
YW
68
69 if (ret)
70 *ret = w;
71
72 TAKE_PTR(w);
73 return 0;
74}
75
76int wiphy_get_by_index(Manager *manager, uint32_t index, Wiphy **ret) {
77 Wiphy *w;
78
79 assert(manager);
80
81 w = hashmap_get(manager->wiphy_by_index, UINT32_TO_PTR(index));
82 if (!w)
83 return -ENODEV;
84
85 if (ret)
86 *ret = w;
87
88 return 0;
89}
90
91int wiphy_get_by_name(Manager *manager, const char *name, Wiphy **ret) {
92 Wiphy *w;
93
94 assert(manager);
95 assert(name);
96
97 w = hashmap_get(manager->wiphy_by_name, name);
98 if (!w)
99 return -ENODEV;
100
101 if (ret)
102 *ret = w;
103
104 return 0;
105}
106
a9d2d037
YW
107static int link_get_wiphy(Link *link, Wiphy **ret) {
108 _cleanup_(sd_device_unrefp) sd_device *phy = NULL;
109 const char *s;
110 int r;
111
112 assert(link);
113 assert(link->manager);
114
115 if (link->iftype != ARPHRD_ETHER)
116 return -EOPNOTSUPP;
117
118 if (!link->dev)
4d79af57 119 return -ENODEV;
a9d2d037
YW
120
121 r = sd_device_get_devtype(link->dev, &s);
122 if (r < 0)
123 return r;
124
125 if (!streq_ptr(s, "wlan"))
126 return -EOPNOTSUPP;
127
68a52f59 128 r = sd_device_new_child(&phy, link->dev, "phy80211");
a9d2d037
YW
129 if (r < 0)
130 return r;
131
132 r = sd_device_get_sysname(phy, &s);
133 if (r < 0)
134 return r;
135
136 /* TODO:
137 * Maybe, it is better to cache the found Wiphy object in the Link object.
138 * To support that, we need to investigate what happens when the _phy_ is renamed. */
139
140 return wiphy_get_by_name(link->manager, s, ret);
141}
142
143static int rfkill_get_state(sd_device *dev) {
144 int r;
145
146 assert(dev);
147
148 /* The previous values may be outdated. Let's clear cache and re-read the values. */
149 device_clear_sysattr_cache(dev);
150
151 r = device_get_sysattr_bool(dev, "soft");
152 if (r < 0 && r != -ENOENT)
153 return r;
154 if (r > 0)
155 return RFKILL_SOFT;
156
157 r = device_get_sysattr_bool(dev, "hard");
158 if (r < 0 && r != -ENOENT)
159 return r;
160 if (r > 0)
161 return RFKILL_HARD;
162
163 return RFKILL_UNBLOCKED;
164}
165
166static int wiphy_rfkilled(Wiphy *w) {
167 int r;
168
169 assert(w);
170
171 if (!udev_available()) {
172 if (w->rfkill_state != RFKILL_UNBLOCKED) {
173 log_wiphy_debug(w, "Running in container, assuming the radio transmitter is unblocked.");
174 w->rfkill_state = RFKILL_UNBLOCKED; /* To suppress the above log message, cache the state. */
175 }
176 return false;
177 }
178
179 if (!w->rfkill) {
180 if (w->rfkill_state != RFKILL_UNBLOCKED) {
181 log_wiphy_debug(w, "No rfkill device found, assuming the radio transmitter is unblocked.");
182 w->rfkill_state = RFKILL_UNBLOCKED; /* To suppress the above log message, cache the state. */
183 }
184 return false;
185 }
186
187 r = rfkill_get_state(w->rfkill);
188 if (r < 0)
189 return log_wiphy_debug_errno(w, r, "Could not get rfkill state: %m");
190
191 if (w->rfkill_state != r)
192 switch (r) {
193 case RFKILL_UNBLOCKED:
194 log_wiphy_debug(w, "The radio transmitter is unblocked.");
195 break;
196 case RFKILL_SOFT:
197 log_wiphy_debug(w, "The radio transmitter is turned off by software.");
198 break;
199 case RFKILL_HARD:
200 log_wiphy_debug(w, "The radio transmitter is forced off by something outside of the driver's control.");
201 break;
202 default:
203 assert_not_reached();
204 }
205
206 w->rfkill_state = r; /* Cache the state to suppress the above log messages. */
207 return r != RFKILL_UNBLOCKED;
208}
209
210int link_rfkilled(Link *link) {
211 Wiphy *w;
212 int r;
213
214 assert(link);
215
216 r = link_get_wiphy(link, &w);
bb44fd07
ZJS
217 if (ERRNO_IS_NEG_NOT_SUPPORTED(r) || ERRNO_IS_NEG_DEVICE_ABSENT(r))
218 return false; /* Typically, non-wifi interface or running in container */
219 if (r < 0)
a9d2d037
YW
220 return log_link_debug_errno(link, r, "Could not get phy: %m");
221
222 return wiphy_rfkilled(w);
223}
224
edb69db2
YW
225static int wiphy_update_name(Wiphy *w, sd_netlink_message *message) {
226 const char *name;
227 int r;
228
229 assert(w);
230 assert(w->manager);
231 assert(message);
232
233 r = sd_netlink_message_read_string(message, NL80211_ATTR_WIPHY_NAME, &name);
234 if (r == -ENODATA)
235 return 0;
236 if (r < 0)
237 return r;
238
fc85b323 239 if (streq(w->name, name))
edb69db2
YW
240 return 0;
241
fc85b323
YW
242 log_wiphy_debug(w, "Wiphy name change detected, renamed to %s.", name);
243
244 hashmap_remove_value(w->manager->wiphy_by_name, w->name, w);
edb69db2
YW
245
246 r = free_and_strdup(&w->name, name);
247 if (r < 0)
248 return r;
249
fc85b323 250 r = hashmap_ensure_put(&w->manager->wiphy_by_name, &string_hash_ops, w->name, w);
edb69db2 251 if (r < 0)
fc85b323 252 return r;
edb69db2 253
fc85b323 254 return 1; /* updated */
edb69db2
YW
255}
256
c49d5362
YW
257static int wiphy_update_device(Wiphy *w) {
258 _cleanup_(sd_device_unrefp) sd_device *dev = NULL;
259 int r;
260
261 assert(w);
262 assert(w->name);
263
264 if (!udev_available())
265 return 0;
266
267 w->dev = sd_device_unref(w->dev);
268
269 r = sd_device_new_from_subsystem_sysname(&dev, "ieee80211", w->name);
4d79af57
YW
270 if (r < 0)
271 return r;
c49d5362
YW
272
273 if (DEBUG_LOGGING) {
274 const char *s = NULL;
275
276 (void) sd_device_get_syspath(dev, &s);
277 log_wiphy_debug(w, "Found device: %s", strna(s));
278 }
279
280 w->dev = TAKE_PTR(dev);
281 return 0;
282}
283
8642e04b
YW
284static int wiphy_update_rfkill(Wiphy *w) {
285 _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
286 sd_device *rfkill;
287 int r;
288
289 assert(w);
290
291 if (!udev_available())
292 return 0;
293
294 w->rfkill = sd_device_unref(w->rfkill);
295
296 if (!w->dev)
297 return 0;
298
299 r = sd_device_enumerator_new(&e);
300 if (r < 0)
301 return r;
302
303 r = sd_device_enumerator_allow_uninitialized(e);
304 if (r < 0)
305 return r;
306
307 r = sd_device_enumerator_add_match_subsystem(e, "rfkill", true);
308 if (r < 0)
309 return r;
310
311 r = sd_device_enumerator_add_match_parent(e, w->dev);
312 if (r < 0)
313 return r;
314
315 rfkill = sd_device_enumerator_get_device_first(e);
4d79af57 316 if (!rfkill)
8642e04b 317 /* rfkill device may not detected by the kernel yet, and may appear later. */
4d79af57 318 return -ENODEV;
8642e04b
YW
319
320 if (sd_device_enumerator_get_device_next(e))
4d79af57 321 return -ENXIO; /* multiple devices found */
8642e04b
YW
322
323 w->rfkill = sd_device_ref(rfkill);
324
325 if (DEBUG_LOGGING) {
326 const char *s = NULL;
327
328 (void) sd_device_get_syspath(rfkill, &s);
329 log_wiphy_debug(w, "Found rfkill device: %s", strna(s));
330 }
331
332 return 0;
333}
334
c49d5362
YW
335static int wiphy_update(Wiphy *w) {
336 int r;
337
338 assert(w);
339
340 r = wiphy_update_device(w);
bb44fd07
ZJS
341 if (ERRNO_IS_NEG_DEVICE_ABSENT(r))
342 log_wiphy_debug_errno(w, r, "Failed to update wiphy device, ignoring: %m");
343 else if (r < 0)
344 return log_wiphy_warning_errno(w, r, "Failed to update wiphy device: %m");
c49d5362 345
8642e04b 346 r = wiphy_update_rfkill(w);
bb44fd07
ZJS
347 if (ERRNO_IS_NEG_DEVICE_ABSENT(r))
348 log_wiphy_debug_errno(w, r, "Failed to update rfkill device, ignoring: %m");
349 else if (r < 0)
350 return log_wiphy_warning_errno(w, r, "Failed to update rfkill device: %m");
8642e04b 351
c49d5362
YW
352 return 0;
353}
354
edb69db2
YW
355int manager_genl_process_nl80211_wiphy(sd_netlink *genl, sd_netlink_message *message, Manager *manager) {
356 const char *family;
357 uint32_t index;
358 uint8_t cmd;
359 Wiphy *w = NULL;
360 int r;
361
362 assert(genl);
363 assert(message);
364 assert(manager);
365
366 if (sd_netlink_message_is_error(message)) {
367 r = sd_netlink_message_get_errno(message);
368 if (r < 0)
369 log_message_warning_errno(message, r, "nl80211: received error message, ignoring");
370
371 return 0;
372 }
373
374 r = sd_genl_message_get_family_name(genl, message, &family);
375 if (r < 0) {
376 log_debug_errno(r, "nl80211: failed to determine genl family, ignoring: %m");
377 return 0;
378 }
379 if (!streq(family, NL80211_GENL_NAME)) {
380 log_debug("nl80211: Received message of unexpected genl family '%s', ignoring.", family);
381 return 0;
382 }
383
384 r = sd_genl_message_get_command(genl, message, &cmd);
385 if (r < 0) {
386 log_debug_errno(r, "nl80211: failed to determine genl message command, ignoring: %m");
387 return 0;
388 }
389
390 r = sd_netlink_message_read_u32(message, NL80211_ATTR_WIPHY, &index);
391 if (r < 0) {
392 log_debug_errno(r, "nl80211: received %s(%u) message without valid index, ignoring: %m",
393 strna(nl80211_cmd_to_string(cmd)), cmd);
394 return 0;
395 }
396
397 (void) wiphy_get_by_index(manager, index, &w);
398
399 switch (cmd) {
400 case NL80211_CMD_NEW_WIPHY: {
edb69db2
YW
401
402 if (!w) {
fc85b323 403 r = wiphy_new(manager, message, &w);
edb69db2 404 if (r < 0) {
fc85b323 405 log_warning_errno(r, "Failed to save new wiphy, ignoring: %m");
edb69db2
YW
406 return 0;
407 }
fc85b323
YW
408 } else {
409 r = wiphy_update_name(w, message);
410 if (r < 0) {
411 log_wiphy_warning_errno(w, r, "Failed to update wiphy name, ignoring: %m");
412 return 0;
413 }
414 if (r == 0)
415 return 0;
edb69db2
YW
416 }
417
c49d5362
YW
418 r = wiphy_update(w);
419 if (r < 0)
420 log_wiphy_warning_errno(w, r, "Failed to update wiphy, ignoring: %m");
421
edb69db2
YW
422 break;
423 }
424 case NL80211_CMD_DEL_WIPHY:
425
426 if (!w) {
427 log_debug("The kernel removes wiphy we do not know, ignoring: %m");
428 return 0;
429 }
430
431 log_wiphy_debug(w, "Removed.");
432 wiphy_free(w);
433 break;
434
435 default:
436 log_wiphy_debug(w, "nl80211: received %s(%u) message.",
437 strna(nl80211_cmd_to_string(cmd)), cmd);
438 }
439
440 return 0;
441}
c49d5362
YW
442
443int manager_udev_process_wiphy(Manager *m, sd_device *device, sd_device_action_t action) {
444 const char *name;
445 Wiphy *w;
446 int r;
447
448 assert(m);
449 assert(device);
450
451 r = sd_device_get_sysname(device, &name);
452 if (r < 0)
453 return log_device_debug_errno(device, r, "Failed to get sysname: %m");
454
455 r = wiphy_get_by_name(m, name, &w);
456 if (r < 0) {
457 /* This error is not critical, as the corresponding genl message may be received later. */
458 log_device_debug_errno(device, r, "Failed to get Wiphy object, ignoring: %m");
459 return 0;
460 }
461
462 return device_unref_and_replace(w->dev, action == SD_DEVICE_REMOVE ? NULL : device);
463}
8642e04b
YW
464
465int manager_udev_process_rfkill(Manager *m, sd_device *device, sd_device_action_t action) {
466 _cleanup_free_ char *parent_path = NULL, *parent_name = NULL;
467 const char *s;
468 Wiphy *w;
469 int r;
470
471 assert(m);
472 assert(device);
473
474 r = sd_device_get_syspath(device, &s);
475 if (r < 0)
476 return log_device_debug_errno(device, r, "Failed to get syspath: %m");
477
478 /* Do not use sd_device_get_parent() here, as this might be a 'remove' uevent. */
479 r = path_extract_directory(s, &parent_path);
480 if (r < 0)
481 return log_device_debug_errno(device, r, "Failed to get parent syspath: %m");
482
483 r = path_extract_filename(parent_path, &parent_name);
484 if (r < 0)
485 return log_device_debug_errno(device, r, "Failed to get parent name: %m");
486
487 r = wiphy_get_by_name(m, parent_name, &w);
488 if (r < 0) {
489 /* This error is not critical, as the corresponding genl message may be received later. */
490 log_device_debug_errno(device, r, "Failed to get Wiphy object: %m");
491 return 0;
492 }
493
494 return device_unref_and_replace(w->rfkill, action == SD_DEVICE_REMOVE ? NULL : device);
495}