sd-ipv4acd.c revision e3dca0089b7b50e2ec21409d1292727921d06102
/***
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 <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "event-util.h"
#include "in-addr-util.h"
#include "list.h"
#include "refcnt.h"
#include "random-util.h"
#include "siphash24.h"
#include "util.h"
#include "arp-util.h"
#include "sd-ipv4acd.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 IPV4ACD_NETWORK 0xA9FE0000L
#define IPV4ACD_NETMASK 0xFFFF0000L
#define log_ipv4acd_full(ll, level, error, fmt, ...) log_internal(level, error, __FILE__, __LINE__, __func__, "ACD: " fmt, ##__VA_ARGS__)
#define log_ipv4acd_debug_errno(ll, error, ...) log_ipv4acd_full(ll, LOG_DEBUG, error, ##__VA_ARGS__)
#define log_ipv4acd_notice_errno(ll, error, ...) log_ipv4acd_full(ll, LOG_NOTICE, error, ##__VA_ARGS__)
#define log_ipv4acd_warning_errno(ll, error, ...) log_ipv4acd_full(ll, LOG_WARNING, error, ##__VA_ARGS__)
typedef enum IPv4ACDState {
} IPv4ACDState;
struct sd_ipv4acd {
int index;
int fd;
int iteration;
int conflict;
/* External */
struct ether_addr mac_addr;
int event_priority;
void* userdata;
};
if (ll)
return ll;
}
return NULL;
return NULL;
}
if (!ll)
return -ENOMEM;
return 0;
}
else {
}
}
}
}
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 IPV4ACD_STATE_INIT:
if (r < 0)
goto out;
} else {
if (r < 0)
goto out;
}
break;
case IPV4ACD_STATE_PROBING:
/* Send a probe */
if (r < 0) {
goto out;
} else {
if (r >= 0)
}
if (r < 0)
goto out;
} else {
if (r < 0)
goto out;
}
break;
case IPV4ACD_STATE_ANNOUNCING:
break;
}
/* Send announcement packet */
if (r < 0) {
goto out;
} else
if (r < 0)
goto out;
}
break;
default:
assert_not_reached("Invalid state.");
}
out:
if (r < 0)
return 1;
}
int r;
if (r >= 0)
}
int r;
if (r < (int) sizeof(struct ether_arp))
goto out;
case IPV4ACD_STATE_ANNOUNCING:
case IPV4ACD_STATE_RUNNING:
/* Defend address */
if (r < 0) {
goto out;
} else
} else
}
break;
case IPV4ACD_STATE_PROBING:
/* BPF ensures this packet indicates a conflict */
break;
default:
assert_not_reached("Invalid state.");
}
out:
if (r < 0)
return 1;
}
return 0;
}
return 0;
}
return 0;
}
int r;
if (event)
else {
if (r < 0)
return r;
}
return 0;
}
return 0;
}
return 0;
}
assert_return(ll, false);
}
const struct ether_addr nul_addr = {};
}
int r;
ll->defend_window = 0;
if (r < 0)
goto out;
if (r < 0)
goto out;
if (r < 0)
goto out;
if (r < 0)
goto out;
r = ipv4acd_set_next_wakeup(ll, 0, 0);
if (r < 0)
goto out;
out:
if (r < 0) {
return r;
}
return 0;
}