#pragma once
#include <arpa/inet.h>
#include <assert.h>
#include <c-list.h>
#include <c-stdaux.h>
#include <endian.h>
#include <inttypes.h>
#include <limits.h>
#include <stdbool.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <syslog.h>
#include "n-dhcp4.h"
typedef struct NDhcp4CConnection NDhcp4CConnection;
typedef struct NDhcp4CEventNode NDhcp4CEventNode;
typedef struct NDhcp4ClientProbeOption NDhcp4ClientProbeOption;
typedef struct NDhcp4Header NDhcp4Header;
typedef struct NDhcp4Incoming NDhcp4Incoming;
typedef struct NDhcp4Message NDhcp4Message;
typedef struct NDhcp4Outgoing NDhcp4Outgoing;
typedef struct NDhcp4SConnection NDhcp4SConnection;
typedef struct NDhcp4SConnectionIp NDhcp4SConnectionIp;
typedef struct NDhcp4SEventNode NDhcp4SEventNode;
typedef struct NDhcp4LogQueue NDhcp4LogQueue;
/* specs */
#define N_DHCP4_NETWORK_IP_MAXIMUM_HEADER_SIZE (60) /* See RFC791 */
#define N_DHCP4_NETWORK_IP_MINIMUM_MAX_SIZE (576) /* See RFC791 */
#define N_DHCP4_NETWORK_SERVER_PORT (67)
#define N_DHCP4_NETWORK_CLIENT_PORT (68)
#define N_DHCP4_MESSAGE_MAGIC ((uint32_t)(0x63825363))
#define N_DHCP4_MESSAGE_FLAG_BROADCAST (htons(0x8000))
enum {
N_DHCP4_OP_BOOTREQUEST = 1,
N_DHCP4_OP_BOOTREPLY = 2,
};
enum {
N_DHCP4_OPTION_PAD = 0,
N_DHCP4_OPTION_SUBNET_MASK = 1,
N_DHCP4_OPTION_TIME_OFFSET = 2,
N_DHCP4_OPTION_ROUTER = 3,
N_DHCP4_OPTION_DOMAIN_NAME_SERVER = 6,
N_DHCP4_OPTION_HOST_NAME = 12,
N_DHCP4_OPTION_BOOT_FILE_SIZE = 13,
N_DHCP4_OPTION_DOMAIN_NAME = 15,
N_DHCP4_OPTION_ROOT_PATH = 17,
N_DHCP4_OPTION_ENABLE_IP_FORWARDING = 19,
N_DHCP4_OPTION_ENABLE_IP_FORWARDING_NL = 20,
N_DHCP4_OPTION_POLICY_FILTER = 21,
N_DHCP4_OPTION_INTERFACE_MDR = 22,
N_DHCP4_OPTION_INTERFACE_TTL = 23,
N_DHCP4_OPTION_INTERFACE_MTU_AGING_TIMEOUT = 24,
N_DHCP4_OPTION_INTERFACE_MTU = 26,
N_DHCP4_OPTION_BROADCAST = 28,
N_DHCP4_OPTION_STATIC_ROUTE = 33,
N_DHCP4_OPTION_NTP_SERVER = 42,
N_DHCP4_OPTION_VENDOR_SPECIFIC = 43,
N_DHCP4_OPTION_REQUESTED_IP_ADDRESS = 50,
N_DHCP4_OPTION_IP_ADDRESS_LEASE_TIME = 51,
N_DHCP4_OPTION_OVERLOAD = 52,
N_DHCP4_OPTION_MESSAGE_TYPE = 53,
N_DHCP4_OPTION_SERVER_IDENTIFIER = 54,
N_DHCP4_OPTION_PARAMETER_REQUEST_LIST = 55,
N_DHCP4_OPTION_ERROR_MESSAGE = 56,
N_DHCP4_OPTION_MAXIMUM_MESSAGE_SIZE = 57,
N_DHCP4_OPTION_RENEWAL_T1_TIME = 58,
N_DHCP4_OPTION_REBINDING_T2_TIME = 59,
N_DHCP4_OPTION_VENDOR_CLASS_IDENTIFIER = 60,
N_DHCP4_OPTION_CLIENT_IDENTIFIER = 61,
N_DHCP4_OPTION_FQDN = 81,
N_DHCP4_OPTION_NEW_POSIX_TIMEZONE = 100,
N_DHCP4_OPTION_NEW_TZDB_TIMEZONE = 101,
N_DHCP4_OPTION_CLASSLESS_STATIC_ROUTE = 121,
N_DHCP4_OPTION_PRIVATE_BASE = 224,
N_DHCP4_OPTION_PRIVATE_LAST = 254,
N_DHCP4_OPTION_END = 255,
_N_DHCP4_OPTION_N = 256,
};
enum {
N_DHCP4_OVERLOAD_FILE = 1,
N_DHCP4_OVERLOAD_SNAME = 2,
};
enum {
N_DHCP4_MESSAGE_DISCOVER = 1,
N_DHCP4_MESSAGE_OFFER = 2,
N_DHCP4_MESSAGE_REQUEST = 3,
N_DHCP4_MESSAGE_DECLINE = 4,
N_DHCP4_MESSAGE_ACK = 5,
N_DHCP4_MESSAGE_NAK = 6,
N_DHCP4_MESSAGE_RELEASE = 7,
N_DHCP4_MESSAGE_INFORM = 8,
N_DHCP4_MESSAGE_FORCERENEW = 9,
};
struct NDhcp4Header {
uint8_t op;
uint8_t htype;
uint8_t hlen;
uint8_t hops;
uint32_t xid;
uint16_t secs;
uint16_t flags;
uint32_t ciaddr;
uint32_t yiaddr;
uint32_t siaddr;
uint32_t giaddr;
uint8_t chaddr[16];
} _c_packed_;
struct NDhcp4Message {
NDhcp4Header header;
uint8_t sname[64];
uint8_t file[128];
uint32_t magic;
uint8_t options[];
} _c_packed_;
/* objects */
enum {
_N_DHCP4_E_INTERNAL = _N_DHCP4_E_N,
N_DHCP4_E_UNEXPECTED,
N_DHCP4_E_NO_SPACE,
N_DHCP4_E_MALFORMED,
N_DHCP4_E_DROPPED,
N_DHCP4_E_DOWN,
N_DHCP4_E_AGAIN,
};
enum {
N_DHCP4_C_CONNECTION_STATE_INIT,
N_DHCP4_C_CONNECTION_STATE_PACKET,
N_DHCP4_C_CONNECTION_STATE_DRAINING,
N_DHCP4_C_CONNECTION_STATE_UDP,
N_DHCP4_C_CONNECTION_STATE_CLOSED,
};
enum {
N_DHCP4_CLIENT_EPOLL_TIMER,
N_DHCP4_CLIENT_EPOLL_IO,
};
enum {
N_DHCP4_CLIENT_PROBE_STATE_INIT,
N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT,
N_DHCP4_CLIENT_PROBE_STATE_SELECTING,
N_DHCP4_CLIENT_PROBE_STATE_REBOOTING,
N_DHCP4_CLIENT_PROBE_STATE_REQUESTING,
N_DHCP4_CLIENT_PROBE_STATE_GRANTED,
N_DHCP4_CLIENT_PROBE_STATE_BOUND,
N_DHCP4_CLIENT_PROBE_STATE_RENEWING,
N_DHCP4_CLIENT_PROBE_STATE_REBINDING,
N_DHCP4_CLIENT_PROBE_STATE_EXPIRED,
};
enum {
N_DHCP4_CLIENT_LEASE_STATE_INIT,
N_DHCP4_CLIENT_LEASE_STATE_OFFERED,
N_DHCP4_CLIENT_LEASE_STATE_SELECTED,
N_DHCP4_CLIENT_LEASE_STATE_DECLINED,
N_DHCP4_CLIENT_LEASE_STATE_ACKED,
};
enum {
N_DHCP4_SERVER_EPOLL_TIMER,
N_DHCP4_SERVER_EPOLL_IO,
};
enum {
_N_DHCP4_C_MESSAGE_INVALID = 0,
N_DHCP4_C_MESSAGE_DISCOVER,
N_DHCP4_C_MESSAGE_INFORM,
N_DHCP4_C_MESSAGE_SELECT,
N_DHCP4_C_MESSAGE_IGNORE,
N_DHCP4_C_MESSAGE_RENEW,
N_DHCP4_C_MESSAGE_REBIND,
N_DHCP4_C_MESSAGE_REBOOT,
N_DHCP4_C_MESSAGE_RELEASE,
N_DHCP4_C_MESSAGE_DECLINE,
};
struct NDhcp4Outgoing {
NDhcp4Message *message;
size_t n_message;
size_t i_message;
size_t max_size;
uint8_t overload : 2;
struct {
uint8_t type;
uint8_t message_type;
uint32_t client_addr;
uint64_t start_time;
uint64_t base_time;
uint64_t send_time;
uint64_t send_jitter;
size_t n_send;
} userdata;
};
#define N_DHCP4_OUTGOING_NULL(_x) { \
}
struct NDhcp4Incoming {
struct {
uint8_t *value;
size_t size;
} options[_N_DHCP4_OPTION_N];
struct {
uint8_t type;
uint64_t start_time;
uint64_t base_time;
} userdata;
size_t n_message;
NDhcp4Message message;
/* @message must be the last member */
};
#define N_DHCP4_INCOMING_NULL(_x) { \
}
struct NDhcp4ClientConfig {
int ifindex;
unsigned int transport;
bool request_broadcast;
uint8_t mac[32]; /* MAX_ADDR_LEN */
size_t n_mac;
uint8_t broadcast_mac[32]; /* MAX_ADDR_LEN */
size_t n_broadcast_mac;
uint8_t *client_id;
size_t n_client_id;
};
#define N_DHCP4_CLIENT_CONFIG_NULL(_x) { \
.transport = _N_DHCP4_TRANSPORT_N, \
}
struct NDhcp4ClientProbeOption {
uint8_t option;
uint8_t n_data;
uint8_t data[];
};
#define N_DHCP4_CLIENT_PROBE_OPTION_NULL(_x) { \
.option = N_DHCP4_OPTION_PAD, \
}
struct NDhcp4ClientProbeConfig {
bool inform_only;
bool init_reboot;
struct in_addr requested_ip;
struct drand48_data entropy; /* entropy pool */
uint64_t ms_start_delay; /* max ms to wait before starting probe */
NDhcp4ClientProbeOption *options[UINT8_MAX + 1];
int8_t request_parameters[UINT8_MAX + 1];
size_t n_request_parameters;
};
#define N_DHCP4_CLIENT_PROBE_CONFIG_NULL(_x) { \
.ms_start_delay = N_DHCP4_CLIENT_START_DELAY_RFC2131, \
}
struct NDhcp4CEventNode {
CList client_link;
CList probe_link;
NDhcp4ClientEvent event;
bool is_public : 1;
};
#define N_DHCP4_C_EVENT_NODE_NULL(_x) { \
.client_link = C_LIST_INIT((_x).client_link), \
.probe_link = C_LIST_INIT((_x).probe_link), \
}
struct NDhcp4LogQueue {
CList *event_list;
NDhcp4CEventNode nomem_node;
int log_level;
bool is_client : 1;
};
#define N_DHCP4_LOG_QUEUE_NULL_DEFUNCT() { \
.log_level = -1, \
.is_client = false, \
}
#define N_DHCP4_LOG_QUEUE_NULL_CLIENT(client) { \
.event_list = &((client).event_list), \
.log_level = -1, \
.is_client = true, \
.nomem_node = { \
.client_link = C_LIST_INIT((client).log_queue.nomem_node.client_link), \
.probe_link = C_LIST_INIT((client).log_queue.nomem_node.probe_link), \
.event = { \
.event = N_DHCP4_CLIENT_EVENT_LOG, \
.log = { \
.level = LOG_CRIT, \
.message = "one or more logging messages dropped due to out of memory", \
.allow_steal_message = false, \
}, \
}, \
.is_public = false, \
}, \
}
struct NDhcp4CConnection {
NDhcp4ClientConfig *client_config;
NDhcp4ClientProbeConfig *probe_config;
NDhcp4LogQueue *log_queue;
int fd_epoll;
unsigned int state; /* current connection state */
int fd_packet; /* packet socket */
int fd_udp; /* udp socket */
NDhcp4Outgoing *request; /* current request */
uint32_t client_ip; /* client IP address, or 0 */
uint32_t server_ip; /* server IP address, or 0 */
uint16_t mtu; /* client mtu, or 0 */
/*
* When we get DHCP packets from the kernel, we need a buffer to read
* the data into. Since UDP packets can be up to 2^16 bytes in size, we
* avoid placing it on the stack and instead read into this scratch
* buffer. It is purely meant as stack replacement, no data is returned
* through this buffer.
*/
uint8_t scratch_buffer[UINT16_MAX];
};
#define N_DHCP4_C_CONNECTION_NULL(_x) { \
.fd_packet = -1, \
.fd_udp = -1, \
}
struct NDhcp4Client {
unsigned long n_refs;
NDhcp4ClientConfig *config;
CList event_list;
NDhcp4LogQueue log_queue;
int fd_epoll;
int fd_timer;
uint16_t mtu;
NDhcp4ClientProbe *current_probe;
uint64_t scheduled_timeout;
bool preempted : 1;
};
#define N_DHCP4_CLIENT_NULL(_x) { \
.n_refs = 1, \
.event_list = C_LIST_INIT((_x).event_list), \
.fd_epoll = -1, \
.fd_timer = -1, \
.log_queue = N_DHCP4_LOG_QUEUE_NULL_CLIENT(_x), \
}
struct NDhcp4ClientProbe {
NDhcp4ClientProbeConfig *config;
NDhcp4Client *client;
CList event_list;
CList lease_list;
void *userdata;
unsigned int state; /* current probe state */
struct in_addr last_address; /* last address obtained */
uint64_t ns_deferred; /* timeout for deferred action */
uint64_t ns_reinit;
uint64_t ns_nak_restart_delay; /* restart delay after a nak */
NDhcp4ClientLease *current_lease; /* current lease */
NDhcp4CConnection connection; /* client connection wrapper */
};
#define N_DHCP4_CLIENT_PROBE_NULL(_x) { \
.event_list = C_LIST_INIT((_x).event_list), \
.lease_list = C_LIST_INIT((_x).lease_list), \
.connection = N_DHCP4_C_CONNECTION_NULL((_x).connection), \
}
struct NDhcp4ClientLease {
unsigned long n_refs;
NDhcp4ClientProbe *probe;
CList probe_link;
NDhcp4Incoming *message;
uint64_t t1;
uint64_t t2;
uint64_t lifetime;
};
#define N_DHCP4_CLIENT_LEASE_NULL(_x) { \
.n_refs = 1, \
.probe_link = C_LIST_INIT((_x).probe_link), \
}
struct NDhcp4ServerConfig {
int ifindex;
};
#define N_DHCP4_SERVER_CONFIG_NULL(_x) { \
}
struct NDhcp4SEventNode {
CList server_link;
NDhcp4ServerEvent event;
bool is_public : 1;
};
#define N_DHCP4_S_EVENT_NODE_NULL(_x) { \
.server_link = C_LIST_INIT((_x).server_link), \
}
struct NDhcp4SConnection {
int ifindex; /* interface index */
int fd_packet; /* packet socket */
int fd_udp; /* udp socket */
uint8_t buf[UINT16_MAX]; /* scratch recevie buffer */
/* XXX: support a set of server addresses */
NDhcp4SConnectionIp *ip; /* server IP address, or NULL */
};
#define N_DHCP4_S_CONNECTION_NULL(_x) { \
.fd_packet = -1, \
.fd_udp = -1, \
}
struct NDhcp4SConnectionIp {
NDhcp4SConnection *connection;
struct in_addr ip;
};
#define N_DHCP4_S_CONNECTION_IP_NULL(_x) { \
}
struct NDhcp4Server {
unsigned long n_refs;
CList event_list;
CList lease_list;
bool preempted : 1;
NDhcp4SConnection connection;
};
#define N_DHCP4_SERVER_NULL(_x) { \
.n_refs = 1, \
.event_list = C_LIST_INIT((_x).event_list), \
.lease_list = C_LIST_INIT((_x).lease_list), \
.connection = N_DHCP4_S_CONNECTION_NULL((_x).connection), \
}
struct NDhcp4ServerIp {
NDhcp4SConnectionIp ip;
};
#define N_DHCP4_SERVER_IP_NULL(_x) { \
.ip = N_DHCP4_S_CONNECTION_IP_NULL((_x).ip), \
}
struct NDhcp4ServerLease {
unsigned long n_refs;
NDhcp4Server *server;
CList server_link;
NDhcp4Incoming *request;
NDhcp4Incoming *reply;
};
#define N_DHCP4_SERVER_LEASE_NULL(_x) { \
.n_refs = 1, \
.server_link = C_LIST_INIT((_x).server_link), \
}
/* outgoing messages */
int n_dhcp4_outgoing_new(NDhcp4Outgoing **outgoingp, size_t max_size, uint8_t overload);
NDhcp4Outgoing *n_dhcp4_outgoing_free(NDhcp4Outgoing *outgoing);
NDhcp4Header *n_dhcp4_outgoing_get_header(NDhcp4Outgoing *outgoing);
size_t n_dhcp4_outgoing_get_raw(NDhcp4Outgoing *outgoing, const void **rawp);
int n_dhcp4_outgoing_append(NDhcp4Outgoing *outgoing, uint8_t option, const void *data, uint8_t n_data);
int n_dhcp4_outgoing_append_t1(NDhcp4Outgoing *message, uint32_t t1);
int n_dhcp4_outgoing_append_t2(NDhcp4Outgoing *message, uint32_t t2);
int n_dhcp4_outgoing_append_lifetime(NDhcp4Outgoing *message, uint32_t lifetime);
int n_dhcp4_outgoing_append_server_identifier(NDhcp4Outgoing *message, struct in_addr addr);
int n_dhcp4_outgoing_append_requested_ip(NDhcp4Outgoing *message, struct in_addr addr);
void n_dhcp4_outgoing_set_secs(NDhcp4Outgoing *message, uint16_t secs);
void n_dhcp4_outgoing_set_xid(NDhcp4Outgoing *message, uint32_t xid);
void n_dhcp4_outgoing_set_yiaddr(NDhcp4Outgoing *message, struct in_addr yiaddr);
void n_dhcp4_outgoing_get_xid(NDhcp4Outgoing *message, uint32_t *xidp);
/* incoming messages */
int n_dhcp4_incoming_new(NDhcp4Incoming **incomingp, const void *raw, size_t n_raw);
NDhcp4Incoming *n_dhcp4_incoming_free(NDhcp4Incoming *incoming);
NDhcp4Header *n_dhcp4_incoming_get_header(NDhcp4Incoming *incoming);
size_t n_dhcp4_incoming_get_raw(NDhcp4Incoming *incoming, const void **rawp);
int n_dhcp4_incoming_query(NDhcp4Incoming *incoming, uint8_t option, uint8_t **datap, size_t *n_datap);
int n_dhcp4_incoming_query_message_type(NDhcp4Incoming *message, uint8_t *typep);
int n_dhcp4_incoming_query_lifetime(NDhcp4Incoming *message, uint32_t *lifetimep);
int n_dhcp4_incoming_query_t2(NDhcp4Incoming *message, uint32_t *t2p);
int n_dhcp4_incoming_query_t1(NDhcp4Incoming *message, uint32_t *t1p);
int n_dhcp4_incoming_query_server_identifier(NDhcp4Incoming *message, struct in_addr *idp);
int n_dhcp4_incoming_query_max_message_size(NDhcp4Incoming *message, uint16_t *max_message_sizep);
int n_dhcp4_incoming_query_requested_ip(NDhcp4Incoming *message, struct in_addr *requested_ipp);
void n_dhcp4_incoming_get_xid(NDhcp4Incoming *message, uint32_t *xidp);
void n_dhcp4_incoming_get_yiaddr(NDhcp4Incoming *message, struct in_addr *yiaddr);
/* sockets */
int n_dhcp4_c_socket_packet_new(int *sockfdp, int ifindex);
int n_dhcp4_c_socket_udp_new(int *sockfdp,
int ifindex,
const struct in_addr *client_addr,
const struct in_addr *server_addr);
int n_dhcp4_s_socket_packet_new(int *sockfdp);
int n_dhcp4_s_socket_udp_new(int *sockfdp, int ifindex);
int n_dhcp4_c_socket_packet_send(int sockfd,
int ifindex,
const unsigned char *dest_haddr,
unsigned char halen,
NDhcp4Outgoing *message);
int n_dhcp4_c_socket_udp_send(int sockfd, NDhcp4Outgoing *message);
int n_dhcp4_c_socket_udp_broadcast(int sockfd, NDhcp4Outgoing *message);
int n_dhcp4_s_socket_packet_send(int sockfd,
int ifindex,
const struct in_addr *src_inaddr,
const unsigned char *dest_haddr,
unsigned char halen,
const struct in_addr *dest_inaddr,
NDhcp4Outgoing *message);
int n_dhcp4_s_socket_udp_send(int sockfd,
const struct in_addr *inaddr_src,
const struct in_addr *inaddr_dest,
NDhcp4Outgoing *message);
int n_dhcp4_s_socket_udp_broadcast(int sockfd,
const struct in_addr *inaddr_src,
NDhcp4Outgoing *message);
int n_dhcp4_c_socket_packet_recv(int sockfd,
uint8_t *buf,
size_t n_buf,
NDhcp4Incoming **messagep);
int n_dhcp4_c_socket_udp_recv(int sockfd,
uint8_t *buf,
size_t n_buf,
NDhcp4Incoming **messagep);
int n_dhcp4_s_socket_udp_recv(int sockfd,
uint8_t *buf,
size_t n_buf,
NDhcp4Incoming **messagep,
struct sockaddr_in *dest);
/* client configs */
int n_dhcp4_client_config_dup(NDhcp4ClientConfig *config,
NDhcp4ClientConfig **dupp);
/* client probe configs */
int n_dhcp4_client_probe_config_dup(NDhcp4ClientProbeConfig *config,
NDhcp4ClientProbeConfig **dupp);
uint32_t n_dhcp4_client_probe_config_get_random(NDhcp4ClientProbeConfig *config);
/* client events */
int n_dhcp4_c_event_node_new(NDhcp4CEventNode **nodep);
NDhcp4CEventNode *n_dhcp4_c_event_node_free(NDhcp4CEventNode *node);
/* client connections */
int n_dhcp4_c_connection_init(NDhcp4CConnection *connection,
NDhcp4ClientConfig *client_config,
NDhcp4ClientProbeConfig *probe_config,
NDhcp4LogQueue *log_queue,
int fd_epoll);
void n_dhcp4_c_connection_deinit(NDhcp4CConnection *connection);
int n_dhcp4_c_connection_listen(NDhcp4CConnection *connection);
int n_dhcp4_c_connection_connect(NDhcp4CConnection *connection,
const struct in_addr *client,
const struct in_addr *server);
void n_dhcp4_c_connection_close(NDhcp4CConnection *connection);
void n_dhcp4_c_connection_get_timeout(NDhcp4CConnection *connection,
uint64_t *timeoutp);
int n_dhcp4_c_connection_discover_new(NDhcp4CConnection *connection,
NDhcp4Outgoing **request);
int n_dhcp4_c_connection_select_new(NDhcp4CConnection *connection,
NDhcp4Outgoing **request,
NDhcp4Incoming *offer);
int n_dhcp4_c_connection_reboot_new(NDhcp4CConnection *connection,
NDhcp4Outgoing **request,
const struct in_addr *client);
int n_dhcp4_c_connection_renew_new(NDhcp4CConnection *connection,
NDhcp4Outgoing **request);
int n_dhcp4_c_connection_rebind_new(NDhcp4CConnection *connection,
NDhcp4Outgoing **request);
int n_dhcp4_c_connection_decline_new(NDhcp4CConnection *connection,
NDhcp4Outgoing **request,
NDhcp4Incoming *ack,
const char *error);
int n_dhcp4_c_connection_inform_new(NDhcp4CConnection *connection,
NDhcp4Outgoing **request);
int n_dhcp4_c_connection_release_new(NDhcp4CConnection *connection,
NDhcp4Outgoing **request,
const char *error);
int n_dhcp4_c_connection_start_request(NDhcp4CConnection *connection,
NDhcp4Outgoing *request,
uint64_t timestamp);
int n_dhcp4_c_connection_dispatch_timer(NDhcp4CConnection *connection,
uint64_t timestamp);
int n_dhcp4_c_connection_dispatch_io(NDhcp4CConnection *connection,
NDhcp4Incoming **messagep);
/* clients */
int n_dhcp4_client_raise(NDhcp4Client *client, NDhcp4CEventNode **nodep, unsigned int event);
void n_dhcp4_client_arm_timer(NDhcp4Client *client);
/* client probes */
int n_dhcp4_client_probe_new(NDhcp4ClientProbe **probep,
NDhcp4ClientProbeConfig *config,
NDhcp4Client *client,
uint64_t ns_now);
int n_dhcp4_client_probe_raise(NDhcp4ClientProbe *probe, NDhcp4CEventNode **nodep, unsigned int event);
void n_dhcp4_client_probe_get_timeout(NDhcp4ClientProbe *probe, uint64_t *timeoutp);
int n_dhcp4_client_probe_dispatch_timer(NDhcp4ClientProbe *probe, uint64_t ns_now);
int n_dhcp4_client_probe_dispatch_io(NDhcp4ClientProbe *probe, uint32_t events);
int n_dhcp4_client_probe_transition_select(NDhcp4ClientProbe *probe, NDhcp4Incoming *offer, uint64_t ns_now);
int n_dhcp4_client_probe_transition_accept(NDhcp4ClientProbe *probe, NDhcp4Incoming *ack);
int n_dhcp4_client_probe_transition_decline(NDhcp4ClientProbe *probe, NDhcp4Incoming *offer, const char *error, uint64_t ns_now);
int n_dhcp4_client_probe_update_mtu(NDhcp4ClientProbe *probe, uint16_t mtu);
/* client leases */
int n_dhcp4_client_lease_new(NDhcp4ClientLease **leasep, NDhcp4Incoming *message);
void n_dhcp4_client_lease_link(NDhcp4ClientLease *lease, NDhcp4ClientProbe *probe);
void n_dhcp4_client_lease_unlink(NDhcp4ClientLease *lease);
/* server connections */
int n_dhcp4_s_connection_init(NDhcp4SConnection *connection, int ifindex);
void n_dhcp4_s_connection_deinit(NDhcp4SConnection *connection);
void n_dhcp4_s_connection_get_fd(NDhcp4SConnection *connection, int *fdp);
int n_dhcp4_s_connection_dispatch_io(NDhcp4SConnection *connection, NDhcp4Incoming **messagep);
int n_dhcp4_s_connection_offer_new(NDhcp4SConnection *connection,
NDhcp4Outgoing **replyp,
NDhcp4Incoming *request,
const struct in_addr *server_address,
const struct in_addr *client_address,
uint32_t lifetime);
int n_dhcp4_s_connection_ack_new(NDhcp4SConnection *connection,
NDhcp4Outgoing **replyp,
NDhcp4Incoming *request,
const struct in_addr *server_address,
const struct in_addr *client_address,
uint32_t lifetime);
int n_dhcp4_s_connection_nak_new(NDhcp4SConnection *connection,
NDhcp4Outgoing **replyp,
NDhcp4Incoming *request,
const struct in_addr *server_address);
int n_dhcp4_s_connection_send_reply(NDhcp4SConnection *connection,
const struct in_addr *server_addr,
NDhcp4Outgoing *reply);
/* server connection ips */
void n_dhcp4_s_connection_ip_init(NDhcp4SConnectionIp *ip, struct in_addr addr);
void n_dhcp4_s_connection_ip_deinit(NDhcp4SConnectionIp *ip);
void n_dhcp4_s_connection_ip_link(NDhcp4SConnectionIp *ip, NDhcp4SConnection *connection);
void n_dhcp4_s_connection_ip_unlink(NDhcp4SConnectionIp *ip);
/* inline helpers */
static inline void n_dhcp4_outgoing_freep(NDhcp4Outgoing **outgoing) {
if (*outgoing)
n_dhcp4_outgoing_free(*outgoing);
}
static inline void n_dhcp4_incoming_freep(NDhcp4Incoming **incoming) {
if (*incoming)
n_dhcp4_incoming_free(*incoming);
}
static inline uint64_t n_dhcp4_gettime(clockid_t clock) {
struct timespec ts;
int r;
r = clock_gettime(clock, &ts);
c_assert(r >= 0);
return ts.tv_sec * 1000ULL * 1000ULL * 1000ULL + ts.tv_nsec;
}
void n_dhcp4_log_queue_fmt(NDhcp4LogQueue *log_queue,
int level,
const char *fmt,
...) _c_printf_(3, 4);
/**
* n_dhcp4_log() - append a logging event
* @x_log_queue: the logging event queue
* @x_level: the syslog logging level for the message.
* @...: the format string and arguments.
*
* Warning: this macro only evaluates the format arguments if the logging
* level is enabled.
*/
#define n_dhcp4_log(x_log_queue, x_level, ...) \
do { \
NDhcp4LogQueue *const _log_queue = (x_log_queue); \
const int _level = (x_level); \
\
if (_level <= _log_queue->log_level) { \
n_dhcp4_log_queue_fmt(_log_queue, \
_level, \
__VA_ARGS__); \
} \
} while (0)