/*
 * DF-3349 event tracer: listen on PF_ROUTE and report RTM_NEWMADDR /
 * RTM_DELMADDR events with the link-level address printed.
 * Build: cc -O -o mtrace mtrace.c ; Run: ./mtrace <seconds>
 */
#include <sys/socket.h>
#include <net/if.h>
#include <net/route.h>
#include <net/if_dl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int
main(int argc, char **argv)
{
	int secs = argc > 1 ? atoi(argv[1]) : 10;
	int s = socket(PF_ROUTE, SOCK_RAW, 0);
	char buf[8192];
	struct timeval tv = { secs, 0 };
	setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
	printf("listening %ds for RTM_NEWMADDR/RTM_DELMADDR...\n", secs);
	fflush(stdout);
	for (;;) {
		ssize_t n = read(s, buf, sizeof(buf));
		if (n <= 0) break;
		struct rt_msghdr *rtm = (struct rt_msghdr *)buf;
		if (rtm->rtm_type != RTM_NEWMADDR && rtm->rtm_type != RTM_DELMADDR)
			continue;
		struct ifma_msghdr *ifam = (struct ifma_msghdr *)buf;
		unsigned char *p = buf + sizeof(struct ifma_msghdr);
		if (p + 2 < (unsigned char *)buf + rtm->rtm_msglen && p[1] == AF_LINK) {
			struct sockaddr_dl *sdl = (struct sockaddr_dl *)p;
			printf("%s: ifindex=%u %02x:%02x:%02x:%02x:%02x:%02x\n",
			    rtm->rtm_type == RTM_NEWMADDR ? "NEWMADDR" : "DELMADDR",
			    ifam->ifmam_index,
			    sdl->sdl_data[0]&0xff, sdl->sdl_data[1]&0xff,
			    sdl->sdl_data[2]&0xff, sdl->sdl_data[3]&0xff,
			    sdl->sdl_data[4]&0xff, sdl->sdl_data[5]&0xff);
		} else {
			printf("%s: (non-AF_LINK)\n",
			    rtm->rtm_type == RTM_NEWMADDR ? "NEWMADDR" : "DELMADDR");
		}
		fflush(stdout);
	}
	printf("listener done\n");
	return (0);
}
