Squashed 'shared/n-dhcp4/' changes from fb1d43449ba8..6876b73ec113
6876b73ec113 all: rework logging to append logging messages to the event queue 65ca0e4bea32 client: check length of client id for n_dhcp4_client_config_set_client_id() 6a9ca10b7ad6 client: close timer file descriptor explicitly when EPOLL_CTL_ADD fails e5f3b27f5301 connection: don't fail dispatch in case of receive errors 68790d5ec950 connection: keep trying after a failure in send() 788b03891cd0 n-dhcp4: fix logging macro 6cd0fd5e8b3f probe: request previous address after expiration ef11c7079ad7 connection: avoid double free of NDhcp4Outgoing 922a9a2326e7 n-dhcp4: fix initialization of the 'secs' DHCP header field 7fff54117436 outgoing: fix uninitialized variable in n_dhcp4_outgoing_append() 27547faaf258 probe: move back to INIT after lease expires d07cb4e32884 incoming: accept options that are longer than requested 34d365e2267f client: handle invalid return codes gracefully during n_dhcp4_client_dispatch() 2e8c6017f85b n-dhcp4: use packet socket in rebinding state 9a7c82143c06 n-dhcp4: support init-reboot state e615e3f5b063 n-dhcp4/socket: use SO_REUSEADDR on UDP socket 8dbfa1ad2549 merge branch 'bengal:log' 6e50189fba86 n-dhcp4: log outgoing packets aea0315d3862 n-dhcp4: log incoming packets 1ca64a82393d n-dhcp4: add logging API 72c16a0028ac client-probe: fix state transitions on timer dispatch c023ae2ad829 merge branch 'leasetime' 780f94c333ca lease: add n_dhcp4_client_lease_get_basetime() a94378274cf4 incoming: don't handle 0xFFFFFFFF timestamps special in n_dhcp4_incoming_query_u32() 6bb277aefe0b probe: unconditionally pass ownership of message in n_dhcp4_client_probe_dispatch_io() 1cf87c90c6a1 probe: fix leaking message during client probe 55239cef2d63 lease: remove unreachable code in n_dhcp4_incoming_get_timeouts() fa5ee7903061 lease: expose the server IP address 0cfce4a4fe07 all: merge branch 'th/build-centos76' cae4868e5f7e all: avoid {net,linux}/if.h clashes on old distros 05859a3e4d32 all: avoid c_min() macro to work with old GCC 0be7033dd940 probe: arm timers in bound state 8735cdb0f95f ci: switch to c-util automation a0bb7c69a11a client: fallback to CLOCK_MONOTONIC for timerfd 308cb242caf7 ci: disable valgrind run 468c93195ad3 build: update submodules 9d0f690f9ee8 ci: switch to github actions 9ba143a037bb probe: allocate memory of right size in n_dhcp4_client_probe_option_new() 2546aa2c809d util/link: suppress gcc warning e4a01f5870a6 ci: drop broken armv7hl 2e2fbfa18f2c build: update submodules 6277dfd20eca Merge pull request #2 from NetworkManager/th/declaration-after-statement 1b660ae2d12a outgoing: avoid "-Werror=declaration-after-statement" warning with static_assert f34a54cd9719 client/probe: fix memory leak 21e68f3bba80 client/connection: fix memory leak git-subtree-dir: shared/n-dhcp4 git-subtree-split: 6876b73ec113328712a5cdc2ffb9497fd774c0e2
This commit is contained in:
@@ -1,12 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
rm -Rf "./ci-build"
|
||||
mkdir "./ci-build"
|
||||
cd "./ci-build"
|
||||
|
||||
${CHERRY_LIB_MESONSETUP} . "${CHERRY_LIB_SRCDIR}"
|
||||
${CHERRY_LIB_NINJABUILD}
|
||||
${CHERRY_LIB_MESONTEST}
|
||||
# no valgrind tests, since setns(2) is not supported by it
|
50
.github/workflows/ci.yml
vendored
Normal file
50
.github/workflows/ci.yml
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
name: Continuous Integration
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
schedule:
|
||||
- cron: '0 0 * * *'
|
||||
|
||||
jobs:
|
||||
ci:
|
||||
name: CI with Default Configuration
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
#
|
||||
# Prepare CI
|
||||
#
|
||||
# We cannot use the github-action of the `ci-c-util` project, because we
|
||||
# need privileges in the container. Therefore, fetch the CI sources and
|
||||
# build the container manually.
|
||||
#
|
||||
- name: Fetch CI
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: c-util/automation
|
||||
ref: v1
|
||||
path: automation
|
||||
- name: Build CI
|
||||
working-directory: automation/src/ci-c-util
|
||||
run: docker build --tag ci-c-util:v1 .
|
||||
|
||||
#
|
||||
# Run CI
|
||||
#
|
||||
# Take the CI image we built and run the CI with the default project
|
||||
# configuration. We do not use valgrind, since it falls-over with bpf(2)
|
||||
# syscalls.
|
||||
#
|
||||
- name: Fetch Sources
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
path: source
|
||||
- name: Run through C-Util CI
|
||||
run: |
|
||||
docker run \
|
||||
--privileged \
|
||||
-v "$(pwd)/source:/github/workspace" \
|
||||
"ci-c-util:v1" \
|
||||
"--m32=1" \
|
||||
"--source=/github/workspace"
|
21
.travis.yml
21
.travis.yml
@@ -1,21 +0,0 @@
|
||||
os: linux
|
||||
dist: trusty
|
||||
language: c
|
||||
|
||||
services:
|
||||
- docker
|
||||
|
||||
before_install:
|
||||
- curl -O -L "https://raw.githubusercontent.com/cherry-pick/cherry-images/v1/scripts/vmrun"
|
||||
- curl -O -L "https://raw.githubusercontent.com/cherry-pick/cherry-ci/v1/scripts/cherryci"
|
||||
- chmod +x "./vmrun" "./cherryci"
|
||||
|
||||
jobs:
|
||||
include:
|
||||
- stage: test
|
||||
script:
|
||||
- ./vmrun -- ../src/cherryci -d ../src/.cherryci -s c-util -m
|
||||
- script:
|
||||
- ./vmrun -T armv7hl -- ../src/cherryci -d ../src/.cherryci -s c-util
|
||||
- script:
|
||||
- ./vmrun -T i686 -- ../src/cherryci -d ../src/.cherryci -s c-util
|
@@ -34,6 +34,7 @@ global:
|
||||
n_dhcp4_client_lease_ref;
|
||||
n_dhcp4_client_lease_unref;
|
||||
n_dhcp4_client_lease_get_yiaddr;
|
||||
n_dhcp4_client_lease_get_siaddr;
|
||||
n_dhcp4_client_lease_get_lifetime;
|
||||
n_dhcp4_client_lease_query;
|
||||
n_dhcp4_client_lease_select;
|
||||
|
@@ -8,6 +8,8 @@
|
||||
#include <c-stdaux.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <sys/socket.h> /* needed by linux/netdevice.h */
|
||||
#include <linux/netdevice.h>
|
||||
#include <net/if_arp.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
@@ -21,6 +23,7 @@
|
||||
* @connection: connection to operate on
|
||||
* @client_config: client configuration to use
|
||||
* @probe_config: client probe configuration to use
|
||||
* @log_queue: the log queue for logging events
|
||||
* @fd_epoll: epoll context to attach to, or -1
|
||||
*
|
||||
* This initializes a new client connection using the configuration given in
|
||||
@@ -45,11 +48,13 @@
|
||||
int n_dhcp4_c_connection_init(NDhcp4CConnection *connection,
|
||||
NDhcp4ClientConfig *client_config,
|
||||
NDhcp4ClientProbeConfig *probe_config,
|
||||
NDhcp4LogQueue *log_queue,
|
||||
int fd_epoll) {
|
||||
*connection = (NDhcp4CConnection)N_DHCP4_C_CONNECTION_NULL(*connection);
|
||||
connection->client_config = client_config;
|
||||
connection->probe_config = probe_config;
|
||||
connection->fd_epoll = fd_epoll;
|
||||
connection->log_queue = log_queue;
|
||||
|
||||
/*
|
||||
* We explicitly allow initializing connections with an invalid
|
||||
@@ -82,11 +87,12 @@ int n_dhcp4_c_connection_init(NDhcp4CConnection *connection,
|
||||
*/
|
||||
void n_dhcp4_c_connection_deinit(NDhcp4CConnection *connection) {
|
||||
n_dhcp4_c_connection_close(connection);
|
||||
n_dhcp4_outgoing_free(connection->request);
|
||||
*connection = (NDhcp4CConnection)N_DHCP4_C_CONNECTION_NULL(*connection);
|
||||
}
|
||||
|
||||
static void n_dhcp4_c_connection_outgoing_set_secs(NDhcp4Outgoing *message) {
|
||||
uint32_t secs;
|
||||
uint64_t secs;
|
||||
|
||||
/*
|
||||
* This function sets the `secs` field for outgoing messages. It
|
||||
@@ -122,12 +128,12 @@ static void n_dhcp4_c_connection_outgoing_set_secs(NDhcp4Outgoing *message) {
|
||||
*
|
||||
* Note: Some DHCP relays reject a `secs` value of 0 (which might look
|
||||
* like it is uninitialized). Hence, we always clamp the value to
|
||||
* the range `[1, INF[`.
|
||||
* the range `[1, 65535]`.
|
||||
*/
|
||||
|
||||
secs = message->userdata.base_time - message->userdata.start_time;
|
||||
secs /= 1000ULL * 1000ULL * 1000ULL; /* nsecs to secs */
|
||||
secs = secs ?: 1; /* clamp to `[1, INF[` */
|
||||
secs = C_CLAMP(secs, 1, UINT16_MAX);
|
||||
|
||||
n_dhcp4_outgoing_set_secs(message, secs);
|
||||
}
|
||||
@@ -136,7 +142,22 @@ int n_dhcp4_c_connection_listen(NDhcp4CConnection *connection) {
|
||||
_c_cleanup_(c_closep) int fd_packet = -1;
|
||||
int r;
|
||||
|
||||
c_assert(connection->state == N_DHCP4_C_CONNECTION_STATE_INIT);
|
||||
if (connection->state == N_DHCP4_C_CONNECTION_STATE_PACKET)
|
||||
return 0;
|
||||
|
||||
c_assert(connection->state == N_DHCP4_C_CONNECTION_STATE_INIT ||
|
||||
connection->state == N_DHCP4_C_CONNECTION_STATE_DRAINING ||
|
||||
connection->state == N_DHCP4_C_CONNECTION_STATE_UDP);
|
||||
|
||||
if (connection->fd_packet >= 0) {
|
||||
epoll_ctl(connection->fd_epoll, EPOLL_CTL_DEL, connection->fd_packet, NULL);
|
||||
connection->fd_packet = c_close(connection->fd_packet);
|
||||
}
|
||||
|
||||
if (connection->fd_udp >= 0) {
|
||||
epoll_ctl(connection->fd_epoll, EPOLL_CTL_DEL, connection->fd_udp, NULL);
|
||||
connection->fd_udp = c_close(connection->fd_udp);
|
||||
}
|
||||
|
||||
r = n_dhcp4_c_socket_packet_new(&fd_packet, connection->client_config->ifindex);
|
||||
if (r)
|
||||
@@ -316,7 +337,6 @@ void n_dhcp4_c_connection_get_timeout(NDhcp4CConnection *connection,
|
||||
switch (connection->request->userdata.type) {
|
||||
case N_DHCP4_C_MESSAGE_DISCOVER:
|
||||
case N_DHCP4_C_MESSAGE_SELECT:
|
||||
case N_DHCP4_C_MESSAGE_REBOOT:
|
||||
case N_DHCP4_C_MESSAGE_INFORM:
|
||||
/*
|
||||
* Resend with an exponential backoff and a one second random
|
||||
@@ -335,6 +355,7 @@ void n_dhcp4_c_connection_get_timeout(NDhcp4CConnection *connection,
|
||||
break;
|
||||
case N_DHCP4_C_MESSAGE_REBIND:
|
||||
case N_DHCP4_C_MESSAGE_RENEW:
|
||||
case N_DHCP4_C_MESSAGE_REBOOT:
|
||||
/*
|
||||
* Resend every sixty seconds with a one second random slack.
|
||||
*
|
||||
@@ -510,6 +531,7 @@ static int n_dhcp4_c_connection_new_message(NDhcp4CConnection *connection,
|
||||
n_dhcp4_c_connection_init_header(connection, header);
|
||||
|
||||
message->userdata.type = type;
|
||||
message->userdata.message_type = message_type;
|
||||
|
||||
/*
|
||||
* Note that some implementations expect the MESSAGE_TYPE option to be
|
||||
@@ -687,6 +709,7 @@ int n_dhcp4_c_connection_select_new(NDhcp4CConnection *connection,
|
||||
*/
|
||||
message->userdata.start_time = offer->userdata.start_time;
|
||||
message->userdata.base_time = offer->userdata.base_time;
|
||||
message->userdata.client_addr = client.s_addr;
|
||||
n_dhcp4_incoming_get_xid(offer, &xid);
|
||||
n_dhcp4_outgoing_set_xid(message, xid);
|
||||
|
||||
@@ -760,6 +783,7 @@ int n_dhcp4_c_connection_renew_new(NDhcp4CConnection *connection,
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
message->userdata.client_addr = connection->client_ip;
|
||||
*requestp = message;
|
||||
message = NULL;
|
||||
return 0;
|
||||
@@ -793,6 +817,7 @@ int n_dhcp4_c_connection_rebind_new(NDhcp4CConnection *connection,
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
message->userdata.client_addr = connection->client_ip;
|
||||
*requestp = message;
|
||||
message = NULL;
|
||||
return 0;
|
||||
@@ -844,6 +869,7 @@ int n_dhcp4_c_connection_decline_new(NDhcp4CConnection *connection,
|
||||
return r;
|
||||
}
|
||||
|
||||
message->userdata.client_addr = client.s_addr;
|
||||
*requestp = message;
|
||||
message = NULL;
|
||||
return 0;
|
||||
@@ -886,6 +912,7 @@ int n_dhcp4_c_connection_inform_new(NDhcp4CConnection *connection,
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
message->userdata.client_addr = connection->client_ip;
|
||||
*requestp = message;
|
||||
message = NULL;
|
||||
return 0;
|
||||
@@ -952,10 +979,39 @@ int n_dhcp4_c_connection_release_new(NDhcp4CConnection *connection,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *message_type_to_str(uint8_t type) {
|
||||
switch (type) {
|
||||
case N_DHCP4_MESSAGE_DISCOVER:
|
||||
return "DISCOVER";
|
||||
case N_DHCP4_MESSAGE_OFFER:
|
||||
return "OFFER";
|
||||
case N_DHCP4_MESSAGE_REQUEST:
|
||||
return "REQUEST";
|
||||
case N_DHCP4_MESSAGE_DECLINE:
|
||||
return "DECLINE";
|
||||
case N_DHCP4_MESSAGE_ACK:
|
||||
return "ACK";
|
||||
case N_DHCP4_MESSAGE_NAK:
|
||||
return "NACK";
|
||||
case N_DHCP4_MESSAGE_RELEASE:
|
||||
return "RELEASE";
|
||||
case N_DHCP4_MESSAGE_INFORM:
|
||||
return "INFORM";
|
||||
case N_DHCP4_MESSAGE_FORCERENEW:
|
||||
return "FORCERENEW";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
static int n_dhcp4_c_connection_send_request(NDhcp4CConnection *connection,
|
||||
NDhcp4Outgoing *request,
|
||||
uint64_t timestamp) {
|
||||
char server_addr[INET_ADDRSTRLEN];
|
||||
char client_addr[INET_ADDRSTRLEN];
|
||||
char error_msg[128];
|
||||
int r;
|
||||
bool broadcast = false;
|
||||
|
||||
/*
|
||||
* Increment the base time and reset the xid field,
|
||||
@@ -990,28 +1046,52 @@ static int n_dhcp4_c_connection_send_request(NDhcp4CConnection *connection,
|
||||
case N_DHCP4_C_MESSAGE_SELECT:
|
||||
case N_DHCP4_C_MESSAGE_REBOOT:
|
||||
case N_DHCP4_C_MESSAGE_DECLINE:
|
||||
case N_DHCP4_C_MESSAGE_REBIND:
|
||||
broadcast = true;
|
||||
r = n_dhcp4_c_connection_packet_broadcast(connection, request);
|
||||
if (r)
|
||||
return r;
|
||||
break;
|
||||
case N_DHCP4_C_MESSAGE_INFORM:
|
||||
case N_DHCP4_C_MESSAGE_REBIND:
|
||||
broadcast = true;
|
||||
r = n_dhcp4_c_connection_udp_broadcast(connection, request);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
break;
|
||||
case N_DHCP4_C_MESSAGE_RENEW:
|
||||
case N_DHCP4_C_MESSAGE_RELEASE:
|
||||
r = n_dhcp4_c_connection_udp_send(connection, request);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
break;
|
||||
default:
|
||||
c_assert(0);
|
||||
}
|
||||
|
||||
if (r) {
|
||||
snprintf(error_msg, sizeof(error_msg), ": error %d", r);
|
||||
} else {
|
||||
error_msg[0] = '\0';
|
||||
}
|
||||
|
||||
if (request->userdata.client_addr == INADDR_ANY) {
|
||||
n_dhcp4_log(connection->log_queue,
|
||||
LOG_INFO,
|
||||
"send %s to %s%s",
|
||||
message_type_to_str(request->userdata.message_type),
|
||||
broadcast ?
|
||||
"255.255.255.255" :
|
||||
inet_ntop(AF_INET, &connection->server_ip,
|
||||
server_addr, sizeof(server_addr)),
|
||||
error_msg);
|
||||
} else {
|
||||
n_dhcp4_log(connection->log_queue,
|
||||
LOG_INFO,
|
||||
"send %s of %s to %s%s",
|
||||
message_type_to_str(request->userdata.message_type),
|
||||
inet_ntop(AF_INET, &request->userdata.client_addr,
|
||||
client_addr, sizeof(client_addr)),
|
||||
broadcast ?
|
||||
"255.255.255.255" :
|
||||
inet_ntop(AF_INET, &connection->server_ip,
|
||||
server_addr, sizeof(server_addr)),
|
||||
error_msg);
|
||||
}
|
||||
|
||||
++request->userdata.n_send;
|
||||
return 0;
|
||||
}
|
||||
@@ -1030,13 +1110,14 @@ int n_dhcp4_c_connection_start_request(NDhcp4CConnection *connection,
|
||||
if (request->userdata.start_time == 0)
|
||||
request->userdata.start_time = timestamp;
|
||||
|
||||
n_dhcp4_outgoing_free(connection->request);
|
||||
connection->request = request;
|
||||
connection->request = n_dhcp4_outgoing_free(connection->request);
|
||||
|
||||
r = n_dhcp4_c_connection_send_request(connection, request, timestamp);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
connection->request = request;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1060,9 +1141,18 @@ int n_dhcp4_c_connection_dispatch_timer(NDhcp4CConnection *connection,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns:
|
||||
* 0 on success
|
||||
* N_DHCP4_E_MALFORMED if a malformed packet was received
|
||||
* N_DHCP4_E_UNEXPECTED if the packet received contains unexpected data
|
||||
* N_DHCP4_E_AGAIN if there was another error (non fatal for the client)
|
||||
*/
|
||||
int n_dhcp4_c_connection_dispatch_io(NDhcp4CConnection *connection,
|
||||
NDhcp4Incoming **messagep) {
|
||||
_c_cleanup_(n_dhcp4_incoming_freep) NDhcp4Incoming *message = NULL;
|
||||
char serv_addr[INET_ADDRSTRLEN];
|
||||
char client_addr[INET_ADDRSTRLEN];
|
||||
uint8_t type;
|
||||
int r;
|
||||
|
||||
@@ -1072,10 +1162,11 @@ int n_dhcp4_c_connection_dispatch_io(NDhcp4CConnection *connection,
|
||||
connection->scratch_buffer,
|
||||
sizeof(connection->scratch_buffer),
|
||||
&message);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
if (!r)
|
||||
break;
|
||||
else if (r == N_DHCP4_E_MALFORMED)
|
||||
return r;
|
||||
return N_DHCP4_E_AGAIN;
|
||||
case N_DHCP4_C_CONNECTION_STATE_DRAINING:
|
||||
r = n_dhcp4_c_socket_packet_recv(connection->fd_packet,
|
||||
connection->scratch_buffer,
|
||||
@@ -1083,8 +1174,10 @@ int n_dhcp4_c_connection_dispatch_io(NDhcp4CConnection *connection,
|
||||
&message);
|
||||
if (!r)
|
||||
break;
|
||||
else if (r != N_DHCP4_E_AGAIN)
|
||||
else if (r == N_DHCP4_E_MALFORMED)
|
||||
return r;
|
||||
else if (r != N_DHCP4_E_AGAIN)
|
||||
return N_DHCP4_E_AGAIN;
|
||||
|
||||
/*
|
||||
* The UDP socket is open and the packet socket has been shut down
|
||||
@@ -1102,18 +1195,39 @@ int n_dhcp4_c_connection_dispatch_io(NDhcp4CConnection *connection,
|
||||
connection->scratch_buffer,
|
||||
sizeof(connection->scratch_buffer),
|
||||
&message);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
if (!r)
|
||||
break;
|
||||
else if (r == N_DHCP4_E_MALFORMED)
|
||||
return r;
|
||||
return N_DHCP4_E_AGAIN;
|
||||
default:
|
||||
abort();
|
||||
return -ENOTRECOVERABLE;
|
||||
}
|
||||
|
||||
r = n_dhcp4_c_connection_verify_incoming(connection, message, &type);
|
||||
if (r)
|
||||
if (r == N_DHCP4_E_MALFORMED || r == N_DHCP4_E_UNEXPECTED)
|
||||
return r;
|
||||
else if (r != 0)
|
||||
return N_DHCP4_E_AGAIN;
|
||||
|
||||
if (type == N_DHCP4_MESSAGE_OFFER || type == N_DHCP4_MESSAGE_ACK) {
|
||||
n_dhcp4_log(connection->log_queue,
|
||||
LOG_INFO,
|
||||
"received %s of %s from %s",
|
||||
message_type_to_str(type),
|
||||
inet_ntop(AF_INET, &message->message.header.yiaddr,
|
||||
client_addr, sizeof(client_addr)),
|
||||
inet_ntop(AF_INET, &message->message.header.siaddr,
|
||||
serv_addr, sizeof(serv_addr)));
|
||||
} else {
|
||||
n_dhcp4_log(connection->log_queue,
|
||||
LOG_INFO,
|
||||
"received %s from %s",
|
||||
message_type_to_str(type),
|
||||
inet_ntop(AF_INET, &message->message.header.siaddr,
|
||||
serv_addr, sizeof(serv_addr)));
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case N_DHCP4_MESSAGE_OFFER:
|
||||
|
@@ -44,9 +44,6 @@ static int n_dhcp4_incoming_get_timeouts(NDhcp4Incoming *message, uint64_t *t1p,
|
||||
} else if (u32 == UINT32_MAX) {
|
||||
lifetime = UINT64_MAX;
|
||||
} else {
|
||||
if (u32 == UINT32_MAX)
|
||||
lifetime = UINT64_MAX;
|
||||
else
|
||||
lifetime = u32 * (1000000000ULL);
|
||||
}
|
||||
|
||||
@@ -206,6 +203,32 @@ _c_public_ void n_dhcp4_client_lease_get_yiaddr(NDhcp4ClientLease *lease, struct
|
||||
yiaddr->s_addr = header->yiaddr;
|
||||
}
|
||||
|
||||
/**
|
||||
* n_dhcp4_client_lease_get_siaddr() - get the server IP address
|
||||
* @lease: the lease to operate on
|
||||
* @siaddr: return argument for the IP address
|
||||
*
|
||||
* Gets the server IP address cotained in the lease. Or INADDR_ANY if the
|
||||
* lease does not contain an IP address.
|
||||
*/
|
||||
_c_public_ void n_dhcp4_client_lease_get_siaddr(NDhcp4ClientLease *lease, struct in_addr *siaddr) {
|
||||
NDhcp4Header *header = n_dhcp4_incoming_get_header(lease->message);
|
||||
|
||||
siaddr->s_addr = header->siaddr;
|
||||
}
|
||||
|
||||
/**
|
||||
* n_dhcp4_client_lease_get_basetime() - get the timestamp when the lease was received.
|
||||
* @lease: the lease to operate on
|
||||
* @ns_basetimep: return argument for the base time in nano seconds
|
||||
*
|
||||
* Gets the timestamp when the lease was received in CLOCK_BOOTTIME. This
|
||||
* is also the base timestamp for the expiration of the lifetime and t1/t2.
|
||||
*/
|
||||
_c_public_ void n_dhcp4_client_lease_get_basetime(NDhcp4ClientLease *lease, uint64_t *ns_basetimep) {
|
||||
*ns_basetimep = lease->message->userdata.base_time;
|
||||
}
|
||||
|
||||
/**
|
||||
* n_dhcp4_client_lease_get_lifetime() - get the lifetime
|
||||
* @lease: the lease to operate on
|
||||
|
@@ -26,7 +26,7 @@ static int n_dhcp4_client_probe_option_new(NDhcp4ClientProbeOption **optionp,
|
||||
uint8_t n_data) {
|
||||
NDhcp4ClientProbeOption *op;
|
||||
|
||||
op = malloc(sizeof(op) + n_data);
|
||||
op = malloc(sizeof(*op) + n_data);
|
||||
if (!op)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -170,8 +170,6 @@ _c_public_ void n_dhcp4_client_probe_config_set_inform_only(NDhcp4ClientProbeCon
|
||||
* INIT-REBOOT path, as described by the DHCP specification. In most cases, you
|
||||
* do not want this.
|
||||
*
|
||||
* XXX: This is currently not implemented, and setting the property has no effect.
|
||||
*
|
||||
* Background: The INIT-REBOOT path allows a DHCP client to skip
|
||||
* server-discovery when rebooting/resuming their machine. The DHCP
|
||||
* client simply re-requests the lease it had acquired before. This
|
||||
@@ -431,17 +429,30 @@ int n_dhcp4_client_probe_new(NDhcp4ClientProbe **probep,
|
||||
*/
|
||||
n_dhcp4_client_probe_config_initialize_random_seed(probe->config);
|
||||
|
||||
/* The new probe keeps a reference on @client. So we are sure that &client->log_queue
|
||||
* stays alive as long as we need it. */
|
||||
|
||||
r = n_dhcp4_c_connection_init(&probe->connection,
|
||||
client->config,
|
||||
probe->config,
|
||||
&client->log_queue,
|
||||
active ? client->fd_epoll : -1);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
if (probe->config->requested_ip.s_addr != INADDR_ANY)
|
||||
probe->last_address = probe->config->requested_ip;
|
||||
|
||||
if (probe->config->init_reboot && probe->last_address.s_addr != INADDR_ANY)
|
||||
probe->state = N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT;
|
||||
else
|
||||
probe->state = N_DHCP4_CLIENT_PROBE_STATE_INIT;
|
||||
|
||||
if (active) {
|
||||
/*
|
||||
* Defer the sending of DISCOVER by a random amount (by default up to 9 seconds).
|
||||
*/
|
||||
if (probe->state == N_DHCP4_CLIENT_PROBE_STATE_INIT)
|
||||
probe->ns_deferred = ns_now + (n_dhcp4_client_probe_config_get_random(probe->config) % (probe->config->ms_start_delay * 1000000ULL));
|
||||
probe->client->current_probe = probe;
|
||||
} else {
|
||||
@@ -483,6 +494,7 @@ _c_public_ NDhcp4ClientProbe *n_dhcp4_client_probe_free(NDhcp4ClientProbe *probe
|
||||
if (probe == probe->client->current_probe)
|
||||
probe->client->current_probe = NULL;
|
||||
|
||||
n_dhcp4_client_lease_unref(probe->current_lease);
|
||||
n_dhcp4_c_connection_deinit(&probe->connection);
|
||||
n_dhcp4_client_unref(probe->client);
|
||||
n_dhcp4_client_probe_config_free(probe->config);
|
||||
@@ -574,6 +586,14 @@ void n_dhcp4_client_probe_get_timeout(NDhcp4ClientProbe *probe, uint64_t *timeou
|
||||
n_dhcp4_c_connection_get_timeout(&probe->connection, &timeout);
|
||||
|
||||
switch (probe->state) {
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT:
|
||||
/* send DHCP request immediately */
|
||||
timeout = 1;
|
||||
break;
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_REBOOTING:
|
||||
if (probe->ns_reinit && (!timeout || probe->ns_reinit < timeout))
|
||||
timeout = probe->ns_reinit;
|
||||
break;
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_INIT:
|
||||
if (probe->ns_deferred && (!timeout || probe->ns_deferred < timeout))
|
||||
timeout = probe->ns_deferred;
|
||||
@@ -625,6 +645,52 @@ static int n_dhcp4_client_probe_outgoing_append_options(NDhcp4ClientProbe *probe
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int n_dhcp4_client_probe_transition_reboot(NDhcp4ClientProbe *probe, uint64_t ns_now) {
|
||||
_c_cleanup_(n_dhcp4_outgoing_freep) NDhcp4Outgoing *request = NULL;
|
||||
int r;
|
||||
|
||||
switch (probe->state) {
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT:
|
||||
r = n_dhcp4_c_connection_listen(&probe->connection);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = n_dhcp4_c_connection_reboot_new(&probe->connection, &request, &probe->last_address);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = n_dhcp4_client_probe_outgoing_append_options(probe, request);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = n_dhcp4_c_connection_start_request(&probe->connection, request, ns_now);
|
||||
if (r)
|
||||
return r;
|
||||
else
|
||||
request = NULL; /* consumed */
|
||||
|
||||
probe->state = N_DHCP4_CLIENT_PROBE_STATE_REBOOTING;
|
||||
probe->ns_reinit = ns_now + 2000000000ULL;
|
||||
|
||||
break;
|
||||
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_SELECTING:
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_INIT:
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_REBOOTING:
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_REQUESTING:
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_GRANTED:
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_BOUND:
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_RENEWING:
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_REBINDING:
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_EXPIRED:
|
||||
default:
|
||||
abort();
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int n_dhcp4_client_probe_transition_deferred(NDhcp4ClientProbe *probe, uint64_t ns_now) {
|
||||
_c_cleanup_(n_dhcp4_outgoing_freep) NDhcp4Outgoing *request = NULL;
|
||||
int r;
|
||||
@@ -634,13 +700,15 @@ static int n_dhcp4_client_probe_transition_deferred(NDhcp4ClientProbe *probe, ui
|
||||
r = n_dhcp4_c_connection_listen(&probe->connection);
|
||||
if (r)
|
||||
return r;
|
||||
/* fall-through */
|
||||
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_REBOOTING:
|
||||
r = n_dhcp4_c_connection_discover_new(&probe->connection, &request);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
if (probe->config->requested_ip.s_addr != INADDR_ANY) {
|
||||
r = n_dhcp4_outgoing_append_requested_ip(request, probe->config->requested_ip);
|
||||
if (probe->last_address.s_addr != INADDR_ANY) {
|
||||
r = n_dhcp4_outgoing_append_requested_ip(request, probe->last_address);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
@@ -662,7 +730,6 @@ static int n_dhcp4_client_probe_transition_deferred(NDhcp4ClientProbe *probe, ui
|
||||
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_SELECTING:
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT:
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_REBOOTING:
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_REQUESTING:
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_GRANTED:
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_BOUND:
|
||||
@@ -725,6 +792,10 @@ static int n_dhcp4_client_probe_transition_t2(NDhcp4ClientProbe *probe, uint64_t
|
||||
switch (probe->state) {
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_BOUND:
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_RENEWING:
|
||||
r = n_dhcp4_c_connection_listen(&probe->connection);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = n_dhcp4_c_connection_rebind_new(&probe->connection, &request);
|
||||
if (r)
|
||||
return r;
|
||||
@@ -777,11 +848,11 @@ static int n_dhcp4_client_probe_transition_lifetime(NDhcp4ClientProbe *probe) {
|
||||
return r;
|
||||
|
||||
c_assert(probe->client->current_probe == probe);
|
||||
probe->client->current_probe = NULL;
|
||||
|
||||
n_dhcp4_c_connection_close(&probe->connection);
|
||||
probe->current_lease = n_dhcp4_client_lease_unref(probe->current_lease);
|
||||
|
||||
probe->state = N_DHCP4_CLIENT_PROBE_STATE_EXPIRED;
|
||||
probe->state = N_DHCP4_CLIENT_PROBE_STATE_INIT;
|
||||
probe->ns_deferred = n_dhcp4_gettime(CLOCK_BOOTTIME) + UINT64_C(1);
|
||||
|
||||
break;
|
||||
|
||||
@@ -799,7 +870,8 @@ static int n_dhcp4_client_probe_transition_lifetime(NDhcp4ClientProbe *probe) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int n_dhcp4_client_probe_transition_offer(NDhcp4ClientProbe *probe, NDhcp4Incoming *message) {
|
||||
static int n_dhcp4_client_probe_transition_offer(NDhcp4ClientProbe *probe, NDhcp4Incoming *message_take) {
|
||||
_c_cleanup_(n_dhcp4_incoming_freep) NDhcp4Incoming *message = message_take;
|
||||
_c_cleanup_(n_dhcp4_client_lease_unrefp) NDhcp4ClientLease *lease = NULL;
|
||||
NDhcp4CEventNode *node;
|
||||
int r;
|
||||
@@ -817,7 +889,7 @@ static int n_dhcp4_client_probe_transition_offer(NDhcp4ClientProbe *probe, NDhcp
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
/* message consumed, do not fail */
|
||||
message = NULL; /* consumed */
|
||||
|
||||
n_dhcp4_client_lease_link(lease, probe);
|
||||
|
||||
@@ -842,14 +914,26 @@ static int n_dhcp4_client_probe_transition_offer(NDhcp4ClientProbe *probe, NDhcp
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int n_dhcp4_client_probe_transition_ack(NDhcp4ClientProbe *probe, NDhcp4Incoming *message) {
|
||||
static int n_dhcp4_client_probe_transition_ack(NDhcp4ClientProbe *probe, NDhcp4Incoming *message_take) {
|
||||
_c_cleanup_(n_dhcp4_incoming_freep) NDhcp4Incoming *message = message_take;
|
||||
_c_cleanup_(n_dhcp4_client_lease_unrefp) NDhcp4ClientLease *lease = NULL;
|
||||
NDhcp4CEventNode *node;
|
||||
struct in_addr client = {};
|
||||
struct in_addr server = {};
|
||||
int r;
|
||||
|
||||
switch (probe->state) {
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_RENEWING:
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_REBINDING:
|
||||
n_dhcp4_incoming_get_yiaddr(message, &client);
|
||||
|
||||
r = n_dhcp4_incoming_query_server_identifier(message, &server);
|
||||
if (r)
|
||||
return r;
|
||||
r = n_dhcp4_c_connection_connect(&probe->connection, &client, &server);
|
||||
if (r)
|
||||
return r;
|
||||
/* fall-through */
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_RENEWING:
|
||||
|
||||
r = n_dhcp4_client_probe_raise(probe,
|
||||
&node,
|
||||
@@ -861,7 +945,7 @@ static int n_dhcp4_client_probe_transition_ack(NDhcp4ClientProbe *probe, NDhcp4I
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
/* message consumed, do not fail */
|
||||
message = NULL; /* consumed */
|
||||
|
||||
n_dhcp4_client_lease_link(lease, probe);
|
||||
|
||||
@@ -869,10 +953,12 @@ static int n_dhcp4_client_probe_transition_ack(NDhcp4ClientProbe *probe, NDhcp4I
|
||||
n_dhcp4_client_lease_unref(probe->current_lease);
|
||||
probe->current_lease = n_dhcp4_client_lease_ref(lease);
|
||||
probe->state = N_DHCP4_CLIENT_PROBE_STATE_BOUND;
|
||||
|
||||
n_dhcp4_client_lease_get_yiaddr(lease, &probe->last_address);
|
||||
probe->ns_nak_restart_delay = 0;
|
||||
break;
|
||||
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_REQUESTING:
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_REBOOTING:
|
||||
|
||||
r = n_dhcp4_client_probe_raise(probe,
|
||||
&node,
|
||||
@@ -884,20 +970,19 @@ static int n_dhcp4_client_probe_transition_ack(NDhcp4ClientProbe *probe, NDhcp4I
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
/* message consumed, don to fail */
|
||||
message = NULL; /* consumed */
|
||||
|
||||
n_dhcp4_client_lease_link(lease, probe);
|
||||
|
||||
node->event.granted.lease = n_dhcp4_client_lease_ref(lease);
|
||||
probe->current_lease = n_dhcp4_client_lease_ref(lease);
|
||||
probe->state = N_DHCP4_CLIENT_PROBE_STATE_GRANTED;
|
||||
|
||||
probe->ns_nak_restart_delay = 0;
|
||||
break;
|
||||
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_INIT:
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_SELECTING:
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT:
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_REBOOTING:
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_BOUND:
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_GRANTED:
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_EXPIRED:
|
||||
@@ -927,9 +1012,11 @@ static int n_dhcp4_client_probe_transition_nak(NDhcp4ClientProbe *probe) {
|
||||
return r;
|
||||
|
||||
probe->state = N_DHCP4_CLIENT_PROBE_STATE_INIT;
|
||||
|
||||
probe->ns_deferred = n_dhcp4_gettime(CLOCK_BOOTTIME) + probe->ns_nak_restart_delay;
|
||||
probe->ns_nak_restart_delay = C_CLAMP(probe->ns_nak_restart_delay * 2u,
|
||||
UINT64_C(2) * UINT64_C(1000000000),
|
||||
UINT64_C(300) * UINT64_C(1000000000));
|
||||
break;
|
||||
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_SELECTING:
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT:
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_INIT:
|
||||
@@ -1008,7 +1095,7 @@ int n_dhcp4_client_probe_transition_accept(NDhcp4ClientProbe *probe, NDhcp4Incom
|
||||
|
||||
probe->state = N_DHCP4_CLIENT_PROBE_STATE_BOUND;
|
||||
|
||||
/* XXX: trigger timers */
|
||||
n_dhcp4_client_arm_timer(probe->client);
|
||||
|
||||
break;
|
||||
|
||||
@@ -1076,6 +1163,19 @@ int n_dhcp4_client_probe_dispatch_timer(NDhcp4ClientProbe *probe, uint64_t ns_no
|
||||
int r;
|
||||
|
||||
switch (probe->state) {
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT:
|
||||
r = n_dhcp4_client_probe_transition_reboot(probe, ns_now);
|
||||
if (r)
|
||||
return r;
|
||||
break;
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_REBOOTING:
|
||||
if (ns_now >= probe->ns_reinit) {
|
||||
r = n_dhcp4_client_probe_transition_deferred(probe, ns_now);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
|
||||
break;
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_INIT:
|
||||
if (ns_now >= probe->ns_deferred) {
|
||||
r = n_dhcp4_client_probe_transition_deferred(probe, ns_now);
|
||||
@@ -1099,16 +1199,17 @@ int n_dhcp4_client_probe_dispatch_timer(NDhcp4ClientProbe *probe, uint64_t ns_no
|
||||
r = n_dhcp4_client_probe_transition_lifetime(probe);
|
||||
if (r)
|
||||
return r;
|
||||
} else if (ns_now >= probe->current_lease->t2) {
|
||||
} else if (ns_now >= probe->current_lease->t2 &&
|
||||
probe->state != N_DHCP4_CLIENT_PROBE_STATE_REBINDING) {
|
||||
r = n_dhcp4_client_probe_transition_t2(probe, ns_now);
|
||||
if (r)
|
||||
return r;
|
||||
} else if (ns_now >= probe->current_lease->t1) {
|
||||
} else if (ns_now >= probe->current_lease->t1 &&
|
||||
probe->state == N_DHCP4_CLIENT_PROBE_STATE_BOUND) {
|
||||
r = n_dhcp4_client_probe_transition_t1(probe, ns_now);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
/* ignore */
|
||||
@@ -1145,6 +1246,7 @@ int n_dhcp4_client_probe_dispatch_io(NDhcp4ClientProbe *probe, uint32_t events)
|
||||
return 0;
|
||||
}
|
||||
|
||||
abort();
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -1166,17 +1268,15 @@ int n_dhcp4_client_probe_dispatch_io(NDhcp4ClientProbe *probe, uint32_t events)
|
||||
switch (type) {
|
||||
case N_DHCP4_MESSAGE_OFFER:
|
||||
r = n_dhcp4_client_probe_transition_offer(probe, message);
|
||||
message = NULL; /* consumed */
|
||||
if (r)
|
||||
return r;
|
||||
else
|
||||
message = NULL; /* consumed */
|
||||
break;
|
||||
case N_DHCP4_MESSAGE_ACK:
|
||||
r = n_dhcp4_client_probe_transition_ack(probe, message);
|
||||
message = NULL; /* consumed */
|
||||
if (r)
|
||||
return r;
|
||||
else
|
||||
message = NULL; /* consumed */
|
||||
break;
|
||||
case N_DHCP4_MESSAGE_NAK:
|
||||
r = n_dhcp4_client_probe_transition_nak(probe);
|
||||
|
@@ -183,7 +183,11 @@ _c_public_ void n_dhcp4_client_config_set_request_broadcast(NDhcp4ClientConfig *
|
||||
*/
|
||||
_c_public_ void n_dhcp4_client_config_set_mac(NDhcp4ClientConfig *config, const uint8_t *mac, size_t n_mac) {
|
||||
config->n_mac = n_mac;
|
||||
memcpy(config->mac, mac, c_min(n_mac, sizeof(config->mac)));
|
||||
|
||||
if (n_mac > sizeof(config->mac))
|
||||
n_mac = sizeof(config->mac);
|
||||
|
||||
memcpy(config->mac, mac, n_mac);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -209,37 +213,77 @@ _c_public_ void n_dhcp4_client_config_set_mac(NDhcp4ClientConfig *config, const
|
||||
*/
|
||||
_c_public_ void n_dhcp4_client_config_set_broadcast_mac(NDhcp4ClientConfig *config, const uint8_t *mac, size_t n_mac) {
|
||||
config->n_broadcast_mac = n_mac;
|
||||
memcpy(config->broadcast_mac, mac, c_min(n_mac, sizeof(config->broadcast_mac)));
|
||||
|
||||
if (n_mac > sizeof(config->mac))
|
||||
n_mac = sizeof(config->mac);
|
||||
|
||||
memcpy(config->broadcast_mac, mac, n_mac);
|
||||
}
|
||||
|
||||
/**
|
||||
* n_dhcp4_client_config_set_client_id() - set client-id property
|
||||
* @config: client configuration to operate on
|
||||
* @id: client id
|
||||
* @n_id: length of the client id in bytes
|
||||
* @n_id: length of the client id in bytes. The length
|
||||
* must be from 2 up to 255 bytes. Set it to 0
|
||||
* to unset the client-id.
|
||||
*
|
||||
* This sets the client-id property of @config. It copies the entire client-id
|
||||
* buffer into the configuration.
|
||||
* See RFC 2132 (section 9.14) for the format of the Client Identifier.
|
||||
*
|
||||
* Return: 0 on success, negative error code on failure.
|
||||
*/
|
||||
_c_public_ int n_dhcp4_client_config_set_client_id(NDhcp4ClientConfig *config, const uint8_t *id, size_t n_id) {
|
||||
uint8_t *t;
|
||||
|
||||
if (n_id == 0) {
|
||||
config->client_id = c_free(config->client_id);
|
||||
config->n_client_id = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (n_id < 2 || n_id > 255)
|
||||
return -EINVAL;
|
||||
|
||||
t = malloc(n_id + 1);
|
||||
if (!t)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(t, id, n_id);
|
||||
t[n_id] = 0; /* safety 0 for debugging */
|
||||
|
||||
free(config->client_id);
|
||||
config->client_id = t;
|
||||
config->n_client_id = n_id;
|
||||
|
||||
memcpy(config->client_id, id, n_id);
|
||||
config->client_id[n_id] = 0; /* safety 0 for debugging */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* n_dhcp4_client_set_log_level() - set the logging level of the client
|
||||
* @client: the client to operate on
|
||||
* @level: the minimum syslog logging level that is
|
||||
* still logged. For example, set to LOG_NOTICE
|
||||
* to receive logging events with level LOG_NOTICE
|
||||
* and higher. Set to -1 to disable generating
|
||||
* logging events (which is also the default).
|
||||
*
|
||||
* By enabling logging, you can get N_DHCP4_CLIENT_EVENT_LOG events.
|
||||
*
|
||||
* From the logging event you may steal the message if (and only if) "allow_steal_message"
|
||||
* is true. In that case, clear the message field and free the message yourself.
|
||||
*
|
||||
* If a logging event cannot be logged due to out of memory, one message
|
||||
* gets logged that messages are missing. Until the event with that message
|
||||
* gets dropped, no further logging events will be queued.
|
||||
*
|
||||
* You may change the logging level at any time, but it does not affect
|
||||
* logging events that are already queued.
|
||||
*/
|
||||
_c_public_ void n_dhcp4_client_set_log_level(NDhcp4Client *client, int level) {
|
||||
client->log_queue.log_level = level;
|
||||
}
|
||||
|
||||
/**
|
||||
* n_dhcp4_c_event_node_new() - allocate new event
|
||||
* @nodep: output argument for new event
|
||||
@@ -293,6 +337,16 @@ NDhcp4CEventNode *n_dhcp4_c_event_node_free(NDhcp4CEventNode *node) {
|
||||
case N_DHCP4_CLIENT_EVENT_EXTENDED:
|
||||
node->event.extended.lease = n_dhcp4_client_lease_unref(node->event.extended.lease);
|
||||
break;
|
||||
case N_DHCP4_CLIENT_EVENT_LOG:
|
||||
if (_c_unlikely_(!node->event.log.allow_steal_message)) {
|
||||
/* @node is the static node "nomem_node". It must not be
|
||||
* freed. */
|
||||
c_list_unlink(&node->client_link);
|
||||
node->is_public = false;
|
||||
return NULL;
|
||||
}
|
||||
node->event.log.message = c_free((char *)node->event.log.message);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -368,13 +422,18 @@ _c_public_ int n_dhcp4_client_new(NDhcp4Client **clientp, NDhcp4ClientConfig *co
|
||||
return -errno;
|
||||
|
||||
client->fd_timer = timerfd_create(CLOCK_BOOTTIME, TFD_CLOEXEC | TFD_NONBLOCK);
|
||||
if (client->fd_timer < 0 && errno == EINVAL)
|
||||
client->fd_timer = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);
|
||||
if (client->fd_timer < 0)
|
||||
return -errno;
|
||||
|
||||
ev.data.u32 = N_DHCP4_CLIENT_EPOLL_TIMER;
|
||||
r = epoll_ctl(client->fd_epoll, EPOLL_CTL_ADD, client->fd_timer, &ev);
|
||||
if (r < 0)
|
||||
if (r < 0) {
|
||||
close(client->fd_timer);
|
||||
client->fd_timer = -1;
|
||||
return -errno;
|
||||
}
|
||||
|
||||
*clientp = client;
|
||||
client = NULL;
|
||||
@@ -464,6 +523,78 @@ int n_dhcp4_client_raise(NDhcp4Client *client, NDhcp4CEventNode **nodep, unsigne
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* n_dhcp4_log_queue_fmt() - add a logging event.
|
||||
* @client: the NDhcp4LogQueue to operate on
|
||||
* @level: the syslog logging level
|
||||
* @fmt: the format string for the message
|
||||
* @... printf arguments for logging
|
||||
*
|
||||
* Appends a logging event to the event queue if logging is
|
||||
* enabled and the logging level sufficiently high.
|
||||
*
|
||||
* Queuing a logging event might fail with out of memory.
|
||||
* In that case, a static event will be queued that informs
|
||||
* about lost messages.
|
||||
*/
|
||||
void n_dhcp4_log_queue_fmt(NDhcp4LogQueue *log_queue,
|
||||
int level,
|
||||
const char *fmt,
|
||||
...) {
|
||||
NDhcp4CEventNode *node;
|
||||
char *message;
|
||||
va_list ap;
|
||||
int r;
|
||||
|
||||
if (level > log_queue->log_level)
|
||||
return;
|
||||
|
||||
/* Currently the logging queue is only implemented for
|
||||
* the client. Nobody would enable logging except a
|
||||
* client instance. */
|
||||
c_assert(log_queue->is_client);
|
||||
|
||||
if (!c_list_is_empty (&log_queue->nomem_node.client_link)) {
|
||||
/* we have the nomem_node queued after a recent out
|
||||
* of memory. This disables all logging messages until
|
||||
* the event gets popped.
|
||||
*
|
||||
* The reason is that we can only queue the nomem_node once,
|
||||
* so if we now try to append another event and succeed, the
|
||||
* user wouldn't know which messages got dropped. Instead,
|
||||
* just drop them all!! */
|
||||
return;
|
||||
}
|
||||
|
||||
r = n_dhcp4_c_event_node_new(&node);
|
||||
if (r < 0)
|
||||
goto handle_nomem;
|
||||
|
||||
va_start(ap, fmt);
|
||||
r = vasprintf(&message, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (r < 0) {
|
||||
n_dhcp4_c_event_node_free(node);
|
||||
goto handle_nomem;
|
||||
}
|
||||
|
||||
node->event = (NDhcp4ClientEvent) {
|
||||
.event = N_DHCP4_CLIENT_EVENT_LOG,
|
||||
.log = {
|
||||
.level = level,
|
||||
.message = message,
|
||||
.allow_steal_message = true,
|
||||
},
|
||||
};
|
||||
|
||||
c_list_link_tail(log_queue->event_list, &node->client_link);
|
||||
return;
|
||||
|
||||
handle_nomem:
|
||||
c_list_link_tail(log_queue->event_list, &log_queue->nomem_node.client_link);
|
||||
}
|
||||
|
||||
/**
|
||||
* n_dhcp4_client_arm_timer() - update timer
|
||||
* @client: client to operate on
|
||||
@@ -472,19 +603,39 @@ int n_dhcp4_client_raise(NDhcp4Client *client, NDhcp4CEventNode **nodep, unsigne
|
||||
* must be called whenever a timeout on @client might have changed.
|
||||
*/
|
||||
void n_dhcp4_client_arm_timer(NDhcp4Client *client) {
|
||||
uint64_t timeout = 0;
|
||||
uint64_t now, offset, timeout = 0;
|
||||
int r;
|
||||
|
||||
if (client->current_probe)
|
||||
n_dhcp4_client_probe_get_timeout(client->current_probe, &timeout);
|
||||
|
||||
if (timeout != client->scheduled_timeout) {
|
||||
/*
|
||||
* Across our codebase, timeouts are specified as absolute
|
||||
* timestamps on CLOCK_BOOTTIME. Unfortunately, there are
|
||||
* systems with CLOCK_BOOTTIME support, but timerfd lacks it
|
||||
* (in particular RHEL). Therefore, our timerfd might be on
|
||||
* CLOCK_MONOTONIC.
|
||||
* To account for this, we always schedule a relative timeout.
|
||||
* We fetch the current time and then calculate the offset
|
||||
* which we then schedule as relative timeout on the timerfd.
|
||||
* This works regardless which clock the timerfd runs on.
|
||||
* Once we no longer support CLOCK_MONOTONIC as fallback, we
|
||||
* can simply switch to TFD_TIMER_ABSTIME here and specify
|
||||
* `timeout` directly as value.
|
||||
*/
|
||||
now = n_dhcp4_gettime(CLOCK_BOOTTIME);
|
||||
if (now >= timeout)
|
||||
offset = 1; /* 0 would disarm the timerfd */
|
||||
else
|
||||
offset = timeout - now;
|
||||
|
||||
r = timerfd_settime(client->fd_timer,
|
||||
TFD_TIMER_ABSTIME,
|
||||
0,
|
||||
&(struct itimerspec){
|
||||
.it_value = {
|
||||
.tv_sec = timeout / UINT64_C(1000000000),
|
||||
.tv_nsec = timeout % UINT64_C(1000000000),
|
||||
.tv_sec = offset / UINT64_C(1000000000),
|
||||
.tv_nsec = offset % UINT64_C(1000000000),
|
||||
},
|
||||
},
|
||||
NULL);
|
||||
@@ -639,7 +790,13 @@ _c_public_ int n_dhcp4_client_dispatch(NDhcp4Client *client) {
|
||||
|
||||
/* continue normally */
|
||||
} else if (r) {
|
||||
c_assert(r < _N_DHCP4_E_INTERNAL);
|
||||
if (r >= _N_DHCP4_E_INTERNAL) {
|
||||
n_dhcp4_log(&client->log_queue,
|
||||
LOG_ERR,
|
||||
"invalid internal error code %d after dispatch",
|
||||
r);
|
||||
return N_DHCP4_E_INTERNAL;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
}
|
||||
@@ -706,6 +863,8 @@ _c_public_ int n_dhcp4_client_dispatch(NDhcp4Client *client) {
|
||||
* the client attempted several incompatible
|
||||
* probes in parallel, then the most recent
|
||||
* ones will be cancelled asynchronously.
|
||||
* * N_DHCP4_CLIENT_EVENT_LOG: A logging event if n_dhcp4_client_set_log_level()
|
||||
* is enabled.
|
||||
*
|
||||
* Return: 0 on success, negative error code on failure.
|
||||
*/
|
||||
|
@@ -326,7 +326,7 @@ static int n_dhcp4_incoming_query_u8(NDhcp4Incoming *message, uint8_t option, ui
|
||||
r = n_dhcp4_incoming_query(message, option, &data, &n_data);
|
||||
if (r)
|
||||
return r;
|
||||
else if (n_data != sizeof(*data))
|
||||
else if (n_data < sizeof(*data))
|
||||
return N_DHCP4_E_MALFORMED;
|
||||
|
||||
*u8p = *data;
|
||||
@@ -342,7 +342,7 @@ static int n_dhcp4_incoming_query_u16(NDhcp4Incoming *message, uint8_t option, u
|
||||
r = n_dhcp4_incoming_query(message, option, &data, &n_data);
|
||||
if (r)
|
||||
return r;
|
||||
else if (n_data != sizeof(be16))
|
||||
else if (n_data < sizeof(be16))
|
||||
return N_DHCP4_E_MALFORMED;
|
||||
|
||||
memcpy(&be16, data, sizeof(be16));
|
||||
@@ -360,14 +360,11 @@ static int n_dhcp4_incoming_query_u32(NDhcp4Incoming *message, uint8_t option, u
|
||||
r = n_dhcp4_incoming_query(message, option, &data, &n_data);
|
||||
if (r)
|
||||
return r;
|
||||
else if (n_data != sizeof(be32))
|
||||
else if (n_data < sizeof(be32))
|
||||
return N_DHCP4_E_MALFORMED;
|
||||
|
||||
memcpy(&be32, data, sizeof(be32));
|
||||
|
||||
if (be32 == (uint32_t)-1)
|
||||
*u32p = 0;
|
||||
else
|
||||
*u32p = ntohl(be32);
|
||||
return 0;
|
||||
}
|
||||
@@ -381,7 +378,7 @@ static int n_dhcp4_incoming_query_in_addr(NDhcp4Incoming *message, uint8_t optio
|
||||
r = n_dhcp4_incoming_query(message, option, &data, &n_data);
|
||||
if (r)
|
||||
return r;
|
||||
else if (n_data != sizeof(be32))
|
||||
else if (n_data < sizeof(be32))
|
||||
return N_DHCP4_E_MALFORMED;
|
||||
|
||||
memcpy(&be32, data, sizeof(be32));
|
||||
|
@@ -54,8 +54,6 @@
|
||||
int n_dhcp4_outgoing_new(NDhcp4Outgoing **outgoingp, size_t max_size, uint8_t overload) {
|
||||
_c_cleanup_(n_dhcp4_outgoing_freep) NDhcp4Outgoing *outgoing = NULL;
|
||||
|
||||
c_assert(!(overload & ~(N_DHCP4_OVERLOAD_FILE | N_DHCP4_OVERLOAD_SNAME)));
|
||||
|
||||
/*
|
||||
* Make sure the minimum limit is bigger than the maximum protocol
|
||||
* header plus the DHCP-message-header plus a single OPTION_END byte.
|
||||
@@ -64,6 +62,8 @@ int n_dhcp4_outgoing_new(NDhcp4Outgoing **outgoingp, size_t max_size, uint8_t ov
|
||||
sizeof(NDhcp4Message) + 1,
|
||||
"Invalid minimum IP packet limit");
|
||||
|
||||
c_assert(!(overload & ~(N_DHCP4_OVERLOAD_FILE | N_DHCP4_OVERLOAD_SNAME)));
|
||||
|
||||
outgoing = calloc(1, sizeof(*outgoing));
|
||||
if (!outgoing)
|
||||
return -ENOMEM;
|
||||
@@ -220,8 +220,9 @@ int n_dhcp4_outgoing_append(NDhcp4Outgoing *outgoing,
|
||||
/* try fitting into allowed OPTIONs space */
|
||||
if (outgoing->max_size - outgoing->i_message >= n_data + 2U + 3U + 1U) {
|
||||
/* try over-allocation to reduce allocation pressure */
|
||||
n = c_min(outgoing->max_size,
|
||||
outgoing->n_message + n_data + 128);
|
||||
n = outgoing->n_message + n_data + 128;
|
||||
if (n > outgoing->max_size)
|
||||
n = outgoing->max_size;
|
||||
m = realloc(outgoing->message, n);
|
||||
if (!m)
|
||||
return -ENOMEM;
|
||||
@@ -276,6 +277,7 @@ int n_dhcp4_outgoing_append(NDhcp4Outgoing *outgoing,
|
||||
return 0;
|
||||
}
|
||||
|
||||
overload = outgoing->overload;
|
||||
if (overload & N_DHCP4_OVERLOAD_SNAME)
|
||||
outgoing->i_message = offsetof(NDhcp4Message, sname);
|
||||
else
|
||||
@@ -340,7 +342,7 @@ int n_dhcp4_outgoing_append_requested_ip(NDhcp4Outgoing *message, struct in_addr
|
||||
return n_dhcp4_outgoing_append_in_addr(message, N_DHCP4_OPTION_REQUESTED_IP_ADDRESS, addr);
|
||||
}
|
||||
|
||||
void n_dhcp4_outgoing_set_secs(NDhcp4Outgoing *message, uint32_t secs) {
|
||||
void n_dhcp4_outgoing_set_secs(NDhcp4Outgoing *message, uint16_t secs) {
|
||||
NDhcp4Header *header = n_dhcp4_outgoing_get_header(message);
|
||||
|
||||
/*
|
||||
@@ -349,7 +351,7 @@ void n_dhcp4_outgoing_set_secs(NDhcp4Outgoing *message, uint32_t secs) {
|
||||
*/
|
||||
c_assert(secs);
|
||||
|
||||
header->secs = htonl(secs);
|
||||
header->secs = htons(secs);
|
||||
}
|
||||
|
||||
void n_dhcp4_outgoing_set_xid(NDhcp4Outgoing *message, uint32_t xid) {
|
||||
|
@@ -7,11 +7,11 @@
|
||||
#include <endian.h>
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <syslog.h>
|
||||
#include "n-dhcp4.h"
|
||||
|
||||
typedef struct NDhcp4CConnection NDhcp4CConnection;
|
||||
@@ -24,6 +24,7 @@ typedef struct NDhcp4Outgoing NDhcp4Outgoing;
|
||||
typedef struct NDhcp4SConnection NDhcp4SConnection;
|
||||
typedef struct NDhcp4SConnectionIp NDhcp4SConnectionIp;
|
||||
typedef struct NDhcp4SEventNode NDhcp4SEventNode;
|
||||
typedef struct NDhcp4LogQueue NDhcp4LogQueue;
|
||||
|
||||
/* specs */
|
||||
|
||||
@@ -199,6 +200,8 @@ struct NDhcp4Outgoing {
|
||||
|
||||
struct {
|
||||
uint8_t type;
|
||||
uint8_t message_type;
|
||||
uint32_t client_addr;
|
||||
uint64_t start_time;
|
||||
uint64_t base_time;
|
||||
uint64_t send_time;
|
||||
@@ -234,9 +237,9 @@ struct NDhcp4ClientConfig {
|
||||
int ifindex;
|
||||
unsigned int transport;
|
||||
bool request_broadcast;
|
||||
uint8_t mac[MAX_ADDR_LEN];
|
||||
uint8_t mac[32]; /* MAX_ADDR_LEN */
|
||||
size_t n_mac;
|
||||
uint8_t broadcast_mac[MAX_ADDR_LEN];
|
||||
uint8_t broadcast_mac[32]; /* MAX_ADDR_LEN */
|
||||
size_t n_broadcast_mac;
|
||||
uint8_t *client_id;
|
||||
size_t n_client_id;
|
||||
@@ -283,9 +286,42 @@ struct NDhcp4CEventNode {
|
||||
.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 */
|
||||
@@ -317,6 +353,9 @@ struct NDhcp4Client {
|
||||
unsigned long n_refs;
|
||||
NDhcp4ClientConfig *config;
|
||||
CList event_list;
|
||||
|
||||
NDhcp4LogQueue log_queue;
|
||||
|
||||
int fd_epoll;
|
||||
int fd_timer;
|
||||
|
||||
@@ -332,6 +371,7 @@ struct NDhcp4Client {
|
||||
.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 {
|
||||
@@ -342,7 +382,10 @@ struct NDhcp4ClientProbe {
|
||||
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 */
|
||||
@@ -467,7 +510,7 @@ 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, uint32_t secs);
|
||||
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);
|
||||
|
||||
@@ -560,6 +603,7 @@ NDhcp4CEventNode *n_dhcp4_c_event_node_free(NDhcp4CEventNode *node);
|
||||
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);
|
||||
|
||||
@@ -687,3 +731,29 @@ static inline uint64_t n_dhcp4_gettime(clockid_t clock) {
|
||||
|
||||
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)
|
||||
|
@@ -5,16 +5,17 @@
|
||||
#include <c-stdaux.h>
|
||||
#include <errno.h>
|
||||
#include <linux/filter.h>
|
||||
#include <sys/socket.h> /* needed by linux/if.h */
|
||||
#include <linux/if.h>
|
||||
#include <linux/if_packet.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/udp.h>
|
||||
#include <net/if.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include "n-dhcp4-private.h"
|
||||
#include "util/packet.h"
|
||||
#include "util/socket.h"
|
||||
@@ -194,6 +195,10 @@ int n_dhcp4_c_socket_udp_new(int *sockfdp,
|
||||
if (sockfd < 0)
|
||||
return -errno;
|
||||
|
||||
r = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
r = setsockopt(sockfd, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog));
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
@@ -61,6 +61,7 @@ enum {
|
||||
N_DHCP4_CLIENT_EVENT_EXTENDED,
|
||||
N_DHCP4_CLIENT_EVENT_EXPIRED,
|
||||
N_DHCP4_CLIENT_EVENT_CANCELLED,
|
||||
N_DHCP4_CLIENT_EVENT_LOG,
|
||||
_N_DHCP4_CLIENT_EVENT_N,
|
||||
};
|
||||
|
||||
@@ -86,6 +87,14 @@ struct NDhcp4ClientEvent {
|
||||
struct {
|
||||
NDhcp4ClientProbe *probe;
|
||||
} retracted, expired, cancelled;
|
||||
struct {
|
||||
/* If allow_steal_message is true, then the user may steal the message when handling
|
||||
* the event. In that case, set the message field to %NULL and free it yourself
|
||||
* with free(). */
|
||||
const char *message;
|
||||
int level;
|
||||
bool allow_steal_message;
|
||||
} log;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -137,6 +146,8 @@ void n_dhcp4_client_get_fd(NDhcp4Client *client, int *fdp);
|
||||
int n_dhcp4_client_dispatch(NDhcp4Client *client);
|
||||
int n_dhcp4_client_pop_event(NDhcp4Client *client, NDhcp4ClientEvent **eventp);
|
||||
|
||||
void n_dhcp4_client_set_log_level(NDhcp4Client *client, int level);
|
||||
|
||||
int n_dhcp4_client_update_mtu(NDhcp4Client *client, uint16_t mtu);
|
||||
|
||||
int n_dhcp4_client_probe(NDhcp4Client *client,
|
||||
@@ -156,6 +167,8 @@ NDhcp4ClientLease *n_dhcp4_client_lease_ref(NDhcp4ClientLease *lease);
|
||||
NDhcp4ClientLease *n_dhcp4_client_lease_unref(NDhcp4ClientLease *lease);
|
||||
|
||||
void n_dhcp4_client_lease_get_yiaddr(NDhcp4ClientLease *lease, struct in_addr *yiaddr);
|
||||
void n_dhcp4_client_lease_get_siaddr(NDhcp4ClientLease *lease, struct in_addr *siaddr);
|
||||
void n_dhcp4_client_lease_get_basetime(NDhcp4ClientLease *lease, uint64_t *ns_basetimep);
|
||||
void n_dhcp4_client_lease_get_lifetime(NDhcp4ClientLease *lease, uint64_t *ns_lifetimep);
|
||||
int n_dhcp4_client_lease_query(NDhcp4ClientLease *lease, uint8_t option, uint8_t **datap, size_t *n_datap);
|
||||
|
||||
|
@@ -104,6 +104,7 @@ static void test_api_functions(void) {
|
||||
(void *)n_dhcp4_client_lease_unrefp,
|
||||
(void *)n_dhcp4_client_lease_unrefv,
|
||||
(void *)n_dhcp4_client_lease_get_yiaddr,
|
||||
(void *)n_dhcp4_client_lease_get_siaddr,
|
||||
(void *)n_dhcp4_client_lease_get_lifetime,
|
||||
(void *)n_dhcp4_client_lease_query,
|
||||
(void *)n_dhcp4_client_lease_select,
|
||||
|
@@ -322,6 +322,7 @@ static void test_connection(void) {
|
||||
NDhcp4CConnection connection_client = N_DHCP4_C_CONNECTION_NULL(connection_client);
|
||||
_c_cleanup_(n_dhcp4_incoming_freep) NDhcp4Incoming *offer = NULL;
|
||||
_c_cleanup_(n_dhcp4_incoming_freep) NDhcp4Incoming *ack = NULL;
|
||||
NDhcp4LogQueue log_queue = N_DHCP4_LOG_QUEUE_NULL_DEFUNCT();
|
||||
|
||||
test_s_connection_init(ns_server, &connection_server, link_server.ifindex);
|
||||
n_dhcp4_s_connection_ip_init(&connection_server_ip, addr_server);
|
||||
@@ -351,6 +352,7 @@ static void test_connection(void) {
|
||||
r = n_dhcp4_c_connection_init(&connection_client,
|
||||
client_config,
|
||||
probe_config,
|
||||
&log_queue,
|
||||
efd_client);
|
||||
c_assert(!r);
|
||||
test_c_connection_listen(ns_client, &connection_client);
|
||||
@@ -358,13 +360,13 @@ static void test_connection(void) {
|
||||
test_discover(&connection_server, &connection_client, &addr_server, &addr_client, &offer);
|
||||
test_select(&connection_server, &connection_client, offer, &addr_server, &addr_client);
|
||||
test_reboot(&connection_server, &connection_client, &addr_server, &addr_client, &ack);
|
||||
test_rebind(&connection_server, &connection_client, &addr_server, &addr_client);
|
||||
test_decline(&connection_server, &connection_client, ack);
|
||||
|
||||
link_add_ip4(&link_client, &addr_client, 8);
|
||||
test_c_connection_connect(ns_client, &connection_client, &addr_client, &addr_server);
|
||||
|
||||
test_renew(&connection_server, &connection_client, &addr_server, &addr_client);
|
||||
test_rebind(&connection_server, &connection_client, &addr_server, &addr_client);
|
||||
test_release(&connection_server, &connection_client, &addr_server, &addr_client);
|
||||
|
||||
n_dhcp4_c_connection_deinit(&connection_client);
|
||||
|
@@ -59,7 +59,7 @@ static void link_query(int netns, const char *name, int *ifindexp, struct ether_
|
||||
s = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
c_assert(s >= 0);
|
||||
|
||||
strncpy(ifr.ifr_name, name, n_name);
|
||||
memcpy(ifr.ifr_name, name, n_name);
|
||||
r = ioctl(s, SIOCGIFHWADDR, &ifr);
|
||||
c_assert(r >= 0);
|
||||
|
||||
|
@@ -7,7 +7,6 @@
|
||||
#include <c-stdaux.h>
|
||||
#include <inttypes.h>
|
||||
#include <linux/if_packet.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
@@ -25,7 +24,7 @@ struct packet_sockaddr_ll {
|
||||
unsigned short sll_hatype;
|
||||
unsigned char sll_pkttype;
|
||||
unsigned char sll_halen;
|
||||
unsigned char sll_addr[MAX_ADDR_LEN];
|
||||
unsigned char sll_addr[32]; /* MAX_ADDR_LEN */
|
||||
};
|
||||
|
||||
uint16_t packet_internet_checksum(const uint8_t *data, size_t len);
|
||||
|
Submodule subprojects/c-list updated: 2e4b605c62...6c53ef1c00
Submodule subprojects/c-siphash updated: 7c42c59258...2d159c7da1
Submodule subprojects/c-stdaux updated: 11930d2592...8b8f941c57
Reference in New Issue
Block a user