Fixes mixed-up messages on netlink socket
Under specific circumstances there might be two mixed-up netlink sessions (one for scan, the other for route change request). This patch separates netlink scans and requests to two fds (and seq counters). This should fix http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=428865
This commit is contained in:
parent
c8a6b9a3d1
commit
e366625c0e
1 changed files with 34 additions and 19 deletions
|
@ -38,8 +38,14 @@
|
||||||
* Synchronous Netlink interface
|
* Synchronous Netlink interface
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int nl_sync_fd = -1; /* Unix socket for synchronous netlink actions */
|
struct nl_sock
|
||||||
static u32 nl_sync_seq; /* Sequence number of last request sent */
|
{
|
||||||
|
int fd;
|
||||||
|
u32 seq;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct nl_sock nl_scan = {-1, 0}; /* Netlink socket for synchronous scan */
|
||||||
|
static struct nl_sock nl_req = {-1, 0}; /* Netlink socket for requests */
|
||||||
|
|
||||||
static byte *nl_rx_buffer; /* Receive buffer */
|
static byte *nl_rx_buffer; /* Receive buffer */
|
||||||
#define NL_RX_SIZE 8192
|
#define NL_RX_SIZE 8192
|
||||||
|
@ -48,28 +54,37 @@ static struct nlmsghdr *nl_last_hdr; /* Recently received packet */
|
||||||
static unsigned int nl_last_size;
|
static unsigned int nl_last_size;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
nl_open(void)
|
nl_open_sock(struct nl_sock *nl)
|
||||||
{
|
{
|
||||||
if (nl_sync_fd < 0)
|
if (nl->fd < 0)
|
||||||
{
|
{
|
||||||
nl_sync_fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
|
nl->fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
|
||||||
if (nl_sync_fd < 0)
|
if (nl->fd < 0)
|
||||||
die("Unable to open rtnetlink socket: %m");
|
die("Unable to open rtnetlink socket: %m");
|
||||||
nl_sync_seq = now;
|
nl->seq = now;
|
||||||
nl_rx_buffer = xmalloc(NL_RX_SIZE);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
nl_send(struct nlmsghdr *nh)
|
nl_open(void)
|
||||||
|
{
|
||||||
|
nl_open_sock(&nl_scan);
|
||||||
|
nl_open_sock(&nl_req);
|
||||||
|
|
||||||
|
if (nl_rx_buffer == NULL)
|
||||||
|
nl_rx_buffer = xmalloc(NL_RX_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
nl_send(struct nl_sock *nl, struct nlmsghdr *nh)
|
||||||
{
|
{
|
||||||
struct sockaddr_nl sa;
|
struct sockaddr_nl sa;
|
||||||
|
|
||||||
memset(&sa, 0, sizeof(sa));
|
memset(&sa, 0, sizeof(sa));
|
||||||
sa.nl_family = AF_NETLINK;
|
sa.nl_family = AF_NETLINK;
|
||||||
nh->nlmsg_pid = 0;
|
nh->nlmsg_pid = 0;
|
||||||
nh->nlmsg_seq = ++nl_sync_seq;
|
nh->nlmsg_seq = ++(nl->seq);
|
||||||
if (sendto(nl_sync_fd, nh, nh->nlmsg_len, 0, (struct sockaddr *)&sa, sizeof(sa)) < 0)
|
if (sendto(nl->fd, nh, nh->nlmsg_len, 0, (struct sockaddr *)&sa, sizeof(sa)) < 0)
|
||||||
die("rtnetlink sendto: %m");
|
die("rtnetlink sendto: %m");
|
||||||
nl_last_hdr = NULL;
|
nl_last_hdr = NULL;
|
||||||
}
|
}
|
||||||
|
@ -85,11 +100,11 @@ nl_request_dump(int cmd)
|
||||||
req.nh.nlmsg_len = sizeof(req);
|
req.nh.nlmsg_len = sizeof(req);
|
||||||
req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
|
req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
|
||||||
req.g.rtgen_family = BIRD_PF;
|
req.g.rtgen_family = BIRD_PF;
|
||||||
nl_send(&req.nh);
|
nl_send(&nl_scan, &req.nh);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct nlmsghdr *
|
static struct nlmsghdr *
|
||||||
nl_get_reply(void)
|
nl_get_reply(struct nl_sock *nl)
|
||||||
{
|
{
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
|
@ -98,7 +113,7 @@ nl_get_reply(void)
|
||||||
struct iovec iov = { nl_rx_buffer, NL_RX_SIZE };
|
struct iovec iov = { nl_rx_buffer, NL_RX_SIZE };
|
||||||
struct sockaddr_nl sa;
|
struct sockaddr_nl sa;
|
||||||
struct msghdr m = { (struct sockaddr *) &sa, sizeof(sa), &iov, 1, NULL, 0, 0 };
|
struct msghdr m = { (struct sockaddr *) &sa, sizeof(sa), &iov, 1, NULL, 0, 0 };
|
||||||
int x = recvmsg(nl_sync_fd, &m, 0);
|
int x = recvmsg(nl->fd, &m, 0);
|
||||||
if (x < 0)
|
if (x < 0)
|
||||||
die("nl_get_reply: %m");
|
die("nl_get_reply: %m");
|
||||||
if (sa.nl_pid) /* It isn't from the kernel */
|
if (sa.nl_pid) /* It isn't from the kernel */
|
||||||
|
@ -115,10 +130,10 @@ nl_get_reply(void)
|
||||||
{
|
{
|
||||||
struct nlmsghdr *h = nl_last_hdr;
|
struct nlmsghdr *h = nl_last_hdr;
|
||||||
nl_last_hdr = NLMSG_NEXT(h, nl_last_size);
|
nl_last_hdr = NLMSG_NEXT(h, nl_last_size);
|
||||||
if (h->nlmsg_seq != nl_sync_seq)
|
if (h->nlmsg_seq != nl->seq)
|
||||||
{
|
{
|
||||||
log(L_WARN "nl_get_reply: Ignoring out of sequence netlink packet (%x != %x)",
|
log(L_WARN "nl_get_reply: Ignoring out of sequence netlink packet (%x != %x)",
|
||||||
h->nlmsg_seq, nl_sync_seq);
|
h->nlmsg_seq, nl->seq);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
return h;
|
return h;
|
||||||
|
@ -152,7 +167,7 @@ nl_error(struct nlmsghdr *h)
|
||||||
static struct nlmsghdr *
|
static struct nlmsghdr *
|
||||||
nl_get_scan(void)
|
nl_get_scan(void)
|
||||||
{
|
{
|
||||||
struct nlmsghdr *h = nl_get_reply();
|
struct nlmsghdr *h = nl_get_reply(&nl_scan);
|
||||||
|
|
||||||
if (h->nlmsg_type == NLMSG_DONE)
|
if (h->nlmsg_type == NLMSG_DONE)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -169,10 +184,10 @@ nl_exchange(struct nlmsghdr *pkt)
|
||||||
{
|
{
|
||||||
struct nlmsghdr *h;
|
struct nlmsghdr *h;
|
||||||
|
|
||||||
nl_send(pkt);
|
nl_send(&nl_req, pkt);
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
h = nl_get_reply();
|
h = nl_get_reply(&nl_req);
|
||||||
if (h->nlmsg_type == NLMSG_ERROR)
|
if (h->nlmsg_type == NLMSG_ERROR)
|
||||||
break;
|
break;
|
||||||
log(L_WARN "nl_exchange: Unexpected reply received");
|
log(L_WARN "nl_exchange: Unexpected reply received");
|
||||||
|
|
Loading…
Reference in a new issue