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