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

Tom Gundersen teg at jklm.no
Tue May 27 08:55:57 PDT 2014


On Tue, May 27, 2014 at 5:41 PM, Zbigniew Jędrzejewski-Szmek
<zbyszek at in.waw.pl> wrote:
> 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 :)

Ha, indeed. I started out with 10 seconds, but watching wireshark was
not possible at that speed :)

>> +        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.

Hm, yes, you are right. We should just make sure that
server_send_offer can only fail with critical errors and then return r
here (same goes for the other server_send_*() methods later in the
patches.

>> +                        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