]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-network/sd-ipv4ll.c
sd-ipv4ll: split run_state_machine() into on_packet() and on_timeout()
[thirdparty/systemd.git] / src / libsystemd-network / sd-ipv4ll.c
CommitLineData
5c1d3fc9
UTL
1/***
2 This file is part of systemd.
3
4 Copyright (C) 2014 Axis Communications AB. All rights reserved.
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18***/
19
20#include <stdlib.h>
21#include <errno.h>
22#include <string.h>
23#include <stdio.h>
24#include <arpa/inet.h>
25
26#include "util.h"
b5db00e5 27#include "siphash24.h"
5c1d3fc9 28#include "list.h"
3df3e884 29#include "random-util.h"
5c1d3fc9 30
996d1697 31#include "arp-util.h"
5c1d3fc9
UTL
32#include "sd-ipv4ll.h"
33
34/* Constants from the RFC */
35#define PROBE_WAIT 1
36#define PROBE_NUM 3
37#define PROBE_MIN 1
38#define PROBE_MAX 2
39#define ANNOUNCE_WAIT 2
40#define ANNOUNCE_NUM 2
41#define ANNOUNCE_INTERVAL 2
42#define MAX_CONFLICTS 10
43#define RATE_LIMIT_INTERVAL 60
44#define DEFEND_INTERVAL 10
45
46#define IPV4LL_NETWORK 0xA9FE0000L
47#define IPV4LL_NETMASK 0xFFFF0000L
48
996d1697
TG
49#define log_ipv4ll(ll, fmt, ...) log_internal(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, "IPv4LL: " fmt, ##__VA_ARGS__)
50
5c1d3fc9
UTL
51typedef enum IPv4LLState {
52 IPV4LL_STATE_INIT,
53 IPV4LL_STATE_WAITING_PROBE,
54 IPV4LL_STATE_PROBING,
55 IPV4LL_STATE_WAITING_ANNOUNCE,
56 IPV4LL_STATE_ANNOUNCING,
57 IPV4LL_STATE_RUNNING,
4d978a46 58 IPV4LL_STATE_STOPPED,
5c1d3fc9
UTL
59 _IPV4LL_STATE_MAX,
60 _IPV4LL_STATE_INVALID = -1
61} IPv4LLState;
62
63struct sd_ipv4ll {
9c8e3101 64 unsigned n_ref;
56cd007a 65
5c1d3fc9
UTL
66 IPv4LLState state;
67 int index;
68 int fd;
5c1d3fc9
UTL
69 int iteration;
70 int conflict;
71 sd_event_source *receive_message;
72 sd_event_source *timer;
73 usec_t next_wakeup;
74 usec_t defend_window;
75 int next_wakeup_valid;
76 be32_t address;
b5db00e5
UTL
77 struct random_data *random_data;
78 char *random_data_state;
5c1d3fc9
UTL
79 /* External */
80 be32_t claimed_address;
81 struct ether_addr mac_addr;
82 sd_event *event;
83 int event_priority;
84 sd_ipv4ll_cb_t cb;
85 void* userdata;
86};
87
5c1d3fc9
UTL
88static void ipv4ll_set_state(sd_ipv4ll *ll, IPv4LLState st, int reset_counter) {
89
90 assert(ll);
91 assert(st < _IPV4LL_STATE_MAX);
92
93 if (st == ll->state && !reset_counter) {
94 ll->iteration++;
95 } else {
96 ll->state = st;
97 ll->iteration = 0;
98 }
99}
100
56cd007a 101static sd_ipv4ll *ipv4ll_client_notify(sd_ipv4ll *ll, int event) {
5c1d3fc9
UTL
102 assert(ll);
103
56cd007a
PF
104 if (ll->cb) {
105 ll = sd_ipv4ll_ref(ll);
5c1d3fc9 106 ll->cb(ll, event, ll->userdata);
56cd007a
PF
107 ll = sd_ipv4ll_unref(ll);
108 }
5c1d3fc9 109
56cd007a 110 return ll;
5c1d3fc9
UTL
111}
112
56cd007a 113static sd_ipv4ll *ipv4ll_stop(sd_ipv4ll *ll, int event) {
5c1d3fc9
UTL
114 assert(ll);
115
116 ll->receive_message = sd_event_source_unref(ll->receive_message);
03e334a1 117 ll->fd = safe_close(ll->fd);
5c1d3fc9
UTL
118
119 ll->timer = sd_event_source_unref(ll->timer);
120
56cd007a 121 log_ipv4ll(ll, "STOPPED");
5c1d3fc9 122
56cd007a 123 ll = ipv4ll_client_notify(ll, event);
5c1d3fc9 124
56cd007a
PF
125 if (ll) {
126 ll->claimed_address = 0;
127 ipv4ll_set_state (ll, IPV4LL_STATE_INIT, 1);
128 }
5c1d3fc9 129
56cd007a 130 return ll;
5c1d3fc9
UTL
131}
132
b5db00e5 133static int ipv4ll_pick_address(sd_ipv4ll *ll, be32_t *address) {
5c1d3fc9 134 be32_t addr;
b5db00e5
UTL
135 int r;
136 int32_t random;
5c1d3fc9
UTL
137
138 assert(ll);
b5db00e5
UTL
139 assert(address);
140 assert(ll->random_data);
5c1d3fc9 141
b5db00e5
UTL
142 do {
143 r = random_r(ll->random_data, &random);
144 if (r < 0)
145 return r;
146 addr = htonl((random & 0x0000FFFF) | IPV4LL_NETWORK);
147 } while (addr == ll->address ||
148 (ntohl(addr) & IPV4LL_NETMASK) != IPV4LL_NETWORK ||
149 (ntohl(addr) & 0x0000FF00) == 0x0000 ||
150 (ntohl(addr) & 0x0000FF00) == 0xFF00);
5c1d3fc9 151
b5db00e5
UTL
152 *address = addr;
153 return 0;
5c1d3fc9
UTL
154}
155
6a0f1f6d 156static void ipv4ll_set_next_wakeup(sd_ipv4ll *ll, int sec, int random_sec) {
5c1d3fc9
UTL
157 usec_t next_timeout = 0;
158 usec_t time_now = 0;
159
160 assert(sec >= 0);
161 assert(random_sec >= 0);
162 assert(ll);
163
164 next_timeout = sec * USEC_PER_SEC;
165
166 if (random_sec)
167 next_timeout += random_u32() % (random_sec * USEC_PER_SEC);
168
38a03f06 169 assert_se(sd_event_now(ll->event, clock_boottime_or_monotonic(), &time_now) >= 0);
5c1d3fc9
UTL
170
171 ll->next_wakeup = time_now + next_timeout;
172 ll->next_wakeup_valid = 1;
173}
174
175static bool ipv4ll_arp_conflict (sd_ipv4ll *ll, struct ether_arp *arp) {
176 assert(ll);
177 assert(arp);
178
996d1697 179 if (memcmp(arp->arp_spa, &ll->address, sizeof(ll->address)) == 0)
5c1d3fc9
UTL
180 return true;
181
182 return false;
183}
184
185static bool ipv4ll_arp_probe_conflict (sd_ipv4ll *ll, struct ether_arp *arp) {
186 assert(ll);
187 assert(arp);
188
189 if (ipv4ll_arp_conflict(ll, arp))
190 return true;
191
996d1697 192 if (memcmp(arp->arp_tpa, &ll->address, sizeof(ll->address)) == 0)
5c1d3fc9
UTL
193 return true;
194
195 return false;
196}
197
8e5787b5
TG
198static int ipv4ll_on_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
199 sd_ipv4ll *ll = userdata;
5c1d3fc9
UTL
200 int r = 0;
201
202 assert(ll);
5c1d3fc9
UTL
203
204 if (ll->state == IPV4LL_STATE_INIT) {
205
206 log_ipv4ll(ll, "PROBE");
207 ipv4ll_set_state(ll, IPV4LL_STATE_WAITING_PROBE, 1);
208 ipv4ll_set_next_wakeup(ll, 0, PROBE_WAIT);
209
8e5787b5
TG
210 } else if (ll->state == IPV4LL_STATE_WAITING_PROBE ||
211 (ll->state == IPV4LL_STATE_PROBING && ll->iteration < PROBE_NUM-2)) {
5c1d3fc9
UTL
212
213 /* Send a probe */
996d1697
TG
214 r = arp_send_probe(ll->fd, ll->index, ll->address, &ll->mac_addr);
215 if (r < 0) {
216 log_ipv4ll(ll, "Failed to send ARP probe.");
217 goto out;
218 }
219
5c1d3fc9
UTL
220 ipv4ll_set_state(ll, IPV4LL_STATE_PROBING, 0);
221
222 ipv4ll_set_next_wakeup(ll, PROBE_MIN, (PROBE_MAX-PROBE_MIN));
223
8e5787b5 224 } else if (ll->state == IPV4LL_STATE_PROBING && ll->iteration >= PROBE_NUM-2) {
5c1d3fc9
UTL
225
226 /* Send the last probe */
996d1697
TG
227 r = arp_send_probe(ll->fd, ll->index, ll->address, &ll->mac_addr);
228 if (r < 0) {
229 log_ipv4ll(ll, "Failed to send ARP probe.");
230 goto out;
231 }
232
5c1d3fc9
UTL
233 ipv4ll_set_state(ll, IPV4LL_STATE_WAITING_ANNOUNCE, 1);
234
235 ipv4ll_set_next_wakeup(ll, ANNOUNCE_WAIT, 0);
236
8e5787b5
TG
237 } else if (ll->state == IPV4LL_STATE_WAITING_ANNOUNCE ||
238 (ll->state == IPV4LL_STATE_ANNOUNCING && ll->iteration < ANNOUNCE_NUM-1)) {
5c1d3fc9
UTL
239
240 /* Send announcement packet */
996d1697
TG
241 r = arp_send_announcement(ll->fd, ll->index, ll->address, &ll->mac_addr);
242 if (r < 0) {
243 log_ipv4ll(ll, "Failed to send ARP announcement.");
244 goto out;
245 }
246
5c1d3fc9
UTL
247 ipv4ll_set_state(ll, IPV4LL_STATE_ANNOUNCING, 0);
248
249 ipv4ll_set_next_wakeup(ll, ANNOUNCE_INTERVAL, 0);
250
251 if (ll->iteration == 0) {
252 log_ipv4ll(ll, "ANNOUNCE");
253 ll->claimed_address = ll->address;
56cd007a 254 ll = ipv4ll_client_notify(ll, IPV4LL_EVENT_BIND);
4d978a46 255 if (!ll || ll->state == IPV4LL_STATE_STOPPED)
56cd007a
PF
256 goto out;
257
5c1d3fc9
UTL
258 ll->conflict = 0;
259 }
260
8e5787b5 261 } else if ((ll->state == IPV4LL_STATE_ANNOUNCING &&
5c1d3fc9
UTL
262 ll->iteration >= ANNOUNCE_NUM-1)) {
263
264 ipv4ll_set_state(ll, IPV4LL_STATE_RUNNING, 0);
265 ll->next_wakeup_valid = 0;
8e5787b5 266 }
5c1d3fc9 267
8e5787b5
TG
268 if (ll->next_wakeup_valid) {
269 ll->timer = sd_event_source_unref(ll->timer);
270 r = sd_event_add_time(ll->event, &ll->timer, clock_boottime_or_monotonic(),
271 ll->next_wakeup, 0, ipv4ll_on_timeout, ll);
272 if (r < 0)
273 goto out;
5c1d3fc9 274
8e5787b5
TG
275 r = sd_event_source_set_priority(ll->timer, ll->event_priority);
276 if (r < 0)
277 goto out;
5c1d3fc9 278
8e5787b5
TG
279 r = sd_event_source_set_description(ll->timer, "ipv4ll-timer");
280 if (r < 0)
281 goto out;
282 }
996d1697 283
8e5787b5
TG
284out:
285 if (r < 0 && ll)
286 ipv4ll_stop(ll, r);
5c1d3fc9 287
8e5787b5
TG
288 return 1;
289}
5c1d3fc9 290
8e5787b5
TG
291static int ipv4ll_on_packet(sd_event_source *s, int fd,
292 uint32_t revents, void *userdata) {
293 sd_ipv4ll *ll = userdata;
294 struct ether_arp packet;
295 int conflicted = 0;
296 usec_t time_now;
297 int r;
5c1d3fc9 298
8e5787b5
TG
299 assert(ll);
300 assert(fd >= 0);
56cd007a 301
8e5787b5
TG
302 r = read(fd, &packet, sizeof(struct ether_arp));
303 if (r < (int) sizeof(struct ether_arp))
304 goto out;
5c1d3fc9 305
8e5787b5 306 if (IN_SET(ll->state, IPV4LL_STATE_ANNOUNCING, IPV4LL_STATE_RUNNING)) {
996d1697 307
8e5787b5 308 if (ipv4ll_arp_conflict(ll, &packet)) {
996d1697 309
8e5787b5 310 r = sd_event_now(ll->event, clock_boottime_or_monotonic(), &time_now);
996d1697
TG
311 if (r < 0)
312 goto out;
313
8e5787b5
TG
314 /* Defend address */
315 if (time_now > ll->defend_window) {
316 ll->defend_window = time_now + DEFEND_INTERVAL * USEC_PER_SEC;
317 r = arp_send_announcement(ll->fd, ll->index, ll->address, &ll->mac_addr);
318 if (r < 0) {
319 log_ipv4ll(ll, "Failed to send ARP announcement.");
320 goto out;
321 }
5c1d3fc9 322
5c1d3fc9 323 } else
8e5787b5 324 conflicted = 1;
5c1d3fc9 325 }
5c1d3fc9 326
8e5787b5
TG
327 } else if (IN_SET(ll->state, IPV4LL_STATE_WAITING_PROBE,
328 IPV4LL_STATE_PROBING,
329 IPV4LL_STATE_WAITING_ANNOUNCE))
330 conflicted = ipv4ll_arp_probe_conflict(ll, &packet);
331
332 if (conflicted) {
333 log_ipv4ll(ll, "CONFLICT");
334 ll = ipv4ll_client_notify(ll, IPV4LL_EVENT_CONFLICT);
335 if (!ll || ll->state == IPV4LL_STATE_STOPPED)
5c1d3fc9
UTL
336 goto out;
337
8e5787b5
TG
338 ll->claimed_address = 0;
339
340 /* Pick a new address */
341 r = ipv4ll_pick_address(ll, &ll->address);
5c1d3fc9
UTL
342 if (r < 0)
343 goto out;
9021bb9f 344
8e5787b5
TG
345 ll->fd = safe_close(ll->fd);
346
347 r = arp_network_bind_raw_socket(ll->index, ll->address, &ll->mac_addr);
9021bb9f
TG
348 if (r < 0)
349 goto out;
8e5787b5
TG
350
351 ll->fd = r;
352
353 ll->conflict++;
354 ll->defend_window = 0;
355 ipv4ll_set_state(ll, IPV4LL_STATE_WAITING_PROBE, 1);
356
357 if (ll->conflict >= MAX_CONFLICTS) {
358 log_ipv4ll(ll, "MAX_CONFLICTS");
359 ipv4ll_set_next_wakeup(ll, RATE_LIMIT_INTERVAL, PROBE_WAIT);
360 } else
361 ipv4ll_set_next_wakeup(ll, 0, PROBE_WAIT);
5c1d3fc9
UTL
362 }
363
364out:
56cd007a 365 if (r < 0 && ll)
5c1d3fc9 366 ipv4ll_stop(ll, r);
5c1d3fc9 367
8e5787b5 368 return 1;
5c1d3fc9
UTL
369}
370
371int sd_ipv4ll_set_index(sd_ipv4ll *ll, int interface_index) {
372 assert_return(ll, -EINVAL);
d9bf4f8c 373 assert_return(interface_index > 0, -EINVAL);
4d978a46
PF
374 assert_return(IN_SET(ll->state, IPV4LL_STATE_INIT,
375 IPV4LL_STATE_STOPPED), -EBUSY);
5c1d3fc9
UTL
376
377 ll->index = interface_index;
378
379 return 0;
380}
381
382int sd_ipv4ll_set_mac(sd_ipv4ll *ll, const struct ether_addr *addr) {
4644fee0
TG
383 bool need_restart = false;
384
5c1d3fc9 385 assert_return(ll, -EINVAL);
4644fee0
TG
386 assert_return(addr, -EINVAL);
387
388 if (memcmp(&ll->mac_addr, addr, ETH_ALEN) == 0)
389 return 0;
390
4d978a46 391 if (!IN_SET(ll->state, IPV4LL_STATE_INIT, IPV4LL_STATE_STOPPED)) {
4644fee0
TG
392 log_ipv4ll(ll, "Changing MAC address on running IPv4LL "
393 "client, restarting");
56cd007a 394 ll = ipv4ll_stop(ll, IPV4LL_EVENT_STOP);
4644fee0
TG
395 need_restart = true;
396 }
397
56cd007a
PF
398 if (!ll)
399 return 0;
400
4644fee0 401 memcpy(&ll->mac_addr, addr, ETH_ALEN);
5c1d3fc9 402
4644fee0
TG
403 if (need_restart)
404 sd_ipv4ll_start(ll);
5c1d3fc9
UTL
405
406 return 0;
407}
408
409int sd_ipv4ll_detach_event(sd_ipv4ll *ll) {
410 assert_return(ll, -EINVAL);
411
412 ll->event = sd_event_unref(ll->event);
413
414 return 0;
415}
416
417int sd_ipv4ll_attach_event(sd_ipv4ll *ll, sd_event *event, int priority) {
418 int r;
419
420 assert_return(ll, -EINVAL);
421 assert_return(!ll->event, -EBUSY);
422
423 if (event)
424 ll->event = sd_event_ref(event);
425 else {
426 r = sd_event_default(&ll->event);
427 if (r < 0) {
428 ipv4ll_stop(ll, IPV4LL_EVENT_STOP);
429 return r;
430 }
431 }
432
433 ll->event_priority = priority;
434
435 return 0;
436}
437
438int sd_ipv4ll_set_callback(sd_ipv4ll *ll, sd_ipv4ll_cb_t cb, void *userdata) {
439 assert_return(ll, -EINVAL);
440
441 ll->cb = cb;
442 ll->userdata = userdata;
443
444 return 0;
445}
446
447int sd_ipv4ll_get_address(sd_ipv4ll *ll, struct in_addr *address){
448 assert_return(ll, -EINVAL);
449 assert_return(address, -EINVAL);
450
ece174c5 451 if (ll->claimed_address == 0)
5c1d3fc9 452 return -ENOENT;
5c1d3fc9
UTL
453
454 address->s_addr = ll->claimed_address;
455 return 0;
456}
457
b5db00e5 458int sd_ipv4ll_set_address_seed (sd_ipv4ll *ll, uint8_t seed[8]) {
d9bf4f8c 459 unsigned int entropy;
b5db00e5
UTL
460 int r;
461
462 assert_return(ll, -EINVAL);
d9bf4f8c
UTL
463 assert_return(seed, -EINVAL);
464
465 entropy = *seed;
b5db00e5
UTL
466
467 free(ll->random_data);
468 free(ll->random_data_state);
469
470 ll->random_data = new0(struct random_data, 1);
471 ll->random_data_state = new0(char, 128);
472
473 if (!ll->random_data || !ll->random_data_state) {
474 r = -ENOMEM;
475 goto error;
476 }
477
478 r = initstate_r((unsigned int)entropy, ll->random_data_state, 128, ll->random_data);
479 if (r < 0)
480 goto error;
481
482error:
483 if (r < 0){
484 free(ll->random_data);
485 free(ll->random_data_state);
486 ll->random_data = NULL;
487 ll->random_data_state = NULL;
488 }
489 return r;
490}
491
aba496a5 492bool sd_ipv4ll_is_running(sd_ipv4ll *ll) {
75677581 493 assert_return(ll, false);
aba496a5 494
4d978a46 495 return !IN_SET(ll->state, IPV4LL_STATE_INIT, IPV4LL_STATE_STOPPED);
aba496a5
UTL
496}
497
b5db00e5
UTL
498#define HASH_KEY SD_ID128_MAKE(df,04,22,98,3f,ad,14,52,f9,87,2e,d1,9c,70,e2,f2)
499
5c1d3fc9
UTL
500int sd_ipv4ll_start (sd_ipv4ll *ll) {
501 int r;
502
503 assert_return(ll, -EINVAL);
504 assert_return(ll->event, -EINVAL);
505 assert_return(ll->index > 0, -EINVAL);
4d978a46
PF
506 assert_return(IN_SET(ll->state, IPV4LL_STATE_INIT,
507 IPV4LL_STATE_STOPPED), -EBUSY);
508
509 ll->state = IPV4LL_STATE_INIT;
5c1d3fc9 510
5c1d3fc9
UTL
511 ll->conflict = 0;
512 ll->defend_window = 0;
513 ll->claimed_address = 0;
514
b5db00e5
UTL
515 if (!ll->random_data) {
516 uint8_t seed[8];
517
518 /* Fallback to mac */
519 siphash24(seed, &ll->mac_addr.ether_addr_octet,
520 ETH_ALEN, HASH_KEY.bytes);
521
522 r = sd_ipv4ll_set_address_seed(ll, seed);
523 if (r < 0)
524 goto out;
525 }
526
527 if (ll->address == 0) {
528 r = ipv4ll_pick_address(ll, &ll->address);
529 if (r < 0)
530 goto out;
531 }
5c1d3fc9 532
996d1697
TG
533 r = arp_network_bind_raw_socket(ll->index, ll->address, &ll->mac_addr);
534 if (r < 0)
535 goto out;
536
537 safe_close(ll->fd);
538 ll->fd = r;
539
5c1d3fc9
UTL
540 ipv4ll_set_state (ll, IPV4LL_STATE_INIT, 1);
541
542 r = sd_event_add_io(ll->event, &ll->receive_message, ll->fd,
8e5787b5 543 EPOLLIN, ipv4ll_on_packet, ll);
5c1d3fc9
UTL
544 if (r < 0)
545 goto out;
546
547 r = sd_event_source_set_priority(ll->receive_message, ll->event_priority);
548 if (r < 0)
549 goto out;
550
356779df 551 r = sd_event_source_set_description(ll->receive_message, "ipv4ll-receive-message");
9021bb9f
TG
552 if (r < 0)
553 goto out;
554
6a0f1f6d
LP
555 r = sd_event_add_time(ll->event,
556 &ll->timer,
fa94c34b
TG
557 clock_boottime_or_monotonic(),
558 now(clock_boottime_or_monotonic()), 0,
8e5787b5 559 ipv4ll_on_timeout, ll);
5c1d3fc9
UTL
560
561 if (r < 0)
562 goto out;
563
564 r = sd_event_source_set_priority(ll->timer, ll->event_priority);
9021bb9f
TG
565 if (r < 0)
566 goto out;
5c1d3fc9 567
356779df 568 r = sd_event_source_set_description(ll->timer, "ipv4ll-timer");
5c1d3fc9
UTL
569out:
570 if (r < 0)
571 ipv4ll_stop(ll, IPV4LL_EVENT_STOP);
572
573 return 0;
574}
575
576int sd_ipv4ll_stop(sd_ipv4ll *ll) {
56cd007a 577 ipv4ll_stop(ll, IPV4LL_EVENT_STOP);
4d978a46
PF
578 if (ll)
579 ipv4ll_set_state(ll, IPV4LL_STATE_STOPPED, 1);
56cd007a
PF
580
581 return 0;
5c1d3fc9
UTL
582}
583
56cd007a 584sd_ipv4ll *sd_ipv4ll_ref(sd_ipv4ll *ll) {
9c8e3101
LP
585
586 if (!ll)
587 return NULL;
588
589 assert(ll->n_ref >= 1);
590 ll->n_ref++;
5c1d3fc9 591
56cd007a
PF
592 return ll;
593}
5c1d3fc9 594
56cd007a 595sd_ipv4ll *sd_ipv4ll_unref(sd_ipv4ll *ll) {
56cd007a 596
9c8e3101
LP
597 if (!ll)
598 return NULL;
56cd007a 599
9c8e3101
LP
600 assert(ll->n_ref >= 1);
601 ll->n_ref--;
56cd007a 602
9c8e3101
LP
603 if (ll->n_ref > 0)
604 return ll;
56cd007a 605
9c8e3101
LP
606 ll->receive_message = sd_event_source_unref(ll->receive_message);
607 ll->fd = safe_close(ll->fd);
56cd007a 608
9c8e3101
LP
609 ll->timer = sd_event_source_unref(ll->timer);
610
611 sd_ipv4ll_detach_event(ll);
612
613 free(ll->random_data);
614 free(ll->random_data_state);
615 free(ll);
616
617 return NULL;
5c1d3fc9
UTL
618}
619
56cd007a
PF
620DEFINE_TRIVIAL_CLEANUP_FUNC(sd_ipv4ll*, sd_ipv4ll_unref);
621#define _cleanup_ipv4ll_free_ _cleanup_(sd_ipv4ll_unrefp)
5c1d3fc9
UTL
622
623int sd_ipv4ll_new(sd_ipv4ll **ret) {
624 _cleanup_ipv4ll_free_ sd_ipv4ll *ll = NULL;
625
626 assert_return(ret, -EINVAL);
627
628 ll = new0(sd_ipv4ll, 1);
629 if (!ll)
630 return -ENOMEM;
631
9c8e3101 632 ll->n_ref = 1;
5c1d3fc9
UTL
633 ll->state = IPV4LL_STATE_INIT;
634 ll->index = -1;
635 ll->fd = -1;
636
637 *ret = ll;
638 ll = NULL;
639
640 return 0;
641}