summaryrefslogtreecommitdiff
path: root/src/libsystemd-network/sd-ipv4ll.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libsystemd-network/sd-ipv4ll.c')
-rw-r--r--src/libsystemd-network/sd-ipv4ll.c54
1 files changed, 43 insertions, 11 deletions
diff --git a/src/libsystemd-network/sd-ipv4ll.c b/src/libsystemd-network/sd-ipv4ll.c
index dd427ddd78..0d915e20e7 100644
--- a/src/libsystemd-network/sd-ipv4ll.c
+++ b/src/libsystemd-network/sd-ipv4ll.c
@@ -18,13 +18,18 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdlib.h>
+#include <arpa/inet.h>
#include <errno.h>
-#include <string.h>
#include <stdio.h>
-#include <arpa/inet.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "sd-ipv4acd.h"
+#include "sd-ipv4ll.h"
+#include "alloc-util.h"
#include "event-util.h"
+#include "in-addr-util.h"
#include "list.h"
#include "random-util.h"
#include "refcnt.h"
@@ -32,9 +37,6 @@
#include "sparse-endian.h"
#include "util.h"
-#include "sd-ipv4acd.h"
-#include "sd-ipv4ll.h"
-
#define IPV4LL_NETWORK 0xA9FE0000L
#define IPV4LL_NETMASK 0xFFFF0000L
@@ -226,12 +228,45 @@ int sd_ipv4ll_set_address_seed(sd_ipv4ll *ll, unsigned seed) {
return 0;
}
-bool sd_ipv4ll_is_running(sd_ipv4ll *ll) {
+int sd_ipv4ll_is_running(sd_ipv4ll *ll) {
assert_return(ll, false);
return sd_ipv4acd_is_running(ll->acd);
}
+static bool ipv4ll_address_is_valid(const struct in_addr *address) {
+ uint32_t addr;
+
+ assert(address);
+
+ if (!in_addr_is_link_local(AF_INET, (const union in_addr_union *) address))
+ return false;
+
+ addr = be32toh(address->s_addr);
+
+ if ((addr & 0x0000FF00) == 0x0000 ||
+ (addr & 0x0000FF00) == 0xFF00)
+ return false;
+
+ return true;
+}
+
+int sd_ipv4ll_set_address(sd_ipv4ll *ll, const struct in_addr *address) {
+ int r;
+
+ assert_return(ll, -EINVAL);
+ assert_return(address, -EINVAL);
+ assert_return(ipv4ll_address_is_valid(address), -EINVAL);
+
+ r = sd_ipv4acd_set_address(ll->acd, address);
+ if (r < 0)
+ return r;
+
+ ll->address = address->s_addr;
+
+ return 0;
+}
+
static int ipv4ll_pick_address(sd_ipv4ll *ll) {
struct in_addr in_addr;
be32_t addr;
@@ -247,18 +282,15 @@ static int ipv4ll_pick_address(sd_ipv4ll *ll) {
return r;
addr = htonl((random & 0x0000FFFF) | IPV4LL_NETWORK);
} while (addr == ll->address ||
- (ntohl(addr) & IPV4LL_NETMASK) != IPV4LL_NETWORK ||
(ntohl(addr) & 0x0000FF00) == 0x0000 ||
(ntohl(addr) & 0x0000FF00) == 0xFF00);
in_addr.s_addr = addr;
- r = sd_ipv4acd_set_address(ll->acd, &in_addr);
+ r = sd_ipv4ll_set_address(ll, &in_addr);
if (r < 0)
return r;
- ll->address = addr;
-
return 0;
}