There is a chance that the socket receives packets it should not
process between its initial creation and when ra_init is finished.
Flush these from the buffer by calling recvmsg and throwing away
everything that is received.
This solves a race condition on a multi-interface device, where
several odhcp6c instances are started, and an RA for one interface
ends up in the queue for another interface's odhcp6c socket.
Signed-off-by: Lincoln Ramsay <a1291762@gmail.com>
Link: https://github.com/openwrt/odhcp6c/pull/133
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
if (fcntl(sock, F_SETFL, val | O_ASYNC) < 0)
goto failure;
if (fcntl(sock, F_SETFL, val | O_ASYNC) < 0)
goto failure;
+ // flush any received messages that may not have had all the options (particularly the bind) applied to them
+ uint8_t buf[1500] _o_aligned(4);
+ union {
+ struct cmsghdr hdr;
+ uint8_t buf[CMSG_SPACE(sizeof(int))];
+ } cmsg_buf;
+
+ while (true) {
+ struct sockaddr_in6 from;
+ struct iovec iov = {buf, sizeof(buf)};
+ struct msghdr msg = {
+ .msg_name = (void *) &from,
+ .msg_namelen = sizeof(from),
+ .msg_iov = &iov,
+ .msg_iovlen = 1,
+ .msg_control = cmsg_buf.buf,
+ .msg_controllen = sizeof(cmsg_buf),
+ .msg_flags = 0
+ };
+
+ ssize_t len = recvmsg(sock, &msg, MSG_DONTWAIT);
+ if (len <= 0)
+ break;
+ }
+
// Send RS
signal(SIGALRM, ra_send_rs);
ra_send_rs(SIGALRM);
// Send RS
signal(SIGALRM, ra_send_rs);
ra_send_rs(SIGALRM);