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