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

Zbigniew Jędrzejewski-Szmek zbyszek at in.waw.pl
Tue May 27 08:41:34 PDT 2014


On Mon, May 26, 2014 at 09:39:39PM +0200, Tom Gundersen wrote:
> ---
>  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 */
The comment appears to be out of date already, it's 60 :)

> +        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));
The error is logged at debug level, but otherwise ignored. Is this enough? It seems that if
server_send_offer() fails, things are significantly off.

> +                        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);
>  }

Zbyszek


More information about the systemd-devel mailing list