On Tue, May 27, 2014 at 5:48 PM, Zbigniew Jędrzejewski-Szmek <zbys...@in.waw.pl> wrote: > On Mon, May 26, 2014 at 09:39:40PM +0200, Tom Gundersen wrote: >> --- >> src/libsystemd-network/dhcp-server-internal.h | 3 + >> src/libsystemd-network/sd-dhcp-server.c | 135 >> +++++++++++++++++++++++++- >> src/libsystemd-network/test-dhcp-server.c | 37 +++++++ >> src/systemd/sd-dhcp-server.h | 1 + >> 4 files changed, 171 insertions(+), 5 deletions(-) >> >> diff --git a/src/libsystemd-network/dhcp-server-internal.h >> b/src/libsystemd-network/dhcp-server-internal.h >> index 381304e..cd480e7 100644 >> --- a/src/libsystemd-network/dhcp-server-internal.h >> +++ b/src/libsystemd-network/dhcp-server-internal.h >> @@ -40,6 +40,8 @@ struct sd_dhcp_server { >> >> int index; >> be32_t address; >> + be32_t pool_start; >> + size_t pool_size; >> }; >> >> typedef struct DHCPClientId { >> @@ -55,6 +57,7 @@ typedef struct DHCPRequest { >> DHCPClientId client_id; >> size_t max_optlen; >> be32_t server_id; >> + be32_t requested_ip; >> } DHCPRequest; >> >> DEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp_server*, sd_dhcp_server_unref); >> diff --git a/src/libsystemd-network/sd-dhcp-server.c >> b/src/libsystemd-network/sd-dhcp-server.c >> index be6938b..01cd8be 100644 >> --- a/src/libsystemd-network/sd-dhcp-server.c >> +++ b/src/libsystemd-network/sd-dhcp-server.c >> @@ -29,6 +29,21 @@ >> >> #define DHCP_DEFAULT_LEASE_TIME 60 >> >> +int sd_dhcp_server_set_lease_pool(sd_dhcp_server *server, struct in_addr >> *address, >> + size_t size) { >> + assert_return(server, -EINVAL); >> + assert_return(address, -EINVAL); >> + assert_return(address->s_addr, -EINVAL); >> + assert_return(size, -EINVAL); >> + assert_return(server->pool_start == htobe32(INADDR_ANY), -EBUSY); >> + assert_return(!server->pool_size, -EBUSY); >> + >> + server->pool_start = address->s_addr; >> + server->pool_size = size; >> + >> + return 0; >> +} >> + >> int sd_dhcp_server_set_address(sd_dhcp_server *server, struct in_addr >> *address) { >> assert_return(server, -EINVAL); >> assert_return(address, -EINVAL); >> @@ -288,7 +303,7 @@ static int server_message_init(sd_dhcp_server *server, >> DHCPPacket **ret, >> assert(server); >> assert(ret); >> assert(_optoffset); >> - assert(type == DHCP_OFFER); >> + assert(IN_SET(type, DHCP_OFFER, DHCP_ACK)); >> >> packet = malloc0(sizeof(DHCPPacket) + req->max_optlen); >> if (!packet) >> @@ -310,7 +325,7 @@ static int server_message_init(sd_dhcp_server *server, >> DHCPPacket **ret, >> return 0; >> } >> >> -static int server_send_offer(sd_dhcp_server *server, DHCPRequest *req) { >> +static int server_send_offer(sd_dhcp_server *server, DHCPRequest *req, >> be32_t address) { >> _cleanup_free_ DHCPPacket *packet = NULL; >> size_t offset; >> be32_t lease_time; >> @@ -320,8 +335,7 @@ static int server_send_offer(sd_dhcp_server *server, >> DHCPRequest *req) { >> if (r < 0) >> return r; >> >> - /* for now offer a random IP */ >> - packet->dhcp.yiaddr = random_u32(); >> + packet->dhcp.yiaddr = address; >> >> /* for ten seconds */ >> lease_time = htobe32(DHCP_DEFAULT_LEASE_TIME); >> @@ -337,6 +351,32 @@ static int server_send_offer(sd_dhcp_server *server, >> DHCPRequest *req) { >> return 0; >> } >> >> +static int server_send_ack(sd_dhcp_server *server, DHCPRequest *req, be32_t >> address) { >> + _cleanup_free_ DHCPPacket *packet = NULL; >> + size_t offset; >> + be32_t lease_time; >> + int r; >> + >> + r = server_message_init(server, &packet, DHCP_ACK, &offset, req); >> + if (r < 0) >> + return r; >> + >> + packet->dhcp.yiaddr = address; >> + >> + /* 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_ACK, 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; >> @@ -344,6 +384,11 @@ static int parse_request(uint8_t code, uint8_t len, >> const uint8_t *option, >> assert(req); >> >> switch(code) { >> + case DHCP_OPTION_REQUESTED_IP_ADDRESS: >> + if (len == 4) >> + req->requested_ip = *(be32_t*)option; >> + >> + break; >> case DHCP_OPTION_SERVER_IDENTIFIER: >> if (len == 4) >> req->server_id = *(be32_t*)option; >> @@ -439,10 +484,21 @@ int dhcp_server_handle_message(sd_dhcp_server *server, >> DHCPMessage *message, >> >> switch(type) { >> case DHCP_DISCOVER: >> + { >> + be32_t address; >> + >> log_dhcp_server(server, "DISCOVER (0x%x)", >> be32toh(req->message->xid)); >> >> - r = server_send_offer(server, req); >> + if (!server->pool_size) >> + /* no pool allocated */ >> + return 0; >> + >> + /* for now pick a random address from the pool */ >> + address = htobe32(be32toh(server->pool_start) + >> + (random_u32() % server->pool_size)); >> + >> + r = server_send_offer(server, req, address); >> if (r < 0) { >> log_dhcp_server(server, "could not send offer: %s", >> strerror(-r)); >> @@ -455,6 +511,75 @@ int dhcp_server_handle_message(sd_dhcp_server *server, >> DHCPMessage *message, >> >> break; >> } >> + case DHCP_REQUEST: >> + { >> + be32_t address; >> + >> + /* see RFC 2131, section 4.3.2 */ >> + >> + if (req->server_id) { >> + log_dhcp_server(server, "REQUEST (selecting) >> (0x%x)", >> + be32toh(req->message->xid)); >> + >> + /* SELECTING */ >> + if (req->server_id != server->address) >> + /* client did not pick us */ >> + return 0; >> + >> + if (req->message->ciaddr) >> + /* this MUST be zero */ >> + return 0; >> + >> + if (!req->requested_ip) >> + /* this must be filled in with the yiaddr >> + from the chosen OFFER */ >> + return 0; >> + >> + address = req->requested_ip; >> + } else if (req->requested_ip) { >> + log_dhcp_server(server, "REQUEST (init-reboot) >> (0x%x)", >> + be32toh(req->message->xid)); >> + >> + /* INIT-REBOOT */ >> + if (req->message->ciaddr) >> + /* this MUST be zero */ >> + return 0; >> + >> + /* TODO: check if requested IP is correct, NAK if >> not */ >> + address = req->requested_ip; >> + } else { >> + log_dhcp_server(server, "REQUEST >> (rebinding/renewing) (0x%x)", >> + be32toh(req->message->xid)); >> + >> + /* REBINDING / RENEWING */ >> + if (!req->message->ciaddr) >> + /* this MUST be filled in with clients IP >> address */ >> + return 0; >> + >> + address = req->message->ciaddr; >> + } >> + >> + /* for now we just verify that the address is from the >> pool, not >> + whether or not it is taken */ >> + if (htobe32(req->requested_ip) >= >> htobe32(server->pool_start) && >> + htobe32(req->requested_ip) < >> htobe32(server->pool_start) + >> + + server->pool_size) { >> + r = server_send_ack(server, req, address); >> + if (r < 0) { >> + log_dhcp_server(server, "could not send >> ack: %s", >> + strerror(-r)); >> + return 0; >> + } else { >> + log_dhcp_server(server, "ACK (0x%x)", >> + be32toh(req->message->xid)); >> + return DHCP_ACK; >> + } >> + } else >> + return 0; >> + >> + break; >> + } >> + } > Should this closing brace be here? (hard to see in the diff format)
Yeah, that's correct. These two close: switch(type) { case DHCP_DISCOVER: { from above. Probably I could improve the indentation here... -t >> return 0; >> } >> diff --git a/src/libsystemd-network/test-dhcp-server.c >> b/src/libsystemd-network/test-dhcp-server.c >> index ed3aaf9..7255a69 100644 >> --- a/src/libsystemd-network/test-dhcp-server.c >> +++ b/src/libsystemd-network/test-dhcp-server.c >> @@ -59,6 +59,11 @@ static void test_basic(sd_event *event) { >> assert_se(sd_dhcp_server_set_address(server, &address_lo) >= 0); >> assert_se(sd_dhcp_server_set_address(server, &address_lo) == >> -EBUSY); >> >> + assert_se(sd_dhcp_server_set_lease_pool(server, &address_any, 1) == >> -EINVAL); >> + assert_se(sd_dhcp_server_set_lease_pool(server, &address_lo, 0) == >> -EINVAL); >> + assert_se(sd_dhcp_server_set_lease_pool(server, &address_lo, 1) >= >> 0); >> + assert_se(sd_dhcp_server_set_lease_pool(server, &address_lo, 1) == >> -EBUSY); >> + >> assert_se(sd_dhcp_server_start(server) >= 0); >> assert_se(sd_dhcp_server_start(server) == -EBUSY); >> assert_se(sd_dhcp_server_stop(server) >= 0); >> @@ -75,11 +80,23 @@ static void test_message_handler(void) { >> uint8_t length; >> uint8_t type; >> } _packed_ option_type; >> + struct { >> + uint8_t code; >> + uint8_t length; >> + be32_t address; >> + } _packed_ option_requested_ip; >> + struct { >> + uint8_t code; >> + uint8_t length; >> + be32_t address; >> + } _packed_ option_server_id; >> uint8_t end; >> } _packed_ test = { >> .message.op = BOOTREQUEST, >> .message.htype = ARPHRD_ETHER, >> .message.hlen = ETHER_ADDR_LEN, >> + .message.xid = htobe32(0x12345678), >> + .message.chaddr = { 'A', 'B', 'C', 'D', 'E', 'F' }, >> .option_type.code = DHCP_OPTION_MESSAGE_TYPE, >> .option_type.length = 1, >> .option_type.type = DHCP_DISCOVER, >> @@ -94,6 +111,8 @@ 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)) == 0); >> + assert_se(sd_dhcp_server_set_lease_pool(server, &address_lo, 10) >= >> 0); >> assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, >> sizeof(test)) == DHCP_OFFER); >> >> test.end = 0; >> @@ -125,6 +144,24 @@ static void test_message_handler(void) { >> 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)) == DHCP_OFFER); >> + >> + test.option_type.type = DHCP_REQUEST; >> + assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, >> sizeof(test)) == 0); >> + test.option_requested_ip.code = DHCP_OPTION_REQUESTED_IP_ADDRESS; >> + test.option_requested_ip.length = 4; >> + test.option_requested_ip.address = htobe32(0x12345678); >> + assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, >> sizeof(test)) == 0); >> + test.option_server_id.code = DHCP_OPTION_SERVER_IDENTIFIER; >> + test.option_server_id.length = 4; >> + test.option_server_id.address = htobe32(INADDR_LOOPBACK); >> + test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 3); >> + assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, >> sizeof(test)) == DHCP_ACK); >> + test.option_server_id.address = htobe32(0x12345678); >> + test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 3); >> + assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, >> sizeof(test)) == 0); >> + test.option_server_id.address = htobe32(INADDR_LOOPBACK + 3); >> + test.option_requested_ip.address = htobe32(0x12345678); >> + assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, >> sizeof(test)) == 0); >> } >> >> int main(int argc, char *argv[]) { >> diff --git a/src/systemd/sd-dhcp-server.h b/src/systemd/sd-dhcp-server.h >> index 5edeffc..cd0ff72 100644 >> --- a/src/systemd/sd-dhcp-server.h >> +++ b/src/systemd/sd-dhcp-server.h >> @@ -42,4 +42,5 @@ int sd_dhcp_server_start(sd_dhcp_server *server); >> int sd_dhcp_server_stop(sd_dhcp_server *server); >> >> int sd_dhcp_server_set_address(sd_dhcp_server *server, struct in_addr >> *address); >> +int sd_dhcp_server_set_lease_pool(sd_dhcp_server *server, struct in_addr >> *start, size_t size); >> #endif > > Zbyszek _______________________________________________ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel