sd-ipv4ll.c revision 6af9144f5ff65cb9f6ae9999e7e0a9edc4841b2b
/***
This file is part of systemd.
Copyright (C) 2014 Axis Communications AB. All rights reserved.
Copyright (C) 2015 Tom Gundersen
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 "event-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__)
#define IPV4LL_DONT_DESTROY(ll) \
typedef enum IPv4LLState {
} IPv4LLState;
struct sd_ipv4ll {
unsigned n_ref;
int index;
int fd;
int iteration;
int conflict;
struct random_data *random_data;
char *random_data_state;
/* External */
struct ether_addr mac_addr;
int event_priority;
void* userdata;
};
if (!ll)
return NULL;
return ll;
}
if (!ll)
return NULL;
return NULL;
return NULL;
}
if (!ll)
return -ENOMEM;
return 0;
}
} else {
}
}
}
ll->claimed_address = 0;
}
return 0;
}
int r;
do {
if (r < 0)
return r;
return 0;
}
int r;
assert(random_sec >= 0);
if (random_sec)
if (r < 0)
return r;
if (r < 0)
return r;
if (r < 0)
return r;
return 0;
}
/* see the BPF */
return true;
/* the TPA matched instead of the SPA, this is not a conflict */
return false;
}
int r = 0;
case IPV4LL_STATE_INIT:
if (r < 0)
return r;
} else {
if (r < 0)
return r;
}
break;
case IPV4LL_STATE_PROBING:
/* Send a probe */
if (r < 0) {
goto out;
}
if (r < 0)
goto out;
} else {
if (r < 0)
goto out;
}
break;
case IPV4LL_STATE_ANNOUNCING:
break;
}
/* Send announcement packet */
if (r < 0) {
goto out;
}
if (r < 0)
goto out;
}
break;
default:
assert_not_reached("Invalid state.");
}
out:
if (r < 0 && ll)
return 1;
}
int r;
/* Pick a new address */
if (r < 0)
return r;
r = sd_ipv4ll_start(ll);
if (r < 0)
return r;
return 0;
}
int r;
if (r < (int) sizeof(struct ether_arp))
goto out;
case IPV4LL_STATE_ANNOUNCING:
case IPV4LL_STATE_RUNNING:
/* Defend address */
if (r < 0) {
goto out;
}
} else {
r = ipv4ll_on_conflict(ll);
if (r < 0)
goto out;
}
}
break;
case IPV4LL_STATE_PROBING:
/* BPF ensures this packet indicates a conflict */
r = ipv4ll_on_conflict(ll);
if (r < 0)
goto out;
break;
default:
assert_not_reached("Invalid state.");
}
out:
if (r < 0 && ll)
return 1;
}
return 0;
}
return 0;
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;
r = ipv4ll_set_next_wakeup(ll, 0, 0);
if (r < 0)
goto out;
out:
if (r < 0)
return 0;
}