]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-wiphy.c
test: also flush and rotate journal before read
[thirdparty/systemd.git] / src / network / networkd-wiphy.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <net/if_arp.h>
4 #include <linux/nl80211.h>
5
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"
14
15 Wiphy *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
25 sd_device_unref(w->dev);
26 sd_device_unref(w->rfkill);
27
28 free(w->name);
29 return mfree(w);
30 }
31
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;
35 uint32_t index;
36 int r;
37
38 assert(manager);
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;
48
49 w = new(Wiphy, 1);
50 if (!w)
51 return -ENOMEM;
52
53 *w = (Wiphy) {
54 .manager = manager,
55 .index = index,
56 .name = TAKE_PTR(name),
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
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);
68
69 if (ret)
70 *ret = w;
71
72 TAKE_PTR(w);
73 return 0;
74 }
75
76 int 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
91 int 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
107 static 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)
119 return -ENODEV;
120
121 if (!device_is_devtype(link->dev, "wlan"))
122 return -EOPNOTSUPP;
123
124 r = sd_device_new_child(&phy, link->dev, "phy80211");
125 if (r < 0)
126 return r;
127
128 r = sd_device_get_sysname(phy, &s);
129 if (r < 0)
130 return r;
131
132 /* TODO:
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. */
135
136 return wiphy_get_by_name(link->manager, s, ret);
137 }
138
139 static int rfkill_get_state(sd_device *dev) {
140 int r;
141
142 assert(dev);
143
144 /* The previous values may be outdated. Let's clear cache and re-read the values. */
145 device_clear_sysattr_cache(dev);
146
147 r = device_get_sysattr_bool(dev, "soft");
148 if (r < 0 && r != -ENOENT)
149 return r;
150 if (r > 0)
151 return RFKILL_SOFT;
152
153 r = device_get_sysattr_bool(dev, "hard");
154 if (r < 0 && r != -ENOENT)
155 return r;
156 if (r > 0)
157 return RFKILL_HARD;
158
159 return RFKILL_UNBLOCKED;
160 }
161
162 static int wiphy_rfkilled(Wiphy *w) {
163 int r;
164
165 assert(w);
166
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. */
171 }
172 return false;
173 }
174
175 if (!w->rfkill) {
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. */
179 }
180 return false;
181 }
182
183 r = rfkill_get_state(w->rfkill);
184 if (r < 0)
185 return log_wiphy_debug_errno(w, r, "Could not get rfkill state: %m");
186
187 if (w->rfkill_state != r)
188 switch (r) {
189 case RFKILL_UNBLOCKED:
190 log_wiphy_debug(w, "The radio transmitter is unblocked.");
191 break;
192 case RFKILL_SOFT:
193 log_wiphy_debug(w, "The radio transmitter is turned off by software.");
194 break;
195 case RFKILL_HARD:
196 log_wiphy_debug(w, "The radio transmitter is forced off by something outside of the driver's control.");
197 break;
198 default:
199 assert_not_reached();
200 }
201
202 w->rfkill_state = r; /* Cache the state to suppress the above log messages. */
203 return r != RFKILL_UNBLOCKED;
204 }
205
206 int link_rfkilled(Link *link) {
207 Wiphy *w;
208 int r;
209
210 assert(link);
211
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 */
215 if (r < 0)
216 return log_link_debug_errno(link, r, "Could not get phy: %m");
217
218 return wiphy_rfkilled(w);
219 }
220
221 static int wiphy_update_name(Wiphy *w, sd_netlink_message *message) {
222 const char *name;
223 int r;
224
225 assert(w);
226 assert(w->manager);
227 assert(message);
228
229 r = sd_netlink_message_read_string(message, NL80211_ATTR_WIPHY_NAME, &name);
230 if (r == -ENODATA)
231 return 0;
232 if (r < 0)
233 return r;
234
235 if (streq(w->name, name))
236 return 0;
237
238 log_wiphy_debug(w, "Wiphy name change detected, renamed to %s.", name);
239
240 hashmap_remove_value(w->manager->wiphy_by_name, w->name, w);
241
242 r = free_and_strdup(&w->name, name);
243 if (r < 0)
244 return r;
245
246 r = hashmap_ensure_put(&w->manager->wiphy_by_name, &string_hash_ops, w->name, w);
247 if (r < 0)
248 return r;
249
250 return 1; /* updated */
251 }
252
253 static int wiphy_update_device(Wiphy *w) {
254 _cleanup_(sd_device_unrefp) sd_device *dev = NULL;
255 int r;
256
257 assert(w);
258 assert(w->name);
259
260 if (!udev_available())
261 return 0;
262
263 w->dev = sd_device_unref(w->dev);
264
265 r = sd_device_new_from_subsystem_sysname(&dev, "ieee80211", w->name);
266 if (r < 0)
267 return r;
268
269 if (DEBUG_LOGGING) {
270 const char *s = NULL;
271
272 (void) sd_device_get_syspath(dev, &s);
273 log_wiphy_debug(w, "Found device: %s", strna(s));
274 }
275
276 w->dev = TAKE_PTR(dev);
277 return 0;
278 }
279
280 static int wiphy_update_rfkill(Wiphy *w) {
281 _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
282 sd_device *rfkill;
283 int r;
284
285 assert(w);
286
287 if (!udev_available())
288 return 0;
289
290 w->rfkill = sd_device_unref(w->rfkill);
291
292 if (!w->dev)
293 return 0;
294
295 r = sd_device_enumerator_new(&e);
296 if (r < 0)
297 return r;
298
299 r = sd_device_enumerator_allow_uninitialized(e);
300 if (r < 0)
301 return r;
302
303 r = sd_device_enumerator_add_match_subsystem(e, "rfkill", true);
304 if (r < 0)
305 return r;
306
307 r = sd_device_enumerator_add_match_parent(e, w->dev);
308 if (r < 0)
309 return r;
310
311 rfkill = sd_device_enumerator_get_device_first(e);
312 if (!rfkill)
313 /* rfkill device may not detected by the kernel yet, and may appear later. */
314 return -ENODEV;
315
316 if (sd_device_enumerator_get_device_next(e))
317 return -ENXIO; /* multiple devices found */
318
319 w->rfkill = sd_device_ref(rfkill);
320
321 if (DEBUG_LOGGING) {
322 const char *s = NULL;
323
324 (void) sd_device_get_syspath(rfkill, &s);
325 log_wiphy_debug(w, "Found rfkill device: %s", strna(s));
326 }
327
328 return 0;
329 }
330
331 static int wiphy_update(Wiphy *w) {
332 int r;
333
334 assert(w);
335
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");
339 else if (r < 0)
340 return log_wiphy_warning_errno(w, r, "Failed to update wiphy device: %m");
341
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");
345 else if (r < 0)
346 return log_wiphy_warning_errno(w, r, "Failed to update rfkill device: %m");
347
348 return 0;
349 }
350
351 int manager_genl_process_nl80211_wiphy(sd_netlink *genl, sd_netlink_message *message, Manager *manager) {
352 const char *family;
353 uint32_t index;
354 uint8_t cmd;
355 Wiphy *w = NULL;
356 int r;
357
358 assert(genl);
359 assert(message);
360 assert(manager);
361
362 if (sd_netlink_message_is_error(message)) {
363 r = sd_netlink_message_get_errno(message);
364 if (r < 0)
365 log_message_warning_errno(message, r, "nl80211: received error message, ignoring");
366
367 return 0;
368 }
369
370 r = sd_genl_message_get_family_name(genl, message, &family);
371 if (r < 0) {
372 log_debug_errno(r, "nl80211: failed to determine genl family, ignoring: %m");
373 return 0;
374 }
375 if (!streq(family, NL80211_GENL_NAME)) {
376 log_debug("nl80211: Received message of unexpected genl family '%s', ignoring.", family);
377 return 0;
378 }
379
380 r = sd_genl_message_get_command(genl, message, &cmd);
381 if (r < 0) {
382 log_debug_errno(r, "nl80211: failed to determine genl message command, ignoring: %m");
383 return 0;
384 }
385
386 r = sd_netlink_message_read_u32(message, NL80211_ATTR_WIPHY, &index);
387 if (r < 0) {
388 log_debug_errno(r, "nl80211: received %s(%u) message without valid index, ignoring: %m",
389 strna(nl80211_cmd_to_string(cmd)), cmd);
390 return 0;
391 }
392
393 (void) wiphy_get_by_index(manager, index, &w);
394
395 switch (cmd) {
396 case NL80211_CMD_NEW_WIPHY: {
397
398 if (!w) {
399 r = wiphy_new(manager, message, &w);
400 if (r < 0) {
401 log_warning_errno(r, "Failed to save new wiphy, ignoring: %m");
402 return 0;
403 }
404 } else {
405 r = wiphy_update_name(w, message);
406 if (r < 0) {
407 log_wiphy_warning_errno(w, r, "Failed to update wiphy name, ignoring: %m");
408 return 0;
409 }
410 if (r == 0)
411 return 0;
412 }
413
414 r = wiphy_update(w);
415 if (r < 0)
416 log_wiphy_warning_errno(w, r, "Failed to update wiphy, ignoring: %m");
417
418 break;
419 }
420 case NL80211_CMD_DEL_WIPHY:
421
422 if (!w) {
423 log_debug("The kernel removes wiphy we do not know, ignoring: %m");
424 return 0;
425 }
426
427 log_wiphy_debug(w, "Removed.");
428 wiphy_free(w);
429 break;
430
431 default:
432 log_wiphy_debug(w, "nl80211: received %s(%u) message.",
433 strna(nl80211_cmd_to_string(cmd)), cmd);
434 }
435
436 return 0;
437 }
438
439 int manager_udev_process_wiphy(Manager *m, sd_device *device, sd_device_action_t action) {
440 const char *name;
441 Wiphy *w;
442 int r;
443
444 assert(m);
445 assert(device);
446
447 r = sd_device_get_sysname(device, &name);
448 if (r < 0)
449 return log_device_debug_errno(device, r, "Failed to get sysname: %m");
450
451 r = wiphy_get_by_name(m, name, &w);
452 if (r < 0) {
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");
455 return 0;
456 }
457
458 return device_unref_and_replace(w->dev, action == SD_DEVICE_REMOVE ? NULL : device);
459 }
460
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;
463 const char *s;
464 Wiphy *w;
465 int r;
466
467 assert(m);
468 assert(device);
469
470 r = sd_device_get_syspath(device, &s);
471 if (r < 0)
472 return log_device_debug_errno(device, r, "Failed to get syspath: %m");
473
474 /* Do not use sd_device_get_parent() here, as this might be a 'remove' uevent. */
475 r = path_extract_directory(s, &parent_path);
476 if (r < 0)
477 return log_device_debug_errno(device, r, "Failed to get parent syspath: %m");
478
479 r = path_extract_filename(parent_path, &parent_name);
480 if (r < 0)
481 return log_device_debug_errno(device, r, "Failed to get parent name: %m");
482
483 r = wiphy_get_by_name(m, parent_name, &w);
484 if (r < 0) {
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");
487 return 0;
488 }
489
490 return device_unref_and_replace(w->rfkill, action == SD_DEVICE_REMOVE ? NULL : device);
491 }