@@ -560,7 +560,11 @@ int dhcpv6_request(enum dhcpv6_msg type)
struct timespec ts = {0, 0};
ts.tv_nsec = (dhcpv6_rand_delay((10000 * DHCPV6_REQ_DELAY) / 2) + (1000 * DHCPV6_REQ_DELAY) / 2) * 1000000;
- while (nanosleep(&ts, &ts) < 0 && errno == EINTR);
+ while (nanosleep(&ts, &ts) < 0 && errno == EINTR) {
+ // Check for pending signal
+ if (odhcp6c_signal_process())
+ return -1;
+ }
}
if (type == DHCPV6_MSG_UNKNOWN)
@@ -16,6 +16,7 @@
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
+#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <stddef.h>
@@ -208,37 +209,42 @@ static int16_t pref_to_priority(uint8_t flags)
bool ra_link_up(void)
{
static bool firstcall = true;
- struct {
- struct nlmsghdr hdr;
- struct ifinfomsg msg;
- uint8_t pad[4000];
- } resp;
+ char buf[4096];
bool ret = false;
ssize_t read;
- do {
- read = recv(rtnl, &resp, sizeof(resp), MSG_DONTWAIT);
+ while ((read = recv(rtnl, &buf, sizeof(buf), MSG_DONTWAIT)) > 0) {
+ for (struct nlmsghdr *nlh = (struct nlmsghdr *)buf;
+ NLMSG_OK (nlh, read) && nlh->nlmsg_type != NLMSG_DONE;
+ nlh = NLMSG_NEXT(nlh, read)) {
+ if (nlh->nlmsg_type != RTM_NEWLINK && nlh->nlmsg_type != RTM_DELLINK)
+ continue;
- if (read < 0 || !NLMSG_OK(&resp.hdr, (size_t)read) ||
- resp.hdr.nlmsg_type != RTM_NEWLINK ||
- resp.msg.ifi_index != if_index)
- continue;
+ struct ifinfomsg *ifi = NLMSG_DATA(nlh);
+ if (ifi->ifi_index != if_index)
+ continue;
- ssize_t alen = NLMSG_PAYLOAD(&resp.hdr, sizeof(resp.msg));
- for (struct rtattr *rta = (struct rtattr*)(resp.pad);
- RTA_OK(rta, alen); rta = RTA_NEXT(rta, alen)) {
- if (rta->rta_type == IFLA_ADDRESS &&
- RTA_PAYLOAD(rta) >= sizeof(rs.lladdr.data))
- memcpy(rs.lladdr.data, RTA_DATA(rta), sizeof(rs.lladdr.data));
- }
+ if (nlh->nlmsg_type == RTM_DELLINK) {
+ syslog(LOG_ERR, "Interface %s has been deleted, exiting", if_name);
+ exit(1);
+ }
- bool hascarrier = resp.msg.ifi_flags & IFF_LOWER_UP;
- if (!firstcall && nocarrier != !hascarrier)
- ret = true;
+ ssize_t alen = IFLA_PAYLOAD(nlh);
+ for (struct rtattr *rta = IFLA_RTA(nlh);
+ RTA_OK(rta, alen); rta = RTA_NEXT(rta, alen)) {
+ if (rta->rta_type == IFLA_ADDRESS &&
+ RTA_PAYLOAD(rta) >= sizeof(rs.lladdr.data))
+ memcpy(rs.lladdr.data, RTA_DATA(rta), sizeof(rs.lladdr.data));
+ }
+
+ bool hascarrier = ifi->ifi_flags & IFF_LOWER_UP;
+ if (!firstcall && nocarrier != !hascarrier)
+ ret = true;
- nocarrier = !hascarrier;
- firstcall = false;
- } while (read > 0);
+ nocarrier = !hascarrier;
+ firstcall = false;
+ }
+ }
if (ret) {
syslog(LOG_NOTICE, "carrier => %i event on %s", (int)!nocarrier, if_name);
Also handle the netlink message correctly (the current code assumes that the entire buffer returned by recv contains just one netlink message). This fixes a timing issue that occurs when wan interface proto is pppoe, wan6 proto is dhcpv6 and PPP session is closed by the peer. Because odhpc6c doesn't react to pppoe-wan device deletion, sometimes netifd device created by the old pppd instance doesn't get released before new pppd instance execute the ppp-up script (pppoe-wan device is reffered by wan6 device alias), so device_claim() doesn't trigger device_set_ifindex(). That will impede default route creation for wan interface (pppoe-wan device will store the incorrect ifindex). Signed-off-by: Alin Nastac <alin.nastac@gmail.com> --- src/dhcpv6.c | 6 +++++- src/ra.c | 54 ++++++++++++++++++++++++++++++------------------------ 2 files changed, 35 insertions(+), 25 deletions(-)