summaryrefslogtreecommitdiff
path: root/src/libsystemd
diff options
context:
space:
mode:
Diffstat (limited to 'src/libsystemd')
-rw-r--r--src/libsystemd/dhcp-internal.h44
-rw-r--r--src/libsystemd/dhcp-network.c106
-rw-r--r--src/libsystemd/dhcp-option.c184
-rw-r--r--src/libsystemd/dhcp-protocol.h120
-rw-r--r--src/libsystemd/sd-dhcp-client.c1254
-rw-r--r--src/libsystemd/test-dhcp-client.c243
-rw-r--r--src/libsystemd/test-dhcp-option.c378
7 files changed, 0 insertions, 2329 deletions
diff --git a/src/libsystemd/dhcp-internal.h b/src/libsystemd/dhcp-internal.h
deleted file mode 100644
index 43b5b1d000..0000000000
--- a/src/libsystemd/dhcp-internal.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright (C) 2013 Intel Corporation. All rights reserved.
-
- systemd is free software; you can redistribute it and/or modify it
- 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 <stdint.h>
-#include <linux/if_packet.h>
-
-#include "socket-util.h"
-
-#include "dhcp-protocol.h"
-
-int dhcp_network_bind_raw_socket(int index, union sockaddr_union *link);
-int dhcp_network_bind_udp_socket(int index, be32_t client_address);
-int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link,
- const void *packet, size_t len);
-int dhcp_network_send_udp_socket(int s, be32_t server_address,
- const void *packet, size_t len);
-
-int dhcp_option_append(uint8_t **buf, size_t *buflen, uint8_t code,
- size_t optlen, const void *optval);
-
-typedef int (*dhcp_option_cb_t)(uint8_t code, uint8_t len,
- const uint8_t *option, void *user_data);
-int dhcp_option_parse(DHCPMessage *message, size_t len,
- dhcp_option_cb_t cb, void *user_data);
diff --git a/src/libsystemd/dhcp-network.c b/src/libsystemd/dhcp-network.c
deleted file mode 100644
index b2de67e8a7..0000000000
--- a/src/libsystemd/dhcp-network.c
+++ /dev/null
@@ -1,106 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright (C) 2013 Intel Corporation. All rights reserved.
-
- systemd is free software; you can redistribute it and/or modify it
- 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 <sys/types.h>
-#include <sys/socket.h>
-#include <string.h>
-#include <linux/if_packet.h>
-#include <net/ethernet.h>
-#include <stdio.h>
-#include <unistd.h>
-
-#include "socket-util.h"
-
-#include "dhcp-internal.h"
-
-int dhcp_network_bind_raw_socket(int index, union sockaddr_union *link)
-{
- int s;
-
- assert(index > 0);
- assert(link);
-
- s = socket(AF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
- htons(ETH_P_IP));
- if (s < 0)
- return -errno;
-
- link->ll.sll_family = AF_PACKET;
- link->ll.sll_protocol = htons(ETH_P_IP);
- link->ll.sll_ifindex = index;
- link->ll.sll_halen = ETH_ALEN;
- memset(link->ll.sll_addr, 0xff, ETH_ALEN);
-
- if (bind(s, &link->sa, sizeof(link->ll)) < 0) {
- close_nointr_nofail(s);
- return -errno;
- }
-
- return s;
-}
-
-int dhcp_network_bind_udp_socket(int index, be32_t client_address)
-{
- int s;
- union sockaddr_union src = {
- .in.sin_family = AF_INET,
- .in.sin_port = htobe16(DHCP_PORT_CLIENT),
- .in.sin_addr.s_addr = client_address,
- };
-
- s = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
- if (s < 0)
- return -errno;
-
- if (bind(s, &src.sa, sizeof(src.in)) < 0) {
- close_nointr_nofail(s);
- return -errno;
- }
-
- return s;
-}
-
-int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link,
- const void *packet, size_t len)
-{
- assert(link);
- assert(packet);
- assert(len);
-
- if (sendto(s, packet, len, 0, &link->sa, sizeof(link->ll)) < 0)
- return -errno;
-
- return 0;
-}
-
-int dhcp_network_send_udp_socket(int s, be32_t server_address,
- const void *packet, size_t len)
-{
- union sockaddr_union dest = {
- .in.sin_family = AF_INET,
- .in.sin_port = htobe16(DHCP_PORT_SERVER),
- .in.sin_addr.s_addr = server_address,
- };
-
- if (sendto(s, packet, len, 0, &dest.sa, sizeof(dest.in)) < 0)
- return -errno;
-
- return 0;
-}
diff --git a/src/libsystemd/dhcp-option.c b/src/libsystemd/dhcp-option.c
deleted file mode 100644
index 4d45b3b3a4..0000000000
--- a/src/libsystemd/dhcp-option.c
+++ /dev/null
@@ -1,184 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright (C) 2013 Intel Corporation. All rights reserved.
-
- systemd is free software; you can redistribute it and/or modify it
- 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 <stdint.h>
-#include <string.h>
-#include <errno.h>
-#include <stdio.h>
-
-#include "dhcp-internal.h"
-
-int dhcp_option_append(uint8_t **buf, size_t *buflen, uint8_t code,
- size_t optlen, const void *optval)
-{
- if (!buf || !buflen)
- return -EINVAL;
-
- switch (code) {
-
- case DHCP_OPTION_PAD:
- case DHCP_OPTION_END:
- if (*buflen < 1)
- return -ENOBUFS;
-
- (*buf)[0] = code;
- *buf += 1;
- *buflen -= 1;
- break;
-
- default:
- if (*buflen < optlen + 2)
- return -ENOBUFS;
-
- if (!optval)
- return -EINVAL;
-
- (*buf)[0] = code;
- (*buf)[1] = optlen;
- memcpy(&(*buf)[2], optval, optlen);
-
- *buf += optlen + 2;
- *buflen -= (optlen + 2);
-
- break;
- }
-
- return 0;
-}
-
-static int parse_options(const uint8_t *buf, size_t buflen, uint8_t *overload,
- uint8_t *message_type, dhcp_option_cb_t cb,
- void *user_data)
-{
- const uint8_t *code = buf;
- const uint8_t *len;
-
- while (buflen > 0) {
- switch (*code) {
- case DHCP_OPTION_PAD:
- buflen -= 1;
- code++;
- break;
-
- case DHCP_OPTION_END:
- return 0;
-
- case DHCP_OPTION_MESSAGE_TYPE:
- if (buflen < 3)
- return -ENOBUFS;
- buflen -= 3;
-
- len = code + 1;
- if (*len != 1)
- return -EINVAL;
-
- if (message_type)
- *message_type = *(len + 1);
-
- code += 3;
-
- break;
-
- case DHCP_OPTION_OVERLOAD:
- if (buflen < 3)
- return -ENOBUFS;
- buflen -= 3;
-
- len = code + 1;
- if (*len != 1)
- return -EINVAL;
-
- if (overload)
- *overload = *(len + 1);
-
- code += 3;
-
- break;
-
- default:
- if (buflen < 3)
- return -ENOBUFS;
-
- len = code + 1;
-
- if (buflen < (size_t)*len + 2)
- return -EINVAL;
- buflen -= *len + 2;
-
- if (cb)
- cb(*code, *len, len + 1, user_data);
-
- code += *len + 2;
-
- break;
- }
- }
-
- if (buflen)
- return -EINVAL;
-
- return 0;
-}
-
-int dhcp_option_parse(DHCPMessage *message, size_t len,
- dhcp_option_cb_t cb, void *user_data)
-{
- uint8_t overload = 0;
- uint8_t message_type = 0;
- uint8_t *opt = (uint8_t *)(message + 1);
- int res;
-
- if (!message)
- return -EINVAL;
-
- if (len < sizeof(DHCPMessage) + 4)
- return -EINVAL;
-
- len -= sizeof(DHCPMessage) + 4;
-
- if (opt[0] != 0x63 && opt[1] != 0x82 && opt[2] != 0x53 &&
- opt[3] != 0x63)
- return -EINVAL;
-
- res = parse_options(&opt[4], len, &overload, &message_type,
- cb, user_data);
- if (res < 0)
- return res;
-
- if (overload & DHCP_OVERLOAD_FILE) {
- res = parse_options(message->file, sizeof(message->file),
- NULL, &message_type, cb, user_data);
- if (res < 0)
- return res;
- }
-
- if (overload & DHCP_OVERLOAD_SNAME) {
- res = parse_options(message->sname, sizeof(message->sname),
- NULL, &message_type, cb, user_data);
- if (res < 0)
- return res;
- }
-
- if (message_type)
- return message_type;
-
- return -ENOMSG;
-}
diff --git a/src/libsystemd/dhcp-protocol.h b/src/libsystemd/dhcp-protocol.h
deleted file mode 100644
index abdfe8d54b..0000000000
--- a/src/libsystemd/dhcp-protocol.h
+++ /dev/null
@@ -1,120 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright (C) 2013 Intel Corporation. All rights reserved.
-
- systemd is free software; you can redistribute it and/or modify it
- 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 <netinet/udp.h>
-#include <netinet/ip.h>
-#include <stdint.h>
-
-#include "macro.h"
-#include "sparse-endian.h"
-
-struct DHCPMessage {
- uint8_t op;
- uint8_t htype;
- uint8_t hlen;
- uint8_t hops;
- be32_t xid;
- be16_t secs;
- be16_t flags;
- be32_t ciaddr;
- be32_t yiaddr;
- be32_t siaddr;
- be32_t giaddr;
- uint8_t chaddr[16];
- uint8_t sname[64];
- uint8_t file[128];
-} _packed_;
-
-typedef struct DHCPMessage DHCPMessage;
-
-struct DHCPPacket {
- struct iphdr ip;
- struct udphdr udp;
- DHCPMessage dhcp;
-} _packed_;
-
-typedef struct DHCPPacket DHCPPacket;
-
-#define DHCP_IP_SIZE (int32_t)(sizeof(struct iphdr))
-#define DHCP_IP_UDP_SIZE (int32_t)(sizeof(struct udphdr) + DHCP_IP_SIZE)
-#define DHCP_MESSAGE_SIZE (int32_t)(sizeof(DHCPMessage))
-
-enum {
- DHCP_PORT_SERVER = 67,
- DHCP_PORT_CLIENT = 68,
-};
-
-enum DHCPState {
- DHCP_STATE_INIT = 0,
- DHCP_STATE_SELECTING = 1,
- DHCP_STATE_INIT_REBOOT = 2,
- DHCP_STATE_REBOOTING = 3,
- DHCP_STATE_REQUESTING = 4,
- DHCP_STATE_BOUND = 5,
- DHCP_STATE_RENEWING = 6,
- DHCP_STATE_REBINDING = 7,
-};
-
-typedef enum DHCPState DHCPState;
-
-enum {
- BOOTREQUEST = 1,
- BOOTREPLY = 2,
-};
-
-enum {
- DHCP_DISCOVER = 1,
- DHCP_OFFER = 2,
- DHCP_REQUEST = 3,
- DHCP_DECLINE = 4,
- DHCP_ACK = 5,
- DHCP_NAK = 6,
- DHCP_RELEASE = 7,
-};
-
-enum {
- DHCP_OVERLOAD_FILE = 1,
- DHCP_OVERLOAD_SNAME = 2,
-};
-
-enum {
- DHCP_OPTION_PAD = 0,
- DHCP_OPTION_SUBNET_MASK = 1,
- DHCP_OPTION_ROUTER = 3,
- DHCP_OPTION_DOMAIN_NAME_SERVER = 6,
- DHCP_OPTION_HOST_NAME = 12,
- DHCP_OPTION_DOMAIN_NAME = 15,
- DHCP_OPTION_INTERFACE_MTU = 26,
- DHCP_OPTION_NTP_SERVER = 42,
- DHCP_OPTION_REQUESTED_IP_ADDRESS = 50,
- DHCP_OPTION_IP_ADDRESS_LEASE_TIME = 51,
- DHCP_OPTION_OVERLOAD = 52,
- DHCP_OPTION_MESSAGE_TYPE = 53,
- DHCP_OPTION_SERVER_IDENTIFIER = 54,
- DHCP_OPTION_PARAMETER_REQUEST_LIST = 55,
- DHCP_OPTION_MAXIMUM_MESSAGE_SIZE = 57,
- DHCP_OPTION_RENEWAL_T1_TIME = 58,
- DHCP_OPTION_REBINDING_T2_TIME = 59,
- DHCP_OPTION_CLIENT_IDENTIFIER = 61,
- DHCP_OPTION_END = 255,
-};
diff --git a/src/libsystemd/sd-dhcp-client.c b/src/libsystemd/sd-dhcp-client.c
deleted file mode 100644
index 3b7b9f4ccd..0000000000
--- a/src/libsystemd/sd-dhcp-client.c
+++ /dev/null
@@ -1,1254 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright (C) 2013 Intel Corporation. All rights reserved.
-
- systemd is free software; you can redistribute it and/or modify it
- 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 <net/ethernet.h>
-#include <sys/param.h>
-
-#include "util.h"
-#include "list.h"
-
-#include "dhcp-protocol.h"
-#include "dhcp-internal.h"
-#include "sd-dhcp-client.h"
-
-#define DHCP_CLIENT_MIN_OPTIONS_SIZE 312
-
-#define client_state_machine_check(s, r) \
- do { \
- if (s != DHCP_STATE_BOUND && \
- s != DHCP_STATE_RENEWING && \
- s != DHCP_STATE_REBINDING) { \
- return (r); \
- } \
- } while (false)
-
-struct DHCPLease {
- uint32_t t1;
- uint32_t t2;
- uint32_t lifetime;
- be32_t address;
- be32_t server_address;
- be32_t subnet_mask;
- be32_t router;
- struct in_addr *dns;
- size_t dns_size;
- uint16_t mtu;
- char *domainname;
- char *hostname;
-};
-
-typedef struct DHCPLease DHCPLease;
-
-struct sd_dhcp_client {
- DHCPState state;
- sd_event *event;
- int event_priority;
- sd_event_source *timeout_resend;
- int index;
- int fd;
- union sockaddr_union link;
- sd_event_source *receive_message;
- uint8_t *req_opts;
- size_t req_opts_allocated;
- size_t req_opts_size;
- be32_t last_addr;
- struct ether_addr mac_addr;
- uint32_t xid;
- usec_t start_time;
- unsigned int attempt;
- usec_t request_sent;
- sd_event_source *timeout_t1;
- sd_event_source *timeout_t2;
- sd_event_source *timeout_expire;
- sd_dhcp_client_cb_t cb;
- void *userdata;
- DHCPLease *lease;
-};
-
-static const uint8_t default_req_opts[] = {
- DHCP_OPTION_SUBNET_MASK,
- DHCP_OPTION_ROUTER,
- DHCP_OPTION_HOST_NAME,
- DHCP_OPTION_DOMAIN_NAME,
- DHCP_OPTION_DOMAIN_NAME_SERVER,
- DHCP_OPTION_NTP_SERVER,
-};
-
-static int client_receive_message(sd_event_source *s, int fd,
- uint32_t revents, void *userdata);
-
-int sd_dhcp_client_set_callback(sd_dhcp_client *client, sd_dhcp_client_cb_t cb,
- void *userdata) {
- assert_return(client, -EINVAL);
-
- client->cb = cb;
- client->userdata = userdata;
-
- return 0;
-}
-
-int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option) {
- size_t i;
-
- assert_return(client, -EINVAL);
- assert_return (client->state == DHCP_STATE_INIT, -EBUSY);
-
- switch(option) {
- case DHCP_OPTION_PAD:
- case DHCP_OPTION_OVERLOAD:
- case DHCP_OPTION_MESSAGE_TYPE:
- case DHCP_OPTION_PARAMETER_REQUEST_LIST:
- case DHCP_OPTION_END:
- return -EINVAL;
-
- default:
- break;
- }
-
- for (i = 0; i < client->req_opts_size; i++)
- if (client->req_opts[i] == option)
- return -EEXIST;
-
- if (!GREEDY_REALLOC(client->req_opts, client->req_opts_allocated,
- client->req_opts_size + 1))
- return -ENOMEM;
-
- client->req_opts[client->req_opts_size++] = option;
-
- return 0;
-}
-
-int sd_dhcp_client_set_request_address(sd_dhcp_client *client,
- const struct in_addr *last_addr) {
- assert_return(client, -EINVAL);
- assert_return(client->state == DHCP_STATE_INIT, -EBUSY);
-
- if (last_addr)
- client->last_addr = last_addr->s_addr;
- else
- client->last_addr = INADDR_ANY;
-
- return 0;
-}
-
-int sd_dhcp_client_set_index(sd_dhcp_client *client, int interface_index) {
- assert_return(client, -EINVAL);
- assert_return(client->state == DHCP_STATE_INIT, -EBUSY);
- assert_return(interface_index >= -1, -EINVAL);
-
- client->index = interface_index;
-
- return 0;
-}
-
-int sd_dhcp_client_set_mac(sd_dhcp_client *client,
- const struct ether_addr *addr) {
- assert_return(client, -EINVAL);
- assert_return(client->state == DHCP_STATE_INIT, -EBUSY);
-
- memcpy(&client->mac_addr, addr, ETH_ALEN);
-
- return 0;
-}
-
-int sd_dhcp_client_get_address(sd_dhcp_client *client, struct in_addr *addr) {
- assert_return(client, -EINVAL);
- assert_return(addr, -EINVAL);
-
- client_state_machine_check (client->state, -EADDRNOTAVAIL);
-
- addr->s_addr = client->lease->address;
-
- return 0;
-}
-
-int sd_dhcp_client_get_mtu(sd_dhcp_client *client, uint16_t *mtu) {
- assert_return(client, -EINVAL);
- assert_return(mtu, -EINVAL);
-
- client_state_machine_check (client->state, -EADDRNOTAVAIL);
-
- if (client->lease->mtu)
- *mtu = client->lease->mtu;
- else
- return -ENOENT;
-
- return 0;
-}
-
-int sd_dhcp_client_get_dns(sd_dhcp_client *client, struct in_addr **addr, size_t *addr_size) {
- assert_return(client, -EINVAL);
- assert_return(addr, -EINVAL);
- assert_return(addr_size, -EINVAL);
-
- client_state_machine_check (client->state, -EADDRNOTAVAIL);
-
- if (client->lease->dns_size) {
- *addr_size = client->lease->dns_size;
- *addr = client->lease->dns;
- } else
- return -ENOENT;
-
- return 0;
-}
-
-int sd_dhcp_client_get_domainname(sd_dhcp_client *client, const char **domainname) {
- assert_return(client, -EINVAL);
- assert_return(domainname, -EINVAL);
-
- client_state_machine_check (client->state, -EADDRNOTAVAIL);
-
- if (client->lease->domainname)
- *domainname = client->lease->domainname;
- else
- return -ENOENT;
-
- return 0;
-}
-
-int sd_dhcp_client_get_hostname(sd_dhcp_client *client, const char **hostname) {
- assert_return(client, -EINVAL);
- assert_return(hostname, -EINVAL);
-
- client_state_machine_check (client->state, -EADDRNOTAVAIL);
-
- if (client->lease->hostname)
- *hostname = client->lease->hostname;
- else
- return -ENOENT;
-
- return 0;
-}
-
-int sd_dhcp_client_prefixlen(const struct in_addr *addr) {
- int len = 0;
- uint32_t mask;
-
- assert_return(addr, -EADDRNOTAVAIL);
-
- mask = be32toh(addr->s_addr);
- while (mask) {
- len++;
- mask = mask << 1;
- }
-
- return len;
-}
-
-int sd_dhcp_client_get_router(sd_dhcp_client *client, struct in_addr *addr) {
- assert_return(client, -EINVAL);
- assert_return(addr, -EINVAL);
-
- client_state_machine_check (client->state, -EADDRNOTAVAIL);
-
- addr->s_addr = client->lease->router;
-
- return 0;
-}
-
-int sd_dhcp_client_get_netmask(sd_dhcp_client *client, struct in_addr *addr) {
- assert_return(client, -EINVAL);
- assert_return(addr, -EINVAL);
-
- client_state_machine_check (client->state, -EADDRNOTAVAIL);
-
- addr->s_addr = client->lease->subnet_mask;
-
- return 0;
-}
-
-static int client_notify(sd_dhcp_client *client, int event) {
- if (client->cb)
- client->cb(client, event, client->userdata);
-
- return 0;
-}
-
-static void lease_free(DHCPLease *lease) {
- if (!lease)
- return;
-
- free(lease->hostname);
- free(lease->domainname);
- free(lease->dns);
- free(lease);
-}
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(DHCPLease*, lease_free);
-#define _cleanup_lease_free_ _cleanup_(lease_freep)
-
-static int client_stop(sd_dhcp_client *client, int error) {
- assert_return(client, -EINVAL);
-
- client->receive_message =
- sd_event_source_unref(client->receive_message);
-
- if (client->fd >= 0)
- close(client->fd);
- client->fd = -1;
-
- client->timeout_resend = sd_event_source_unref(client->timeout_resend);
-
- client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
- client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
- client->timeout_expire = sd_event_source_unref(client->timeout_expire);
-
- client->attempt = 1;
-
- client_notify(client, error);
-
- switch (client->state) {
-
- case DHCP_STATE_INIT:
- case DHCP_STATE_SELECTING:
- case DHCP_STATE_REQUESTING:
- case DHCP_STATE_BOUND:
-
- client->start_time = 0;
- client->state = DHCP_STATE_INIT;
- break;
-
- case DHCP_STATE_INIT_REBOOT:
- case DHCP_STATE_REBOOTING:
- case DHCP_STATE_RENEWING:
- case DHCP_STATE_REBINDING:
-
- break;
- }
-
- if (client->lease) {
- lease_free(client->lease);
- client->lease = NULL;
- }
-
- return 0;
-}
-
-static int client_packet_init(sd_dhcp_client *client, uint8_t type,
- DHCPMessage *message, uint16_t secs,
- uint8_t **opt, size_t *optlen) {
- int err;
- be16_t max_size;
-
- *opt = (uint8_t *)(message + 1);
-
- if (*optlen < 4)
- return -ENOBUFS;
- *optlen -= 4;
-
- message->op = BOOTREQUEST;
- message->htype = 1;
- message->hlen = ETHER_ADDR_LEN;
- message->xid = htobe32(client->xid);
-
- /* Although 'secs' field is a SHOULD in RFC 2131, certain DHCP servers
- refuse to issue an DHCP lease if 'secs' is set to zero */
- message->secs = htobe16(secs);
-
- if (client->state == DHCP_STATE_RENEWING ||
- client->state == DHCP_STATE_REBINDING)
- message->ciaddr = client->lease->address;
-
- memcpy(&message->chaddr, &client->mac_addr, ETH_ALEN);
- (*opt)[0] = 0x63;
- (*opt)[1] = 0x82;
- (*opt)[2] = 0x53;
- (*opt)[3] = 0x63;
-
- *opt += 4;
-
- err = dhcp_option_append(opt, optlen, DHCP_OPTION_MESSAGE_TYPE, 1,
- &type);
- if (err < 0)
- return err;
-
- /* Some DHCP servers will refuse to issue an DHCP lease if the Cliient
- Identifier option is not set */
- err = dhcp_option_append(opt, optlen, DHCP_OPTION_CLIENT_IDENTIFIER,
- ETH_ALEN, &client->mac_addr);
- if (err < 0)
- return err;
-
- if (type == DHCP_DISCOVER || type == DHCP_REQUEST) {
- err = dhcp_option_append(opt, optlen,
- DHCP_OPTION_PARAMETER_REQUEST_LIST,
- client->req_opts_size,
- client->req_opts);
- if (err < 0)
- return err;
-
- /* Some DHCP servers will send bigger DHCP packets than the
- defined default size unless the Maximum Messge Size option
- is explicitely set */
- max_size = htobe16(DHCP_IP_UDP_SIZE + DHCP_MESSAGE_SIZE +
- DHCP_CLIENT_MIN_OPTIONS_SIZE);
- err = dhcp_option_append(opt, optlen,
- DHCP_OPTION_MAXIMUM_MESSAGE_SIZE,
- 2, &max_size);
- if (err < 0)
- return err;
- }
-
- return 0;
-}
-
-static uint16_t client_checksum(void *buf, int len) {
- uint32_t sum;
- uint16_t *check;
- int i;
- uint8_t *odd;
-
- sum = 0;
- check = buf;
-
- for (i = 0; i < len / 2 ; i++)
- sum += check[i];
-
- if (len & 0x01) {
- odd = buf;
- sum += odd[len - 1];
- }
-
- while (sum >> 16)
- sum = (sum & 0xffff) + (sum >> 16);
-
- return ~sum;
-}
-
-static void client_append_ip_headers(DHCPPacket *packet, uint16_t len) {
- packet->ip.version = IPVERSION;
- packet->ip.ihl = DHCP_IP_SIZE / 4;
- packet->ip.tot_len = htobe16(len);
-
- packet->ip.protocol = IPPROTO_UDP;
- packet->ip.saddr = INADDR_ANY;
- packet->ip.daddr = INADDR_BROADCAST;
-
- packet->udp.source = htobe16(DHCP_PORT_CLIENT);
- packet->udp.dest = htobe16(DHCP_PORT_SERVER);
- packet->udp.len = htobe16(len - DHCP_IP_SIZE);
-
- packet->ip.check = packet->udp.len;
- packet->udp.check = client_checksum(&packet->ip.ttl, len - 8);
-
- packet->ip.ttl = IPDEFTTL;
- packet->ip.check = 0;
- packet->ip.check = client_checksum(&packet->ip, DHCP_IP_SIZE);
-}
-
-static int client_send_discover(sd_dhcp_client *client, uint16_t secs) {
- int err = 0;
- _cleanup_free_ DHCPPacket *discover;
- size_t optlen, len;
- uint8_t *opt;
-
- optlen = DHCP_CLIENT_MIN_OPTIONS_SIZE;
- len = sizeof(DHCPPacket) + optlen;
-
- discover = malloc0(len);
-
- if (!discover)
- return -ENOMEM;
-
- err = client_packet_init(client, DHCP_DISCOVER, &discover->dhcp,
- secs, &opt, &optlen);
- if (err < 0)
- return err;
-
- if (client->last_addr != INADDR_ANY) {
- err = dhcp_option_append(&opt, &optlen,
- DHCP_OPTION_REQUESTED_IP_ADDRESS,
- 4, &client->last_addr);
- if (err < 0)
- return err;
- }
-
- err = dhcp_option_append(&opt, &optlen, DHCP_OPTION_END, 0, NULL);
- if (err < 0)
- return err;
-
- client_append_ip_headers(discover, len);
-
- err = dhcp_network_send_raw_socket(client->fd, &client->link,
- discover, len);
-
- return err;
-}
-
-static int client_send_request(sd_dhcp_client *client, uint16_t secs) {
- _cleanup_free_ DHCPPacket *request;
- size_t optlen, len;
- int err;
- uint8_t *opt;
-
- optlen = DHCP_CLIENT_MIN_OPTIONS_SIZE;
- len = DHCP_MESSAGE_SIZE + optlen;
-
- request = malloc0(len);
- if (!request)
- return -ENOMEM;
-
- err = client_packet_init(client, DHCP_REQUEST, &request->dhcp, secs,
- &opt, &optlen);
- if (err < 0)
- return err;
-
- if (client->state == DHCP_STATE_REQUESTING) {
- err = dhcp_option_append(&opt, &optlen,
- DHCP_OPTION_REQUESTED_IP_ADDRESS,
- 4, &client->lease->address);
- if (err < 0)
- return err;
-
- err = dhcp_option_append(&opt, &optlen,
- DHCP_OPTION_SERVER_IDENTIFIER,
- 4, &client->lease->server_address);
- if (err < 0)
- return err;
- }
-
- err = dhcp_option_append(&opt, &optlen, DHCP_OPTION_END, 0, NULL);
- if (err < 0)
- return err;
-
- if (client->state == DHCP_STATE_RENEWING) {
- err = dhcp_network_send_udp_socket(client->fd,
- client->lease->server_address,
- &request->dhcp,
- len - DHCP_IP_UDP_SIZE);
- } else {
- client_append_ip_headers(request, len);
-
- err = dhcp_network_send_raw_socket(client->fd, &client->link,
- request, len);
- }
-
- return err;
-}
-
-static int client_timeout_resend(sd_event_source *s, uint64_t usec,
- void *userdata) {
- sd_dhcp_client *client = userdata;
- usec_t next_timeout = 0;
- uint32_t time_left;
- uint16_t secs;
- int r = 0;
-
- assert(s);
- assert(client);
- assert(client->event);
-
- switch (client->state) {
- case DHCP_STATE_RENEWING:
-
- time_left = (client->lease->t2 - client->lease->t1)/2;
- if (time_left < 60)
- time_left = 60;
-
- next_timeout = usec + time_left * USEC_PER_SEC;
-
- break;
-
- case DHCP_STATE_REBINDING:
-
- time_left = (client->lease->lifetime - client->lease->t2)/2;
- if (time_left < 60)
- time_left = 60;
-
- next_timeout = usec + time_left * USEC_PER_SEC;
- break;
-
- case DHCP_STATE_INIT:
- case DHCP_STATE_INIT_REBOOT:
- case DHCP_STATE_REBOOTING:
- case DHCP_STATE_SELECTING:
- case DHCP_STATE_REQUESTING:
- case DHCP_STATE_BOUND:
-
- if (client->attempt < 64)
- client->attempt *= 2;
-
- next_timeout = usec + (client->attempt - 1) * USEC_PER_SEC;
-
- break;
- }
-
- next_timeout += (random_u32() & 0x1fffff);
-
- r = sd_event_add_monotonic(client->event, next_timeout,
- 10 * USEC_PER_MSEC,
- client_timeout_resend, client,
- &client->timeout_resend);
- if (r < 0)
- goto error;
-
- r = sd_event_source_set_priority(client->timeout_resend, client->event_priority);
- if (r < 0)
- goto error;
-
- secs = (usec - client->start_time) / USEC_PER_SEC;
-
- switch (client->state) {
- case DHCP_STATE_INIT:
- r = client_send_discover(client, secs);
- if (r >= 0) {
- client->state = DHCP_STATE_SELECTING;
- client->attempt = 1;
- } else {
- if (client->attempt >= 64)
- goto error;
- }
-
- break;
-
- case DHCP_STATE_SELECTING:
- r = client_send_discover(client, secs);
- if (r < 0 && client->attempt >= 64)
- goto error;
-
- break;
-
- case DHCP_STATE_REQUESTING:
- case DHCP_STATE_RENEWING:
- case DHCP_STATE_REBINDING:
- r = client_send_request(client, secs);
- if (r < 0 && client->attempt >= 64)
- goto error;
-
- client->request_sent = usec;
-
- break;
-
- case DHCP_STATE_INIT_REBOOT:
- case DHCP_STATE_REBOOTING:
- case DHCP_STATE_BOUND:
-
- break;
- }
-
- return 0;
-
-error:
- client_stop(client, r);
-
- /* Errors were dealt with when stopping the client, don't spill
- errors into the event loop handler */
- return 0;
-}
-
-static int client_initialize_events(sd_dhcp_client *client, usec_t usec) {
- int r;
-
- assert(client);
- assert(client->event);
-
- r = sd_event_add_io(client->event, client->fd, EPOLLIN,
- client_receive_message, client,
- &client->receive_message);
- if (r < 0)
- goto error;
-
- r = sd_event_source_set_priority(client->receive_message, client->event_priority);
- if (r < 0)
- goto error;
-
- r = sd_event_add_monotonic(client->event, usec, 0,
- client_timeout_resend, client,
- &client->timeout_resend);
- if (r < 0)
- goto error;
-
- r = sd_event_source_set_priority(client->timeout_resend, client->event_priority);
-
-error:
- if (r < 0)
- client_stop(client, r);
-
- return 0;
-
-}
-
-static int client_timeout_expire(sd_event_source *s, uint64_t usec,
- void *userdata) {
- sd_dhcp_client *client = userdata;
-
- client_stop(client, DHCP_EVENT_EXPIRED);
-
- return 0;
-}
-
-static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) {
- sd_dhcp_client *client = userdata;
- int r;
-
- if (client->fd >= 0) {
- client->receive_message =
- sd_event_source_unref(client->receive_message);
- close(client->fd);
- client->fd = -1;
- }
-
- client->state = DHCP_STATE_REBINDING;
- client->attempt = 1;
-
- r = dhcp_network_bind_raw_socket(client->index, &client->link);
- if (r < 0) {
- client_stop(client, r);
- return 0;
- }
-
- client->fd = r;
-
- return client_initialize_events(client, usec);
-}
-
-static int client_timeout_t1(sd_event_source *s, uint64_t usec, void *userdata) {
- sd_dhcp_client *client = userdata;
- int r;
-
- client->state = DHCP_STATE_RENEWING;
- client->attempt = 1;
-
- r = dhcp_network_bind_udp_socket(client->index,
- client->lease->address);
- if (r < 0) {
- client_stop(client, r);
- return 0;
- }
-
- client->fd = r;
-
- return client_initialize_events(client, usec);
-}
-
-static int client_parse_offer(uint8_t code, uint8_t len, const uint8_t *option,
- void *user_data) {
- DHCPLease *lease = user_data;
- be32_t val;
-
- switch(code) {
-
- case DHCP_OPTION_IP_ADDRESS_LEASE_TIME:
- if (len == 4) {
- memcpy(&val, option, 4);
- lease->lifetime = be32toh(val);
- }
-
- break;
-
- case DHCP_OPTION_SERVER_IDENTIFIER:
- if (len >= 4)
- memcpy(&lease->server_address, option, 4);
-
- break;
-
- case DHCP_OPTION_SUBNET_MASK:
- if (len >= 4)
- memcpy(&lease->subnet_mask, option, 4);
-
- break;
-
- case DHCP_OPTION_ROUTER:
- if (len >= 4)
- memcpy(&lease->router, option, 4);
-
- break;
-
- case DHCP_OPTION_DOMAIN_NAME_SERVER:
- if (len >= 4) {
- unsigned i;
-
- lease->dns_size = len / 4;
-
- free(lease->dns);
- lease->dns = new0(struct in_addr, lease->dns_size);
- if (!lease->dns)
- return -ENOMEM;
-
- for (i = 0; i < lease->dns_size; i++) {
- memcpy(&lease->dns[i].s_addr, option + 4 * i, 4);
- }
- }
-
- break;
-
- case DHCP_OPTION_INTERFACE_MTU:
- if (len >= 2) {
- be16_t mtu;
-
- memcpy(&mtu, option, 2);
- lease->mtu = be16toh(mtu);
-
- if (lease->mtu < 68)
- lease->mtu = 0;
- }
-
- break;
-
- case DHCP_OPTION_DOMAIN_NAME:
- if (len >= 1) {
- free(lease->domainname);
- lease->domainname = strndup((const char *)option, len);
- }
-
- break;
-
- case DHCP_OPTION_HOST_NAME:
- if (len >= 1) {
- free(lease->hostname);
- lease->hostname = strndup((const char *)option, len);
- }
-
- break;
-
- case DHCP_OPTION_RENEWAL_T1_TIME:
- if (len == 4) {
- memcpy(&val, option, 4);
- lease->t1 = be32toh(val);
- }
-
- break;
-
- case DHCP_OPTION_REBINDING_T2_TIME:
- if (len == 4) {
- memcpy(&val, option, 4);
- lease->t2 = be32toh(val);
- }
-
- break;
- }
-
- return 0;
-}
-
-static int client_verify_headers(sd_dhcp_client *client, DHCPPacket *message,
- size_t len) {
- size_t hdrlen;
-
- if (len < (DHCP_IP_UDP_SIZE + DHCP_MESSAGE_SIZE))
- return -EINVAL;
-
- hdrlen = message->ip.ihl * 4;
- if (hdrlen < 20 || hdrlen > len || client_checksum(&message->ip,
- hdrlen))
- return -EINVAL;
-
- message->ip.check = message->udp.len;
- message->ip.ttl = 0;
-
- if (hdrlen + be16toh(message->udp.len) > len ||
- client_checksum(&message->ip.ttl, be16toh(message->udp.len) + 12))
- return -EINVAL;
-
- if (be16toh(message->udp.source) != DHCP_PORT_SERVER ||
- be16toh(message->udp.dest) != DHCP_PORT_CLIENT)
- return -EINVAL;
-
- if (message->dhcp.op != BOOTREPLY)
- return -EINVAL;
-
- if (be32toh(message->dhcp.xid) != client->xid)
- return -EINVAL;
-
- if (memcmp(&message->dhcp.chaddr[0], &client->mac_addr.ether_addr_octet,
- ETHER_ADDR_LEN))
- return -EINVAL;
-
- return 0;
-}
-
-static int client_receive_offer(sd_dhcp_client *client, DHCPPacket *offer,
- size_t len) {
- _cleanup_lease_free_ DHCPLease *lease = NULL;
- int r;
-
- r = client_verify_headers(client, offer, len);
- if (r < 0)
- return r;
-
- lease = new0(DHCPLease, 1);
- if (!lease)
- return -ENOMEM;
-
- len = len - DHCP_IP_UDP_SIZE;
- r = dhcp_option_parse(&offer->dhcp, len, client_parse_offer,
- lease);
- if (r != DHCP_OFFER)
- return -ENOMSG;
-
- lease->address = offer->dhcp.yiaddr;
-
- if (lease->address == INADDR_ANY ||
- lease->server_address == INADDR_ANY ||
- lease->subnet_mask == INADDR_ANY ||
- lease->lifetime == 0)
- return -ENOMSG;
-
- client->lease = lease;
- lease = NULL;
-
- return 0;
-}
-
-static int client_receive_ack(sd_dhcp_client *client, const uint8_t *buf,
- size_t len) {
- DHCPPacket *ack;
- DHCPMessage *dhcp;
- _cleanup_lease_free_ DHCPLease *lease = NULL;
- int r;
-
- if (client->state == DHCP_STATE_RENEWING) {
- dhcp = (DHCPMessage *)buf;
- } else {
- ack = (DHCPPacket *)buf;
-
- r = client_verify_headers(client, ack, len);
- if (r < 0)
- return r;
-
- dhcp = &ack->dhcp;
- len -= DHCP_IP_UDP_SIZE;
- }
-
- lease = new0(DHCPLease, 1);
- if (!lease)
- return -ENOMEM;
-
- r = dhcp_option_parse(dhcp, len, client_parse_offer, lease);
- if (r == DHCP_NAK)
- return DHCP_EVENT_NO_LEASE;
-
- if (r != DHCP_ACK)
- return -ENOMSG;
-
- lease->address = dhcp->yiaddr;
-
- if (lease->address == INADDR_ANY ||
- lease->server_address == INADDR_ANY ||
- lease->subnet_mask == INADDR_ANY || lease->lifetime == 0)
- return -ENOMSG;
-
- r = DHCP_EVENT_IP_ACQUIRE;
- if (client->lease) {
- if (client->lease->address != lease->address ||
- client->lease->subnet_mask != lease->subnet_mask ||
- client->lease->router != lease->router) {
- r = DHCP_EVENT_IP_CHANGE;
- }
-
- lease_free(client->lease);
- }
-
- client->lease = lease;
- lease = NULL;
-
- return r;
-}
-
-static uint64_t client_compute_timeout(uint64_t request_sent,
- uint32_t lifetime) {
- return request_sent + (lifetime - 3) * USEC_PER_SEC +
- + (random_u32() & 0x1fffff);
-}
-
-static int client_set_lease_timeouts(sd_dhcp_client *client, uint64_t usec) {
- uint64_t next_timeout;
- int r;
-
- assert(client);
- assert(client->event);
-
- if (client->lease->lifetime < 10)
- return -EINVAL;
-
- client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
- client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
- client->timeout_expire = sd_event_source_unref(client->timeout_expire);
-
- if (!client->lease->t1)
- client->lease->t1 = client->lease->lifetime / 2;
-
- next_timeout = client_compute_timeout(client->request_sent,
- client->lease->t1);
- if (next_timeout < usec)
- return -EINVAL;
-
- r = sd_event_add_monotonic(client->event, next_timeout,
- 10 * USEC_PER_MSEC,
- client_timeout_t1, client,
- &client->timeout_t1);
- if (r < 0)
- return r;
-
- r = sd_event_source_set_priority(client->timeout_t1, client->event_priority);
- if (r < 0)
- return r;
-
- if (!client->lease->t2)
- client->lease->t2 = client->lease->lifetime * 7 / 8;
-
- if (client->lease->t2 < client->lease->t1)
- return -EINVAL;
-
- if (client->lease->lifetime < client->lease->t2)
- return -EINVAL;
-
- next_timeout = client_compute_timeout(client->request_sent,
- client->lease->t2);
- if (next_timeout < usec)
- return -EINVAL;
-
- r = sd_event_add_monotonic(client->event, next_timeout,
- 10 * USEC_PER_MSEC,
- client_timeout_t2, client,
- &client->timeout_t2);
- if (r < 0)
- return r;
-
- r = sd_event_source_set_priority(client->timeout_t2, client->event_priority);
- if (r < 0)
- return r;
-
- next_timeout = client_compute_timeout(client->request_sent,
- client->lease->lifetime);
- if (next_timeout < usec)
- return -EINVAL;
-
- r = sd_event_add_monotonic(client->event, next_timeout,
- 10 * USEC_PER_MSEC,
- client_timeout_expire, client,
- &client->timeout_expire);
- if (r < 0)
- return r;
-
- r = sd_event_source_set_priority(client->timeout_expire, client->event_priority);
- if (r < 0)
- return r;
-
- return 0;
-}
-
-static int client_receive_message(sd_event_source *s, int fd,
- uint32_t revents, void *userdata) {
- sd_dhcp_client *client = userdata;
- uint8_t buf[sizeof(DHCPPacket) + DHCP_CLIENT_MIN_OPTIONS_SIZE];
- int buflen = sizeof(buf);
- int len, r = 0, notify_event = 0;
- DHCPPacket *message;
- usec_t time_now;
-
- assert(s);
- assert(client);
- assert(client->event);
-
- len = read(fd, &buf, buflen);
- if (len < 0)
- return 0;
-
- r = sd_event_get_now_monotonic(client->event, &time_now);
- if (r < 0)
- goto error;
-
- switch (client->state) {
- case DHCP_STATE_SELECTING:
-
- message = (DHCPPacket *)&buf;
-
- if (client_receive_offer(client, message, len) >= 0) {
-
- client->timeout_resend =
- sd_event_source_unref(client->timeout_resend);
-
- client->state = DHCP_STATE_REQUESTING;
- client->attempt = 1;
-
- r = sd_event_add_monotonic(client->event, time_now, 0,
- client_timeout_resend,
- client,
- &client->timeout_resend);
- if (r < 0)
- goto error;
-
- r = sd_event_source_set_priority(client->timeout_resend, client->event_priority);
- if (r < 0)
- goto error;
- }
-
- break;
-
- case DHCP_STATE_REQUESTING:
- case DHCP_STATE_RENEWING:
- case DHCP_STATE_REBINDING:
-
- r = client_receive_ack(client, buf, len);
-
- if (r == DHCP_EVENT_NO_LEASE)
- goto error;
-
- if (r >= 0) {
- client->timeout_resend =
- sd_event_source_unref(client->timeout_resend);
-
- if (client->state == DHCP_STATE_REQUESTING)
- notify_event = DHCP_EVENT_IP_ACQUIRE;
- else if (r != DHCP_EVENT_IP_ACQUIRE)
- notify_event = r;
-
- client->state = DHCP_STATE_BOUND;
- client->attempt = 1;
-
- client->last_addr = client->lease->address;
-
- r = client_set_lease_timeouts(client, time_now);
- if (r < 0)
- goto error;
-
- if (notify_event)
- client_notify(client, notify_event);
-
- client->receive_message =
- sd_event_source_unref(client->receive_message);
- close(client->fd);
- client->fd = -1;
- }
-
- r = 0;
-
- break;
-
- case DHCP_STATE_INIT:
- case DHCP_STATE_INIT_REBOOT:
- case DHCP_STATE_REBOOTING:
- case DHCP_STATE_BOUND:
-
- break;
- }
-
-error:
- if (r < 0 || r == DHCP_EVENT_NO_LEASE)
- return client_stop(client, r);
-
- return 0;
-}
-
-int sd_dhcp_client_start(sd_dhcp_client *client) {
- int r;
-
- assert_return(client, -EINVAL);
- assert_return(client->event, -EINVAL);
- assert_return(client->index > 0, -EINVAL);
- assert_return(client->state == DHCP_STATE_INIT ||
- client->state == DHCP_STATE_INIT_REBOOT, -EBUSY);
-
- client->xid = random_u32();
-
- r = dhcp_network_bind_raw_socket(client->index, &client->link);
-
- if (r < 0) {
- client_stop(client, r);
- return r;
- }
-
- client->fd = r;
- client->start_time = now(CLOCK_MONOTONIC);
-
- return client_initialize_events(client, client->start_time);
-}
-
-int sd_dhcp_client_stop(sd_dhcp_client *client) {
- return client_stop(client, DHCP_EVENT_STOP);
-}
-
-int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event, int priority) {
- int r;
-
- assert_return(client, -EINVAL);
- assert_return(!client->event, -EBUSY);
-
- if (event)
- client->event = sd_event_ref(event);
- else {
- r = sd_event_default(&client->event);
- if (r < 0)
- return 0;
- }
-
- client->event_priority = priority;
-
- return 0;
-}
-
-int sd_dhcp_client_detach_event(sd_dhcp_client *client) {
- assert_return(client, -EINVAL);
-
- client->event = sd_event_unref(client->event);
-
- return 0;
-}
-
-sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client) {
- if (!client)
- return NULL;
-
- return client->event;
-}
-
-void sd_dhcp_client_free(sd_dhcp_client *client) {
- if (!client)
- return;
-
- sd_dhcp_client_stop(client);
- sd_dhcp_client_detach_event(client);
-
- free(client->req_opts);
- free(client);
-}
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp_client*, sd_dhcp_client_free);
-#define _cleanup_dhcp_client_free_ _cleanup_(sd_dhcp_client_freep)
-
-int sd_dhcp_client_new(sd_dhcp_client **ret) {
- _cleanup_dhcp_client_free_ sd_dhcp_client *client = NULL;
-
- assert_return(ret, -EINVAL);
-
- client = new0(sd_dhcp_client, 1);
- if (!client)
- return -ENOMEM;
-
- client->state = DHCP_STATE_INIT;
- client->index = -1;
- client->fd = -1;
- client->attempt = 1;
-
- client->req_opts_size = ELEMENTSOF(default_req_opts);
-
- client->req_opts = memdup(default_req_opts, client->req_opts_size);
- if (!client->req_opts)
- return -ENOMEM;
-
- *ret = client;
- client = NULL;
-
- return 0;
-}
diff --git a/src/libsystemd/test-dhcp-client.c b/src/libsystemd/test-dhcp-client.c
deleted file mode 100644
index 56a10b3dfc..0000000000
--- a/src/libsystemd/test-dhcp-client.c
+++ /dev/null
@@ -1,243 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright (C) 2013 Intel Corporation. All rights reserved.
-
- systemd is free software; you can redistribute it and/or modify it
- 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 <assert.h>
-#include <errno.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <unistd.h>
-
-#include "util.h"
-#include "socket-util.h"
-
-#include "dhcp-protocol.h"
-#include "dhcp-internal.h"
-#include "sd-dhcp-client.h"
-
-static struct ether_addr mac_addr = {
- .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}
-};
-
-static int test_fd[2];
-
-static void test_request_basic(sd_event *e)
-{
- int r;
-
- sd_dhcp_client *client;
-
- r = sd_dhcp_client_new(&client);
-
- assert(r >= 0);
- assert(client);
-
- r = sd_dhcp_client_attach_event(client, e, 0);
- assert(r >= 0);
-
- assert(sd_dhcp_client_set_request_option(NULL, 0) == -EINVAL);
- assert(sd_dhcp_client_set_request_address(NULL, NULL) == -EINVAL);
- assert(sd_dhcp_client_set_index(NULL, 0) == -EINVAL);
-
- assert(sd_dhcp_client_set_index(client, 15) == 0);
- assert(sd_dhcp_client_set_index(client, -42) == -EINVAL);
- assert(sd_dhcp_client_set_index(client, -1) == 0);
-
- assert(sd_dhcp_client_set_request_option(client,
- DHCP_OPTION_SUBNET_MASK) == -EEXIST);
- assert(sd_dhcp_client_set_request_option(client,
- DHCP_OPTION_ROUTER) == -EEXIST);
- assert(sd_dhcp_client_set_request_option(client,
- DHCP_OPTION_HOST_NAME) == -EEXIST);
- assert(sd_dhcp_client_set_request_option(client,
- DHCP_OPTION_DOMAIN_NAME) == -EEXIST);
- assert(sd_dhcp_client_set_request_option(client,
- DHCP_OPTION_DOMAIN_NAME_SERVER)
- == -EEXIST);
- assert(sd_dhcp_client_set_request_option(client,
- DHCP_OPTION_NTP_SERVER) == -EEXIST);
-
- assert(sd_dhcp_client_set_request_option(client,
- DHCP_OPTION_PAD) == -EINVAL);
- assert(sd_dhcp_client_set_request_option(client,
- DHCP_OPTION_END) == -EINVAL);
- assert(sd_dhcp_client_set_request_option(client,
- DHCP_OPTION_MESSAGE_TYPE) == -EINVAL);
- assert(sd_dhcp_client_set_request_option(client,
- DHCP_OPTION_OVERLOAD) == -EINVAL);
- assert(sd_dhcp_client_set_request_option(client,
- DHCP_OPTION_PARAMETER_REQUEST_LIST)
- == -EINVAL);
-
- assert(sd_dhcp_client_set_request_option(client, 33) == 0);
- assert(sd_dhcp_client_set_request_option(client, 33) == -EEXIST);
- assert(sd_dhcp_client_set_request_option(client, 44) == 0);
- assert(sd_dhcp_client_set_request_option(client, 33) == -EEXIST);
-}
-
-static uint16_t client_checksum(void *buf, int len)
-{
- uint32_t sum;
- uint16_t *check;
- int i;
- uint8_t *odd;
-
- sum = 0;
- check = buf;
-
- for (i = 0; i < len / 2 ; i++)
- sum += check[i];
-
- if (len & 0x01) {
- odd = buf;
- sum += odd[len - 1];
- }
-
- while (sum >> 16)
- sum = (sum & 0xffff) + (sum >> 16);
-
- return ~sum;
-}
-
-static void test_checksum(void)
-{
- uint8_t buf[20] = {
- 0x45, 0x00, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00,
- 0x40, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xff, 0xff, 0xff, 0xff
- };
-
- assert(client_checksum(&buf, 20) == be16toh(0x78ae));
-}
-
-static int check_options(uint8_t code, uint8_t len, const uint8_t *option,
- void *user_data)
-{
- return 0;
-}
-
-int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link,
- const void *packet, size_t len)
-{
- size_t size;
- _cleanup_free_ DHCPPacket *discover;
- uint16_t ip_check, udp_check;
- int res;
-
- assert(s >= 0);
- assert(packet);
-
- size = sizeof(DHCPPacket) + 4;
- assert(len > size);
-
- discover = memdup(packet, len);
-
- assert(memcmp(discover->dhcp.chaddr,
- &mac_addr.ether_addr_octet, 6) == 0);
- assert(discover->ip.ttl == IPDEFTTL);
- assert(discover->ip.protocol == IPPROTO_UDP);
- assert(discover->ip.saddr == INADDR_ANY);
- assert(discover->ip.daddr == INADDR_BROADCAST);
- assert(discover->udp.source == be16toh(DHCP_PORT_CLIENT));
- assert(discover->udp.dest == be16toh(DHCP_PORT_SERVER));
-
- ip_check = discover->ip.check;
-
- discover->ip.ttl = 0;
- discover->ip.check = discover->udp.len;
-
- udp_check = ~client_checksum(&discover->ip.ttl, len - 8);
- assert(udp_check == 0xffff);
-
- discover->ip.ttl = IPDEFTTL;
- discover->ip.check = ip_check;
-
- ip_check = ~client_checksum(&discover->ip, sizeof(discover->ip));
- assert(ip_check == 0xffff);
-
- size = len - sizeof(struct iphdr) - sizeof(struct udphdr);
-
- res = dhcp_option_parse(&discover->dhcp, size, check_options, NULL);
- if (res < 0)
- return res;
-
- return 575;
-}
-
-int dhcp_network_bind_raw_socket(int index, union sockaddr_union *link)
-{
- if (socketpair(AF_UNIX, SOCK_STREAM, 0, test_fd) < 0)
- return -errno;
-
- return test_fd[0];
-}
-
-int dhcp_network_bind_udp_socket(int index, be32_t client_address)
-{
- return 0;
-}
-
-int dhcp_network_send_udp_socket(int s, be32_t server_address,
- const void *packet, size_t len)
-{
- return 0;
-}
-
-static void test_discover_message(sd_event *e)
-{
- sd_dhcp_client *client;
- int res, r;
-
- r = sd_dhcp_client_new(&client);
- assert(r >= 0);
- assert(client);
-
- r = sd_dhcp_client_attach_event(client, e, 0);
- assert(r >= 0);
-
- assert(sd_dhcp_client_set_index(client, 42) >= 0);
- assert(sd_dhcp_client_set_mac(client, &mac_addr) >= 0);
-
- assert(sd_dhcp_client_set_request_option(client, 248) >= 0);
-
- res = sd_dhcp_client_start(client);
-
- assert(res == 0 || res == -EINPROGRESS);
-
- close(test_fd[0]);
- close(test_fd[1]);
-}
-
-int main(int argc, char *argv[])
-{
- sd_event *e;
-
- assert(sd_event_new(&e) >= 0);
-
- test_request_basic(e);
- test_checksum();
-
- test_discover_message(e);
- sd_event_run(e, (uint64_t) -1);
-
- return 0;
-}
diff --git a/src/libsystemd/test-dhcp-option.c b/src/libsystemd/test-dhcp-option.c
deleted file mode 100644
index ac0b0a435a..0000000000
--- a/src/libsystemd/test-dhcp-option.c
+++ /dev/null
@@ -1,378 +0,0 @@
-
-#include <stdio.h>
-#include <stdbool.h>
-#include <errno.h>
-#include <string.h>
-#include <assert.h>
-
-#include "util.h"
-#include "macro.h"
-
-#include "dhcp-protocol.h"
-#include "dhcp-internal.h"
-
-struct option_desc {
- uint8_t sname[64];
- int snamelen;
- uint8_t file[128];
- int filelen;
- uint8_t options[128];
- int len;
- bool success;
- int filepos;
- int snamepos;
- int pos;
-};
-
-static bool verbose = false;
-
-static struct option_desc option_tests[] = {
- { {}, 0, {}, 0, { 42, 5, 65, 66, 67, 68, 69 }, 7, false, },
- { {}, 0, {}, 0, { 42, 5, 65, 66, 67, 68, 69, 0, 0,
- DHCP_OPTION_MESSAGE_TYPE, 1, DHCP_ACK }, 12, true, },
- { {}, 0, {}, 0, { 8, 255, 70, 71, 72 }, 5, false, },
- { {}, 0, {}, 0, { 0x35, 0x01, 0x05, 0x36, 0x04, 0x01, 0x00, 0xa8,
- 0xc0, 0x33, 0x04, 0x00, 0x01, 0x51, 0x80, 0x01,
- 0x04, 0xff, 0xff, 0xff, 0x00, 0x03, 0x04, 0xc0,
- 0xa8, 0x00, 0x01, 0x06, 0x04, 0xc0, 0xa8, 0x00,
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
- 40, true, },
- { {}, 0, {}, 0, { DHCP_OPTION_MESSAGE_TYPE, 1, DHCP_OFFER,
- 42, 3, 0, 0, 0 }, 8, true, },
- { {}, 0, {}, 0, { 42, 2, 1, 2, 44 }, 5, false, },
-
- { {}, 0,
- { 222, 3, 1, 2, 3, DHCP_OPTION_MESSAGE_TYPE, 1, DHCP_NAK }, 8,
- { DHCP_OPTION_OVERLOAD, 1, DHCP_OVERLOAD_FILE }, 3, true, },
-
- { { 1, 4, 1, 2, 3, 4, DHCP_OPTION_MESSAGE_TYPE, 1, DHCP_ACK }, 9,
- { 222, 3, 1, 2, 3 }, 5,
- { DHCP_OPTION_OVERLOAD, 1,
- DHCP_OVERLOAD_FILE|DHCP_OVERLOAD_SNAME }, 3, true, },
-};
-
-static const char *dhcp_type(int type)
-{
- switch(type) {
- case DHCP_DISCOVER:
- return "DHCPDISCOVER";
- case DHCP_OFFER:
- return "DHCPOFFER";
- case DHCP_REQUEST:
- return "DHCPREQUEST";
- case DHCP_DECLINE:
- return "DHCPDECLINE";
- case DHCP_ACK:
- return "DHCPACK";
- case DHCP_NAK:
- return "DHCPNAK";
- case DHCP_RELEASE:
- return "DHCPRELEASE";
- default:
- return "unknown";
- }
-}
-
-static void test_invalid_buffer_length(void)
-{
- DHCPMessage message;
-
- assert(dhcp_option_parse(&message, 0, NULL, NULL) == -EINVAL);
- assert(dhcp_option_parse(&message, sizeof(DHCPMessage), NULL, NULL)
- == -EINVAL);
-}
-
-static void test_cookie(void)
-{
- _cleanup_free_ DHCPMessage *message;
- size_t len = sizeof(DHCPMessage) + 4;
- uint8_t *opt;
-
- message = malloc0(len);
-
- opt = (uint8_t *)(message + 1);
- opt[0] = 0xff;
-
- assert(dhcp_option_parse(message, len, NULL, NULL) == -EINVAL);
-
- opt[0] = 99;
- opt[1] = 130;
- opt[2] = 83;
- opt[3] = 99;
-
- assert(dhcp_option_parse(message, len, NULL, NULL) == -ENOMSG);
-}
-
-static DHCPMessage *create_message(uint8_t *options, uint16_t optlen,
- uint8_t *file, uint8_t filelen,
- uint8_t *sname, uint8_t snamelen)
-{
- DHCPMessage *message;
- size_t len = sizeof(DHCPMessage) + 4 + optlen;
- uint8_t *opt;
-
- message = malloc0(len);
- opt = (uint8_t *)(message + 1);
-
- opt[0] = 99;
- opt[1] = 130;
- opt[2] = 83;
- opt[3] = 99;
-
- if (options && optlen)
- memcpy(&opt[4], options, optlen);
-
- if (file && filelen <= 128)
- memcpy(&message->file, file, filelen);
-
- if (sname && snamelen <= 64)
- memcpy(&message->sname, sname, snamelen);
-
- return message;
-}
-
-static void test_ignore_opts(uint8_t *descoption, int *descpos, int *desclen)
-{
- while (*descpos < *desclen) {
- switch(descoption[*descpos]) {
- case DHCP_OPTION_PAD:
- *descpos += 1;
- break;
-
- case DHCP_OPTION_MESSAGE_TYPE:
- case DHCP_OPTION_OVERLOAD:
- *descpos += 3;
- break;
-
- default:
- return;
- }
- }
-}
-
-static int test_options_cb(uint8_t code, uint8_t len, const uint8_t *option,
- void *user_data)
-{
- struct option_desc *desc = user_data;
- uint8_t *descoption = NULL;
- int *desclen = NULL, *descpos = NULL;
- uint8_t optcode = 0;
- uint8_t optlen = 0;
- uint8_t i;
-
- assert((!desc && !code && !len) || desc);
-
- if (!desc)
- return -EINVAL;
-
- assert(code != DHCP_OPTION_PAD);
- assert(code != DHCP_OPTION_END);
- assert(code != DHCP_OPTION_MESSAGE_TYPE);
- assert(code != DHCP_OPTION_OVERLOAD);
-
- while (desc->pos >= 0 || desc->filepos >= 0 || desc->snamepos >= 0) {
-
- if (desc->pos >= 0) {
- descoption = &desc->options[0];
- desclen = &desc->len;
- descpos = &desc->pos;
- } else if (desc->filepos >= 0) {
- descoption = &desc->file[0];
- desclen = &desc->filelen;
- descpos = &desc->filepos;
- } else if (desc->snamepos >= 0) {
- descoption = &desc->sname[0];
- desclen = &desc->snamelen;
- descpos = &desc->snamepos;
- }
-
- assert(descoption && desclen && descpos);
-
- if (*desclen)
- test_ignore_opts(descoption, descpos, desclen);
-
- if (*descpos < *desclen)
- break;
-
- if (*descpos == *desclen)
- *descpos = -1;
- }
-
- assert(descpos);
- assert(*descpos != -1);
-
- optcode = descoption[*descpos];
- optlen = descoption[*descpos + 1];
-
- if (verbose)
- printf("DHCP code %2d(%2d) len %2d(%2d) ", code, optcode,
- len, optlen);
-
- assert(code == optcode);
- assert(len == optlen);
-
- for (i = 0; i < len; i++) {
-
- if (verbose)
- printf("0x%02x(0x%02x) ", option[i],
- descoption[*descpos + 2 + i]);
-
- assert(option[i] == descoption[*descpos + 2 + i]);
- }
-
- if (verbose)
- printf("\n");
-
- *descpos += optlen + 2;
-
- test_ignore_opts(descoption, descpos, desclen);
-
- if (desc->pos != -1 && desc->pos == desc->len)
- desc->pos = -1;
-
- if (desc->filepos != -1 && desc->filepos == desc->filelen)
- desc->filepos = -1;
-
- if (desc->snamepos != -1 && desc->snamepos == desc->snamelen)
- desc->snamepos = -1;
-
- return 0;
-}
-
-static void test_options(struct option_desc *desc)
-{
- uint8_t *options = NULL;
- uint8_t *file = NULL;
- uint8_t *sname = NULL;
- int optlen = 0;
- int filelen = 0;
- int snamelen = 0;
- int buflen = 0;
- _cleanup_free_ DHCPMessage *message;
- int res;
-
- if (desc) {
- file = &desc->file[0];
- filelen = desc->filelen;
- if (!filelen)
- desc->filepos = -1;
-
- sname = &desc->sname[0];
- snamelen = desc->snamelen;
- if (!snamelen)
- desc->snamepos = -1;
-
- options = &desc->options[0];
- optlen = desc->len;
- desc->pos = 0;
- }
- message = create_message(options, optlen, file, filelen,
- sname, snamelen);
-
- buflen = sizeof(DHCPMessage) + 4 + optlen;
-
- if (!desc) {
- assert((res = dhcp_option_parse(message, buflen,
- test_options_cb,
- NULL)) == -ENOMSG);
- } else if (desc->success) {
- assert((res = dhcp_option_parse(message, buflen,
- test_options_cb,
- desc)) >= 0);
- assert(desc->pos == -1 && desc->filepos == -1 &&
- desc->snamepos == -1);
- } else
- assert((res = dhcp_option_parse(message, buflen,
- test_options_cb,
- desc)) < 0);
-
- if (verbose)
- printf("DHCP type %s\n", dhcp_type(res));
-}
-
-static uint8_t result[64] = {
- 'A', 'B', 'C', 'D',
-};
-
-static uint8_t options[64] = {
- 'A', 'B', 'C', 'D',
- 160, 2, 0x11, 0x12,
- 0,
- 31, 8, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
- 0,
- 55, 3, 0x51, 0x52, 0x53,
- 17, 7, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
- 255
-};
-
-static void test_option_set(void)
-{
- size_t len, oldlen;
- int pos, i;
- uint8_t *opt;
-
- assert(dhcp_option_append(NULL, NULL, 0, 0, NULL) == -EINVAL);
-
- len = 0;
- opt = &result[0];
- assert(dhcp_option_append(&opt, NULL, 0, 0, NULL) == -EINVAL);
- assert(opt == &result[0] && len == 0);
-
- assert(dhcp_option_append(&opt, &len, DHCP_OPTION_PAD,
- 0, NULL) == -ENOBUFS);
- assert(opt == &result[0] && len == 0);
-
- opt = &result[4];
- len = 1;
- assert(dhcp_option_append(&opt, &len, DHCP_OPTION_PAD,
- 0, NULL) >= 0);
- assert(opt == &result[5] && len == 0);
-
- pos = 4;
- len = 60;
- while (pos < 64 && options[pos] != DHCP_OPTION_END) {
- opt = &result[pos];
- oldlen = len;
-
- assert(dhcp_option_append(&opt, &len, options[pos],
- options[pos + 1],
- &options[pos + 2]) >= 0);
-
- if (options[pos] == DHCP_OPTION_PAD) {
- assert(opt == &result[pos + 1]);
- assert(len == oldlen - 1);
- pos++;
- } else {
- assert(opt == &result[pos + 2 + options[pos + 1]]);
- assert(len == oldlen - 2 - options[pos + 1]);
- pos += 2 + options[pos + 1];
- }
- }
-
- for (i = 0; i < pos; i++) {
- if (verbose)
- printf("%2d: 0x%02x(0x%02x)\n", i, result[i],
- options[i]);
- assert(result[i] == options[i]);
- }
-
- if (verbose)
- printf ("\n");
-}
-
-int main(int argc, char *argv[])
-{
- unsigned int i;
-
- test_invalid_buffer_length();
- test_cookie();
-
- test_options(NULL);
-
- for (i = 0; i < ELEMENTSOF(option_tests); i++)
- test_options(&option_tests[i]);
-
- test_option_set();
-
- return 0;
-}