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