[systemd-devel] [PATCH 10/17] sd-dhcp-server: add basic DISCOVER/OFFER support

Tom Gundersen teg at jklm.no
Mon May 26 12:39:39 PDT 2014


---
 src/libsystemd-network/sd-dhcp-server.c   | 81 ++++++++++++++++++++++++++++++-
 src/libsystemd-network/test-dhcp-server.c | 14 +++---
 2 files changed, 86 insertions(+), 9 deletions(-)

diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c
index cea7390..be6938b 100644
--- a/src/libsystemd-network/sd-dhcp-server.c
+++ b/src/libsystemd-network/sd-dhcp-server.c
@@ -27,6 +27,8 @@
 #include "dhcp-server-internal.h"
 #include "dhcp-internal.h"
 
+#define DHCP_DEFAULT_LEASE_TIME         60
+
 int sd_dhcp_server_set_address(sd_dhcp_server *server, struct in_addr *address) {
         assert_return(server, -EINVAL);
         assert_return(address, -EINVAL);
@@ -277,6 +279,64 @@ int dhcp_server_send_packet(sd_dhcp_server *server,
                                                     sizeof(DHCPPacket) + optoffset);
 }
 
+static int server_message_init(sd_dhcp_server *server, DHCPPacket **ret,
+                               uint8_t type, size_t *_optoffset, DHCPRequest *req) {
+        _cleanup_free_ DHCPPacket *packet = NULL;
+        size_t optoffset;
+        int r;
+
+        assert(server);
+        assert(ret);
+        assert(_optoffset);
+        assert(type == DHCP_OFFER);
+
+        packet = malloc0(sizeof(DHCPPacket) + req->max_optlen);
+        if (!packet)
+                return -ENOMEM;
+
+        r = dhcp_message_init(&packet->dhcp, BOOTREPLY, be32toh(req->message->xid),
+                              type, req->max_optlen, &optoffset);
+        if (r < 0)
+                return r;
+
+        packet->dhcp.flags = req->message->flags;
+        packet->dhcp.giaddr = req->message->giaddr;
+        memcpy(&packet->dhcp.chaddr, &req->message->chaddr, ETH_ALEN);
+
+        *_optoffset = optoffset;
+        *ret = packet;
+        packet = NULL;
+
+        return 0;
+}
+
+static int server_send_offer(sd_dhcp_server *server, DHCPRequest *req) {
+        _cleanup_free_ DHCPPacket *packet = NULL;
+        size_t offset;
+        be32_t lease_time;
+        int r;
+
+        r = server_message_init(server, &packet, DHCP_OFFER, &offset, req);
+        if (r < 0)
+                return r;
+
+        /* for now offer a random IP */
+        packet->dhcp.yiaddr = random_u32();
+
+        /* for ten seconds */
+        lease_time = htobe32(DHCP_DEFAULT_LEASE_TIME);
+        r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
+                               DHCP_OPTION_IP_ADDRESS_LEASE_TIME, 4, &lease_time);
+        if (r < 0)
+                return r;
+
+        r = dhcp_server_send_packet(server, req, packet, DHCP_OFFER, offset);
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
 static int parse_request(uint8_t code, uint8_t len, const uint8_t *option,
                          void *user_data) {
         DHCPRequest *req = user_data;
@@ -377,9 +437,26 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message,
                 /* this only fails on critical errors */
                 return r;
 
-        log_dhcp_server(server, "received message of type %d", type);
+        switch(type) {
+        case DHCP_DISCOVER:
+                log_dhcp_server(server, "DISCOVER (0x%x)",
+                                be32toh(req->message->xid));
+
+                r = server_send_offer(server, req);
+                if (r < 0) {
+                        log_dhcp_server(server, "could not send offer: %s",
+                                        strerror(-r));
+                        return 0;
+                } else {
+                        log_dhcp_server(server, "OFFER (0x%x)",
+                                        be32toh(req->message->xid));
+                        return DHCP_OFFER;
+                }
+
+                break;
+        }
 
-        return 1;
+        return 0;
 }
 
 static int server_receive_message(sd_event_source *s, int fd,
diff --git a/src/libsystemd-network/test-dhcp-server.c b/src/libsystemd-network/test-dhcp-server.c
index 0cbb4df..ed3aaf9 100644
--- a/src/libsystemd-network/test-dhcp-server.c
+++ b/src/libsystemd-network/test-dhcp-server.c
@@ -94,13 +94,13 @@ static void test_message_handler(void) {
         assert_se(sd_dhcp_server_attach_event(server, NULL, 0) >= 0);
         assert_se(sd_dhcp_server_start(server) >= 0);
 
-        assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 1);
+        assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_OFFER);
 
         test.end = 0;
         /* TODO, shouldn't this fail? */
-        assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 1);
+        assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_OFFER);
         test.end = DHCP_OPTION_END;
-        assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 1);
+        assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_OFFER);
 
         test.option_type.code = 0;
         test.option_type.length = 0;
@@ -109,22 +109,22 @@ static void test_message_handler(void) {
         test.option_type.code = DHCP_OPTION_MESSAGE_TYPE;
         test.option_type.length = 1;
         test.option_type.type = DHCP_DISCOVER;
-        assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 1);
+        assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_OFFER);
 
         test.message.op = 0;
         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 0);
         test.message.op = BOOTREQUEST;
-        assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 1);
+        assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_OFFER);
 
         test.message.htype = 0;
         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 0);
         test.message.htype = ARPHRD_ETHER;
-        assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 1);
+        assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_OFFER);
 
         test.message.hlen = 0;
         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 0);
         test.message.hlen = ETHER_ADDR_LEN;
-        assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 1);
+        assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_OFFER);
 }
 
 int main(int argc, char *argv[]) {
-- 
1.9.0



More information about the systemd-devel mailing list