]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-address.c
networkd: address - update link operstate when address is updated
[thirdparty/systemd.git] / src / network / networkd-address.c
CommitLineData
f579559b
TG
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2013 Tom Gundersen <teg@jklm.no>
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <net/if.h>
23
b5efdb8a 24#include "alloc-util.h"
f579559b 25#include "conf-parser.h"
12c2884c 26#include "firewall-util.h"
fc2f9534 27#include "netlink-util.h"
6bedfcbb 28#include "networkd-address.h"
07630cea 29#include "networkd.h"
6bedfcbb 30#include "parse-util.h"
3ac8e543 31#include "set.h"
07630cea 32#include "string-util.h"
3ac8e543
TG
33#include "utf8.h"
34#include "util.h"
f579559b 35
f0213e37
TG
36int address_new(Address **ret) {
37 _cleanup_address_free_ Address *address = NULL;
38
39 address = new0(Address, 1);
40 if (!address)
41 return -ENOMEM;
aba496a5
UTL
42
43 address->family = AF_UNSPEC;
44 address->scope = RT_SCOPE_UNIVERSE;
45 address->cinfo.ifa_prefered = CACHE_INFO_INFINITY_LIFE_TIME;
46 address->cinfo.ifa_valid = CACHE_INFO_INFINITY_LIFE_TIME;
f0213e37
TG
47
48 *ret = address;
49 address = NULL;
50
51 return 0;
aba496a5
UTL
52}
53
f048a16b 54int address_new_static(Network *network, unsigned section, Address **ret) {
f579559b 55 _cleanup_address_free_ Address *address = NULL;
f0213e37 56 int r;
f579559b 57
6ae115c1 58 if (section) {
16aa63a0 59 address = hashmap_get(network->addresses_by_section, UINT_TO_PTR(section));
6ae115c1
TG
60 if (address) {
61 *ret = address;
62 address = NULL;
63
64 return 0;
65 }
66 }
67
f0213e37
TG
68 r = address_new(&address);
69 if (r < 0)
70 return r;
801bd9e8 71
f579559b
TG
72 address->network = network;
73
1e39ff92 74 LIST_APPEND(addresses, network->static_addresses, address);
f579559b 75
6ae115c1
TG
76 if (section) {
77 address->section = section;
16aa63a0
TG
78 hashmap_put(network->addresses_by_section,
79 UINT_TO_PTR(address->section), address);
6ae115c1
TG
80 }
81
f579559b
TG
82 *ret = address;
83 address = NULL;
84
85 return 0;
86}
87
88void address_free(Address *address) {
89 if (!address)
90 return;
91
f048a16b 92 if (address->network) {
3d3d4255 93 LIST_REMOVE(addresses, address->network->static_addresses, address);
f579559b 94
f048a16b
TG
95 if (address->section)
96 hashmap_remove(address->network->addresses_by_section,
16aa63a0 97 UINT_TO_PTR(address->section));
f048a16b 98 }
6ae115c1 99
adda1ed9 100 if (address->link) {
cf1d700d 101 set_remove(address->link->addresses, address);
adda1ed9
TG
102 set_remove(address->link->addresses_foreign, address);
103 }
cf1d700d 104
f579559b
TG
105 free(address);
106}
107
3ac8e543
TG
108static void address_hash_func(const void *b, struct siphash *state) {
109 const Address *a = b;
110
111 assert(a);
112
113 siphash24_compress(&a->family, sizeof(a->family), state);
114
115 switch (a->family) {
116 case AF_INET:
117 siphash24_compress(&a->prefixlen, sizeof(a->prefixlen), state);
118
119 /* peer prefix */
120 if (a->prefixlen != 0) {
121 uint32_t prefix;
122
123 if (a->in_addr_peer.in.s_addr != 0)
124 prefix = be32toh(a->in_addr_peer.in.s_addr) >> (32 - a->prefixlen);
125 else
126 prefix = be32toh(a->in_addr.in.s_addr) >> (32 - a->prefixlen);
127
128 siphash24_compress(&prefix, sizeof(prefix), state);
129 }
130
131 /* fallthrough */
132 case AF_INET6:
133 /* local address */
134 siphash24_compress(&a->in_addr, FAMILY_ADDRESS_SIZE(a->family), state);
135
136 break;
137 default:
138 /* treat any other address family as AF_UNSPEC */
139 break;
140 }
141}
142
143static int address_compare_func(const void *c1, const void *c2) {
144 const Address *a1 = c1, *a2 = c2;
145
146 if (a1->family < a2->family)
147 return -1;
148 if (a1->family > a2->family)
149 return 1;
150
151 switch (a1->family) {
152 /* use the same notion of equality as the kernel does */
153 case AF_INET:
154 if (a1->prefixlen < a2->prefixlen)
155 return -1;
156 if (a1->prefixlen > a2->prefixlen)
157 return 1;
158
159 /* compare the peer prefixes */
160 if (a1->prefixlen != 0) {
161 /* make sure we don't try to shift by 32.
162 * See ISO/IEC 9899:TC3 § 6.5.7.3. */
163 uint32_t b1, b2;
164
165 if (a1->in_addr_peer.in.s_addr != 0)
166 b1 = be32toh(a1->in_addr_peer.in.s_addr) >> (32 - a1->prefixlen);
167 else
168 b1 = be32toh(a1->in_addr.in.s_addr) >> (32 - a1->prefixlen);
169
170 if (a2->in_addr_peer.in.s_addr != 0)
171 b2 = be32toh(a2->in_addr_peer.in.s_addr) >> (32 - a1->prefixlen);
172 else
173 b2 = be32toh(a2->in_addr.in.s_addr) >> (32 - a1->prefixlen);
174
175 if (b1 < b2)
176 return -1;
177 if (b1 > b2)
178 return 1;
179 }
180
181 /* fall-through */
182 case AF_INET6:
183 return memcmp(&a1->in_addr, &a2->in_addr, FAMILY_ADDRESS_SIZE(a1->family));
184 default:
185 /* treat any other address family as AF_UNSPEC */
186 return 0;
187 }
188}
189
190static const struct hash_ops address_hash_ops = {
191 .hash = address_hash_func,
192 .compare = address_compare_func
193};
194
195bool address_equal(Address *a1, Address *a2) {
196 if (a1 == a2)
197 return true;
198
199 if (!a1 || !a2)
200 return false;
201
202 return address_compare_func(a1, a2) == 0;
203}
204
91b5f997
TG
205static int address_establish(Address *address, Link *link) {
206 bool masq;
207 int r;
208
209 assert(address);
210 assert(link);
211
212 masq = link->network &&
fcf50cff
TG
213 link->network->ip_masquerade &&
214 address->family == AF_INET &&
215 address->scope < RT_SCOPE_LINK;
91b5f997
TG
216
217 /* Add firewall entry if this is requested */
218 if (address->ip_masquerade_done != masq) {
219 union in_addr_union masked = address->in_addr;
220 in_addr_mask(address->family, &masked, address->prefixlen);
221
222 r = fw_add_masquerade(masq, AF_INET, 0, &masked, address->prefixlen, NULL, NULL, 0);
223 if (r < 0)
224 log_link_warning_errno(link, r, "Could not enable IP masquerading: %m");
225
226 address->ip_masquerade_done = masq;
227 }
228
229 return 0;
230}
231
adda1ed9
TG
232static int address_add_internal(Link *link, Set **addresses,
233 int family,
234 const union in_addr_union *in_addr,
235 unsigned char prefixlen,
236 Address **ret) {
054f0db4 237 _cleanup_address_free_ Address *address = NULL;
cf1d700d
TG
238 int r;
239
240 assert(link);
adda1ed9 241 assert(addresses);
054f0db4 242 assert(in_addr);
054f0db4
TG
243
244 r = address_new(&address);
245 if (r < 0)
246 return r;
247
248 address->family = family;
249 address->in_addr = *in_addr;
250 address->prefixlen = prefixlen;
cf1d700d 251
adda1ed9 252 r = set_ensure_allocated(addresses, &address_hash_ops);
cf1d700d
TG
253 if (r < 0)
254 return r;
255
adda1ed9 256 r = set_put(*addresses, address);
cf1d700d
TG
257 if (r < 0)
258 return r;
259
260 address->link = link;
261
adda1ed9
TG
262 if (ret)
263 *ret = address;
264
054f0db4
TG
265 address = NULL;
266
cf1d700d
TG
267 return 0;
268}
269
adda1ed9
TG
270int address_add_foreign(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret) {
271 return address_add_internal(link, &link->addresses_foreign, family, in_addr, prefixlen, ret);
272}
273
274static int address_add(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret) {
e7780c8d
TG
275 int r;
276
277 r = address_add_internal(link, &link->addresses, family, in_addr, prefixlen, ret);
278 if (r < 0)
279 return r;
280
84de38c5
TG
281 link_update_operstate(link);
282 link_dirty(link);
e7780c8d
TG
283
284 return 0;
adda1ed9
TG
285}
286
fcf50cff 287static int address_release(Address *address) {
5a8bcb67
LP
288 int r;
289
290 assert(address);
fcf50cff 291 assert(address->link);
5a8bcb67 292
91b5f997
TG
293 /* Remove masquerading firewall entry if it was added */
294 if (address->ip_masquerade_done) {
5a8bcb67
LP
295 union in_addr_union masked = address->in_addr;
296 in_addr_mask(address->family, &masked, address->prefixlen);
297
91b5f997 298 r = fw_add_masquerade(false, AF_INET, 0, &masked, address->prefixlen, NULL, NULL, 0);
5a8bcb67 299 if (r < 0)
fcf50cff 300 log_link_warning_errno(address->link, r, "Failed to disable IP masquerading: %m");
5a8bcb67 301
91b5f997 302 address->ip_masquerade_done = false;
5a8bcb67
LP
303 }
304
305 return 0;
306}
307
36c32f61
TG
308int address_update(Address *address, unsigned char flags, unsigned char scope, struct ifa_cacheinfo *cinfo) {
309 bool ready;
310
311 assert(address);
312 assert(cinfo);
313
314 ready = address_is_ready(address);
315
adda1ed9 316 address->added = true;
36c32f61
TG
317 address->flags = flags;
318 address->scope = scope;
319 address->cinfo = *cinfo;
320
a3a019e1
TG
321 if (address->link) {
322 link_update_operstate(address->link);
323
324 if (!ready && address_is_ready(address))
325 link_check_ready(address->link);
326 }
36c32f61
TG
327
328 return 0;
329}
330
91b5f997 331int address_drop(Address *address) {
8012cd39
TG
332 Link *link;
333 bool ready;
334
5a8bcb67 335 assert(address);
91b5f997 336
8012cd39
TG
337 ready = address_is_ready(address);
338 link = address->link;
339
fcf50cff 340 address_release(address);
91b5f997
TG
341 address_free(address);
342
84de38c5
TG
343 link_update_operstate(link);
344
8012cd39
TG
345 if (link && !ready)
346 link_check_ready(link);
347
91b5f997
TG
348 return 0;
349}
350
351int address_get(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret) {
352 Address address = {}, *existing;
353
5a8bcb67 354 assert(link);
91b5f997
TG
355 assert(in_addr);
356 assert(ret);
5a8bcb67 357
91b5f997
TG
358 address.family = family;
359 address.in_addr = *in_addr;
360 address.prefixlen = prefixlen;
5a8bcb67 361
91b5f997 362 existing = set_get(link->addresses, &address);
adda1ed9
TG
363 if (!existing) {
364 existing = set_get(link->addresses_foreign, &address);
365 if (!existing)
366 return -ENOENT;
367 }
5a8bcb67 368
91b5f997 369 *ret = existing;
5a8bcb67
LP
370
371 return 0;
372}
373
91b5f997 374int address_remove(Address *address, Link *link,
1c4baffc
TG
375 sd_netlink_message_handler_t callback) {
376 _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL;
407fe036
TG
377 int r;
378
379 assert(address);
380 assert(address->family == AF_INET || address->family == AF_INET6);
381 assert(link);
382 assert(link->ifindex > 0);
383 assert(link->manager);
384 assert(link->manager->rtnl);
385
151b9b96
LP
386 r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_DELADDR,
387 link->ifindex, address->family);
eb56eb9b
MS
388 if (r < 0)
389 return log_error_errno(r, "Could not allocate RTM_DELADDR message: %m");
407fe036 390
5a723174 391 r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
eb56eb9b
MS
392 if (r < 0)
393 return log_error_errno(r, "Could not set prefixlen: %m");
5a723174 394
407fe036 395 if (address->family == AF_INET)
1c4baffc 396 r = sd_netlink_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
407fe036 397 else if (address->family == AF_INET6)
1c4baffc 398 r = sd_netlink_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
eb56eb9b
MS
399 if (r < 0)
400 return log_error_errno(r, "Could not append IFA_LOCAL attribute: %m");
407fe036 401
1c4baffc 402 r = sd_netlink_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
eb56eb9b
MS
403 if (r < 0)
404 return log_error_errno(r, "Could not send rtnetlink message: %m");
407fe036 405
563c69c6
TG
406 link_ref(link);
407
407fe036
TG
408 return 0;
409}
410
11bf3cce
LP
411static int address_acquire(Link *link, Address *original, Address **ret) {
412 union in_addr_union in_addr = {};
413 struct in_addr broadcast = {};
0099bc15 414 _cleanup_address_free_ Address *na = NULL;
11bf3cce
LP
415 int r;
416
417 assert(link);
418 assert(original);
419 assert(ret);
420
421 /* Something useful was configured? just use it */
af93291c 422 if (in_addr_is_null(original->family, &original->in_addr) <= 0)
11bf3cce
LP
423 return 0;
424
425 /* The address is configured to be 0.0.0.0 or [::] by the user?
426 * Then let's acquire something more useful from the pool. */
427 r = manager_address_pool_acquire(link->manager, original->family, original->prefixlen, &in_addr);
6a7a4e4d
LP
428 if (r < 0)
429 return log_link_error_errno(link, r, "Failed to acquire address from pool: %m");
11bf3cce 430 if (r == 0) {
79008bdd 431 log_link_error(link, "Couldn't find free address for interface, all taken.");
11bf3cce
LP
432 return -EBUSY;
433 }
434
435 if (original->family == AF_INET) {
d076c6f9 436 /* Pick first address in range for ourselves ... */
11bf3cce
LP
437 in_addr.in.s_addr = in_addr.in.s_addr | htobe32(1);
438
439 /* .. and use last as broadcast address */
440 broadcast.s_addr = in_addr.in.s_addr | htobe32(0xFFFFFFFFUL >> original->prefixlen);
441 } else if (original->family == AF_INET6)
442 in_addr.in6.s6_addr[15] |= 1;
443
f0213e37 444 r = address_new(&na);
11bf3cce
LP
445 if (r < 0)
446 return r;
447
448 na->family = original->family;
449 na->prefixlen = original->prefixlen;
450 na->scope = original->scope;
451 na->cinfo = original->cinfo;
452
453 if (original->label) {
454 na->label = strdup(original->label);
0099bc15 455 if (!na->label)
11bf3cce 456 return -ENOMEM;
11bf3cce
LP
457 }
458
459 na->broadcast = broadcast;
460 na->in_addr = in_addr;
461
462 LIST_PREPEND(addresses, link->pool_addresses, na);
463
464 *ret = na;
0099bc15
SS
465 na = NULL;
466
11bf3cce
LP
467 return 0;
468}
469
66669078 470int address_configure(Address *address, Link *link, sd_netlink_message_handler_t callback, bool update) {
1c4baffc 471 _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL;
f579559b
TG
472 int r;
473
c166a070
TG
474 assert(address);
475 assert(address->family == AF_INET || address->family == AF_INET6);
476 assert(link);
477 assert(link->ifindex > 0);
f882c247 478 assert(link->manager);
c166a070 479 assert(link->manager->rtnl);
f882c247 480
11bf3cce
LP
481 r = address_acquire(link, address, &address);
482 if (r < 0)
483 return r;
484
66669078
TG
485 if (update)
486 r = sd_rtnl_message_new_addr_update(link->manager->rtnl, &req,
487 link->ifindex, address->family);
488 else
489 r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_NEWADDR,
490 link->ifindex, address->family);
eb56eb9b
MS
491 if (r < 0)
492 return log_error_errno(r, "Could not allocate RTM_NEWADDR message: %m");
f579559b 493
5a723174 494 r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
eb56eb9b
MS
495 if (r < 0)
496 return log_error_errno(r, "Could not set prefixlen: %m");
5a723174 497
851c9f82
PF
498 address->flags |= IFA_F_PERMANENT;
499
500 r = sd_rtnl_message_addr_set_flags(req, (address->flags & 0xff));
eb56eb9b
MS
501 if (r < 0)
502 return log_error_errno(r, "Could not set flags: %m");
5a723174 503
851c9f82 504 if (address->flags & ~0xff) {
1c4baffc 505 r = sd_netlink_message_append_u32(req, IFA_FLAGS, address->flags);
851c9f82
PF
506 if (r < 0)
507 return log_error_errno(r, "Could not set extended flags: %m");
508 }
509
5c1d3fc9 510 r = sd_rtnl_message_addr_set_scope(req, address->scope);
eb56eb9b
MS
511 if (r < 0)
512 return log_error_errno(r, "Could not set scope: %m");
5a723174 513
0a0dc69b 514 if (address->family == AF_INET)
1c4baffc 515 r = sd_netlink_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
0a0dc69b 516 else if (address->family == AF_INET6)
1c4baffc 517 r = sd_netlink_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
eb56eb9b
MS
518 if (r < 0)
519 return log_error_errno(r, "Could not append IFA_LOCAL attribute: %m");
f579559b 520
af93291c 521 if (!in_addr_is_null(address->family, &address->in_addr_peer)) {
c081882f 522 if (address->family == AF_INET)
1c4baffc 523 r = sd_netlink_message_append_in_addr(req, IFA_ADDRESS, &address->in_addr_peer.in);
c081882f 524 else if (address->family == AF_INET6)
1c4baffc 525 r = sd_netlink_message_append_in6_addr(req, IFA_ADDRESS, &address->in_addr_peer.in6);
eb56eb9b
MS
526 if (r < 0)
527 return log_error_errno(r, "Could not append IFA_ADDRESS attribute: %m");
c081882f
SS
528 } else {
529 if (address->family == AF_INET) {
1c4baffc 530 r = sd_netlink_message_append_in_addr(req, IFA_BROADCAST, &address->broadcast);
eb56eb9b
MS
531 if (r < 0)
532 return log_error_errno(r, "Could not append IFA_BROADCAST attribute: %m");
c081882f 533 }
f579559b
TG
534 }
535
536 if (address->label) {
1c4baffc 537 r = sd_netlink_message_append_string(req, IFA_LABEL, address->label);
eb56eb9b
MS
538 if (r < 0)
539 return log_error_errno(r, "Could not append IFA_LABEL attribute: %m");
f579559b
TG
540 }
541
1c4baffc 542 r = sd_netlink_message_append_cache_info(req, IFA_CACHEINFO,
68ceb9df 543 &address->cinfo);
eb56eb9b
MS
544 if (r < 0)
545 return log_error_errno(r, "Could not append IFA_CACHEINFO attribute: %m");
68ceb9df 546
fcf50cff 547 r = address_establish(address, link);
eb56eb9b 548 if (r < 0)
fcf50cff
TG
549 return r;
550
551 r = sd_netlink_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
552 if (r < 0) {
553 address_release(address);
eb56eb9b 554 return log_error_errno(r, "Could not send rtnetlink message: %m");
fcf50cff 555 }
f579559b 556
563c69c6
TG
557 link_ref(link);
558
adda1ed9
TG
559 r = address_add(link, address->family, &address->in_addr, address->prefixlen, NULL);
560 if (r < 0) {
561 address_release(address);
562 return log_error_errno(r, "Could not add address: %m");
563 }
564
f579559b
TG
565 return 0;
566}
567
44e7b949
LP
568int config_parse_broadcast(
569 const char *unit,
eb0ea358
TG
570 const char *filename,
571 unsigned line,
572 const char *section,
573 unsigned section_line,
574 const char *lvalue,
575 int ltype,
576 const char *rvalue,
577 void *data,
578 void *userdata) {
44e7b949 579
eb0ea358
TG
580 Network *network = userdata;
581 _cleanup_address_free_ Address *n = NULL;
eb0ea358
TG
582 int r;
583
584 assert(filename);
585 assert(section);
586 assert(lvalue);
587 assert(rvalue);
588 assert(data);
589
590 r = address_new_static(network, section_line, &n);
591 if (r < 0)
592 return r;
593
482e2ac1 594 if (n->family == AF_INET6) {
12ca818f 595 log_syntax(unit, LOG_ERR, filename, line, 0, "Broadcast is not valid for IPv6 addresses, ignoring assignment: %s", rvalue);
482e2ac1
TG
596 return 0;
597 }
598
44e7b949 599 r = in_addr_from_string(AF_INET, rvalue, (union in_addr_union*) &n->broadcast);
eb0ea358 600 if (r < 0) {
12ca818f 601 log_syntax(unit, LOG_ERR, filename, line, r, "Broadcast is invalid, ignoring assignment: %s", rvalue);
eb0ea358
TG
602 return 0;
603 }
604
44e7b949 605 n->family = AF_INET;
eb0ea358
TG
606 n = NULL;
607
608 return 0;
609}
610
f579559b
TG
611int config_parse_address(const char *unit,
612 const char *filename,
613 unsigned line,
614 const char *section,
71a61510 615 unsigned section_line,
f579559b
TG
616 const char *lvalue,
617 int ltype,
618 const char *rvalue,
619 void *data,
620 void *userdata) {
44e7b949 621
6ae115c1 622 Network *network = userdata;
f579559b 623 _cleanup_address_free_ Address *n = NULL;
44e7b949
LP
624 const char *address, *e;
625 union in_addr_union buffer;
626 int r, f;
f579559b
TG
627
628 assert(filename);
6ae115c1 629 assert(section);
f579559b
TG
630 assert(lvalue);
631 assert(rvalue);
632 assert(data);
633
92fe133a
TG
634 if (streq(section, "Network")) {
635 /* we are not in an Address section, so treat
636 * this as the special '0' section */
637 section_line = 0;
638 }
639
f048a16b 640 r = address_new_static(network, section_line, &n);
f579559b
TG
641 if (r < 0)
642 return r;
643
644 /* Address=address/prefixlen */
645
646 /* prefixlen */
647 e = strchr(rvalue, '/');
648 if (e) {
649 unsigned i;
12ca818f 650
f579559b
TG
651 r = safe_atou(e + 1, &i);
652 if (r < 0) {
12ca818f 653 log_syntax(unit, LOG_ERR, filename, line, r, "Prefix length is invalid, ignoring assignment: %s", e + 1);
f579559b
TG
654 return 0;
655 }
656
657 n->prefixlen = (unsigned char) i;
8cd11a0f 658
44e7b949
LP
659 address = strndupa(rvalue, e - rvalue);
660 } else
661 address = rvalue;
f579559b 662
44e7b949 663 r = in_addr_from_string_auto(address, &f, &buffer);
f579559b 664 if (r < 0) {
12ca818f 665 log_syntax(unit, LOG_ERR, filename, line, r, "Address is invalid, ignoring assignment: %s", address);
f579559b
TG
666 return 0;
667 }
668
a2a85a22
TG
669 if (!e && f == AF_INET) {
670 r = in_addr_default_prefixlen(&buffer.in, &n->prefixlen);
671 if (r < 0) {
12ca818f 672 log_syntax(unit, LOG_ERR, filename, line, r, "Prefix length not specified, and a default one can not be deduced for '%s', ignoring assignment", address);
a2a85a22
TG
673 return 0;
674 }
675 }
676
44e7b949 677 if (n->family != AF_UNSPEC && f != n->family) {
12ca818f 678 log_syntax(unit, LOG_ERR, filename, line, 0, "Address is incompatible, ignoring assignment: %s", address);
44e7b949
LP
679 return 0;
680 }
681
682 n->family = f;
683
684 if (streq(lvalue, "Address"))
685 n->in_addr = buffer;
686 else
687 n->in_addr_peer = buffer;
688
689 if (n->family == AF_INET && n->broadcast.s_addr == 0)
690 n->broadcast.s_addr = n->in_addr.in.s_addr | htonl(0xfffffffflu >> n->prefixlen);
eb0ea358 691
f579559b
TG
692 n = NULL;
693
694 return 0;
695}
6ae115c1
TG
696
697int config_parse_label(const char *unit,
698 const char *filename,
699 unsigned line,
700 const char *section,
701 unsigned section_line,
702 const char *lvalue,
703 int ltype,
704 const char *rvalue,
705 void *data,
706 void *userdata) {
707 Network *network = userdata;
708 _cleanup_address_free_ Address *n = NULL;
6ae115c1
TG
709 char *label;
710 int r;
711
712 assert(filename);
713 assert(section);
714 assert(lvalue);
715 assert(rvalue);
716 assert(data);
717
f048a16b 718 r = address_new_static(network, section_line, &n);
6ae115c1
TG
719 if (r < 0)
720 return r;
721
722 label = strdup(rvalue);
723 if (!label)
724 return log_oom();
725
726 if (!ascii_is_valid(label) || strlen(label) >= IFNAMSIZ) {
12ca818f 727 log_syntax(unit, LOG_ERR, filename, line, 0, "Interface label is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
6ae115c1
TG
728 free(label);
729 return 0;
730 }
731
732 free(n->label);
733 if (*label)
734 n->label = label;
735 else {
736 free(label);
737 n->label = NULL;
738 }
739
740 n = NULL;
741
742 return 0;
743}
ce6c77eb
TG
744
745bool address_is_ready(const Address *a) {
746 assert(a);
747
adda1ed9 748 return a->added && !(a->flags & (IFA_F_TENTATIVE | IFA_F_DEPRECATED));
ce6c77eb 749}