From 22a3fd2da9db2a61ff1dffc55f9e07f175fcca3e Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Sun, 17 Feb 2019 19:06:34 +0100 Subject: [PATCH] dhcp: don't stop receiving packets when the link goes down When the link goes down, DHCP client_receive_message*() functions return an error and the related I/O source is removed from the main loop. With the current implementation of systemd-networkd this doesn't matter because the DHCP client is always stopped on carrier down and restarted on carrier up. However it seems wrong to have the DHCP client crippled (because no packet can be received anymore) once the link goes temporarily down. Change the receive functions to ignore a ENETDOWN event so that the client will be able to receive packets again after the link comes back. --- src/libsystemd-network/sd-dhcp-client.c | 13 +++++++++++-- src/libsystemd-network/sd-dhcp6-client.c | 9 ++++++++- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index ece1631..7975cfe 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -1684,6 +1684,12 @@ static int client_receive_message_udp( assert(client); buflen = next_datagram_size_fd(fd); + if (buflen == -ENETDOWN) { + /* the link is down. Don't return an error or the I/O event + source will be disconnected and we won't be able to receive + packets again when the link comes back. */ + return 0; + } if (buflen < 0) return buflen; @@ -1693,7 +1699,8 @@ static int client_receive_message_udp( len = recv(fd, message, buflen, 0); if (len < 0) { - if (IN_SET(errno, EAGAIN, EINTR)) + /* see comment above for why we shouldn't error out on ENETDOWN. */ + if (IN_SET(errno, EAGAIN, EINTR, ENETDOWN)) return 0; return log_dhcp_client_errno(client, errno, @@ -1771,6 +1778,8 @@ static int client_receive_message_raw( assert(client); buflen = next_datagram_size_fd(fd); + if (buflen == -ENETDOWN) + return 0; if (buflen < 0) return buflen; @@ -1782,7 +1791,7 @@ static int client_receive_message_raw( len = recvmsg(fd, &msg, 0); if (len < 0) { - if (IN_SET(errno, EAGAIN, EINTR)) + if (IN_SET(errno, EAGAIN, EINTR, ENETDOWN)) return 0; return log_dhcp_client_errno(client, errno, diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index 593ffd1..68b41df 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -1112,6 +1112,12 @@ static int client_receive_message( assert(client->event); buflen = next_datagram_size_fd(fd); + if (buflen == -ENETDOWN) { + /* the link is down. Don't return an error or the I/O event + source will be disconnected and we won't be able to receive + packets again when the link comes back. */ + return 0; + } if (buflen < 0) return buflen; @@ -1121,7 +1127,8 @@ static int client_receive_message( len = recv(fd, message, buflen, 0); if (len < 0) { - if (IN_SET(errno, EAGAIN, EINTR)) + /* see comment above for why we shouldn't error out on ENETDOWN. */ + if (IN_SET(errno, EAGAIN, EINTR, ENETDOWN)) return 0; return log_dhcp6_client_errno(client, errno, "Could not receive message from UDP socket: %m"); -- 2.7.4