sd-ipv4ll.c revision 996d16975b4d802335188a3be2bbc3635c1287f3
/***
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 "random-util.h"
#include "arp-util.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
#define log_ipv4ll(ll, fmt, ...) log_internal(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, "IPv4LL: " fmt, ##__VA_ARGS__)
typedef enum IPv4LLTrigger{
typedef enum IPv4LLState {
} IPv4LLState;
struct sd_ipv4ll {
unsigned n_ref;
int index;
int fd;
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;
}
int r = 0;
(ll->state == IPV4LL_STATE_PROBING && trigger == IPV4LL_TRIGGER_TIMEOUT && ll->iteration < PROBE_NUM-2)) {
/* Send a probe */
if (r < 0) {
goto out;
}
} else if (ll->state == IPV4LL_STATE_PROBING && trigger == IPV4LL_TRIGGER_TIMEOUT && ll->iteration >= PROBE_NUM-2) {
/* Send the last probe */
if (r < 0) {
goto out;
}
(ll->state == IPV4LL_STATE_ANNOUNCING && trigger == IPV4LL_TRIGGER_TIMEOUT && ll->iteration < ANNOUNCE_NUM-1)) {
/* Send announcement packet */
if (r < 0) {
goto out;
}
goto out;
}
ll->next_wakeup_valid = 0;
} else if (trigger == IPV4LL_TRIGGER_PACKET) {
int conflicted = 0;
if (r < 0)
goto out;
/* Defend address */
if (r < 0) {
goto out;
}
} else
conflicted = 1;
}
}
if (conflicted) {
goto out;
ll->claimed_address = 0;
/* Pick a new address */
if (r < 0)
goto out;
if (r < 0)
goto out;
ll->defend_window = 0;
} else
}
}
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;
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;
}
assert_return(ll, false);
}
int r;
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;
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 NULL;
return ll;
}
if (!ll)
return NULL;
return ll;
return NULL;
}
if (!ll)
return -ENOMEM;
return 0;
}