Modified do_get_nl_link to potentially process multiple netlink dump replies.

Prior to this commit, do_get_nl_link assumed there would only be a single
reply for a dump request. On my system with multiple can interfaces, this
would cause only half of them to be listed in the dump reply. This change
checks for NLMSG_DONE dump terminator and stops receiving messages once
received.

Signed-off-by: Andrew Beard <abeard@ovro.caltech.edu>
[mkl: fix indention, move variable init out of loop]
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
pull/106/head^2
Andrew Beard 2012-08-03 11:10:27 -07:00 committed by Marc Kleine-Budde
parent 5b990a4771
commit 5ba2310d85
1 changed files with 123 additions and 118 deletions

View File

@ -323,6 +323,7 @@ static int do_get_nl_link(int fd, __u8 acquire, const char *name, void *res)
char nlbuf[1024 * 8]; char nlbuf[1024 * 8];
int ret = -1; int ret = -1;
int done = 0;
struct iovec iov = { struct iovec iov = {
.iov_base = (void *)nlbuf, .iov_base = (void *)nlbuf,
@ -349,141 +350,145 @@ static int do_get_nl_link(int fd, __u8 acquire, const char *name, void *res)
return ret; return ret;
} }
if ((msglen = recvmsg(fd, &msg, 0)) <= 0) { while (!done && (msglen = recvmsg(fd, &msg, 0)) > 0) {
perror("Receive error"); size_t u_msglen = (size_t) msglen;
return ret; /* Check to see if the buffers in msg get truncated */
} if (msg.msg_namelen != sizeof(peer) ||
size_t u_msglen = (size_t) msglen; (msg.msg_flags & (MSG_TRUNC | MSG_CTRUNC))) {
/* Check to see if the buffers in msg get truncated */ fprintf(stderr, "Uhoh... truncated message.\n");
if (msg.msg_namelen != sizeof(peer) || return -1;
(msg.msg_flags & (MSG_TRUNC | MSG_CTRUNC))) { }
fprintf(stderr, "Uhoh... truncated message.\n");
return ret;
}
for (nl_msg = (struct nlmsghdr *)nlbuf; for (nl_msg = (struct nlmsghdr *)nlbuf;
NLMSG_OK(nl_msg, u_msglen); NLMSG_OK(nl_msg, u_msglen);
nl_msg = NLMSG_NEXT(nl_msg, u_msglen)) { nl_msg = NLMSG_NEXT(nl_msg, u_msglen)) {
int type = nl_msg->nlmsg_type; int type = nl_msg->nlmsg_type;
int len; int len;
if (type != RTM_NEWLINK)
continue;
struct ifinfomsg *ifi = NLMSG_DATA(nl_msg); if (type == NLMSG_DONE) {
struct rtattr *tb[IFLA_MAX + 1]; done++;
continue;
len =
nl_msg->nlmsg_len - NLMSG_LENGTH(sizeof(struct ifaddrmsg));
parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len);
if (strncmp
((char *)RTA_DATA(tb[IFLA_IFNAME]), name,
sizeof(name)) != 0)
continue;
if (tb[IFLA_LINKINFO])
parse_rtattr_nested(linkinfo,
IFLA_INFO_MAX, tb[IFLA_LINKINFO]);
else
continue;
if (acquire == GET_XSTATS) {
if (!linkinfo[IFLA_INFO_XSTATS])
fprintf(stderr, "no can statistics found\n");
else {
memcpy(res, RTA_DATA(linkinfo[IFLA_INFO_XSTATS]),
sizeof(struct can_device_stats));
ret = 0;
} }
continue; if (type != RTM_NEWLINK)
} continue;
if (!linkinfo[IFLA_INFO_DATA]) { struct ifinfomsg *ifi = NLMSG_DATA(nl_msg);
fprintf(stderr, "no link data found\n"); struct rtattr *tb[IFLA_MAX + 1];
return ret;
}
parse_rtattr_nested(can_attr, IFLA_CAN_MAX, len =
linkinfo[IFLA_INFO_DATA]); nl_msg->nlmsg_len - NLMSG_LENGTH(sizeof(struct ifaddrmsg));
parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len);
switch (acquire) { if (strncmp
case GET_STATE: ((char *)RTA_DATA(tb[IFLA_IFNAME]), name,
if (can_attr[IFLA_CAN_STATE]) { sizeof(name)) != 0)
*((int *)res) = *((__u32 *) continue;
RTA_DATA(can_attr
[IFLA_CAN_STATE])); if (tb[IFLA_LINKINFO])
ret = 0; parse_rtattr_nested(linkinfo,
} else { IFLA_INFO_MAX, tb[IFLA_LINKINFO]);
fprintf(stderr, "no state data found\n"); else
continue;
if (acquire == GET_XSTATS) {
if (!linkinfo[IFLA_INFO_XSTATS])
fprintf(stderr, "no can statistics found\n");
else {
memcpy(res, RTA_DATA(linkinfo[IFLA_INFO_XSTATS]),
sizeof(struct can_device_stats));
ret = 0;
}
continue;
} }
break; if (!linkinfo[IFLA_INFO_DATA]) {
case GET_RESTART_MS: fprintf(stderr, "no link data found\n");
if (can_attr[IFLA_CAN_RESTART_MS]) { return ret;
*((__u32 *) res) = *((__u32 *) }
RTA_DATA(can_attr
[IFLA_CAN_RESTART_MS]));
ret = 0;
} else
fprintf(stderr, "no restart_ms data found\n");
break; parse_rtattr_nested(can_attr, IFLA_CAN_MAX,
case GET_BITTIMING: linkinfo[IFLA_INFO_DATA]);
if (can_attr[IFLA_CAN_BITTIMING]) {
memcpy(res,
RTA_DATA(can_attr[IFLA_CAN_BITTIMING]),
sizeof(struct can_bittiming));
ret = 0;
} else
fprintf(stderr, "no bittiming data found\n");
break; switch (acquire) {
case GET_CTRLMODE: case GET_STATE:
if (can_attr[IFLA_CAN_CTRLMODE]) { if (can_attr[IFLA_CAN_STATE]) {
memcpy(res, *((int *)res) = *((__u32 *)
RTA_DATA(can_attr[IFLA_CAN_CTRLMODE]), RTA_DATA(can_attr
sizeof(struct can_ctrlmode)); [IFLA_CAN_STATE]));
ret = 0; ret = 0;
} else } else {
fprintf(stderr, "no ctrlmode data found\n"); fprintf(stderr, "no state data found\n");
}
break; break;
case GET_CLOCK: case GET_RESTART_MS:
if (can_attr[IFLA_CAN_CLOCK]) { if (can_attr[IFLA_CAN_RESTART_MS]) {
memcpy(res, *((__u32 *) res) = *((__u32 *)
RTA_DATA(can_attr[IFLA_CAN_CLOCK]), RTA_DATA(can_attr
sizeof(struct can_clock)); [IFLA_CAN_RESTART_MS]));
ret = 0; ret = 0;
} else } else
fprintf(stderr, fprintf(stderr, "no restart_ms data found\n");
"no clock parameter data found\n");
break; break;
case GET_BITTIMING_CONST: case GET_BITTIMING:
if (can_attr[IFLA_CAN_BITTIMING_CONST]) { if (can_attr[IFLA_CAN_BITTIMING]) {
memcpy(res, memcpy(res,
RTA_DATA(can_attr[IFLA_CAN_BITTIMING_CONST]), RTA_DATA(can_attr[IFLA_CAN_BITTIMING]),
sizeof(struct can_bittiming_const)); sizeof(struct can_bittiming));
ret = 0; ret = 0;
} else } else
fprintf(stderr, "no bittiming_const data found\n"); fprintf(stderr, "no bittiming data found\n");
break; break;
case GET_BERR_COUNTER: case GET_CTRLMODE:
if (can_attr[IFLA_CAN_BERR_COUNTER]) { if (can_attr[IFLA_CAN_CTRLMODE]) {
memcpy(res, memcpy(res,
RTA_DATA(can_attr[IFLA_CAN_BERR_COUNTER]), RTA_DATA(can_attr[IFLA_CAN_CTRLMODE]),
sizeof(struct can_berr_counter)); sizeof(struct can_ctrlmode));
ret = 0; ret = 0;
} else } else
fprintf(stderr, "no berr_counter data found\n"); fprintf(stderr, "no ctrlmode data found\n");
break; break;
case GET_CLOCK:
if (can_attr[IFLA_CAN_CLOCK]) {
memcpy(res,
RTA_DATA(can_attr[IFLA_CAN_CLOCK]),
sizeof(struct can_clock));
ret = 0;
} else
fprintf(stderr,
"no clock parameter data found\n");
default: break;
fprintf(stderr, "unknown acquire mode\n"); case GET_BITTIMING_CONST:
if (can_attr[IFLA_CAN_BITTIMING_CONST]) {
memcpy(res,
RTA_DATA(can_attr[IFLA_CAN_BITTIMING_CONST]),
sizeof(struct can_bittiming_const));
ret = 0;
} else
fprintf(stderr, "no bittiming_const data found\n");
break;
case GET_BERR_COUNTER:
if (can_attr[IFLA_CAN_BERR_COUNTER]) {
memcpy(res,
RTA_DATA(can_attr[IFLA_CAN_BERR_COUNTER]),
sizeof(struct can_berr_counter));
ret = 0;
} else
fprintf(stderr, "no berr_counter data found\n");
break;
default:
fprintf(stderr, "unknown acquire mode\n");
}
} }
} }
return ret; return ret;
} }