sd-ipv4ll.c revision f697185e5b45287b6a62592129e726d8a636d3ff
/***
This file is part of systemd.
Copyright (C) 2014 Axis Communications AB. All rights reserved.
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include "util.h"
#include "siphash24.h"
#include "list.h"
#include "refcnt.h"
#include "ipv4ll-internal.h"
#include "sd-ipv4ll.h"
/* Constants from the RFC */
#define PROBE_WAIT 1
#define PROBE_NUM 3
#define PROBE_MIN 1
#define PROBE_MAX 2
#define ANNOUNCE_WAIT 2
#define ANNOUNCE_NUM 2
#define ANNOUNCE_INTERVAL 2
#define MAX_CONFLICTS 10
#define RATE_LIMIT_INTERVAL 60
#define DEFEND_INTERVAL 10
#define IPV4LL_NETWORK 0xA9FE0000L
#define IPV4LL_NETMASK 0xFFFF0000L
typedef enum IPv4LLTrigger{
typedef enum IPv4LLState {
} IPv4LLState;
struct sd_ipv4ll {
int index;
int fd;
union sockaddr_union link;
int iteration;
int conflict;
int next_wakeup_valid;
struct random_data *random_data;
char *random_data_state;
/* External */
struct ether_addr mac_addr;
int event_priority;
void* userdata;
};
} else {
}
}
}
return ll;
}
if (ll) {
ll->claimed_address = 0;
}
return ll;
}
int r;
do {
if (r < 0)
return r;
return 0;
}
ll->next_wakeup_valid = 0;
return 0;
}
usec_t next_timeout = 0;
assert(random_sec >= 0);
if (random_sec)
}
return true;
return false;
}
return true;
return true;
return false;
}
struct ether_arp out_packet;
int out_packet_ready = 0;
int r = 0;
(ll->state == IPV4LL_STATE_PROBING && trigger == IPV4LL_TRIGGER_TIMEOUT && ll->iteration < PROBE_NUM-2)) {
/* Send a probe */
out_packet_ready = 1;
} else if (ll->state == IPV4LL_STATE_PROBING && trigger == IPV4LL_TRIGGER_TIMEOUT && ll->iteration >= PROBE_NUM-2) {
/* Send the last probe */
out_packet_ready = 1;
(ll->state == IPV4LL_STATE_ANNOUNCING && trigger == IPV4LL_TRIGGER_TIMEOUT && ll->iteration < ANNOUNCE_NUM-1)) {
/* Send announcement packet */
out_packet_ready = 1;
goto out;
}
ll->next_wakeup_valid = 0;
} else if (trigger == IPV4LL_TRIGGER_PACKET) {
int conflicted = 0;
if (r < 0)
goto out;
/* Defend address */
out_packet_ready = 1;
} else
conflicted = 1;
}
}
if (conflicted) {
goto out;
ll->claimed_address = 0;
/* Pick a new address */
if (r < 0)
goto out;
ll->defend_window = 0;
} else
}
}
if (out_packet_ready) {
if (r < 0) {
goto out;
}
}
if (ll->next_wakeup_valid) {
if (r < 0)
goto out;
if (r < 0)
goto out;
if (r < 0)
goto out;
}
out:
if (r < 0 && ll)
ipv4ll_stop(ll, r);
}
int r;
if (r < (int) sizeof(struct ether_arp))
return 0;
r = arp_packet_verify_headers(&arp);
if (r < 0)
return 0;
return 0;
}
return 0;
}
bool need_restart = false;
return 0;
"client, restarting");
need_restart = true;
}
if (!ll)
return 0;
if (need_restart)
return 0;
}
return 0;
}
int r;
if (event)
else {
if (r < 0) {
return r;
}
}
return 0;
}
return 0;
}
if (ll->claimed_address == 0) {
return -ENOENT;
}
return 0;
}
unsigned int entropy;
int r;
r = -ENOMEM;
goto error;
}
if (r < 0)
goto error;
if (r < 0){
}
return r;
}
}
int r;
if (r < 0)
goto out;
ll->defend_window = 0;
ll->claimed_address = 0;
if (!ll->random_data) {
/* Fallback to mac */
if (r < 0)
goto out;
}
if (r < 0)
goto out;
}
if (r < 0)
goto out;
if (r < 0)
goto out;
if (r < 0)
goto out;
now(clock_boottime_or_monotonic()), 0,
ipv4ll_timer, ll);
if (r < 0)
goto out;
if (r < 0)
goto out;
out:
if (r < 0)
return 0;
}
if (ll)
return 0;
}
if (ll)
return ll;
}
return NULL;
}
return ll;
}
if (!ll)
return -ENOMEM;
return 0;
}