LCOV - code coverage report
Current view: top level - libsystemd-network - sd-ipv4ll.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 197 323 61.0 %
Date: 2015-07-29 18:47:03 Functions: 19 24 79.2 %

          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             : }

Generated by: LCOV version 1.11