xref: /freebsd/lib/libsysdecode/netlink.c (revision 8ef0093f297af7c917037f058af9813105e67662)
1*8ef0093fSIshan Agrawal /*
2*8ef0093fSIshan Agrawal  * Copyright (c) 2026 Ishan Agrawal
3*8ef0093fSIshan Agrawal  *
4*8ef0093fSIshan Agrawal  * SPDX-License-Identifier: BSD-2-Clause
5*8ef0093fSIshan Agrawal  */
6*8ef0093fSIshan Agrawal 
7*8ef0093fSIshan Agrawal #include <sys/param.h>
8*8ef0093fSIshan Agrawal #include <netlink/netlink.h>
9*8ef0093fSIshan Agrawal 
10*8ef0093fSIshan Agrawal #include <stdio.h>
11*8ef0093fSIshan Agrawal #include <stdbool.h>
12*8ef0093fSIshan Agrawal #include <stddef.h>
13*8ef0093fSIshan Agrawal 
14*8ef0093fSIshan Agrawal #include "sysdecode.h"
15*8ef0093fSIshan Agrawal 
16*8ef0093fSIshan Agrawal /*
17*8ef0093fSIshan Agrawal  * Decodes a buffer as a Netlink message stream.
18*8ef0093fSIshan Agrawal  *
19*8ef0093fSIshan Agrawal  * Returns true if the data was successfully decoded as Netlink.
20*8ef0093fSIshan Agrawal  * Returns false if the data is malformed, allowing the caller
21*8ef0093fSIshan Agrawal  * to fallback to a standard hex/string dump.
22*8ef0093fSIshan Agrawal  */
23*8ef0093fSIshan Agrawal bool
sysdecode_netlink(FILE * fp,const void * buf,size_t len)24*8ef0093fSIshan Agrawal sysdecode_netlink(FILE *fp, const void *buf, size_t len)
25*8ef0093fSIshan Agrawal {
26*8ef0093fSIshan Agrawal 	const struct nlmsghdr *nl = buf;
27*8ef0093fSIshan Agrawal 	size_t remaining = len;
28*8ef0093fSIshan Agrawal 	bool first = true;
29*8ef0093fSIshan Agrawal 
30*8ef0093fSIshan Agrawal 	/* Basic sanity check: Buffer must be at least one header size. */
31*8ef0093fSIshan Agrawal 	if (remaining < sizeof(struct nlmsghdr))
32*8ef0093fSIshan Agrawal 		return (false);
33*8ef0093fSIshan Agrawal 
34*8ef0093fSIshan Agrawal 	/* * Protocol Sanity Check:
35*8ef0093fSIshan Agrawal 	 * The first message length must be valid (>= header) and fit
36*8ef0093fSIshan Agrawal 	 * inside the provided buffer snapshot.
37*8ef0093fSIshan Agrawal 	 */
38*8ef0093fSIshan Agrawal 	if (nl->nlmsg_len < sizeof(struct nlmsghdr) || nl->nlmsg_len > remaining)
39*8ef0093fSIshan Agrawal 		return (false);
40*8ef0093fSIshan Agrawal 
41*8ef0093fSIshan Agrawal 	fprintf(fp, "netlink{");
42*8ef0093fSIshan Agrawal 
43*8ef0093fSIshan Agrawal 	while (remaining >= sizeof(struct nlmsghdr)) {
44*8ef0093fSIshan Agrawal 		if (!first)
45*8ef0093fSIshan Agrawal 			fprintf(fp, ",");
46*8ef0093fSIshan Agrawal 
47*8ef0093fSIshan Agrawal 		/* Safety check for current message. */
48*8ef0093fSIshan Agrawal 		if (nl->nlmsg_len < sizeof(struct nlmsghdr) ||
49*8ef0093fSIshan Agrawal 		    nl->nlmsg_len > remaining) {
50*8ef0093fSIshan Agrawal 			fprintf(fp, "<truncated>");
51*8ef0093fSIshan Agrawal 			break;
52*8ef0093fSIshan Agrawal 		}
53*8ef0093fSIshan Agrawal 
54*8ef0093fSIshan Agrawal 		fprintf(fp, "len=%u,type=", nl->nlmsg_len);
55*8ef0093fSIshan Agrawal 
56*8ef0093fSIshan Agrawal 		/* Decode Standard Message Types. */
57*8ef0093fSIshan Agrawal 		switch (nl->nlmsg_type) {
58*8ef0093fSIshan Agrawal 		case NLMSG_NOOP:
59*8ef0093fSIshan Agrawal 			fprintf(fp, "NLMSG_NOOP");
60*8ef0093fSIshan Agrawal 			break;
61*8ef0093fSIshan Agrawal 		case NLMSG_ERROR:
62*8ef0093fSIshan Agrawal 			fprintf(fp, "NLMSG_ERROR");
63*8ef0093fSIshan Agrawal 			break;
64*8ef0093fSIshan Agrawal 		case NLMSG_DONE:
65*8ef0093fSIshan Agrawal 			fprintf(fp, "NLMSG_DONE");
66*8ef0093fSIshan Agrawal 			break;
67*8ef0093fSIshan Agrawal 		case NLMSG_OVERRUN:
68*8ef0093fSIshan Agrawal 			fprintf(fp, "NLMSG_OVERRUN");
69*8ef0093fSIshan Agrawal 			break;
70*8ef0093fSIshan Agrawal 		default:
71*8ef0093fSIshan Agrawal 			fprintf(fp, "%u", nl->nlmsg_type);
72*8ef0093fSIshan Agrawal 			break;
73*8ef0093fSIshan Agrawal 		}
74*8ef0093fSIshan Agrawal 
75*8ef0093fSIshan Agrawal 		fprintf(fp, ",flags=");
76*8ef0093fSIshan Agrawal 		/* TODO: decode flags symbolically using sysdecode_mask. */
77*8ef0093fSIshan Agrawal 		fprintf(fp, "0x%x", nl->nlmsg_flags);
78*8ef0093fSIshan Agrawal 
79*8ef0093fSIshan Agrawal 		fprintf(fp, ",seq=%u,pid=%u", nl->nlmsg_seq, nl->nlmsg_pid);
80*8ef0093fSIshan Agrawal 
81*8ef0093fSIshan Agrawal 		/* Handle Alignment (Netlink messages are 4-byte aligned). */
82*8ef0093fSIshan Agrawal 		size_t aligned_len = NLMSG_ALIGN(nl->nlmsg_len);
83*8ef0093fSIshan Agrawal 		if (aligned_len > remaining)
84*8ef0093fSIshan Agrawal 			remaining = 0;
85*8ef0093fSIshan Agrawal 		else
86*8ef0093fSIshan Agrawal 			remaining -= aligned_len;
87*8ef0093fSIshan Agrawal 
88*8ef0093fSIshan Agrawal 		nl = (const struct nlmsghdr *)(const void *)((const char *)nl + aligned_len);
89*8ef0093fSIshan Agrawal 		first = false;
90*8ef0093fSIshan Agrawal 	}
91*8ef0093fSIshan Agrawal 
92*8ef0093fSIshan Agrawal 	fprintf(fp, "}");
93*8ef0093fSIshan Agrawal 	return (true);
94*8ef0093fSIshan Agrawal }
95