diff --git a/Makefile b/Makefile index 74c32a9..68a888c 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ -OBJ=main.o ddhcp.o netsock.o packet.o dhcp.o dhcp_packet.o dhcp_options.o tools.o block.o control.o hook.o logger.o statistics.o epoll.o netlink.o -OBJCTL=ddhcpctl.o netsock.o packet.o dhcp.o dhcp_packet.o dhcp_options.o tools.o block.o hook.o logger.o +OBJ=main.o ddhcp.o netsock.o packet.o dhcp.o dhcp_packet.o dhcp_option.o util.o block.o control.o hook.o logger.o statistics.o epoll.o netlink.o +OBJCTL=ddhcpctl.o netsock.o packet.o dhcp.o dhcp_packet.o dhcp_option.o util.o block.o hook.o logger.o HDRS=$(wildcard *.h) REVISION=$(shell git rev-list --first-parent HEAD --max-count=1) diff --git a/block.c b/block.c index 808b539..d2296a1 100644 --- a/block.c +++ b/block.c @@ -1,564 +1,624 @@ -#include "block.h" +/* SPDX-License-Identifier: GPL-3.0-only */ +/* + * DDHCP - Handling of IP address blocks for DHCP redistribution + * + * See AUTHORS file for copyright holders + */ #include #include +#include "block.h" #include "dhcp.h" #include "logger.h" #include "statistics.h" -#include "tools.h" +#include "util.h" -// TODO define sane value +/* TODO define sane value */ #define UPDATE_CLAIM_MAX_BLOCKS 32 -int block_alloc(ddhcp_block* block) { - DEBUG("block_alloc(block)\n"); +int block_alloc(ddhcp_block_t *block) +{ + DEBUG("block_alloc(block)\n"); - if (!block) { - WARNING("block_alloc(...): No block given to initialize\n"); - return 1; - } + if (!block) { + WARNING("block_alloc(...): No block given to initialize\n"); + return 1; + } - // Do not allocate memory and initialise, when the block is already allocated - if (block->addresses) { - return 0; - } + /* Do not allocate memory and initialise, when the block is already allocated */ + if (block->addresses) + return 0; - block->addresses = (struct dhcp_lease*) calloc(sizeof(struct dhcp_lease), block->subnet_len); + block->addresses = (struct dhcp_lease *)calloc( + sizeof(struct dhcp_lease), block->subnet_len); - if (!block->addresses) { - WARNING("block_alloc(...): Failed to allocate memory for lease management on block %i\n", block->index); - return 1; - } + if (!block->addresses) { + WARNING("block_alloc(...): Failed to allocate memory for lease management on block %i\n", + block->index); + return 1; + } - for (unsigned int index = 0; index < block->subnet_len; index++) { - block->addresses[index].state = FREE; - block->addresses[index].lease_end = 0; - } + for (unsigned int index = 0; index < block->subnet_len; index++) { + block->addresses[index].state = FREE; + block->addresses[index].lease_end = 0; + } - return 0; + return 0; } -ATTR_NONNULL(2) int block_own(ddhcp_block* block, ddhcp_config* config) { - if (!block) { - WARNING("block_own(...): No block given to own\n"); - return 1; - } - - if (block_alloc(block)) { - WARNING("block_own(...): Failed to initialize block %i for owning\n", block->index); - return 1; - } - - block->state = DDHCP_OURS; - block->first_claimed = time(NULL); - NODE_ID_CP(&block->node_id, &config->node_id); - return 0; +ATTR_NONNULL(2) int block_own(ddhcp_block_t *block, ddhcp_config_t *config) +{ + if (!block) { + WARNING("block_own(...): No block given to own\n"); + return 1; + } + + if (block_alloc(block)) { + WARNING("block_own(...): Failed to initialize block %i for owning\n", + block->index); + return 1; + } + + block->state = DDHCP_OURS; + block->first_claimed = time(NULL); + NODE_ID_CP(&block->node_id, &config->node_id); + + return 0; } -ATTR_NONNULL_ALL void block_free(ddhcp_block* block) { - DEBUG("block_free(%i)\n", block->index); - - if (block->state != DDHCP_BLOCKED) { - NODE_ID_CLEAR(&block->node_id); - block->state = DDHCP_FREE; - } - - if (block->addresses) { - DEBUG("block_free(%i): Freeing DHCP leases\n", block->index); - free(block->addresses); - block->addresses = NULL; - // Reset needless timeout - block->needless_since = 0; - } +ATTR_NONNULL_ALL void block_free(ddhcp_block_t *block) +{ + DEBUG("block_free(%i)\n", block->index); + + if (block->state != DDHCP_BLOCKED) { + NODE_ID_CLEAR(&block->node_id); + block->state = DDHCP_FREE; + } + + if (block->addresses) { + DEBUG("block_free(%i): Freeing DHCP leases\n", block->index); + free(block->addresses); + block->addresses = NULL; + /* Reset needless timeout */ + block->needless_since = 0; + } } -ATTR_NONNULL_ALL ddhcp_block* block_find_free(ddhcp_config* config) { - DEBUG("block_find_free(config)\n"); - ddhcp_block* block = config->blocks; +ATTR_NONNULL_ALL ddhcp_block_t *block_find_free(ddhcp_config_t *config) +{ + ddhcp_block_t *random_free = NULL; + uint32_t r = ~0u; - ddhcp_block_list free_blocks; - INIT_LIST_HEAD(&free_blocks); - uint32_t num_free_blocks = 0; + DEBUG("block_find_free(config)\n"); + ddhcp_block_t *block = config->blocks; - for (uint32_t i = 0; i < config->number_of_blocks; i++) { - if (block->state == DDHCP_FREE) { - list_add_tail((&block->tmp_list), &free_blocks); - num_free_blocks++; - } + ddhcp_block_list free_blocks; + INIT_LIST_HEAD(&free_blocks); + uint32_t num_free_blocks = 0; - block++; - } + for (uint32_t i = 0; i < config->number_of_blocks; i++) { + if (block->state == DDHCP_FREE) { + list_add_tail((&block->tmp_list), &free_blocks); + num_free_blocks++; + } - DEBUG("block_find_free(...): found %i free blocks\n", num_free_blocks); + block++; + } - ddhcp_block* random_free = NULL; - uint32_t r = ~0u; + DEBUG("block_find_free(...): found %i free blocks\n", num_free_blocks); - if (num_free_blocks > 0) { - r = (uint32_t)rand() % num_free_blocks; - } else { - DEBUG("block_find_free(...): no free block found\n"); - return NULL; - } + if (num_free_blocks > 0) { + r = (uint32_t)rand() % num_free_blocks; + } else { + DEBUG("block_find_free(...): no free block found\n"); + return NULL; + } - struct list_head* pos, *q; + struct list_head *pos, *q; - list_for_each_safe(pos, q, &free_blocks) { - block = list_entry(pos, ddhcp_block, tmp_list); - list_del(pos); + list_for_each_safe (pos, q, &free_blocks) { + block = list_entry(pos, ddhcp_block, tmp_list); + list_del(pos); - if (r == 0) { - random_free = block; - break; - } + if (r == 0) { + random_free = block; + break; + } - r--; - } + r--; + } #if LOG_LEVEL_LIMIT >= LOG_WARNING - if (random_free) { - DEBUG("block_find_free(...): found block %i\n", random_free->index); - } else { - WARNING("block_find_free(...): no free block found\n"); - } + if (random_free) { + DEBUG("block_find_free(...): found block %i\n", + random_free->index); + } else { + WARNING("block_find_free(...): no free block found\n"); + } #endif - return random_free; + return random_free; } -ATTR_NONNULL_ALL int block_claim(int32_t num_blocks, ddhcp_config* config) { - DEBUG("block_claim(count:%i, config)\n", num_blocks); - - // Handle blocks already in claiming prozess - struct list_head* pos, *q; - time_t now = time(NULL); - - list_for_each_safe(pos, q, &config->claiming_blocks) { - ddhcp_block* block = list_entry(pos, ddhcp_block, claim_list); - - if (block->claiming_counts == 3) { - if ( block_own(block, config) > 0) { - ERROR("block_claim(...): Claiming block (%i) failed, reseting claim counter.", block->index); - block->claiming_counts = 0; - } else { - //Reduce number of blocks we need to claim - num_blocks--; - INFO("block_claim(...): block %i claimed after 3 claims.\n", block->index); - } - - list_del(pos); - config->claiming_blocks_amount--; - } else if (block->state != DDHCP_CLAIMING) { - DEBUG("block_claim(...): block %i is no longer marked for claiming\n", block->index); - list_del(pos); - config->claiming_blocks_amount--; - } - } - - // Do we still need more, then lets find some. - if (num_blocks > config->claiming_blocks_amount) { - // find num_blocks - config->claiming_blocks_amount free blocks - uint32_t needed_blocks = (uint32_t) num_blocks - config->claiming_blocks_amount; - - for (uint32_t i = 0; i < needed_blocks; i++) { - ddhcp_block* block = block_find_free(config); - - if (block) { - block->state = DDHCP_CLAIMING; - block->claiming_counts = 0; - block->timeout = now + config->tentative_timeout; - list_add_tail(&(block->claim_list), &config->claiming_blocks); - config->claiming_blocks_amount++; - } else { - // We are short on free blocks in the network. - WARNING("block_claim(...): Network has no free blocks left!\n"); - // TODO In a future version we could start to forward DHCP requests - // to other servers. - } - } - } - - // TODO Sort blocks in claiming process by number of claims already processed. - - // TODO If we have more blocks in claiming process than we need, drop the tail - // of blocks for which we had less claim announcements. - - if (config->claiming_blocks_amount < 1) { - DEBUG("block_claim(...): No blocks need claiming.\n"); - return 0; - } - - // Send claim message for all blocks in claiming process. - struct ddhcp_mcast_packet* packet = new_ddhcp_packet(DDHCP_MSG_INQUIRE, config); - - if (!packet) { - WARNING("block_claim(...): Failed to allocate ddhcpd mcast packet.\n"); - return -ENOMEM; - } - - packet->count = config->claiming_blocks_amount; - - packet->payload = (struct ddhcp_payload*) calloc(sizeof(struct ddhcp_payload), config->claiming_blocks_amount); - - if (!packet->payload) { - free(packet); - WARNING("block_claim(...): Failed to allocate ddhcpd mcast packet payload.\n"); - return -ENOMEM; - } - - int index = 0; - ddhcp_block* block; - - list_for_each_entry(block, &config->claiming_blocks, claim_list) { - packet->payload[index].block_index = block->index; - packet->payload[index].timeout = 0; - packet->payload[index].reserved = 0; - index++; - } - - statistics_record(config, STAT_MCAST_SEND_PKG, 1); - statistics_record(config, STAT_MCAST_SEND_INQUIRE, 1); - ssize_t bytes_send = send_packet_mcast(packet, DDHCP_SKT_MCAST(config)); - statistics_record(config, STAT_MCAST_SEND_BYTE, (long int) bytes_send); - - if (bytes_send > 0) { - list_for_each_entry(block, &config->claiming_blocks, claim_list) { - block->claiming_counts++; - } - } else { - DEBUG("block_claim(...): Send failed, no updates made.\n"); - } - - free(packet->payload); - free(packet); - return 0; +ATTR_NONNULL_ALL int block_claim(int32_t num_blocks, ddhcp_config_t *config) +{ + DEBUG("block_claim(count:%i, config)\n", num_blocks); + + /* Handle blocks already in claiming process */ + struct list_head *pos, *q; + time_t now = time(NULL); + + list_for_each_safe (pos, q, &config->claiming_blocks) { + ddhcp_block_t *block = list_entry(pos, ddhcp_block, claim_list); + + if (block->claiming_counts == 3) { + if (block_own(block, config) > 0) { + ERROR("block_claim(...): Claiming block (%i) failed, reseting claim counter.", + block->index); + block->claiming_counts = 0; + } else { + /* Reduce number of blocks we need to claim */ + num_blocks--; + INFO("block_claim(...): block %i claimed after 3 claims.\n", + block->index); + } + + list_del(pos); + config->claiming_blocks_amount--; + } else if (block->state != DDHCP_CLAIMING) { + DEBUG("block_claim(...): block %i is no longer marked for claiming\n", + block->index); + list_del(pos); + config->claiming_blocks_amount--; + } + } + + /* Do we still need more, then lets find some. */ + if (num_blocks > config->claiming_blocks_amount) { + /* find num_blocks - config->claiming_blocks_amount free blocks */ + uint32_t needed_blocks = + (uint32_t)num_blocks - config->claiming_blocks_amount; + + for (uint32_t i = 0; i < needed_blocks; i++) { + ddhcp_block_t *block = block_find_free(config); + + if (block) { + block->state = DDHCP_CLAIMING; + block->claiming_counts = 0; + block->timeout = + now + config->tentative_timeout; + list_add_tail(&(block->claim_list), + &config->claiming_blocks); + config->claiming_blocks_amount++; + } else { + /* We are short on free blocks in the network */ + WARNING("block_claim(...): Network has no free blocks left!\n"); + /* TODO In a future version we could start to forward DHCP requests + * to other servers. + */ + } + } + } + + /* TODO Sort blocks in claiming process by number of claims already processed. */ + + /* TODO If we have more blocks in claiming process than we need, drop the tail + * of blocks for which we had less claim announcements. + */ + + if (config->claiming_blocks_amount < 1) { + DEBUG("block_claim(...): No blocks need claiming.\n"); + return 0; + } + + /* Send claim message for all blocks in claiming process. */ + struct ddhcp_mcast_packet *packet = + new_ddhcp_packet(DDHCP_MSG_INQUIRE, config); + + if (!packet) { + WARNING("block_claim(...): Failed to allocate ddhcpd mcast packet.\n"); + return -ENOMEM; + } + + packet->count = config->claiming_blocks_amount; + + packet->payload = (struct ddhcp_payload *)calloc( + sizeof(struct ddhcp_payload), config->claiming_blocks_amount); + + if (!packet->payload) { + free(packet); + WARNING("block_claim(...): Failed to allocate ddhcpd mcast packet payload.\n"); + return -ENOMEM; + } + + int index = 0; + ddhcp_block_t *block; + + list_for_each_entry (block, &config->claiming_blocks, claim_list) { + packet->payload[index].block_index = block->index; + packet->payload[index].timeout = 0; + packet->payload[index].reserved = 0; + index++; + } + + statistics_record(config, STAT_MCAST_SEND_PKG, 1); + statistics_record(config, STAT_MCAST_SEND_INQUIRE, 1); + ssize_t bytes_send = send_packet_mcast(packet, DDHCP_SKT_MCAST(config)); + statistics_record(config, STAT_MCAST_SEND_BYTE, (long int)bytes_send); + + if (bytes_send > 0) { + list_for_each_entry (block, &config->claiming_blocks, + claim_list) { + block->claiming_counts++; + } + } else { + DEBUG("block_claim(...): Send failed, no updates made.\n"); + } + + free(packet->payload); + free(packet); + return 0; } -ATTR_NONNULL_ALL uint32_t block_num_free_leases(ddhcp_config* config) { - DEBUG("block_num_free_leases(config)\n"); +ATTR_NONNULL_ALL uint32_t block_num_free_leases(ddhcp_config_t *config) +{ + DEBUG("block_num_free_leases(config)\n"); - ddhcp_block* block = config->blocks; - uint32_t free_leases = 0; + ddhcp_block_t *block = config->blocks; + uint32_t free_leases = 0, i; #if LOG_LEVEL_LIMIT >= LOG_DEBUG - uint32_t num_blocks = 0; + uint32_t num_blocks = 0; #endif - for (uint32_t i = 0; i < config->number_of_blocks; i++) { - if (block->state == DDHCP_OURS) { - free_leases += dhcp_num_free(block); + for (i = 0; i < config->number_of_blocks; i++) { + if (block->state == DDHCP_OURS) { + free_leases += dhcp_num_free(block); #if LOG_LEVEL_LIMIT >= LOG_DEBUG - num_blocks++; + num_blocks++; #endif - } + } - block++; - } + block++; + } - DEBUG("block_num_free_leases(...): Found %lu free DHCP leases in OUR (%lu) blocks\n", free_leases, num_blocks); - return free_leases; + DEBUG("block_num_free_leases(...): Found %lu free DHCP leases in OUR (%lu) blocks\n", + free_leases, num_blocks); + return free_leases; } -ATTR_NONNULL_ALL uint32_t block_num_owned(ddhcp_config* config) { - uint32_t owned_blocks = 0; - ddhcp_block* block = config->blocks; - for (uint32_t i = 0; i < config->number_of_blocks; i++) { - if (block->state == DDHCP_OURS) { - owned_blocks++; - } - } - DEBUG("block_num_owned(...): We own %lu blocks\n", owned_blocks); - return owned_blocks; +ATTR_NONNULL_ALL uint32_t block_num_owned(ddhcp_config_t *config) +{ + uint32_t owned_blocks = 0, i; + ddhcp_block_t *block = config->blocks; + for (i = 0; i < config->number_of_blocks; i++) { + if (block->state == DDHCP_OURS) { + owned_blocks++; + } + } + DEBUG("block_num_owned(...): We own %lu blocks\n", owned_blocks); + + return owned_blocks; } -ATTR_NONNULL_ALL ddhcp_block* block_find_free_leases(ddhcp_config* config) { - DEBUG("block_find_free_leases(config)\n"); - - ddhcp_block* block = config->blocks; - ddhcp_block* selected = NULL; - - for (uint32_t i = 0; i < config->number_of_blocks; i++) { - if (block->state == DDHCP_OURS) { - if (dhcp_has_free(block)) { - if (selected) { - // If observed block is claimed earlier, select that block. - if (selected->first_claimed > block->first_claimed) { - selected = block; - } - } else { - selected = block; - } - } - } - - block++; - } +ATTR_NONNULL_ALL ddhcp_block_t *block_find_free_leases(ddhcp_config_t *config) +{ + DEBUG("block_find_free_leases(config)\n"); + + ddhcp_block_t *block = config->blocks; + ddhcp_block_t *selected = NULL; + + for (uint32_t i = 0; i < config->number_of_blocks; i++) { + if (block->state == DDHCP_OURS && dhcp_has_free(block) && + (!selected || + selected->first_claimed > block->first_claimed)) + selected = block; + + block++; + } #if LOG_LEVEL_LIMIT >= LOG_DEBUG - if (selected) { - DEBUG("block_find_free_leases(...): Block %i selected\n", selected->index); - } else { - DEBUG("block_find_free_leases(...): No block found!\n"); - } + if (selected) { + DEBUG("block_find_free_leases(...): Block %i selected\n", + selected->index); + } else { + DEBUG("block_find_free_leases(...): No block found!\n"); + } #endif - return selected; + return selected; } -ATTR_NONNULL_ALL void block_drop_unused(ddhcp_config* config) { - DEBUG("block_drop_unsued(config)\n"); - ddhcp_block* block = config->blocks; - ddhcp_block* freeable_block = NULL; - - for (uint32_t i = 0; i < config->number_of_blocks; i++) { - if (block->state == DDHCP_OURS) { - if (dhcp_num_free(block) == config->block_size) { - DEBUG("block_drop unused(...): block %i is unused.\n", block->index); - - if (freeable_block) { - // If observed block is younger than current selected, select block. - if (freeable_block->first_claimed < block->first_claimed) { - freeable_block = block; - } - } else { - freeable_block = block; - } - } - } - - block++; - } - - if (freeable_block) { - time_t now = time(NULL); - if ( freeable_block->needless_since == 0 ) { - DEBUG("block_drop_unused(...): mark block %i to be needless\n",freeable_block->index); - freeable_block->needless_since = now; - // Set needless marks flag - config->needless_marks = 1; - } else { - if ( freeable_block->needless_since <= now - config->block_needless_timeout) { - DEBUG("block_drop_unused(...): free block %i.\n", freeable_block->index); - block_free(freeable_block); - config->needless_marks = 0; - } else { +ATTR_NONNULL_ALL void block_drop_unused(ddhcp_config_t *config) +{ + DEBUG("block_drop_unsued(config)\n"); + ddhcp_block_t *block = config->blocks; + ddhcp_block_t *freeable_block = NULL; + + for (uint32_t i = 0; i < config->number_of_blocks; i++) { + if (block->state == DDHCP_OURS) { + if (dhcp_num_free(block) == config->block_size) { + DEBUG("block_drop unused(...): block %i is unused.\n", + block->index); + + if (freeable_block) { + /* If observed block is younger than current selected, select block. */ + if (freeable_block->first_claimed < + block->first_claimed) { + freeable_block = block; + } + } else { + freeable_block = block; + } + } + } + + block++; + } + + if (freeable_block) { + time_t now = time(NULL); + if (freeable_block->needless_since == 0) { + DEBUG("block_drop_unused(...): mark block %i to be needless\n", + freeable_block->index); + freeable_block->needless_since = now; + /* Set needless marks flag */ + config->needless_marks = 1; + } else { + if (freeable_block->needless_since <= + now - config->block_needless_timeout) { + DEBUG("block_drop_unused(...): free block %i.\n", + freeable_block->index); + block_free(freeable_block); + config->needless_marks = 0; + } else { #if LOG_LEVEL_LIMIT >= LOG_DEBUG - time_t time_left = now - config->block_needless_timeout - freeable_block->needless_since; - DEBUG("block_drop_unused(...): free block %i in about %li seconds\n",freeable_block->index,time_left); + time_t time_left = + now - config->block_needless_timeout - + freeable_block->needless_since; + DEBUG("block_drop_unused(...): free block %i in about %li seconds\n", + freeable_block->index, time_left); #endif - } - } - } + } + } + } } -ATTR_NONNULL_ALL static void _block_update_claim_send(struct ddhcp_mcast_packet* packet, time_t new_block_timeout, ddhcp_config* config) { - DEBUG("block_update_claims_send(packet:%i,%li,config)\n",packet->count,new_block_timeout); - - statistics_record(config, STAT_MCAST_SEND_PKG, 1); - statistics_record(config, STAT_MCAST_SEND_UPDATECLAIM, 1); - ssize_t bytes_send = send_packet_mcast(packet, DDHCP_SKT_MCAST(config)); - statistics_record(config, STAT_MCAST_SEND_BYTE, (long int) bytes_send); - // TODO? Stat the number of blocks reclaimed. - - if (bytes_send > 0) { - // Update the timeout value of all contained blocks - // iff the packet has been transmitted - for (uint8_t i = 0; i < packet->count; i++) { - uint32_t index = packet->payload[i].block_index; - DEBUG("block_update_claims_send(...): updated claim for block %i\n", index); - config->blocks[index].timeout = new_block_timeout; - } - } else { - DEBUG("block_update_claims_send(...): Send failed, no updates made.\n"); - } +ATTR_NONNULL_ALL static void +_block_update_claim_send(struct ddhcp_mcast_packet *packet, + time_t new_block_timeout, ddhcp_config_t *config) +{ + uint32_t index; + + DEBUG("block_update_claims_send(packet:%i,%li,config)\n", packet->count, + new_block_timeout); + + statistics_record(config, STAT_MCAST_SEND_PKG, 1); + statistics_record(config, STAT_MCAST_SEND_UPDATECLAIM, 1); + ssize_t bytes_send = send_packet_mcast(packet, DDHCP_SKT_MCAST(config)); + statistics_record(config, STAT_MCAST_SEND_BYTE, (long int)bytes_send); + /* TODO? Stat the number of blocks reclaimed. */ + + if (bytes_send > 0) { + /* Update the timeout value of all contained blocks + * iff the packet has been transmitted + */ + for (uint8_t i = 0; i < packet->count; i++) { + index = packet->payload[i].block_index; + DEBUG("block_update_claims_send(...): updated claim for block %i\n", + index); + config->blocks[index].timeout = new_block_timeout; + } + } else { + DEBUG("block_update_claims_send(...): Send failed, no updates made.\n"); + } } -ATTR_NONNULL_ALL void block_update_claims(ddhcp_config* config) { - DEBUG("block_update_claims(config)\n"); - uint32_t our_blocks = 0; - ddhcp_block* block = config->blocks; - time_t now = time(NULL); - time_t timeout_factor = now + config->block_timeout - (time_t)(config->block_timeout / config->block_refresh_factor); - - // Determine if we need to run a full update claim run - // we run through the list until we see one block which needs update. - // Running a full update claims (see below) is much more expensive - for (uint32_t i = 0; i < config->number_of_blocks; i++) { - if (block->state == DDHCP_OURS && block->timeout < timeout_factor) { - our_blocks++; - break; - } - - block++; - } - - if (our_blocks == 0) { - DEBUG("block_update_claims(...): No blocks need claim updates.\n"); - return; - } - - struct ddhcp_mcast_packet* packet = new_ddhcp_packet(DDHCP_MSG_UPDATECLAIM, config); - - if (!packet) { - WARNING("block_update_claims(...): Failed to allocate ddhcpd mcast packet.\n"); - return; - } - - // Aggressively group blocks into packets, send packet iff - // at least one block in a packet is below the baseline. - - packet->payload = (struct ddhcp_payload*) calloc(sizeof(struct ddhcp_payload), UPDATE_CLAIM_MAX_BLOCKS); - - if (!packet->payload) { - WARNING("block_update_claims(...): Failed to allocate ddhcpd packet payload.\n"); - free(packet); - return; - } - - block = config->blocks; - uint8_t send_packet = 0; - uint8_t index = 0; - time_t new_block_timeout = now + config->block_timeout; - - for (uint32_t i = 0; i < config->number_of_blocks; i++) { - if (block->state == DDHCP_OURS) { - - if (block->timeout < timeout_factor) { - DEBUG("block_update_claims(...): update claim for block %i needed\n", block->index); - send_packet = 1; - } - - packet->payload[index].block_index = block->index; - packet->payload[index].timeout = config->block_timeout; - packet->payload[index].reserved = 0; - - index++; - - if (index == UPDATE_CLAIM_MAX_BLOCKS) { - if (send_packet) { - packet->count = index; - send_packet = 0; - _block_update_claim_send(packet, new_block_timeout, config); - } - - index = 0; - } - } - - block++; - } - - if (send_packet) { - packet->count = index; - _block_update_claim_send(packet, new_block_timeout, config); - } - - free(packet->payload); - free(packet); +ATTR_NONNULL_ALL void block_update_claims(ddhcp_config_t *config) +{ + DEBUG("block_update_claims(config)\n"); + uint32_t our_blocks = 0, i; + ddhcp_block_t *block = config->blocks; + time_t now = time(NULL); + time_t timeout_factor = + now + config->block_timeout - + (time_t)(config->block_timeout / config->block_refresh_factor); + + /* Determine if we need to run a full update claim run + * we run through the list until we see one block which needs update. + * Running a full update claims (see below) is much more expensive + */ + for (i = 0; i < config->number_of_blocks; i++) { + if (block->state == DDHCP_OURS && + block->timeout < timeout_factor) { + our_blocks++; + break; + } + + block++; + } + + if (our_blocks == 0) { + DEBUG("block_update_claims(...): No blocks need claim updates.\n"); + return; + } + + struct ddhcp_mcast_packet *packet = + new_ddhcp_packet(DDHCP_MSG_UPDATECLAIM, config); + + if (!packet) { + WARNING("block_update_claims(...): Failed to allocate ddhcpd mcast packet.\n"); + return; + } + + /* Aggressively group blocks into packets, send packet iff + * at least one block in a packet is below the baseline. + */ + + packet->payload = (struct ddhcp_payload *)calloc( + sizeof(struct ddhcp_payload), UPDATE_CLAIM_MAX_BLOCKS); + + if (!packet->payload) { + WARNING("block_update_claims(...): Failed to allocate ddhcpd packet payload.\n"); + free(packet); + return; + } + + block = config->blocks; + uint8_t send_packet = 0; + uint8_t index = 0; + time_t new_block_timeout = now + config->block_timeout; + + for (uint32_t i = 0; i < config->number_of_blocks; i++) { + if (block->state == DDHCP_OURS) { + if (block->timeout < timeout_factor) { + DEBUG("block_update_claims(...): update claim for block %i needed\n", + block->index); + send_packet = 1; + } + + packet->payload[index].block_index = block->index; + packet->payload[index].timeout = config->block_timeout; + packet->payload[index].reserved = 0; + + index++; + + if (index == UPDATE_CLAIM_MAX_BLOCKS) { + if (send_packet) { + packet->count = index; + send_packet = 0; + _block_update_claim_send( + packet, new_block_timeout, + config); + } + + index = 0; + } + } + + block++; + } + + if (send_packet) { + packet->count = index; + _block_update_claim_send(packet, new_block_timeout, config); + } + + free(packet->payload); + free(packet); } -ATTR_NONNULL_ALL void block_check_timeouts(ddhcp_config* config) { - DEBUG("block_check_timeouts(config)\n"); - ddhcp_block* block = config->blocks; - time_t now = time(NULL); - - for (uint32_t i = 0; i < config->number_of_blocks; i++) { - if (block->timeout < now && block->state != DDHCP_BLOCKED && block->state != DDHCP_FREE) { - INFO("block_check_timeouts(...): Block %i FREE through timeout.\n", block->index); - block_free(block); - } - - if (block->state == DDHCP_OURS) { - dhcp_check_timeouts(block); - } else if (block->addresses) { - int free_leases = dhcp_check_timeouts(block); - - if (free_leases == block->subnet_len) { - block_free(block); - } - } - - block++; - } +ATTR_NONNULL_ALL void block_check_timeouts(ddhcp_config_t *config) +{ + DEBUG("block_check_timeouts(config)\n"); + ddhcp_block_t *block = config->blocks; + time_t now = time(NULL); + uint32_t i; + + for (i = 0; i < config->number_of_blocks; i++) { + if (block->timeout < now && block->state != DDHCP_BLOCKED && + block->state != DDHCP_FREE) { + INFO("block_check_timeouts(...): Block %i FREE through timeout.\n", + block->index); + block_free(block); + } + + if (block->state == DDHCP_OURS) { + dhcp_check_timeouts(block); + } else if (block->addresses && + block->subnet_len == dhcp_check_timeouts(block)) { + block_free(block); + } + + block++; + } } -ATTR_NONNULL_ALL void block_show_status(int fd, ddhcp_config* config) { - ddhcp_block* block = config->blocks; - dprintf(fd, "block size/number\t%u/%u \n", config->block_size, config->number_of_blocks); - dprintf(fd, " tentative timeout\t%u\n", config->tentative_timeout); - dprintf(fd, " timeout\t%u\n", config->block_timeout); - dprintf(fd, " refresh factor\t%u\n", config->block_refresh_factor); - dprintf(fd, " spare leases needed\t%u\n", config->spare_leases_needed); - dprintf(fd, " network: %s/%i \n", inet_ntoa(config->prefix), config->prefix_len); - - char node_id[17]; - - for (uint32_t j = 0; j < 8; j++) { - sprintf(node_id + 2 * j, "%02X", config->node_id[j]); - } - - node_id[16] = '\0'; - - dprintf(fd, "node id\t%s\n", node_id); - - dprintf(fd, "ddhcp blocks\n"); - dprintf(fd, "index\tstate\towner\t\t\tclaim\tleases\ttimeout\n"); - - time_t now = time(NULL); - - uint32_t num_reserved_blocks = 0; - - for (uint32_t i = 0; i < config->number_of_blocks; i++) { - uint32_t free_leases = 0; - uint32_t offered_leases = 0; - - if (block->addresses) { - free_leases = dhcp_num_free(block); - offered_leases = dhcp_num_offered(block); - } - - for (uint32_t j = 0; j < 8; j++) { - sprintf(node_id + 2 * j, "%02X", block->node_id[j]); - } - - node_id[16] = '\0'; - - char leases[16]; - - if (block->addresses) { - snprintf(leases, sizeof(leases), "%u/%u", offered_leases, config->block_size - free_leases - offered_leases); - } else { - leases[0] = '-'; - leases[1] = '\0'; - } - - time_t timeout = block->timeout - now; - - if (timeout > 0) { - num_reserved_blocks++; - dprintf(fd, "%i\t%i\t%s\t%u\t%s\t%lu\n", block->index, block->state, node_id, block->claiming_counts, leases, timeout); - } +ATTR_NONNULL_ALL void block_show_status(int fd, ddhcp_config_t *config) +{ + uint32_t num_reserved_blocks = 0, free_leases, offered_leases, i, j; + ddhcp_block_t *block = config->blocks; + time_t now = time(NULL); + char node_id[17]; + + dprintf(fd, "block size/number\t%u/%u \n", config->block_size, + config->number_of_blocks); + dprintf(fd, " tentative timeout\t%u\n", config->tentative_timeout); + dprintf(fd, " timeout\t%u\n", config->block_timeout); + dprintf(fd, " refresh factor\t%u\n", config->block_refresh_factor); + dprintf(fd, " spare leases needed\t%u\n", + config->spare_leases_needed); + dprintf(fd, " network: %s/%i \n", inet_ntoa(config->prefix), + config->prefix_len); + + for (j = 0; j < 8; j++) + sprintf(node_id + 2 * j, "%02X", config->node_id[j]); + node_id[16] = '\0'; + + dprintf(fd, "node id\t%s\n", node_id); + + dprintf(fd, "ddhcp blocks\n"); + dprintf(fd, "index\tstate\towner\t\t\tclaim\tleases\ttimeout\n"); + + for (i = 0; i < config->number_of_blocks; i++) { + free_leases = 0; + offered_leases = 0; + + if (block->addresses) { + free_leases = dhcp_num_free(block); + offered_leases = dhcp_num_offered(block); + } + + for (j = 0; j < 8; j++) + sprintf(node_id + 2 * j, "%02X", block->node_id[j]); + node_id[16] = '\0'; + + char leases[16]; + + if (block->addresses) { + snprintf(leases, sizeof(leases), "%u/%u", + offered_leases, + config->block_size - free_leases - + offered_leases); + } else { + leases[0] = '-'; + leases[1] = '\0'; + } + + time_t timeout = block->timeout - now; + + if (timeout > 0) { + num_reserved_blocks++; + dprintf(fd, "%i\t%i\t%s\t%u\t%s\t%lu\n", block->index, + block->state, node_id, block->claiming_counts, + leases, timeout); + } + + block++; + } + + dprintf(fd, "\nblocks in use: %i\n", num_reserved_blocks); +} - block++; - } +void block_unmark_needless(ddhcp_config_t *config) +{ + ddhcp_block_t *block = config->blocks; + uint32_t i; - dprintf(fd, "\nblocks in use: %i\n", num_reserved_blocks); -} + DEBUG("block_unmark_needless(config)\n"); -void block_unmark_needless(ddhcp_config* config){ - DEBUG("block_unmark_needless(config)\n"); - ddhcp_block* block = config->blocks; - for (uint32_t i = 0; i < config->number_of_blocks; i++) { + for (i = 0; i < config->number_of_blocks; i++) { #if LOG_LEVEL_LIMIT >= LOG_DEBUG - if (block->needless_since > 0) { - DEBUG("block_unmark_needless(...): Unmark block %i\n",block->index); - } + if (block->needless_since > 0) { + DEBUG("block_unmark_needless(...): Unmark block %i\n", + block->index); + } #endif - block->needless_since = 0; - block++; - } - // Remove needless marks flag - config->needless_marks = 0; + block->needless_since = 0; + block++; + } + /* Remove needless marks flag */ + config->needless_marks = 0; } diff --git a/block.h b/block.h index 29f04b2..6145aac 100644 --- a/block.h +++ b/block.h @@ -1,3 +1,10 @@ +/* SPDX-License-Identifier: GPL-3.0-only */ +/* + * DDHCP - Handling of IP address blocks for DHCP redistribution + * + * See AUTHORS file for copyright holders + */ + #ifndef _BLOCK_H #define _BLOCK_H @@ -8,47 +15,47 @@ * Allocate block. * This will also malloc and prepare a dhcp_lease_block inside the given block. */ -int block_alloc(ddhcp_block* block); +int block_alloc(ddhcp_block_t *block); /** * Own a block, possibly after you have claimed it an amount of times. * This will also malloc and prepare a dhcp_lease_block inside the given block. */ -ATTR_NONNULL(2) int block_own(ddhcp_block* block, ddhcp_config* config); +ATTR_NONNULL(2) int block_own(ddhcp_block_t *block, ddhcp_config_t *config); /** * Free a block and release dhcp_lease_block when allocated. */ -ATTR_NONNULL_ALL void block_free(ddhcp_block* block); +ATTR_NONNULL_ALL void block_free(ddhcp_block_t *block); /** * Find a free block and return it or otherwise NULL. * A block is called free, when no other node claims it. */ -ATTR_NONNULL_ALL ddhcp_block* block_find_free(ddhcp_config* config); +ATTR_NONNULL_ALL ddhcp_block_t *block_find_free(ddhcp_config_t *config); /** * Claim a block! A block is only claimable when it is free. * Returns a value greater 0 if something goes sideways. */ -ATTR_NONNULL_ALL int block_claim(int32_t num_blocks, ddhcp_config* config); +ATTR_NONNULL_ALL int block_claim(int32_t num_blocks, ddhcp_config_t *config); /** * Sum the number of free leases in blocks you own. */ -ATTR_NONNULL_ALL uint32_t block_num_free_leases(ddhcp_config* config); +ATTR_NONNULL_ALL uint32_t block_num_free_leases(ddhcp_config_t *config); /** * Sum the number of owned blocks. */ -ATTR_NONNULL_ALL uint32_t block_num_owned(ddhcp_config* config); +ATTR_NONNULL_ALL uint32_t block_num_owned(ddhcp_config_t *config); /** * Find and return claimed block with free leases. Try to * reduce fragmentation of lease usage by returning already * used blocks. */ -ATTR_NONNULL_ALL ddhcp_block* block_find_free_leases(ddhcp_config* config); +ATTR_NONNULL_ALL ddhcp_block_t *block_find_free_leases(ddhcp_config_t *config); /** * Drop the youngest unused block. @@ -56,7 +63,7 @@ ATTR_NONNULL_ALL ddhcp_block* block_find_free_leases(ddhcp_config* config); * and stop updating the claim. Freeing the block after its * timeout. */ -ATTR_NONNULL_ALL void block_drop_unused(ddhcp_config* config); +ATTR_NONNULL_ALL void block_drop_unused(ddhcp_config_t *config); /** * Update the timeout of claimed blocks and send packets to @@ -65,28 +72,27 @@ ATTR_NONNULL_ALL void block_drop_unused(ddhcp_config* config); * Due to fragmented timeouts this packet may send 2 times more packets * than optimal. TODO fixthis */ -ATTR_NONNULL_ALL void block_update_claims(ddhcp_config* config); +ATTR_NONNULL_ALL void block_update_claims(ddhcp_config_t *config); /** * Check the timeout of all blocks, and mark timed out once as FREE. * Blocks which are marked as BLOCKED are ignored in this process. */ -ATTR_NONNULL_ALL void block_check_timeouts(ddhcp_config* config); +ATTR_NONNULL_ALL void block_check_timeouts(ddhcp_config_t *config); /** * Free block claim list structure. */ -#define block_free_claims(config) \ - INIT_LIST_HEAD(&(config)->claiming_blocks); +#define block_free_claims(config) INIT_LIST_HEAD(&(config)->claiming_blocks); /** * Show Block Status */ -ATTR_NONNULL_ALL void block_show_status(int fd, ddhcp_config* config); +ATTR_NONNULL_ALL void block_show_status(int fd, ddhcp_config_t *config); /** * Reset needless markers in all blocks */ -void block_unmark_needless(ddhcp_config* config); +void block_unmark_needless(ddhcp_config_t *config); #endif diff --git a/control.c b/control.c index 066ea06..a303fd2 100644 --- a/control.c +++ b/control.c @@ -1,123 +1,133 @@ +/* SPDX-License-Identifier: GPL-3.0-only */ +/* + * DDHCP - Command interface abstraction + * + * See AUTHORS file for copyright holders + */ + #include "control.h" #include "logger.h" #include "block.h" -#include "dhcp_options.h" +#include "dhcp_option.h" #include "statistics.h" extern int log_level; -ATTR_NONNULL_ALL int handle_command(int socket, uint8_t* buffer, ssize_t msglen, ddhcp_config* config) { - if (msglen == 0) { - DEBUG("handle_command(...): zero length command received\n"); - return -2; - } - - // TODO Rethink command handling and command design - DEBUG("handle_command(socket, cmd:%u, len:%i, blocks, config)\n", buffer[0], msglen); - - switch (buffer[0]) { - case DDHCPCTL_BLOCK_SHOW: - if (msglen != 1) { - DEBUG("handle_command(...): message length mismatch\n"); - return -2; - } +ATTR_NONNULL_ALL int handle_command(int socket, uint8_t *buf, ssize_t msglen, + ddhcp_config_t *config) +{ + if (msglen == 0) { + DEBUG("handle_command(...): zero length command received\n"); + return -2; + } + + /* TODO Rethink command handling and command design */ + DEBUG("handle_command(socket, cmd:%u, len:%i, blocks, config)\n", + buf[0], msglen); + + switch (buf[0]) { + case DDHCPCTL_BLOCK_SHOW: + if (msglen != 1) { + DEBUG("handle_command(...): message length mismatch\n"); + return -2; + } + + DEBUG("handle_command(...): show block status\n"); + block_show_status(socket, config); + return 0; + + case DDHCPCTL_DHCP_OPTIONS_SHOW: + if (msglen != 1) { + DEBUG("handle_command(...): message length mismatch\n"); + return -2; + } + + DEBUG("handle_command(...): show dhcp options\n"); + dhcp_option_show(socket, config); + return 0; - DEBUG("handle_command(...): show block status\n"); - block_show_status(socket, config); - return 0; +#ifdef DDHCPD_STATISTICS + case DDHCPCTL_STATISTICS: + if (msglen != 1) + DEBUG("handle_command(...): message length mismatch\n"); - case DDHCPCTL_DHCP_OPTIONS_SHOW: - if (msglen != 1) { - DEBUG("handle_command(...): message length mismatch\n"); - return -2; - } + DEBUG("handle_command(...): show statistics\n"); + statistics_show(socket, 0, config); + return 0; - DEBUG("handle_command(...): show dhcp options\n"); - dhcp_options_show(socket, config); - return 0; + case DDHCPCTL_STATISTICS_RESET: + if (msglen != 1) + DEBUG("handle_command(...): message length mismatch\n"); -#ifdef DDHCPD_STATISTICS - case DDHCPCTL_STATISTICS: - if (msglen != 1) { - DEBUG("handle_command(...): message length mismatch\n"); - } - - DEBUG("handle_command(...): show statistics\n"); - statistics_show(socket, 0, config); - return 0; - - case DDHCPCTL_STATISTICS_RESET: - if (msglen != 1) { - DEBUG("handle_command(...): message length mismatch\n"); - } - - DEBUG("handle_command(...): show statistics reset\n"); - statistics_show(socket, 1, config); - return 0; + DEBUG("handle_command(...): show statistics reset\n"); + statistics_show(socket, 1, config); + return 0; #endif - case DDHCPCTL_DHCP_OPTION_SET: - DEBUG("handle_command(...): set dhcp option\n"); + case DDHCPCTL_DHCP_OPTION_SET: + DEBUG("handle_command(...): set dhcp option\n"); - if (msglen < 3) { - DEBUG("handle_command(...): message not long enough\n"); - return -2; - } + if (msglen < 3) { + DEBUG("handle_command(...): message not long enough\n"); + return -2; + } - if (buffer[2] + 3ul > (size_t) msglen) { - DEBUG("handle_command(...): message not long enough\n"); - return -2; - } + if (buf[2] + 3ul > (size_t)msglen) { + DEBUG("handle_command(...): message not long enough\n"); + return -2; + } - dhcp_option* option = (dhcp_option*) calloc(sizeof(dhcp_option), 1); + dhcp_option *option = + (dhcp_option *)calloc(sizeof(dhcp_option), 1); - if (!option) { - WARNING("handle_command(...): Failed to allocate memory for dhcp option\n"); - return -1; - } + if (!option) { + WARNING("handle_command(...): Failed to allocate memory for dhcp option\n"); + return -1; + } - option->code = buffer[1]; - option->len = buffer[2]; - printf("%i:%i\n", buffer[1], buffer[2]); - option->payload = (uint8_t*) calloc(sizeof(uint8_t), option->len); + option->code = buf[1]; + option->len = buf[2]; + printf("%i:%i\n", buf[1], buf[2]); + option->payload = + (uint8_t *)calloc(sizeof(uint8_t), option->len); - if (!option->payload) { - WARNING("handle_command(...): Failed to allocate memory for dhcp option payload\n"); - free(option); - return -1; - } + if (!option->payload) { + WARNING("handle_command(...): Failed to allocate memory for dhcp option payload\n"); + free(option); + return -1; + } - memcpy(option->payload, buffer + 3, option->len); + memcpy(option->payload, buf + 3, option->len); - set_option_in_store(&config->options, option); - return 0; + dhcp_option_set_in_store(&config->options, option); + return 0; - case DDHCPCTL_DHCP_OPTION_REMOVE: - DEBUG("handle_command(...): remove dhcp option\n"); + case DDHCPCTL_DHCP_OPTION_REMOVE: + DEBUG("handle_command(...): remove dhcp option\n"); - if (msglen < 2) { - DEBUG("handle_command(...): message not long enough\n"); - return -2; - } + if (msglen < 2) { + DEBUG("handle_command(...): message not long enough\n"); + return -2; + } - uint8_t code = buffer[1]; - remove_option_in_store(&config->options, code); - return 0; + uint8_t code = buf[1]; + dhcp_option_remove_in_store(&config->options, code); + return 0; - case DDHCPCTL_LOG_LEVEL_SET: - DEBUG("handle_command(...): set log level\n"); + case DDHCPCTL_LOG_LEVEL_SET: + DEBUG("handle_command(...): set log level\n"); - if (msglen < 2) { - DEBUG("handle_command(...): message not long enough\n"); - return -2; - } + if (msglen < 2) { + DEBUG("handle_command(...): message not long enough\n"); + return -2; + } - log_level = buffer[1]; - return 0; + log_level = buf[1]; + return 0; - default: - WARNING("handle_command(...): unknown command\n"); - } + default: + WARNING("handle_command(...): unknown command\n"); + } - return -1; + return -1; } diff --git a/control.h b/control.h index 6a701ee..ebda170 100644 --- a/control.h +++ b/control.h @@ -1,18 +1,25 @@ -#ifndef _CONTROL_H -#define _CONTROL_H +/* SPDX-License-Identifier: GPL-3.0-only */ +/* + * DDHCP - Command interface abstraction + * + * See AUTHORS file for copyright holders + */ + +#ifndef _DDHCP_CONTROL_H +#define _DDHCP_CONTROL_H #include "types.h" -enum { - DDHCPCTL_BLOCK_SHOW = 1, - DDHCPCTL_DHCP_OPTIONS_SHOW, - DDHCPCTL_DHCP_OPTION_SET, - DDHCPCTL_DHCP_OPTION_REMOVE, - DDHCPCTL_LOG_LEVEL_SET, - DDHCPCTL_STATISTICS, - DDHCPCTL_STATISTICS_RESET, +enum { DDHCPCTL_BLOCK_SHOW = 1, + DDHCPCTL_DHCP_OPTIONS_SHOW, + DDHCPCTL_DHCP_OPTION_SET, + DDHCPCTL_DHCP_OPTION_REMOVE, + DDHCPCTL_LOG_LEVEL_SET, + DDHCPCTL_STATISTICS, + DDHCPCTL_STATISTICS_RESET, }; -ATTR_NONNULL_ALL int handle_command(int socket, uint8_t* buffer, ssize_t msglen, ddhcp_config* config); +ATTR_NONNULL_ALL int handle_command(int socket, uint8_t *buf, ssize_t msglen, + ddhcp_config *config); #endif diff --git a/ddhcp.c b/ddhcp.c index 5848de5..277bde3 100644 --- a/ddhcp.c +++ b/ddhcp.c @@ -1,324 +1,385 @@ +/* SPDX-License-Identifier: GPL-3.0-only */ +/* + * DDHCP - Handling of decentral block negotiation + * + * See AUTHORS file for copyright holders + */ + #include #include "ddhcp.h" #include "dhcp.h" #include "logger.h" -#include "tools.h" +#include "util.h" #include "statistics.h" -ATTR_NONNULL_ALL int ddhcp_block_init(ddhcp_config* config) { - DEBUG("ddhcp_block_init(config)\n"); - - if (config->number_of_blocks < 1) { - FATAL("ddhcp_block_init(...): Need at least 1 block to be configured\n"); - return 1; - } - - config->blocks = (struct ddhcp_block*) calloc(sizeof(struct ddhcp_block), config->number_of_blocks); - - if (!config->blocks) { - FATAL("ddhcp_block_init(...): Can't allocate memory for block structure\n"); - return 1; - } - - time_t now = time(NULL); - - // TODO Maybe we should allocate number_of_blocks dhcp_lease_blocks previous - // and assign one here instead of NULL. Performance boost, Memory defrag? - struct ddhcp_block* block = config->blocks; - - for (uint32_t index = 0; index < config->number_of_blocks; index++) { - block->index = index; - block->state = DDHCP_FREE; - addr_add(&config->prefix, &block->subnet, (int)(index * config->block_size)); - block->subnet_len = config->block_size; - memset(&block->owner_address, 0, sizeof(struct in6_addr)); - block->timeout = now + config->block_timeout; - block->claiming_counts = 0; - block->addresses = NULL; - block++; - } - - return 0; +ATTR_NONNULL_ALL int ddhcp_block_init(ddhcp_config_t *config) +{ + DEBUG("ddhcp_block_init(config)\n"); + + if (config->number_of_blocks < 1) { + FATAL("ddhcp_block_init(...): Need at least 1 block to be configured\n"); + return 1; + } + + config->blocks = (ddhcp_block_t *)calloc(sizeof(ddhcp_block_t), + config->number_of_blocks); + + if (!config->blocks) { + FATAL("ddhcp_block_init(...): Can't allocate memory for block structure\n"); + return 1; + } + + time_t now = time(NULL); + + /* TODO Maybe we should allocate number_of_blocks dhcp_lease_blocks previous + * and assign one here instead of NULL. Performance boost, Memory defrag? + */ + ddhcp_block_t *block = config->blocks; + + for (uint32_t index = 0; index < config->number_of_blocks; index++) { + block->index = index; + block->state = DDHCP_FREE; + addr_add(&config->prefix, &block->subnet, + (int)(index * config->block_size)); + block->subnet_len = config->block_size; + memset(&block->owner_address, 0, sizeof(struct in6_addr)); + block->timeout = now + config->block_timeout; + block->claiming_counts = 0; + block->addresses = NULL; + block++; + } + + return 0; } -ATTR_NONNULL_ALL void ddhcp_block_free(ddhcp_config* config) { - ddhcp_block* block = config->blocks; +ATTR_NONNULL_ALL void ddhcp_block_free(ddhcp_config_t *config) +{ + ddhcp_block_t *block = config->blocks; - for (uint32_t i = 0; i < config->number_of_blocks; i++) { - block_free(block++); - } + for (uint32_t i = 0; i < config->number_of_blocks; i++) + block_free(block++); - block_free_claims(config); - free(config->blocks); + block_free_claims(config); + free(config->blocks); } -ATTR_NONNULL_ALL int ddhcp_check_packet(struct ddhcp_mcast_packet* packet, ddhcp_config* config) { - if (memcmp(&packet->prefix, &config->prefix, sizeof(struct in_addr)) != 0 || - packet->prefix_len != config->prefix_len || - packet->blocksize != config->block_size) { - return 1; - } - - return 0; +ATTR_NONNULL_ALL int ddhcp_check_packet(struct ddhcp_mcast_packet *packet, + ddhcp_config_t *config) +{ + if (memcmp(&packet->prefix, &config->prefix, sizeof(struct in_addr)) != + 0 || + packet->prefix_len != config->prefix_len || + packet->blocksize != config->block_size) { + return 1; + } + + return 0; } -ATTR_NONNULL_ALL void ddhcp_block_process(uint8_t* buffer, ssize_t len, struct sockaddr_in6 sender, ddhcp_config* config) { - struct ddhcp_mcast_packet packet; - ssize_t ret = ntoh_mcast_packet(buffer, len, &packet); - packet.sender = &sender; - - if (ret == 0) { - // Check if this packet is for our swarm - if (ddhcp_check_packet(&packet, config)) { - DEBUG("ddhcp_block_process(...): drop foreign packet before processing"); - free(packet.payload); - return; - } - - switch (packet.command) { - case DDHCP_MSG_UPDATECLAIM: - statistics_record(config, STAT_MCAST_RECV_UPDATECLAIM, 1); - ddhcp_block_process_claims(&packet, config); - break; - - case DDHCP_MSG_INQUIRE: - statistics_record(config, STAT_MCAST_RECV_INQUIRE, 1); - ddhcp_block_process_inquire(&packet, config); - break; - - default: - break; - } - - free(packet.payload); - } else { - DEBUG("ddhcp_block_process(...): epoll returned status %i\n", ret); - } +ATTR_NONNULL_ALL void ddhcp_block_process(uint8_t *buf, ssize_t len, + struct sockaddr_in6 sender, + ddhcp_config_t *config) +{ + struct ddhcp_mcast_packet packet; + ssize_t ret = ntoh_mcast_packet(buf, len, &packet); + packet.sender = &sender; + + if (ret == 0) { + /* Check if this packet is for our swarm */ + if (ddhcp_check_packet(&packet, config)) { + DEBUG("ddhcp_block_process(...): drop foreign packet before processing"); + free(packet.payload); + return; + } + + switch (packet.command) { + case DDHCP_MSG_UPDATECLAIM: + statistics_record(config, STAT_MCAST_RECV_UPDATECLAIM, + 1); + ddhcp_block_process_claims(&packet, config); + break; + case DDHCP_MSG_INQUIRE: + statistics_record(config, STAT_MCAST_RECV_INQUIRE, 1); + ddhcp_block_process_inquire(&packet, config); + break; + default: + break; + } + + free(packet.payload); + } else { + DEBUG("ddhcp_block_process(...): epoll returned status %i\n", + ret); + } } -ATTR_NONNULL_ALL void ddhcp_block_process_claims(struct ddhcp_mcast_packet* packet, ddhcp_config* config) { - DEBUG("ddhcp_block_process_claims(packet,config)\n"); - - assert(packet->command == 1); - time_t now = time(NULL); - - ddhcp_block* blocks = config->blocks; - - for (unsigned int i = 0; i < packet->count; i++) { - struct ddhcp_payload* claim = &packet->payload[i]; - uint32_t block_index = claim->block_index; - - if (block_index >= config->number_of_blocks) { - WARNING("ddhcp_block_process_claims(...): Malformed block number\n"); - continue; - } - - if (blocks[block_index].state == DDHCP_OURS && NODE_ID_CMP(packet->node_id, config->node_id) < 0) { - INFO("ddhcp_block_process_claims(...): node 0x%02x%02x%02x%02x%02x%02x%02x%02x claims our block %i\n", HEX_NODE_ID(packet->node_id), block_index); - // TODO Decide when and if we reclaim this block - // Which node has more leases in this block, ..., who has the better node_id. - // Unrelated from the above, the original concept is claiming the block now. - blocks[block_index].timeout = 0; - block_update_claims(config); - } else { - // Notice the ownership - blocks[block_index].state = DDHCP_CLAIMED; - blocks[block_index].timeout = now + claim->timeout; - // Save the connection details for the claiming node - // We need to contact him, for dhcp forwarding actions. - memcpy(&blocks[block_index].owner_address, &packet->sender->sin6_addr, sizeof(struct in6_addr)); - memcpy(&blocks[block_index].node_id, &packet->node_id, sizeof(ddhcp_node_id)); +ATTR_NONNULL_ALL void +ddhcp_block_process_claims(struct ddhcp_mcast_packet *packet, + ddhcp_config_t *config) +{ + ddhcp_block_t *blocks = config->blocks; + time_t now = time(NULL); + unsigned int i; + + DEBUG("ddhcp_block_process_claims(packet,config)\n"); + + assert(packet->command == 1); + + for (i = 0; i < packet->count; i++) { + struct ddhcp_payload *claim = &packet->payload[i]; + uint32_t block_index = claim->block_index; + + if (block_index >= config->number_of_blocks) { + WARNING("ddhcp_block_process_claims(...): Malformed block number\n"); + continue; + } + + if (blocks[block_index].state == DDHCP_OURS && + NODE_ID_CMP(packet->node_id, config->node_id) < 0) { + INFO("ddhcp_block_process_claims(...): node 0x%02x%02x%02x%02x%02x%02x%02x%02x claims our block %i\n", + HEX_NODE_ID(packet->node_id), block_index); + /* TODO Decide when and if we reclaim this block + * Which node has more leases in this block, ..., who has the better node_id. + * Unrelated from the above, the original concept is claiming the block now. + */ + blocks[block_index].timeout = 0; + block_update_claims(config); + } else { + /* Notice the ownership */ + blocks[block_index].state = DDHCP_CLAIMED; + blocks[block_index].timeout = now + claim->timeout; + /* Save the connection details for the claiming node + * We need to contact him, for dhcp forwarding actions. + */ + memcpy(&blocks[block_index].owner_address, + &packet->sender->sin6_addr, + sizeof(struct in6_addr)); + memcpy(&blocks[block_index].node_id, &packet->node_id, + sizeof(ddhcp_node_id)); #if LOG_LEVEL_LIMIT >= LOG_DEBUG - char ipv6_sender[INET6_ADDRSTRLEN]; - DEBUG("ddhcp_block_process_claims(...): Register block to %s\n", - inet_ntop(AF_INET6, &blocks[block_index].owner_address, ipv6_sender, INET6_ADDRSTRLEN)); + char ipv6_sender[INET6_ADDRSTRLEN]; + DEBUG("ddhcp_block_process_claims(...): Register block to %s\n", + inet_ntop(AF_INET6, + &blocks[block_index].owner_address, + ipv6_sender, INET6_ADDRSTRLEN)); #endif - INFO("ddhcp_block_process_claims(...): node 0x%02x%02x%02x%02x%02x%02x%02x%02x claims block %i with TTL %i\n", HEX_NODE_ID(packet->node_id), block_index, claim->timeout); - } - } + INFO("ddhcp_block_process_claims(...): node 0x%02x%02x%02x%02x%02x%02x%02x%02x claims block %i with TTL %i\n", + HEX_NODE_ID(packet->node_id), block_index, + claim->timeout); + } + } } -ATTR_NONNULL_ALL void ddhcp_block_process_inquire(struct ddhcp_mcast_packet* packet, ddhcp_config* config) { - DEBUG("ddhcp_block_process_inquire(packet,config)\n"); - - assert(packet->command == 2); - time_t now = time(NULL); - - ddhcp_block* blocks = config->blocks; - - for (unsigned int i = 0; i < packet->count; i++) { - struct ddhcp_payload* tmp = &packet->payload[i]; - - if (tmp->block_index >= config->number_of_blocks) { - WARNING("ddhcp_block_process_inquire(...): Malformed block number\n"); - continue; - } - - INFO("ddhcp_block_process_inquire(...): node 0x%02x%02x%02x%02x%02x%02x%02x%02x inquires block %i\n", HEX_NODE_ID(packet->node_id), tmp->block_index); - - if (blocks[tmp->block_index].state == DDHCP_OURS) { - // Update Claims - INFO("ddhcp_block_process_inquire(...): block %i is ours, notify network\n", tmp->block_index); - blocks[tmp->block_index].timeout = 0; - block_update_claims(config); - } else if (blocks[tmp->block_index].state == DDHCP_CLAIMING) { - INFO("ddhcp_block_process_inquire(...): we are furthermore interested in block %i\n", tmp->block_index); - - // QUESTION Why do we need multiple states for the same process? - if (NODE_ID_CMP(packet->node_id, config->node_id) > 0) { - INFO("ddhcp_block_process_inquire(...): ... but other node wins.\n"); - blocks[tmp->block_index].state = DDHCP_TENTATIVE; - blocks[tmp->block_index].timeout = now + config->tentative_timeout; - } - - // otherwise keep inquiring, the other node should see our inquires and step back. - } else { - INFO("ddhcp_block_process_inquire(...): set block %i to tentative\n", tmp->block_index); - blocks[tmp->block_index].state = DDHCP_TENTATIVE; - blocks[tmp->block_index].timeout = now + config->tentative_timeout; - } - } +ATTR_NONNULL_ALL void +ddhcp_block_process_inquire(struct ddhcp_mcast_packet *packet, + ddhcp_config_t *config) +{ + ddhcp_block_t *blocks = config->blocks; + time_t now = time(NULL); + unsigned int i; + + DEBUG("ddhcp_block_process_inquire(packet,config)\n"); + + assert(packet->command == 2); + + for (i = 0; i < packet->count; i++) { + struct ddhcp_payload *tmp = &packet->payload[i]; + + if (tmp->block_index >= config->number_of_blocks) { + WARNING("ddhcp_block_process_inquire(...): Malformed block number\n"); + continue; + } + + INFO("ddhcp_block_process_inquire(...): node 0x%02x%02x%02x%02x%02x%02x%02x%02x inquires block %i\n", + HEX_NODE_ID(packet->node_id), tmp->block_index); + + if (blocks[tmp->block_index].state == DDHCP_OURS) { + /* Update Claims */ + INFO("ddhcp_block_process_inquire(...): block %i is ours, notify network\n", + tmp->block_index); + blocks[tmp->block_index].timeout = 0; + block_update_claims(config); + } else if (blocks[tmp->block_index].state == DDHCP_CLAIMING) { + INFO("ddhcp_block_process_inquire(...): we are furthermore interested in block %i\n", + tmp->block_index); + + /* QUESTION Why do we need multiple states for the same process? */ + if (NODE_ID_CMP(packet->node_id, config->node_id) > 0) { + INFO("ddhcp_block_process_inquire(...): ... but other node wins.\n"); + blocks[tmp->block_index].state = + DDHCP_TENTATIVE; + blocks[tmp->block_index].timeout = + now + config->tentative_timeout; + } + + /* otherwise keep inquiring, the other node should see our inquires and step back. */ + } else { + INFO("ddhcp_block_process_inquire(...): set block %i to tentative\n", + tmp->block_index); + blocks[tmp->block_index].state = DDHCP_TENTATIVE; + blocks[tmp->block_index].timeout = + now + config->tentative_timeout; + } + } } -ATTR_NONNULL_ALL void ddhcp_dhcp_process(uint8_t* buffer, ssize_t len, struct sockaddr_in6 sender, ddhcp_config* config) { - struct ddhcp_mcast_packet packet; - ssize_t ret = ntoh_mcast_packet(buffer, len, &packet); - packet.sender = &sender; - - if (ret == 0) { - // Check if this packet is for our swarm - if (ddhcp_check_packet(&packet, config)) { - DEBUG("ddhcp_dhcp_process(...): drop foreign packet before processing"); - free(packet.renew_payload); - return; - } - - switch (packet.command) { - case DDHCP_MSG_RENEWLEASE: - statistics_record(config, STAT_DIRECT_RECV_RENEWLEASE, 1); - ddhcp_dhcp_renewlease(&packet, config); - break; - - case DDHCP_MSG_LEASEACK: - statistics_record(config, STAT_DIRECT_RECV_LEASEACK, 1); - ddhcp_dhcp_leaseack(&packet, config); - break; - - case DDHCP_MSG_LEASENAK: - statistics_record(config, STAT_DIRECT_RECV_LEASENAK, 1); - ddhcp_dhcp_leasenak(&packet, config); - break; - - case DDHCP_MSG_RELEASE: - statistics_record(config, STAT_DIRECT_RECV_RELEASE, 1); - ddhcp_dhcp_release(&packet, config); - break; - - default: - break; - } - } +ATTR_NONNULL_ALL void ddhcp_dhcp_process(uint8_t *buf, ssize_t len, + struct sockaddr_in6 sender, + ddhcp_config_t *config) +{ + struct ddhcp_mcast_packet packet; + ssize_t ret = ntoh_mcast_packet(buf, len, &packet); + packet.sender = &sender; + + if (ret) + return; + + /* Check if this packet is for our swarm */ + if (ddhcp_check_packet(&packet, config)) { + DEBUG("ddhcp_dhcp_process(...): drop foreign packet before processing"); + free(packet.renew_payload); + return; + } + + switch (packet.command) { + case DDHCP_MSG_RENEWLEASE: + statistics_record(config, STAT_DIRECT_RECV_RENEWLEASE, 1); + ddhcp_dhcp_renewlease(&packet, config); + break; + case DDHCP_MSG_LEASEACK: + statistics_record(config, STAT_DIRECT_RECV_LEASEACK, 1); + ddhcp_dhcp_leaseack(&packet, config); + break; + case DDHCP_MSG_LEASENAK: + statistics_record(config, STAT_DIRECT_RECV_LEASENAK, 1); + ddhcp_dhcp_leasenak(&packet, config); + break; + case DDHCP_MSG_RELEASE: + statistics_record(config, STAT_DIRECT_RECV_RELEASE, 1); + ddhcp_dhcp_release(&packet, config); + break; + default: + break; + } } -ATTR_NONNULL_ALL void ddhcp_dhcp_renewlease(struct ddhcp_mcast_packet* packet, ddhcp_config* config) { - DEBUG("ddhcp_dhcp_renewlease(request,config)\n"); +ATTR_NONNULL_ALL void ddhcp_dhcp_renewlease(struct ddhcp_mcast_packet *packet, + ddhcp_config_t *config) +{ + ddhcp_mcast_packet *answer = NULL; + + DEBUG("ddhcp_dhcp_renewlease(request,config)\n"); #if LOG_LEVEL_LIMIT >= LOG_DEBUG - char* hwaddr = hwaddr2c(packet->renew_payload->chaddr); - DEBUG("ddhcp_dhcp_renewlease(...): Request for xid: %u chaddr: %s\n", packet->renew_payload->xid, hwaddr); - free(hwaddr); + char *hwaddr = hwaddr2c(packet->renew_payload->chaddr); + DEBUG("ddhcp_dhcp_renewlease(...): Request for xid: %u chaddr: %s\n", + packet->renew_payload->xid, hwaddr); + free(hwaddr); #endif - int ret = dhcp_rhdl_request(&(packet->renew_payload->address), config); - - ddhcp_mcast_packet* answer = NULL; - - if (ret == 0) { - DEBUG("ddhcp_dhcp_renewlease(...): %i ACK\n", ret); - answer = new_ddhcp_packet(DDHCP_MSG_LEASEACK, config); - statistics_record(config, STAT_DIRECT_SEND_LEASEACK, 1); - } else if (ret == 1) { - DEBUG("ddhcp_dhcp_renewlease(...): %i NAK\n", ret); - answer = new_ddhcp_packet(DDHCP_MSG_LEASENAK, config); - statistics_record(config, STAT_DIRECT_SEND_LEASENAK, 1); - // TODO Can we hand over the block? - } else { - // Unexpected behaviour - WARNING("ddhcp_dhcp_renewlease(...): Unexpected return value from dhcp_rhdl_request."); - return; - } - - if (!answer) { - WARNING("ddhcp_dhcp_renewlease(...): Failed to allocate memory for ddhcpd mcast packet.\n"); - return; - } - - answer->renew_payload = packet->renew_payload; - - statistics_record(config, STAT_DIRECT_SEND_PKG, 1); - ssize_t bytes_send = send_packet_direct(answer, &packet->sender->sin6_addr, DDHCP_SKT_SERVER(config)); - statistics_record(config, STAT_DIRECT_SEND_BYTE, (long int) bytes_send); - UNUSED(bytes_send); - - free(answer->renew_payload); - free(answer); + int ret = dhcp_rhdl_request(&(packet->renew_payload->address), config); + + if (!ret) { + DEBUG("ddhcp_dhcp_renewlease(...): %i ACK\n", ret); + answer = new_ddhcp_packet(DDHCP_MSG_LEASEACK, config); + statistics_record(config, STAT_DIRECT_SEND_LEASEACK, 1); + } else if (ret == 1) { + DEBUG("ddhcp_dhcp_renewlease(...): %i NAK\n", ret); + answer = new_ddhcp_packet(DDHCP_MSG_LEASENAK, config); + statistics_record(config, STAT_DIRECT_SEND_LEASENAK, 1); + /* TODO Can we hand over the block? */ + } else { + /* Unexpected behaviour */ + WARNING("ddhcp_dhcp_renewlease(...): Unexpected return value from dhcp_rhdl_request."); + return; + } + + if (!answer) { + WARNING("ddhcp_dhcp_renewlease(...): Failed to allocate memory for ddhcpd mcast packet.\n"); + return; + } + + answer->renew_payload = packet->renew_payload; + + statistics_record(config, STAT_DIRECT_SEND_PKG, 1); + ssize_t bytes_send = send_packet_direct( + answer, &packet->sender->sin6_addr, DDHCP_SKT_SERVER(config)); + statistics_record(config, STAT_DIRECT_SEND_BYTE, (long int)bytes_send); + UNUSED(bytes_send); + + free(answer->renew_payload); + free(answer); } -ATTR_NONNULL_ALL void ddhcp_dhcp_leaseack(struct ddhcp_mcast_packet* request, ddhcp_config* config) { - // Stub functions - DEBUG("ddhcp_dhcp_leaseack(request,config)\n"); +ATTR_NONNULL_ALL void ddhcp_dhcp_leaseack(struct ddhcp_mcast_packet *request, + ddhcp_config_t *config) +{ + /* Stub functions */ + DEBUG("ddhcp_dhcp_leaseack(request,config)\n"); #if LOG_LEVEL_LIMIT >= LOG_DEBUG - char* hwaddr = hwaddr2c(request->renew_payload->chaddr); - DEBUG("ddhcp_dhcp_leaseack(...): ACK for xid: %u chaddr: %s\n", request->renew_payload->xid, hwaddr); - free(hwaddr); + char *hwaddr = hwaddr2c(request->renew_payload->chaddr); + DEBUG("ddhcp_dhcp_leaseack(...): ACK for xid: %u chaddr: %s\n", + request->renew_payload->xid, hwaddr); + free(hwaddr); #endif - dhcp_packet* packet = dhcp_packet_list_find(&config->dhcp_packet_cache, request->renew_payload->xid, request->renew_payload->chaddr); - - if (!packet) { - // Ignore packet - DEBUG("ddhcp_dhcp_leaseack(...): No matching packet found, message ignored\n"); - } else { - // Process packet - dhcp_rhdl_ack(DDHCP_SKT_DHCP(config)->fd, packet, config); - dhcp_packet_free(packet, 1); - free(packet); - } - - free(request->renew_payload); + dhcp_packet_t *packet = + dhcp_packet_list_find(&config->dhcp_packet_cache, + request->renew_payload->xid, + request->renew_payload->chaddr); + + if (!packet) { + /* Ignore packet */ + DEBUG("ddhcp_dhcp_leaseack(...): No matching packet found, message ignored\n"); + } else { + /* Process packet */ + dhcp_rhdl_ack(DDHCP_SKT_DHCP(config)->fd, packet, config); + dhcp_packet_free(packet, 1); + free(packet); + } + + free(request->renew_payload); } -ATTR_NONNULL_ALL void ddhcp_dhcp_leasenak(struct ddhcp_mcast_packet* request, ddhcp_config* config) { - // Stub functions - DEBUG("ddhcp_dhcp_leasenak(request,config)\n"); +ATTR_NONNULL_ALL void ddhcp_dhcp_leasenak(struct ddhcp_mcast_packet *request, + ddhcp_config_t *config) +{ + /* Stub functions */ + DEBUG("ddhcp_dhcp_leasenak(request,config)\n"); #if LOG_LEVEL_LIMIT >= LOG_DEBUG - char* hwaddr = hwaddr2c(request->renew_payload->chaddr); - DEBUG("ddhcp_dhcp_leaseack(...): NAK for xid: %u chaddr: %s\n", request->renew_payload->xid, hwaddr); - free(hwaddr); + char *hwaddr = hwaddr2c(request->renew_payload->chaddr); + DEBUG("ddhcp_dhcp_leaseack(...): NAK for xid: %u chaddr: %s\n", + request->renew_payload->xid, hwaddr); + free(hwaddr); #endif - dhcp_packet* packet = dhcp_packet_list_find(&config->dhcp_packet_cache, request->renew_payload->xid, request->renew_payload->chaddr); - - if (!packet) { - // Ignore packet - DEBUG("ddhcp_dhcp_leaseack(...): No matching packet found, message ignored\n"); - } else { - // Process packet - dhcp_nack(DDHCP_SKT_DHCP(config)->fd, packet, config); - dhcp_packet_free(packet, 1); - free(packet); - } - - free(request->renew_payload); + dhcp_packet_t *packet = + dhcp_packet_list_find(&config->dhcp_packet_cache, + request->renew_payload->xid, + request->renew_payload->chaddr); + + if (!packet) { + /* Ignore packet */ + DEBUG("ddhcp_dhcp_leaseack(...): No matching packet found, message ignored\n"); + } else { + /* Process packet */ + dhcp_nack(DDHCP_SKT_DHCP(config)->fd, packet, config); + dhcp_packet_free(packet, 1); + free(packet); + } + + free(request->renew_payload); } -ATTR_NONNULL_ALL void ddhcp_dhcp_release(struct ddhcp_mcast_packet* packet, ddhcp_config* config) { - DEBUG("ddhcp_dhcp_release(packet,config)\n"); - dhcp_release_lease(packet->renew_payload->address, config); - free(packet->renew_payload); +ATTR_NONNULL_ALL void ddhcp_dhcp_release(struct ddhcp_mcast_packet *packet, + ddhcp_config_t *config) +{ + DEBUG("ddhcp_dhcp_release(packet,config)\n"); + dhcp_release_lease(packet->renew_payload->address, config); + free(packet->renew_payload); } diff --git a/ddhcp.h b/ddhcp.h index 51542b6..cfca797 100644 --- a/ddhcp.h +++ b/ddhcp.h @@ -1,3 +1,10 @@ +/* SPDX-License-Identifier: GPL-3.0-only */ +/* + * DDHCP - Handling of decentral block negotiation + * + * See AUTHORS file for copyright holders + */ + #ifndef _DDHCP_H #define _DDHCP_H @@ -9,61 +16,73 @@ * Initialise the blocks data structure in the global configuration state. * It should only be called by the main program. */ -ATTR_NONNULL_ALL int ddhcp_block_init(ddhcp_config* config); +ATTR_NONNULL_ALL int ddhcp_block_init(ddhcp_config_t *config); /** * This is the inverse function to ddhcp_block_init. */ -ATTR_NONNULL_ALL void ddhcp_block_free(ddhcp_config* config); +ATTR_NONNULL_ALL void ddhcp_block_free(ddhcp_config_t *config); /** * ddhcp_block_process is part of the network message processing chain. * Here messages related to the block consensus are processed. */ -ATTR_NONNULL_ALL void ddhcp_block_process(uint8_t* buffer, ssize_t len, struct sockaddr_in6 sender, ddhcp_config* config); +ATTR_NONNULL_ALL void ddhcp_block_process(uint8_t *buf, ssize_t len, + struct sockaddr_in6 sender, + ddhcp_config_t *config); /** * A node sends a claim message for each block he thinks he owns, handling these * message is handled in ddhcp_block_process_claims. */ -ATTR_NONNULL_ALL void ddhcp_block_process_claims(struct ddhcp_mcast_packet* packet, ddhcp_config* config); +ATTR_NONNULL_ALL void +ddhcp_block_process_claims(struct ddhcp_mcast_packet *packet, + ddhcp_config_t *config); /** * Before claiming a block, a node inquires that block three times, by sending * an inquire message. Handling these messages is done in ddhcp_block_process_inquire. */ -ATTR_NONNULL_ALL void ddhcp_block_process_inquire(struct ddhcp_mcast_packet* packet, ddhcp_config* config); +ATTR_NONNULL_ALL void +ddhcp_block_process_inquire(struct ddhcp_mcast_packet *packet, + ddhcp_config_t *config); /** * ddhcp_dhcp_process is part of the network message processing chain. * In this part of the chain dhcp packages which are forwarded between ddhcpd nodes * or related messages are processed. */ -ATTR_NONNULL_ALL void ddhcp_dhcp_process(uint8_t* buffer, ssize_t len, struct sockaddr_in6 sender, ddhcp_config* config); +ATTR_NONNULL_ALL void ddhcp_dhcp_process(uint8_t *buf, ssize_t len, + struct sockaddr_in6 sender, + ddhcp_config_t *config); /** * When a ddhcpd node gets a dhcp renew request for an address in a block that * is owned by another node, it requests a renew from the owning node. The * function ddhcp_dhcp_renewlease handles receiving such a request. */ -ATTR_NONNULL_ALL void ddhcp_dhcp_renewlease(struct ddhcp_mcast_packet* packet, ddhcp_config* config); +ATTR_NONNULL_ALL void ddhcp_dhcp_renewlease(struct ddhcp_mcast_packet *packet, + ddhcp_config_t *config); /** * After this node has send a renew request to another node. The other node * may send an acknowledge package. We handle receiving such a message * in ddhcp_dhcp_leaseack. */ -ATTR_NONNULL_ALL void ddhcp_dhcp_leaseack(struct ddhcp_mcast_packet* packet, ddhcp_config* config); +ATTR_NONNULL_ALL void ddhcp_dhcp_leaseack(struct ddhcp_mcast_packet *packet, + ddhcp_config_t *config); /** * After this node has send a renew request to another node. The other node * may send an no acknowledge package. We handle receiving such a message * in ddhcp_dhcp_leasenack. */ -ATTR_NONNULL_ALL void ddhcp_dhcp_leasenak(struct ddhcp_mcast_packet* packet, ddhcp_config* config); +ATTR_NONNULL_ALL void ddhcp_dhcp_leasenak(struct ddhcp_mcast_packet *packet, + ddhcp_config_t *config); /** * When a node receives a dhcp release packet for an address in a block owned * by another node, it should forward a release request to the owner. * The ddhcp_dhcp_release function handles processing of such a package. */ -ATTR_NONNULL_ALL void ddhcp_dhcp_release(struct ddhcp_mcast_packet* packet, ddhcp_config* config); +ATTR_NONNULL_ALL void ddhcp_dhcp_release(struct ddhcp_mcast_packet *packet, + ddhcp_config_t *config); -ATTR_NONNULL_ALL ddhcp_block* block_find_lease(ddhcp_config* config); +ATTR_NONNULL_ALL ddhcp_block_t *block_find_lease(ddhcp_config_t *config); -ATTR_NONNULL_ALL void house_keeping(ddhcp_config* config); +ATTR_NONNULL_ALL void house_keeping(ddhcp_config_t *config); #endif diff --git a/ddhcpctl.c b/ddhcpctl.c index fde8ac6..fe1e605 100644 --- a/ddhcpctl.c +++ b/ddhcpctl.c @@ -7,173 +7,163 @@ #include #include -#include "tools.h" +#include "util.h" #include "control.h" #include "version.h" -int main(int argc, char** argv) { +int main(int argc, char **argv) +{ + int c; + int ctl_sock; + int show_usage = 0; + unsigned int msglen = 0; + dhcp_option *option = NULL; - int c; - int ctl_sock; - int show_usage = 0; - unsigned int msglen = 0; - dhcp_option* option = NULL; + if (argc == 1) + show_usage = 1; - if (argc == 1) { - show_usage = 1; - } - - char* path = (char*)"/tmp/ddhcpd_ctl"; + char *path = (char *)"/tmp/ddhcpd_ctl"; #define BUFSIZE_MAX 1500 - uint8_t* buffer = (uint8_t*) calloc(sizeof(uint8_t), BUFSIZE_MAX); - - if (!buffer) { - fprintf(stderr, "Failed to allocate message buffer\n"); - exit(1); - } - - while ((c = getopt(argc, argv, "bC:dhl:o:r:sSt:v:V")) != -1) { - switch (c) { - case 'h': - show_usage = 1; - break; - - case 'b': - //show blocks - msglen = 1; - buffer[0] = (uint8_t) DDHCPCTL_BLOCK_SHOW; - break; - - case 'd': - // show dhcp - msglen = 1; - buffer[0] = (uint8_t) DDHCPCTL_DHCP_OPTIONS_SHOW; - break; - + uint8_t *buf = (uint8_t *)calloc(sizeof(uint8_t), BUFSIZE_MAX); + + if (!buf) { + fprintf(stderr, "Failed to allocate message buf\n"); + exit(1); + } + + while ((c = getopt(argc, argv, "bC:dhl:o:r:sSt:v:V")) != -1) { + switch (c) { + case 'h': + show_usage = 1; + break; + case 'b': + /* show blocks */ + msglen = 1; + buf[0] = (uint8_t)DDHCPCTL_BLOCK_SHOW; + break; + case 'd': + /* show dhcp */ + msglen = 1; + buf[0] = (uint8_t)DDHCPCTL_DHCP_OPTIONS_SHOW; + break; #ifdef DDHCPD_STATISTICS - case 's': - msglen = 1; - buffer[0] = (uint8_t) DDHCPCTL_STATISTICS; - break; - - case 'S': - msglen = 1; - buffer[0] = (uint8_t) DDHCPCTL_STATISTICS_RESET; - break; + case 's': + msglen = 1; + buf[0] = (uint8_t)DDHCPCTL_STATISTICS; + break; + case 'S': + msglen = 1; + buf[0] = (uint8_t)DDHCPCTL_STATISTICS_RESET; + break; #endif - - case 'o': - option = parse_option(); - break; - - case 'l': - msglen = 7; - buffer[0] = (uint8_t) DDHCPCTL_DHCP_OPTION_SET; - buffer[1] = (uint8_t) 51; - buffer[2] = (uint8_t) 4; - uint32_t leasetime = htonl((uint32_t)strtoul(optarg, NULL, 0)); - memcpy(buffer + 3, (uint8_t*) &leasetime, sizeof(uint32_t)); - break; - - case 'r': - msglen = 2; - buffer[0] = (uint8_t) DDHCPCTL_DHCP_OPTION_REMOVE; - buffer[1] = (uint8_t) atoi(optarg); - break; - - case 'C': - path = optarg; - break; - - case 'v': - msglen = 2; - buffer[0] = (uint8_t) DDHCPCTL_LOG_LEVEL_SET; - buffer[1] = (uint8_t) atoi(optarg); - break; - - case 'V': - printf("Revision: %s\n", REVISION); - return 0; - - default: - printf("ARGC: %i\n", argc); - show_usage = 1; - break; - } - } - - // Check if a dhcp option code should be set and if all parameters - // for that are given. - if (option) { - msglen = 3u + option->len; - buffer[0] = (uint8_t) 3; - buffer[1] = (uint8_t) option->code; - buffer[2] = (uint8_t) option->len; - memcpy(buffer + 3, option->payload, option->len); - free(option); - } - - if (show_usage) { - printf("Usage: ddhcpctl [-h|-V|-b|-d|-o