]>
Commit | Line | Data |
---|---|---|
db9ecf05 | 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
f579559b | 2 | |
9aa5d8ba | 3 | #include <netinet/in.h> |
091a364c | 4 | #include <sys/socket.h> |
9aa5d8ba | 5 | #include <unistd.h> |
bbf7c048 | 6 | #include <linux/if.h> |
bce67bbe | 7 | #include <linux/fib_rules.h> |
c16c7808 | 8 | #include <linux/nexthop.h> |
96f5f9ef | 9 | #include <linux/nl80211.h> |
3bef724f | 10 | |
07630cea | 11 | #include "sd-netlink.h" |
fc2f9534 | 12 | |
b5efdb8a | 13 | #include "alloc-util.h" |
f63e09ef | 14 | #include "bus-error.h" |
b607fd3f | 15 | #include "bus-locator.h" |
ac9f55ed | 16 | #include "bus-log-control-api.h" |
269e4d2d | 17 | #include "bus-polkit.h" |
a97dcc12 | 18 | #include "bus-util.h" |
07630cea | 19 | #include "conf-parser.h" |
af7a86b8 | 20 | #include "daemon-util.h" |
a97dcc12 | 21 | #include "def.h" |
1fd3ac1e YW |
22 | #include "device-private.h" |
23 | #include "device-util.h" | |
482d1aeb | 24 | #include "dns-domain.h" |
3ffd4af2 | 25 | #include "fd-util.h" |
0d39fa9c | 26 | #include "fileio.h" |
761cf19d | 27 | #include "firewall-util.h" |
af664001 | 28 | #include "fs-util.h" |
4f5f911e | 29 | #include "local-addresses.h" |
07630cea | 30 | #include "netlink-util.h" |
dc0d4078 | 31 | #include "network-internal.h" |
bfbf150e | 32 | #include "networkd-address-pool.h" |
3b6a3bde | 33 | #include "networkd-address.h" |
cf72a786 | 34 | #include "networkd-dhcp-server-bus.h" |
ca5ad760 | 35 | #include "networkd-dhcp6.h" |
6a1af3d4 | 36 | #include "networkd-link-bus.h" |
79a59fa5 | 37 | #include "networkd-manager-bus.h" |
23f53b99 | 38 | #include "networkd-manager.h" |
1939ebeb | 39 | #include "networkd-neighbor.h" |
ceac2c2b | 40 | #include "networkd-network-bus.h" |
75156ccb | 41 | #include "networkd-nexthop.h" |
19d9a5ad | 42 | #include "networkd-queue.h" |
3b6a3bde | 43 | #include "networkd-route.h" |
ca183bf8 | 44 | #include "networkd-routing-policy-rule.h" |
a879e1a4 | 45 | #include "networkd-speed-meter.h" |
3b5a4fc6 | 46 | #include "networkd-state-file.h" |
96f5f9ef | 47 | #include "networkd-wifi.h" |
edb69db2 | 48 | #include "networkd-wiphy.h" |
00616955 | 49 | #include "ordered-set.h" |
b0c82192 | 50 | #include "path-lookup.h" |
07630cea | 51 | #include "path-util.h" |
828a81a9 | 52 | #include "qdisc.h" |
92b555aa | 53 | #include "selinux-util.h" |
07630cea | 54 | #include "set.h" |
ab76be55 | 55 | #include "signal-util.h" |
d31f33e3 | 56 | #include "stat-util.h" |
21486d9e | 57 | #include "strv.h" |
4b600505 | 58 | #include "sysctl-util.h" |
828a81a9 | 59 | #include "tclass.h" |
e4de7287 | 60 | #include "tmpfile-util.h" |
af7a86b8 | 61 | #include "tuntap.h" |
82f52245 | 62 | #include "udev-util.h" |
505f8da7 | 63 | |
48d0248e YW |
64 | /* use 128 MB for receive socket kernel queue. */ |
65 | #define RCVBUF_SIZE (128*1024*1024) | |
be660c37 | 66 | |
9c0a72f9 TG |
67 | static int manager_reset_all(Manager *m) { |
68 | Link *link; | |
9c0a72f9 TG |
69 | int r; |
70 | ||
71 | assert(m); | |
72 | ||
6eab614d | 73 | HASHMAP_FOREACH(link, m->links_by_index) { |
d09a179e | 74 | r = link_reconfigure_after_sleep(link); |
f0269653 | 75 | if (r < 0) { |
d09a179e | 76 | log_link_warning_errno(link, r, "Failed to reconfigure interface: %m"); |
f0269653 YW |
77 | link_enter_failed(link); |
78 | } | |
9c0a72f9 TG |
79 | } |
80 | ||
81 | return 0; | |
82 | } | |
83 | ||
19070062 | 84 | static int match_prepare_for_sleep(sd_bus_message *message, void *userdata, sd_bus_error *ret_error) { |
9c0a72f9 TG |
85 | Manager *m = userdata; |
86 | int b, r; | |
87 | ||
19070062 | 88 | assert(message); |
d7afd945 | 89 | assert(m); |
9c0a72f9 TG |
90 | |
91 | r = sd_bus_message_read(message, "b", &b); | |
92 | if (r < 0) { | |
d67b1d18 | 93 | bus_log_parse_error(r); |
9c0a72f9 TG |
94 | return 0; |
95 | } | |
96 | ||
97 | if (b) | |
98 | return 0; | |
99 | ||
100 | log_debug("Coming back from suspend, resetting all connections..."); | |
101 | ||
e1694a75 | 102 | (void) manager_reset_all(m); |
9c0a72f9 TG |
103 | |
104 | return 0; | |
105 | } | |
106 | ||
d7afd945 LP |
107 | static int on_connected(sd_bus_message *message, void *userdata, sd_bus_error *ret_error) { |
108 | Manager *m = userdata; | |
9c0a72f9 | 109 | |
d7afd945 | 110 | assert(message); |
9c0a72f9 TG |
111 | assert(m); |
112 | ||
d7afd945 LP |
113 | /* Did we get a timezone or transient hostname from DHCP while D-Bus wasn't up yet? */ |
114 | if (m->dynamic_hostname) | |
115 | (void) manager_set_hostname(m, m->dynamic_hostname); | |
116 | if (m->dynamic_timezone) | |
117 | (void) manager_set_timezone(m, m->dynamic_timezone); | |
ccffa166 | 118 | if (m->product_uuid_requested) |
4e26a5ba | 119 | (void) manager_request_product_uuid(m); |
9c0a72f9 | 120 | |
d7afd945 LP |
121 | return 0; |
122 | } | |
9c0a72f9 | 123 | |
96243149 | 124 | static int manager_connect_bus(Manager *m) { |
d7afd945 LP |
125 | int r; |
126 | ||
127 | assert(m); | |
96243149 | 128 | assert(!m->bus); |
7d6884b6 | 129 | |
621e4509 | 130 | r = bus_open_system_watch_bind_with_description(&m->bus, "bus-api-network"); |
9c0a72f9 | 131 | if (r < 0) |
d7afd945 | 132 | return log_error_errno(r, "Failed to connect to bus: %m"); |
9c0a72f9 | 133 | |
6e194652 | 134 | r = bus_add_implementation(m->bus, &manager_object, m); |
e331e246 | 135 | if (r < 0) |
6e194652 | 136 | return r; |
e331e246 | 137 | |
ac9f55ed LP |
138 | r = bus_log_control_api_register(m->bus); |
139 | if (r < 0) | |
140 | return r; | |
141 | ||
696fc836 | 142 | r = sd_bus_request_name_async(m->bus, NULL, "org.freedesktop.network1", 0, NULL, NULL); |
e331e246 | 143 | if (r < 0) |
0c0b9306 | 144 | return log_error_errno(r, "Failed to request name: %m"); |
e331e246 TG |
145 | |
146 | r = sd_bus_attach_event(m->bus, m->event, 0); | |
147 | if (r < 0) | |
148 | return log_error_errno(r, "Failed to attach bus to event loop: %m"); | |
149 | ||
d7afd945 LP |
150 | r = sd_bus_match_signal_async( |
151 | m->bus, | |
cad43595 | 152 | NULL, |
d7afd945 LP |
153 | "org.freedesktop.DBus.Local", |
154 | NULL, | |
155 | "org.freedesktop.DBus.Local", | |
156 | "Connected", | |
157 | on_connected, NULL, m); | |
158 | if (r < 0) | |
159 | return log_error_errno(r, "Failed to request match on Connected signal: %m"); | |
160 | ||
161 | r = sd_bus_match_signal_async( | |
162 | m->bus, | |
cad43595 | 163 | NULL, |
d7afd945 LP |
164 | "org.freedesktop.login1", |
165 | "/org/freedesktop/login1", | |
166 | "org.freedesktop.login1.Manager", | |
167 | "PrepareForSleep", | |
168 | match_prepare_for_sleep, NULL, m); | |
169 | if (r < 0) | |
170 | log_warning_errno(r, "Failed to request match for PrepareForSleep, ignoring: %m"); | |
7901cea1 | 171 | |
9c0a72f9 TG |
172 | return 0; |
173 | } | |
174 | ||
1fd3ac1e YW |
175 | static int manager_process_uevent(sd_device_monitor *monitor, sd_device *device, void *userdata) { |
176 | Manager *m = ASSERT_PTR(userdata); | |
177 | sd_device_action_t action; | |
178 | const char *s; | |
179 | int r; | |
180 | ||
181 | assert(device); | |
182 | ||
183 | r = sd_device_get_action(device, &action); | |
184 | if (r < 0) | |
185 | return log_device_warning_errno(device, r, "Failed to get udev action, ignoring: %m"); | |
186 | ||
187 | r = sd_device_get_subsystem(device, &s); | |
188 | if (r < 0) | |
189 | return log_device_warning_errno(device, r, "Failed to get subsystem, ignoring: %m"); | |
190 | ||
191 | if (streq(s, "net")) | |
192 | r = manager_udev_process_link(m, device, action); | |
c49d5362 YW |
193 | else if (streq(s, "ieee80211")) |
194 | r = manager_udev_process_wiphy(m, device, action); | |
8642e04b YW |
195 | else if (streq(s, "rfkill")) |
196 | r = manager_udev_process_rfkill(m, device, action); | |
1fd3ac1e YW |
197 | else { |
198 | log_device_debug(device, "Received device with unexpected subsystem \"%s\", ignoring.", s); | |
199 | return 0; | |
200 | } | |
201 | if (r < 0) | |
202 | log_device_warning_errno(device, r, "Failed to process \"%s\" uevent, ignoring: %m", | |
203 | device_action_to_string(action)); | |
204 | ||
205 | return 0; | |
206 | } | |
207 | ||
5fae368b TG |
208 | static int manager_connect_udev(Manager *m) { |
209 | int r; | |
f579559b | 210 | |
d31f33e3 YW |
211 | /* udev does not initialize devices inside containers, so we rely on them being already |
212 | * initialized before entering the container. */ | |
82f52245 | 213 | if (!udev_available()) |
5fae368b | 214 | return 0; |
f579559b | 215 | |
d2ebf952 | 216 | r = sd_device_monitor_new(&m->device_monitor); |
02b59d57 | 217 | if (r < 0) |
d2ebf952 | 218 | return log_error_errno(r, "Failed to initialize device monitor: %m"); |
02b59d57 | 219 | |
a725efb0 YW |
220 | r = sd_device_monitor_set_receive_buffer_size(m->device_monitor, RCVBUF_SIZE); |
221 | if (r < 0) | |
222 | log_warning_errno(r, "Failed to increase buffer size for device monitor, ignoring: %m"); | |
223 | ||
d2ebf952 YW |
224 | r = sd_device_monitor_filter_add_match_subsystem_devtype(m->device_monitor, "net", NULL); |
225 | if (r < 0) | |
1fd3ac1e | 226 | return log_error_errno(r, "Could not add device monitor filter for net subsystem: %m"); |
505f8da7 | 227 | |
c49d5362 YW |
228 | r = sd_device_monitor_filter_add_match_subsystem_devtype(m->device_monitor, "ieee80211", NULL); |
229 | if (r < 0) | |
230 | return log_error_errno(r, "Could not add device monitor filter for ieee80211 subsystem: %m"); | |
231 | ||
8642e04b YW |
232 | r = sd_device_monitor_filter_add_match_subsystem_devtype(m->device_monitor, "rfkill", NULL); |
233 | if (r < 0) | |
234 | return log_error_errno(r, "Could not add device monitor filter for rfkill subsystem: %m"); | |
235 | ||
deb2b734 | 236 | r = sd_device_monitor_attach_event(m->device_monitor, m->event); |
5fae368b | 237 | if (r < 0) |
d2ebf952 | 238 | return log_error_errno(r, "Failed to attach event to device monitor: %m"); |
505f8da7 | 239 | |
1fd3ac1e | 240 | r = sd_device_monitor_start(m->device_monitor, manager_process_uevent, m); |
505f8da7 | 241 | if (r < 0) |
d2ebf952 | 242 | return log_error_errno(r, "Failed to start device monitor: %m"); |
11a7f229 | 243 | |
505f8da7 TG |
244 | return 0; |
245 | } | |
f579559b | 246 | |
af7a86b8 YW |
247 | static int manager_listen_fds(Manager *m, int *ret_rtnl_fd) { |
248 | _cleanup_strv_free_ char **names = NULL; | |
249 | int n, rtnl_fd = -1; | |
5fae368b | 250 | |
af7a86b8 YW |
251 | assert(m); |
252 | assert(ret_rtnl_fd); | |
253 | ||
254 | n = sd_listen_fds_with_names(/* unset_environment = */ true, &names); | |
255 | if (n < 0) | |
256 | return n; | |
257 | ||
258 | if (strv_length(names) != (size_t) n) | |
5fae368b TG |
259 | return -EINVAL; |
260 | ||
af7a86b8 YW |
261 | for (int i = 0; i < n; i++) { |
262 | int fd = i + SD_LISTEN_FDS_START; | |
263 | ||
5fae368b | 264 | if (sd_is_socket(fd, AF_NETLINK, SOCK_RAW, -1) > 0) { |
af7a86b8 YW |
265 | if (rtnl_fd >= 0) { |
266 | log_debug("Received multiple netlink socket, ignoring."); | |
267 | safe_close(fd); | |
268 | continue; | |
269 | } | |
5fae368b TG |
270 | |
271 | rtnl_fd = fd; | |
af7a86b8 | 272 | continue; |
5fae368b | 273 | } |
5fae368b | 274 | |
af7a86b8 YW |
275 | if (manager_add_tuntap_fd(m, fd, names[i]) >= 0) |
276 | continue; | |
277 | ||
278 | if (m->test_mode) | |
279 | safe_close(fd); | |
280 | else | |
281 | close_and_notify_warn(fd, names[i]); | |
282 | } | |
283 | ||
284 | *ret_rtnl_fd = rtnl_fd; | |
285 | return 0; | |
5fae368b TG |
286 | } |
287 | ||
05d0c2e3 JT |
288 | static int manager_connect_genl(Manager *m) { |
289 | int r; | |
290 | ||
291 | assert(m); | |
292 | ||
293 | r = sd_genl_socket_open(&m->genl); | |
294 | if (r < 0) | |
295 | return r; | |
296 | ||
78cca583 | 297 | r = sd_netlink_increase_rxbuf(m->genl, RCVBUF_SIZE); |
05d0c2e3 | 298 | if (r < 0) |
8c63924c | 299 | log_warning_errno(r, "Failed to increase receive buffer size for general netlink socket, ignoring: %m"); |
05d0c2e3 JT |
300 | |
301 | r = sd_netlink_attach_event(m->genl, m->event, 0); | |
302 | if (r < 0) | |
303 | return r; | |
304 | ||
96f5f9ef YW |
305 | r = genl_add_match(m->genl, NULL, NL80211_GENL_NAME, NL80211_MULTICAST_GROUP_CONFIG, 0, |
306 | &manager_genl_process_nl80211_config, NULL, m, "network-genl_process_nl80211_config"); | |
307 | if (r < 0 && r != -EOPNOTSUPP) | |
308 | return r; | |
309 | ||
310 | r = genl_add_match(m->genl, NULL, NL80211_GENL_NAME, NL80211_MULTICAST_GROUP_MLME, 0, | |
311 | &manager_genl_process_nl80211_mlme, NULL, m, "network-genl_process_nl80211_mlme"); | |
312 | if (r < 0 && r != -EOPNOTSUPP) | |
313 | return r; | |
314 | ||
05d0c2e3 JT |
315 | return 0; |
316 | } | |
317 | ||
26a8be48 YW |
318 | static int manager_setup_rtnl_filter(Manager *manager) { |
319 | struct sock_filter filter[] = { | |
320 | /* Check the packet length. */ | |
321 | BPF_STMT(BPF_LD + BPF_W + BPF_LEN, 0), /* A <- packet length */ | |
322 | BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, sizeof(struct nlmsghdr), 1, 0), /* A (packet length) >= sizeof(struct nlmsghdr) ? */ | |
323 | BPF_STMT(BPF_RET + BPF_K, 0), /* reject */ | |
324 | /* Always accept multipart message. */ | |
325 | BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct nlmsghdr, nlmsg_flags)), /* A <- message flags */ | |
326 | BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, htobe16(NLM_F_MULTI), 0, 1), /* message flags has NLM_F_MULTI ? */ | |
327 | BPF_STMT(BPF_RET + BPF_K, UINT32_MAX), /* accept */ | |
328 | /* Accept all message types except for RTM_NEWNEIGH or RTM_DELNEIGH. */ | |
329 | BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct nlmsghdr, nlmsg_type)), /* A <- message type */ | |
330 | BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, htobe16(RTM_NEWNEIGH), 2, 0), /* message type == RTM_NEWNEIGH ? */ | |
331 | BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, htobe16(RTM_DELNEIGH), 1, 0), /* message type == RTM_DELNEIGH ? */ | |
332 | BPF_STMT(BPF_RET + BPF_K, UINT32_MAX), /* accept */ | |
333 | /* Check the packet length. */ | |
334 | BPF_STMT(BPF_LD + BPF_W + BPF_LEN, 0), /* A <- packet length */ | |
335 | BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, sizeof(struct nlmsghdr) + sizeof(struct ndmsg), 1, 0), | |
336 | /* packet length >= sizeof(struct nlmsghdr) + sizeof(struct ndmsg) ? */ | |
337 | BPF_STMT(BPF_RET + BPF_K, 0), /* reject */ | |
338 | /* Reject the message when the neighbor state does not have NUD_PERMANENT flag. */ | |
339 | BPF_STMT(BPF_LD + BPF_H + BPF_ABS, sizeof(struct nlmsghdr) + offsetof(struct ndmsg, ndm_state)), | |
340 | /* A <- neighbor state */ | |
341 | BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, htobe16(NUD_PERMANENT), 1, 0), /* neighbor state has NUD_PERMANENT ? */ | |
342 | BPF_STMT(BPF_RET + BPF_K, 0), /* reject */ | |
343 | BPF_STMT(BPF_RET + BPF_K, UINT32_MAX), /* accept */ | |
344 | }; | |
345 | ||
346 | assert(manager); | |
347 | assert(manager->rtnl); | |
348 | ||
349 | return sd_netlink_attach_filter(manager->rtnl, ELEMENTSOF(filter), filter); | |
350 | } | |
351 | ||
af7a86b8 YW |
352 | static int manager_connect_rtnl(Manager *m, int fd) { |
353 | _unused_ _cleanup_close_ int fd_close = fd; | |
354 | int r; | |
505f8da7 TG |
355 | |
356 | assert(m); | |
505f8da7 | 357 | |
af7a86b8 YW |
358 | /* This takes input fd. */ |
359 | ||
5fae368b | 360 | if (fd < 0) |
1c4baffc | 361 | r = sd_netlink_open(&m->rtnl); |
5fae368b | 362 | else |
1c4baffc | 363 | r = sd_netlink_open_fd(&m->rtnl, fd); |
505f8da7 TG |
364 | if (r < 0) |
365 | return r; | |
af7a86b8 | 366 | TAKE_FD(fd_close); |
505f8da7 | 367 | |
e13af7bd YW |
368 | /* Bump receiver buffer, but only if we are not called via socket activation, as in that |
369 | * case systemd sets the receive buffer size for us, and the value in the .socket unit | |
370 | * should take full effect. */ | |
371 | if (fd < 0) { | |
78cca583 | 372 | r = sd_netlink_increase_rxbuf(m->rtnl, RCVBUF_SIZE); |
e13af7bd YW |
373 | if (r < 0) |
374 | log_warning_errno(r, "Failed to increase receive buffer size for rtnl socket, ignoring: %m"); | |
375 | } | |
f579559b | 376 | |
1c4baffc | 377 | r = sd_netlink_attach_event(m->rtnl, m->event, 0); |
505f8da7 TG |
378 | if (r < 0) |
379 | return r; | |
f579559b | 380 | |
8dfed23d | 381 | r = netlink_add_match(m->rtnl, NULL, RTM_NEWLINK, &manager_rtnl_process_link, NULL, m, "network-rtnl_process_link"); |
5fae368b TG |
382 | if (r < 0) |
383 | return r; | |
505f8da7 | 384 | |
8dfed23d | 385 | r = netlink_add_match(m->rtnl, NULL, RTM_DELLINK, &manager_rtnl_process_link, NULL, m, "network-rtnl_process_link"); |
5fae368b TG |
386 | if (r < 0) |
387 | return r; | |
45af44d4 | 388 | |
828a81a9 YW |
389 | r = netlink_add_match(m->rtnl, NULL, RTM_NEWQDISC, &manager_rtnl_process_qdisc, NULL, m, "network-rtnl_process_qdisc"); |
390 | if (r < 0) | |
391 | return r; | |
392 | ||
393 | r = netlink_add_match(m->rtnl, NULL, RTM_DELQDISC, &manager_rtnl_process_qdisc, NULL, m, "network-rtnl_process_qdisc"); | |
394 | if (r < 0) | |
395 | return r; | |
396 | ||
397 | r = netlink_add_match(m->rtnl, NULL, RTM_NEWTCLASS, &manager_rtnl_process_tclass, NULL, m, "network-rtnl_process_tclass"); | |
398 | if (r < 0) | |
399 | return r; | |
400 | ||
401 | r = netlink_add_match(m->rtnl, NULL, RTM_DELTCLASS, &manager_rtnl_process_tclass, NULL, m, "network-rtnl_process_tclass"); | |
402 | if (r < 0) | |
403 | return r; | |
404 | ||
8dfed23d | 405 | r = netlink_add_match(m->rtnl, NULL, RTM_NEWADDR, &manager_rtnl_process_address, NULL, m, "network-rtnl_process_address"); |
5fae368b TG |
406 | if (r < 0) |
407 | return r; | |
408 | ||
8dfed23d | 409 | r = netlink_add_match(m->rtnl, NULL, RTM_DELADDR, &manager_rtnl_process_address, NULL, m, "network-rtnl_process_address"); |
5fae368b TG |
410 | if (r < 0) |
411 | return r; | |
412 | ||
8dfed23d | 413 | r = netlink_add_match(m->rtnl, NULL, RTM_NEWNEIGH, &manager_rtnl_process_neighbor, NULL, m, "network-rtnl_process_neighbor"); |
d1bdafd2 WKI |
414 | if (r < 0) |
415 | return r; | |
416 | ||
8dfed23d | 417 | r = netlink_add_match(m->rtnl, NULL, RTM_DELNEIGH, &manager_rtnl_process_neighbor, NULL, m, "network-rtnl_process_neighbor"); |
d1bdafd2 WKI |
418 | if (r < 0) |
419 | return r; | |
420 | ||
8dfed23d | 421 | r = netlink_add_match(m->rtnl, NULL, RTM_NEWROUTE, &manager_rtnl_process_route, NULL, m, "network-rtnl_process_route"); |
1c8e710c TG |
422 | if (r < 0) |
423 | return r; | |
424 | ||
8dfed23d | 425 | r = netlink_add_match(m->rtnl, NULL, RTM_DELROUTE, &manager_rtnl_process_route, NULL, m, "network-rtnl_process_route"); |
1c8e710c TG |
426 | if (r < 0) |
427 | return r; | |
428 | ||
8dfed23d | 429 | r = netlink_add_match(m->rtnl, NULL, RTM_NEWRULE, &manager_rtnl_process_rule, NULL, m, "network-rtnl_process_rule"); |
bce67bbe SS |
430 | if (r < 0) |
431 | return r; | |
432 | ||
8dfed23d | 433 | r = netlink_add_match(m->rtnl, NULL, RTM_DELRULE, &manager_rtnl_process_rule, NULL, m, "network-rtnl_process_rule"); |
bce67bbe SS |
434 | if (r < 0) |
435 | return r; | |
436 | ||
8dfed23d | 437 | r = netlink_add_match(m->rtnl, NULL, RTM_NEWNEXTHOP, &manager_rtnl_process_nexthop, NULL, m, "network-rtnl_process_nexthop"); |
c16c7808 SS |
438 | if (r < 0) |
439 | return r; | |
440 | ||
8dfed23d | 441 | r = netlink_add_match(m->rtnl, NULL, RTM_DELNEXTHOP, &manager_rtnl_process_nexthop, NULL, m, "network-rtnl_process_nexthop"); |
c16c7808 SS |
442 | if (r < 0) |
443 | return r; | |
444 | ||
26a8be48 | 445 | return manager_setup_rtnl_filter(m); |
45af44d4 | 446 | } |
505f8da7 | 447 | |
84de38c5 TG |
448 | static int manager_dirty_handler(sd_event_source *s, void *userdata) { |
449 | Manager *m = userdata; | |
450 | Link *link; | |
d23a66f2 | 451 | int r; |
84de38c5 TG |
452 | |
453 | assert(m); | |
454 | ||
d23a66f2 YW |
455 | if (m->dirty) { |
456 | r = manager_save(m); | |
457 | if (r < 0) | |
458 | log_warning_errno(r, "Failed to update state file %s, ignoring: %m", m->state_file); | |
459 | } | |
84de38c5 | 460 | |
d23a66f2 YW |
461 | SET_FOREACH(link, m->dirty_links) { |
462 | r = link_save_and_clean(link); | |
463 | if (r < 0) | |
464 | log_link_warning_errno(link, r, "Failed to update link state file %s, ignoring: %m", link->state_file); | |
465 | } | |
84de38c5 TG |
466 | |
467 | return 1; | |
468 | } | |
469 | ||
ab76be55 ZJS |
470 | static int signal_terminate_callback(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) { |
471 | Manager *m = userdata; | |
472 | ||
473 | assert(m); | |
474 | m->restarting = false; | |
475 | ||
476 | log_debug("Terminate operation initiated."); | |
477 | ||
478 | return sd_event_exit(sd_event_source_get_event(s), 0); | |
479 | } | |
480 | ||
481 | static int signal_restart_callback(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) { | |
482 | Manager *m = userdata; | |
483 | ||
484 | assert(m); | |
485 | m->restarting = true; | |
486 | ||
487 | log_debug("Restart operation initiated."); | |
488 | ||
489 | return sd_event_exit(sd_event_source_get_event(s), 0); | |
490 | } | |
491 | ||
ea853de5 YW |
492 | static int manager_set_keep_configuration(Manager *m) { |
493 | int r; | |
494 | ||
495 | assert(m); | |
496 | ||
497 | if (in_initrd()) { | |
498 | log_debug("Running in initrd, keep DHCPv4 addresses on stopping networkd by default."); | |
499 | m->keep_configuration = KEEP_CONFIGURATION_DHCP_ON_STOP; | |
500 | return 0; | |
501 | } | |
502 | ||
503 | r = path_is_network_fs("/"); | |
504 | if (r < 0) | |
505 | return log_error_errno(r, "Failed to detect if root is network filesystem: %m"); | |
506 | if (r == 0) { | |
507 | m->keep_configuration = _KEEP_CONFIGURATION_INVALID; | |
508 | return 0; | |
509 | } | |
510 | ||
511 | log_debug("Running on network filesystem, enabling KeepConfiguration= by default."); | |
512 | m->keep_configuration = KEEP_CONFIGURATION_YES; | |
513 | return 0; | |
514 | } | |
515 | ||
4c78dc17 | 516 | int manager_setup(Manager *m) { |
af7a86b8 | 517 | _cleanup_close_ int rtnl_fd = -1; |
45af44d4 | 518 | int r; |
f579559b | 519 | |
96243149 | 520 | assert(m); |
5fae368b | 521 | |
3534a043 YW |
522 | r = sd_event_default(&m->event); |
523 | if (r < 0) | |
524 | return r; | |
525 | ||
ab76be55 ZJS |
526 | assert_se(sigprocmask_many(SIG_SETMASK, NULL, SIGINT, SIGTERM, SIGUSR2, -1) >= 0); |
527 | ||
05e21627 | 528 | (void) sd_event_set_watchdog(m->event, true); |
ab76be55 ZJS |
529 | (void) sd_event_add_signal(m->event, NULL, SIGTERM, signal_terminate_callback, m); |
530 | (void) sd_event_add_signal(m->event, NULL, SIGINT, signal_terminate_callback, m); | |
531 | (void) sd_event_add_signal(m->event, NULL, SIGUSR2, signal_restart_callback, m); | |
5fae368b | 532 | |
84de38c5 TG |
533 | r = sd_event_add_post(m->event, NULL, manager_dirty_handler, m); |
534 | if (r < 0) | |
535 | return r; | |
536 | ||
19d9a5ad YW |
537 | r = sd_event_add_post(m->event, NULL, manager_process_requests, m); |
538 | if (r < 0) | |
539 | return r; | |
540 | ||
af7a86b8 YW |
541 | r = manager_listen_fds(m, &rtnl_fd); |
542 | if (r < 0) | |
543 | return r; | |
544 | ||
545 | r = manager_connect_rtnl(m, TAKE_FD(rtnl_fd)); | |
45af44d4 TG |
546 | if (r < 0) |
547 | return r; | |
548 | ||
05d0c2e3 JT |
549 | r = manager_connect_genl(m); |
550 | if (r < 0) | |
551 | return r; | |
552 | ||
4c78dc17 | 553 | if (m->test_mode) |
96243149 YW |
554 | return 0; |
555 | ||
556 | r = manager_connect_bus(m); | |
557 | if (r < 0) | |
558 | return r; | |
559 | ||
5fae368b TG |
560 | r = manager_connect_udev(m); |
561 | if (r < 0) | |
562 | return r; | |
45af44d4 | 563 | |
05d0c2e3 JT |
564 | r = sd_resolve_default(&m->resolve); |
565 | if (r < 0) | |
566 | return r; | |
567 | ||
568 | r = sd_resolve_attach_event(m->resolve, m->event, 0); | |
569 | if (r < 0) | |
570 | return r; | |
571 | ||
ed76f585 | 572 | r = address_pool_setup_default(m); |
5fae368b TG |
573 | if (r < 0) |
574 | return r; | |
f579559b | 575 | |
ea853de5 YW |
576 | r = manager_set_keep_configuration(m); |
577 | if (r < 0) | |
578 | return r; | |
579 | ||
96243149 YW |
580 | m->state_file = strdup("/run/systemd/netif/state"); |
581 | if (!m->state_file) | |
582 | return -ENOMEM; | |
583 | ||
584 | return 0; | |
585 | } | |
586 | ||
4c78dc17 | 587 | int manager_new(Manager **ret, bool test_mode) { |
96243149 | 588 | _cleanup_(manager_freep) Manager *m = NULL; |
f579559b | 589 | |
96243149 YW |
590 | m = new(Manager, 1); |
591 | if (!m) | |
592 | return -ENOMEM; | |
593 | ||
594 | *m = (Manager) { | |
ea853de5 | 595 | .keep_configuration = _KEEP_CONFIGURATION_INVALID, |
4c78dc17 | 596 | .test_mode = test_mode, |
96243149 YW |
597 | .speed_meter_interval_usec = SPEED_METER_DEFAULT_TIME_INTERVAL, |
598 | .online_state = _LINK_ONLINE_STATE_INVALID, | |
599 | .manage_foreign_routes = true, | |
600 | .manage_foreign_rules = true, | |
601 | .ethtool_fd = -1, | |
602 | .dhcp_duid.type = DUID_TYPE_EN, | |
603 | .dhcp6_duid.type = DUID_TYPE_EN, | |
604 | .duid_product_uuid.type = DUID_TYPE_UUID, | |
605 | }; | |
606 | ||
607 | *ret = TAKE_PTR(m); | |
f579559b TG |
608 | return 0; |
609 | } | |
610 | ||
75db809a | 611 | Manager* manager_free(Manager *m) { |
5fae368b | 612 | Link *link; |
f579559b | 613 | |
5fae368b | 614 | if (!m) |
75db809a | 615 | return NULL; |
505f8da7 | 616 | |
5fae368b | 617 | free(m->state_file); |
505f8da7 | 618 | |
6eab614d | 619 | HASHMAP_FOREACH(link, m->links_by_index) |
2a99eed0 | 620 | (void) link_stop_engines(link, true); |
946f8e14 | 621 | |
40b12fa2 | 622 | m->request_queue = ordered_set_free(m->request_queue); |
19d9a5ad | 623 | |
c4397d94 | 624 | m->dirty_links = set_free_with_destructor(m->dirty_links, link_unref); |
0b54c870 | 625 | m->links_by_name = hashmap_free(m->links_by_name); |
fe321d45 | 626 | m->links_by_hw_addr = hashmap_free(m->links_by_hw_addr); |
a27588d4 | 627 | m->links_by_dhcp_pd_subnet_prefix = hashmap_free(m->links_by_dhcp_pd_subnet_prefix); |
6eab614d | 628 | m->links_by_index = hashmap_free_with_destructor(m->links_by_index, link_unref); |
27dfc982 | 629 | |
a27588d4 | 630 | m->dhcp_pd_subnet_ids = set_free(m->dhcp_pd_subnet_ids); |
715d398e | 631 | m->networks = ordered_hashmap_free_with_destructor(m->networks, network_unref); |
dbffab87 | 632 | |
c4397d94 | 633 | m->netdevs = hashmap_free_with_destructor(m->netdevs, netdev_unref); |
5fae368b | 634 | |
af7a86b8 YW |
635 | m->tuntap_fds_by_name = hashmap_free(m->tuntap_fds_by_name); |
636 | ||
edb69db2 YW |
637 | m->wiphy_by_name = hashmap_free(m->wiphy_by_name); |
638 | m->wiphy_by_index = hashmap_free_with_destructor(m->wiphy_by_index, wiphy_free); | |
639 | ||
bfbf150e | 640 | ordered_set_free_free(m->address_pools); |
5fae368b | 641 | |
552b90a2 YW |
642 | hashmap_free(m->route_table_names_by_number); |
643 | hashmap_free(m->route_table_numbers_by_name); | |
c038ce46 | 644 | |
eb72fa3a | 645 | set_free(m->rules); |
bce67bbe | 646 | |
d4df6326 SS |
647 | sd_netlink_unref(m->rtnl); |
648 | sd_netlink_unref(m->genl); | |
649 | sd_resolve_unref(m->resolve); | |
650 | ||
450fa34b YW |
651 | /* reject (e.g. unreachable) type routes are managed by Manager, but may be referenced by a |
652 | * link. E.g., DHCP6 with prefix delegation creates unreachable routes, and they are referenced | |
653 | * by the upstream link. And the links may be referenced by netlink slots. Hence, two | |
654 | * set_free() must be called after the above sd_netlink_unref(). */ | |
655 | m->routes = set_free(m->routes); | |
656 | m->routes_foreign = set_free(m->routes_foreign); | |
657 | ||
30f10837 | 658 | m->nexthops = set_free(m->nexthops); |
69e244e3 YW |
659 | m->nexthops_by_id = hashmap_free(m->nexthops_by_id); |
660 | ||
a879e1a4 | 661 | sd_event_source_unref(m->speed_meter_event_source); |
2f5b4a77 | 662 | sd_event_unref(m->event); |
5fae368b | 663 | |
d2ebf952 | 664 | sd_device_monitor_unref(m->device_monitor); |
7d20d375 | 665 | |
15761549 | 666 | bus_verify_polkit_async_registry_free(m->polkit_registry); |
92e31da1 | 667 | sd_bus_flush_close_unref(m->bus); |
7d20d375 | 668 | |
7901cea1 MP |
669 | free(m->dynamic_timezone); |
670 | free(m->dynamic_hostname); | |
671 | ||
c643bda5 YW |
672 | safe_close(m->ethtool_fd); |
673 | ||
761cf19d FW |
674 | m->fw_ctx = fw_ctx_free(m->fw_ctx); |
675 | ||
75db809a | 676 | return mfree(m); |
5fae368b TG |
677 | } |
678 | ||
b76d99d9 | 679 | int manager_start(Manager *m) { |
84de38c5 | 680 | Link *link; |
a879e1a4 | 681 | int r; |
84de38c5 | 682 | |
a97dcc12 TG |
683 | assert(m); |
684 | ||
a879e1a4 YW |
685 | r = manager_start_speed_meter(m); |
686 | if (r < 0) | |
687 | return log_error_errno(r, "Failed to initialize speed meter: %m"); | |
688 | ||
84de38c5 TG |
689 | /* The dirty handler will deal with future serialization, but the first one |
690 | must be done explicitly. */ | |
691 | ||
d23a66f2 YW |
692 | r = manager_save(m); |
693 | if (r < 0) | |
694 | log_warning_errno(r, "Failed to update state file %s, ignoring: %m", m->state_file); | |
84de38c5 | 695 | |
6eab614d | 696 | HASHMAP_FOREACH(link, m->links_by_index) { |
d23a66f2 YW |
697 | r = link_save(link); |
698 | if (r < 0) | |
699 | log_link_warning_errno(link, r, "Failed to update link state file %s, ignoring: %m", link->state_file); | |
700 | } | |
84de38c5 | 701 | |
b76d99d9 | 702 | return 0; |
a97dcc12 TG |
703 | } |
704 | ||
5fae368b TG |
705 | int manager_load_config(Manager *m) { |
706 | int r; | |
707 | ||
708 | /* update timestamp */ | |
dc0d4078 | 709 | paths_check_timestamp(NETWORK_DIRS, &m->network_dirs_ts_usec, true); |
5fae368b | 710 | |
e272b621 | 711 | r = netdev_load(m, false); |
f579559b TG |
712 | if (r < 0) |
713 | return r; | |
714 | ||
af7a86b8 YW |
715 | manager_clear_unmanaged_tuntap_fds(m); |
716 | ||
7f06b3e1 | 717 | r = network_load(m, &m->networks); |
9021bb9f TG |
718 | if (r < 0) |
719 | return r; | |
720 | ||
a27588d4 | 721 | return manager_build_dhcp_pd_subnet_ids(m); |
f579559b | 722 | } |
f882c247 | 723 | |
5fae368b | 724 | bool manager_should_reload(Manager *m) { |
dc0d4078 | 725 | return paths_check_timestamp(NETWORK_DIRS, &m->network_dirs_ts_usec, false); |
5fae368b TG |
726 | } |
727 | ||
446aaaf3 YW |
728 | static int manager_enumerate_internal( |
729 | Manager *m, | |
bdcd4ab2 | 730 | sd_netlink *nl, |
446aaaf3 | 731 | sd_netlink_message *req, |
f12629ae | 732 | int (*process)(sd_netlink *, sd_netlink_message *, Manager *)) { |
446aaaf3 YW |
733 | |
734 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *reply = NULL; | |
bdcd4ab2 | 735 | int k, r; |
f882c247 | 736 | |
5da8149f | 737 | assert(m); |
bdcd4ab2 | 738 | assert(nl); |
446aaaf3 YW |
739 | assert(req); |
740 | assert(process); | |
f882c247 | 741 | |
1c4baffc | 742 | r = sd_netlink_message_request_dump(req, true); |
dd3efc09 TG |
743 | if (r < 0) |
744 | return r; | |
745 | ||
bdcd4ab2 | 746 | r = sd_netlink_call(nl, req, 0, &reply); |
f12629ae | 747 | if (r < 0) |
f2236469 TG |
748 | return r; |
749 | ||
a6b08423 | 750 | m->enumerating = true; |
446aaaf3 | 751 | for (sd_netlink_message *reply_one = reply; reply_one; reply_one = sd_netlink_message_next(reply_one)) { |
bdcd4ab2 | 752 | k = process(nl, reply_one, m); |
446aaaf3 | 753 | if (k < 0 && r >= 0) |
5fae368b TG |
754 | r = k; |
755 | } | |
a6b08423 | 756 | m->enumerating = false; |
2e9f08ea | 757 | |
5fae368b | 758 | return r; |
f882c247 | 759 | } |
3bef724f | 760 | |
446aaaf3 YW |
761 | static int manager_enumerate_links(Manager *m) { |
762 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; | |
1346b1f0 TG |
763 | int r; |
764 | ||
5fae368b TG |
765 | assert(m); |
766 | assert(m->rtnl); | |
bcbca829 | 767 | |
446aaaf3 | 768 | r = sd_rtnl_message_new_link(m->rtnl, &req, RTM_GETLINK, 0); |
5fae368b TG |
769 | if (r < 0) |
770 | return r; | |
771 | ||
f12629ae | 772 | return manager_enumerate_internal(m, m->rtnl, req, manager_rtnl_process_link); |
446aaaf3 | 773 | } |
5fae368b | 774 | |
828a81a9 YW |
775 | static int manager_enumerate_qdisc(Manager *m) { |
776 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; | |
777 | int r; | |
778 | ||
779 | assert(m); | |
780 | assert(m->rtnl); | |
781 | ||
782 | r = sd_rtnl_message_new_traffic_control(m->rtnl, &req, RTM_GETQDISC, 0, 0, 0); | |
783 | if (r < 0) | |
784 | return r; | |
785 | ||
786 | return manager_enumerate_internal(m, m->rtnl, req, manager_rtnl_process_qdisc); | |
787 | } | |
788 | ||
789 | static int manager_enumerate_tclass(Manager *m) { | |
790 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; | |
791 | int r; | |
792 | ||
793 | assert(m); | |
794 | assert(m->rtnl); | |
795 | ||
796 | r = sd_rtnl_message_new_traffic_control(m->rtnl, &req, RTM_GETTCLASS, 0, 0, 0); | |
797 | if (r < 0) | |
798 | return r; | |
799 | ||
800 | return manager_enumerate_internal(m, m->rtnl, req, manager_rtnl_process_tclass); | |
801 | } | |
802 | ||
446aaaf3 YW |
803 | static int manager_enumerate_addresses(Manager *m) { |
804 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; | |
805 | int r; | |
6a24f148 | 806 | |
446aaaf3 YW |
807 | assert(m); |
808 | assert(m->rtnl); | |
6a24f148 | 809 | |
446aaaf3 YW |
810 | r = sd_rtnl_message_new_addr(m->rtnl, &req, RTM_GETADDR, 0, 0); |
811 | if (r < 0) | |
812 | return r; | |
5fae368b | 813 | |
f12629ae | 814 | return manager_enumerate_internal(m, m->rtnl, req, manager_rtnl_process_address); |
1346b1f0 | 815 | } |
d1bdafd2 | 816 | |
446aaaf3 YW |
817 | static int manager_enumerate_neighbors(Manager *m) { |
818 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; | |
d1bdafd2 WKI |
819 | int r; |
820 | ||
821 | assert(m); | |
822 | assert(m->rtnl); | |
823 | ||
824 | r = sd_rtnl_message_new_neigh(m->rtnl, &req, RTM_GETNEIGH, 0, AF_UNSPEC); | |
825 | if (r < 0) | |
826 | return r; | |
827 | ||
f12629ae | 828 | return manager_enumerate_internal(m, m->rtnl, req, manager_rtnl_process_neighbor); |
d1bdafd2 | 829 | } |
1346b1f0 | 830 | |
446aaaf3 YW |
831 | static int manager_enumerate_routes(Manager *m) { |
832 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; | |
1c8e710c TG |
833 | int r; |
834 | ||
835 | assert(m); | |
836 | assert(m->rtnl); | |
837 | ||
5ff1ef31 YW |
838 | if (!m->manage_foreign_routes) |
839 | return 0; | |
840 | ||
1c8e710c TG |
841 | r = sd_rtnl_message_new_route(m->rtnl, &req, RTM_GETROUTE, 0, 0); |
842 | if (r < 0) | |
843 | return r; | |
844 | ||
f12629ae | 845 | return manager_enumerate_internal(m, m->rtnl, req, manager_rtnl_process_route); |
1c8e710c TG |
846 | } |
847 | ||
446aaaf3 YW |
848 | static int manager_enumerate_rules(Manager *m) { |
849 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; | |
bce67bbe SS |
850 | int r; |
851 | ||
852 | assert(m); | |
853 | assert(m->rtnl); | |
854 | ||
d94dfe70 YW |
855 | if (!m->manage_foreign_rules) |
856 | return 0; | |
857 | ||
bce67bbe SS |
858 | r = sd_rtnl_message_new_routing_policy_rule(m->rtnl, &req, RTM_GETRULE, 0); |
859 | if (r < 0) | |
860 | return r; | |
861 | ||
f12629ae | 862 | return manager_enumerate_internal(m, m->rtnl, req, manager_rtnl_process_rule); |
bce67bbe SS |
863 | } |
864 | ||
446aaaf3 YW |
865 | static int manager_enumerate_nexthop(Manager *m) { |
866 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; | |
c16c7808 SS |
867 | int r; |
868 | ||
869 | assert(m); | |
870 | assert(m->rtnl); | |
871 | ||
872 | r = sd_rtnl_message_new_nexthop(m->rtnl, &req, RTM_GETNEXTHOP, 0, 0); | |
873 | if (r < 0) | |
874 | return r; | |
875 | ||
f12629ae | 876 | return manager_enumerate_internal(m, m->rtnl, req, manager_rtnl_process_nexthop); |
446aaaf3 | 877 | } |
c16c7808 | 878 | |
edb69db2 YW |
879 | static int manager_enumerate_nl80211_wiphy(Manager *m) { |
880 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; | |
881 | int r; | |
882 | ||
883 | assert(m); | |
884 | assert(m->genl); | |
885 | ||
886 | r = sd_genl_message_new(m->genl, NL80211_GENL_NAME, NL80211_CMD_GET_WIPHY, &req); | |
887 | if (r < 0) | |
888 | return r; | |
889 | ||
890 | return manager_enumerate_internal(m, m->genl, req, manager_genl_process_nl80211_wiphy); | |
891 | } | |
892 | ||
96f5f9ef YW |
893 | static int manager_enumerate_nl80211_config(Manager *m) { |
894 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; | |
895 | int r; | |
896 | ||
897 | assert(m); | |
898 | assert(m->genl); | |
899 | ||
900 | r = sd_genl_message_new(m->genl, NL80211_GENL_NAME, NL80211_CMD_GET_INTERFACE, &req); | |
901 | if (r < 0) | |
902 | return r; | |
903 | ||
904 | return manager_enumerate_internal(m, m->genl, req, manager_genl_process_nl80211_config); | |
905 | } | |
906 | ||
907 | static int manager_enumerate_nl80211_mlme(Manager *m) { | |
908 | Link *link; | |
909 | int r; | |
910 | ||
911 | assert(m); | |
912 | assert(m->genl); | |
913 | ||
914 | HASHMAP_FOREACH(link, m->links_by_index) { | |
915 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; | |
916 | ||
917 | if (link->wlan_iftype != NL80211_IFTYPE_STATION) | |
918 | continue; | |
919 | ||
920 | r = sd_genl_message_new(m->genl, NL80211_GENL_NAME, NL80211_CMD_GET_STATION, &req); | |
921 | if (r < 0) | |
922 | return r; | |
923 | ||
924 | r = sd_netlink_message_append_u32(req, NL80211_ATTR_IFINDEX, link->ifindex); | |
925 | if (r < 0) | |
926 | return r; | |
927 | ||
928 | r = manager_enumerate_internal(m, m->genl, req, manager_genl_process_nl80211_mlme); | |
929 | if (r < 0) | |
930 | return r; | |
931 | } | |
932 | ||
933 | return 0; | |
934 | } | |
935 | ||
446aaaf3 YW |
936 | int manager_enumerate(Manager *m) { |
937 | int r; | |
c16c7808 | 938 | |
446aaaf3 YW |
939 | r = manager_enumerate_links(m); |
940 | if (r < 0) | |
941 | return log_error_errno(r, "Could not enumerate links: %m"); | |
c16c7808 | 942 | |
828a81a9 | 943 | r = manager_enumerate_qdisc(m); |
15ac2a62 YW |
944 | if (r == -EOPNOTSUPP) |
945 | log_debug_errno(r, "Could not enumerate QDiscs, ignoring: %m"); | |
946 | else if (r < 0) | |
828a81a9 YW |
947 | return log_error_errno(r, "Could not enumerate QDisc: %m"); |
948 | ||
949 | r = manager_enumerate_tclass(m); | |
15ac2a62 YW |
950 | if (r == -EOPNOTSUPP) |
951 | log_debug_errno(r, "Could not enumerate TClasses, ignoring: %m"); | |
952 | else if (r < 0) | |
828a81a9 YW |
953 | return log_error_errno(r, "Could not enumerate TClass: %m"); |
954 | ||
446aaaf3 YW |
955 | r = manager_enumerate_addresses(m); |
956 | if (r < 0) | |
957 | return log_error_errno(r, "Could not enumerate addresses: %m"); | |
c16c7808 | 958 | |
446aaaf3 YW |
959 | r = manager_enumerate_neighbors(m); |
960 | if (r < 0) | |
961 | return log_error_errno(r, "Could not enumerate neighbors: %m"); | |
c16c7808 | 962 | |
f12629ae YW |
963 | /* NextHop support is added in kernel v5.3 (65ee00a9409f751188a8cdc0988167858eb4a536), |
964 | * and older kernels return -EOPNOTSUPP, or -EINVAL if SELinux is enabled. */ | |
0c0585ca | 965 | r = manager_enumerate_nexthop(m); |
f12629ae YW |
966 | if (r == -EOPNOTSUPP || (r == -EINVAL && mac_selinux_enforcing())) |
967 | log_debug_errno(r, "Could not enumerate nexthops, ignoring: %m"); | |
968 | else if (r < 0) | |
969 | return log_error_errno(r, "Could not enumerate nexthops: %m"); | |
0c0585ca | 970 | |
446aaaf3 YW |
971 | r = manager_enumerate_routes(m); |
972 | if (r < 0) | |
973 | return log_error_errno(r, "Could not enumerate routes: %m"); | |
c16c7808 | 974 | |
f12629ae | 975 | /* If kernel is built with CONFIG_FIB_RULES=n, it returns -EOPNOTSUPP. */ |
446aaaf3 | 976 | r = manager_enumerate_rules(m); |
f12629ae YW |
977 | if (r == -EOPNOTSUPP) |
978 | log_debug_errno(r, "Could not enumerate routing policy rules, ignoring: %m"); | |
979 | else if (r < 0) | |
446aaaf3 | 980 | return log_error_errno(r, "Could not enumerate routing policy rules: %m"); |
c16c7808 | 981 | |
edb69db2 YW |
982 | r = manager_enumerate_nl80211_wiphy(m); |
983 | if (r == -EOPNOTSUPP) | |
984 | log_debug_errno(r, "Could not enumerate wireless LAN phy, ignoring: %m"); | |
985 | else if (r < 0) | |
986 | return log_error_errno(r, "Could not enumerate wireless LAN phy: %m"); | |
987 | ||
96f5f9ef YW |
988 | r = manager_enumerate_nl80211_config(m); |
989 | if (r == -EOPNOTSUPP) | |
990 | log_debug_errno(r, "Could not enumerate wireless LAN interfaces, ignoring: %m"); | |
991 | else if (r < 0) | |
992 | return log_error_errno(r, "Could not enumerate wireless LAN interfaces: %m"); | |
993 | ||
994 | r = manager_enumerate_nl80211_mlme(m); | |
995 | if (r == -EOPNOTSUPP) | |
996 | log_debug_errno(r, "Could not enumerate wireless LAN stations, ignoring: %m"); | |
997 | else if (r < 0) | |
998 | return log_error_errno(r, "Could not enumerate wireless LAN stations: %m"); | |
999 | ||
446aaaf3 | 1000 | return 0; |
c16c7808 SS |
1001 | } |
1002 | ||
59eb33e0 | 1003 | static int set_hostname_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { |
59eb33e0 | 1004 | const sd_bus_error *e; |
f63e09ef | 1005 | int r; |
59eb33e0 MP |
1006 | |
1007 | assert(m); | |
59eb33e0 MP |
1008 | |
1009 | e = sd_bus_message_get_error(m); | |
f63e09ef YW |
1010 | if (e) { |
1011 | r = sd_bus_error_get_errno(e); | |
1012 | log_warning_errno(r, "Could not set hostname: %s", bus_error_message(e, r)); | |
1013 | } | |
59eb33e0 MP |
1014 | |
1015 | return 1; | |
1016 | } | |
1017 | ||
1018 | int manager_set_hostname(Manager *m, const char *hostname) { | |
1019 | int r; | |
1020 | ||
1021 | log_debug("Setting transient hostname: '%s'", strna(hostname)); | |
d7afd945 | 1022 | |
b3f9c17a YW |
1023 | r = free_and_strdup_warn(&m->dynamic_hostname, hostname); |
1024 | if (r < 0) | |
1025 | return r; | |
59eb33e0 | 1026 | |
5dbec9bd ZJS |
1027 | if (sd_bus_is_ready(m->bus) <= 0) { |
1028 | log_debug("Not connected to system bus, setting system hostname later."); | |
59eb33e0 MP |
1029 | return 0; |
1030 | } | |
1031 | ||
d2775306 | 1032 | r = bus_call_method_async( |
59eb33e0 MP |
1033 | m->bus, |
1034 | NULL, | |
d2775306 | 1035 | bus_hostname, |
59eb33e0 MP |
1036 | "SetHostname", |
1037 | set_hostname_handler, | |
1038 | m, | |
1039 | "sb", | |
1040 | hostname, | |
1041 | false); | |
59eb33e0 MP |
1042 | if (r < 0) |
1043 | return log_error_errno(r, "Could not set transient hostname: %m"); | |
1044 | ||
1045 | return 0; | |
1046 | } | |
1047 | ||
1048 | static int set_timezone_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { | |
59eb33e0 | 1049 | const sd_bus_error *e; |
f63e09ef | 1050 | int r; |
59eb33e0 MP |
1051 | |
1052 | assert(m); | |
59eb33e0 MP |
1053 | |
1054 | e = sd_bus_message_get_error(m); | |
f63e09ef YW |
1055 | if (e) { |
1056 | r = sd_bus_error_get_errno(e); | |
1057 | log_warning_errno(r, "Could not set timezone: %s", bus_error_message(e, r)); | |
1058 | } | |
59eb33e0 MP |
1059 | |
1060 | return 1; | |
1061 | } | |
1062 | ||
1063 | int manager_set_timezone(Manager *m, const char *tz) { | |
1064 | int r; | |
1065 | ||
1066 | assert(m); | |
1067 | assert(tz); | |
1068 | ||
1069 | log_debug("Setting system timezone: '%s'", tz); | |
b3f9c17a YW |
1070 | r = free_and_strdup_warn(&m->dynamic_timezone, tz); |
1071 | if (r < 0) | |
1072 | return r; | |
59eb33e0 | 1073 | |
5dbec9bd ZJS |
1074 | if (sd_bus_is_ready(m->bus) <= 0) { |
1075 | log_debug("Not connected to system bus, setting system timezone later."); | |
59eb33e0 MP |
1076 | return 0; |
1077 | } | |
1078 | ||
b607fd3f | 1079 | r = bus_call_method_async( |
59eb33e0 MP |
1080 | m->bus, |
1081 | NULL, | |
b607fd3f | 1082 | bus_timedate, |
59eb33e0 MP |
1083 | "SetTimezone", |
1084 | set_timezone_handler, | |
1085 | m, | |
1086 | "sb", | |
1087 | tz, | |
1088 | false); | |
1089 | if (r < 0) | |
1090 | return log_error_errno(r, "Could not set timezone: %m"); | |
1091 | ||
1092 | return 0; | |
1093 | } |