| #include <err.h>
|
| #include <errno.h>
|
| #include <string.h>
|
| #include <stdio.h>
|
| #include <stdint.h>
|
|
|
| #include <sys/types.h>
|
| #include <sys/socket.h>
|
| #include <asm/types.h>
|
|
|
| #include <linux/netlink.h>
|
| #include <linux/rtnetlink.h>
|
|
|
| #define NB_COLS 8
|
| #define GROUP_DIV 2
|
| #define COL_SIZE 4
|
|
|
| #define CEILDIV(_x, _n) ({ \
|
| __auto_type x = (_x); \
|
| __auto_type n = (_n); \
|
| (x + (n - 1)) / n; \
|
| })
|
|
|
| #define __unused __attribute__((__unused__))
|
|
|
| void hexdump(void *buf, int len)
|
| {
|
| for (int i = 0; i < CEILDIV(len, NB_COLS * COL_SIZE); i++)
|
| {
|
| printf("%04X |", NB_COLS * COL_SIZE * i);
|
| for (int j = 0; j < NB_COLS; j++)
|
| {
|
| if (i * NB_COLS * COL_SIZE + j * COL_SIZE >= len)
|
| break;
|
| printf(" ");
|
| if (j > 0 && ((j % (NB_COLS / GROUP_DIV)) == 0))
|
| {
|
| printf("| ");
|
| }
|
| for (int k = 0; k < COL_SIZE; k++)
|
| {
|
| if (i * NB_COLS * COL_SIZE + j * COL_SIZE + k >= len)
|
| break;
|
| printf("%02X", ((uint8_t *)buf)[i * NB_COLS * COL_SIZE + j * COL_SIZE + k]);
|
| }
|
| }
|
| printf("\n");
|
| }
|
| }
|
|
|
| int main(int argc __unused, char *argv[] __unused)
|
| {
|
| int fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
|
| if (fd < 0) err(1, "Can't open netlink socket");
|
|
|
| struct sockaddr_nl sa;
|
| memset(&sa, 0, sizeof (sa));
|
| sa.nl_family = AF_NETLINK;
|
| if (bind(fd, (struct sockaddr *)&sa, sizeof (sa)) < 0)
|
| err(1, "Cannot bind socket");
|
|
|
| int group = RTNLGRP_LINK;
|
| if (setsockopt(fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &group, sizeof (group)) < 0)
|
| err(1, "Cannot join RTNLGRP_LINK");
|
|
|
| for (;;)
|
| {
|
| char buf[8192];
|
|
|
| struct iovec iov[] = {
|
| {.iov_base = buf, .iov_len = sizeof (buf)}
|
| };
|
| struct sockaddr_nl sa;
|
|
|
| struct msghdr msg = {&sa, sizeof (sa), iov, sizeof (iov) / sizeof (*iov), NULL, 0, 0};
|
| int len = recvmsg(fd, &msg, 0);
|
| if (len < 0)
|
| err(1, "Cannot receive netlink message");
|
|
|
| if (msg.msg_flags & MSG_TRUNC)
|
| errx(1, "Receive buffer too small");
|
|
|
| if (len > 0)
|
| {
|
| printf("received data (%dB):\n", len);
|
| hexdump(buf, len);
|
| }
|
|
|
| for (struct nlmsghdr *nh = (void *)buf; NLMSG_OK(nh, len); nh = NLMSG_NEXT(nh, len))
|
| {
|
| if (nh->nlmsg_type == NLMSG_NOOP)
|
| continue;
|
| else if (nh->nlmsg_type == NLMSG_ERROR)
|
| {
|
| errx(1, "Error");
|
| }
|
| else if (nh->nlmsg_type == NLMSG_DONE)
|
| {
|
| printf("Done\n");
|
| break; // Done with multipart message
|
| }
|
|
|
| printf("Message type:\t%02X\n", nh->nlmsg_type);
|
| printf("Message flags:\t%02X\n", nh->nlmsg_flags);
|
| printf("Message seq:\t%u\n", nh->nlmsg_seq);
|
|
|
| if (nh->nlmsg_type == RTM_NEWLINK)
|
| {
|
| printf("RTM_NEWLINK\n");
|
| }
|
| else if (nh->nlmsg_type == RTM_DELLINK)
|
| {
|
| printf("RTM_DELLINK\n");
|
| }
|
| }
|
|
|
| printf("=======================\n");
|
| }
|
|
|
| return 0;
|
| }
|