Handle the case where there are several messages in the buffer.
This is very useful to some protocols like SOCK_DIAG.

* netlink.c (nlmsg_fetch, nlmsg_next): New functions.
(decode_netlink_msg): New function.
(decode_netlink): Call decode_netlink_msg().
* tests/netlink_parsing.c (send_query): Adapt test.
---
 netlink.c               | 85 +++++++++++++++++++++++++++++++++++++++++--------
 tests/netlink_parsing.c | 19 ++++++++++-
 2 files changed, 90 insertions(+), 14 deletions(-)

diff --git a/netlink.c b/netlink.c
index c43f6e7..e05e50c 100644
--- a/netlink.c
+++ b/netlink.c
@@ -31,34 +31,93 @@
 #include "xlat/netlink_flags.h"
 #include "xlat/netlink_types.h"
 
-void
-decode_netlink(struct tcb *tcp, unsigned long addr, unsigned long size)
-{
-       struct nlmsghdr nlmsghdr;
+/* since our target is not in the same process, here are some utils for nlmsg 
*/
+static int
+nlmsg_fetch(struct tcb *tcp, struct nlmsghdr *nlmsghdr, unsigned long addr,
+           unsigned long len) {
+       if (len < sizeof(struct nlmsghdr)) {
+               if (len != 0)
+                       printstr(tcp, addr, len);
+               return 0;
+       }
+
+       if (umove_or_printaddr(tcp, addr, nlmsghdr) == -1)
+               return 0;
+
+       if (len < nlmsghdr->nlmsg_len) {
+               printstr(tcp, addr, len);
+               return 0;
+       }
+
+       return 1;
+}
 
+static unsigned long
+nlmsg_next(struct nlmsghdr *nlmsghdr, unsigned long addr, unsigned long *len) {
+       if (NLMSG_ALIGN(nlmsghdr->nlmsg_len) == 0 ||
+           NLMSG_ALIGN(nlmsghdr->nlmsg_len) > *len)
+               return 0;
+
+       *len -= NLMSG_ALIGN(nlmsghdr->nlmsg_len);
+
+       if (addr + NLMSG_ALIGN(nlmsghdr->nlmsg_len) > addr) {
+               return addr + NLMSG_ALIGN(nlmsghdr->nlmsg_len);
+       } else {
+               *len = 0;
+               return 0;
+       }
+}
+
+static void
+decode_netlink_msg(struct tcb *tcp, struct nlmsghdr *nlmsghdr,
+                  unsigned long addr, unsigned long size)
+{
        if (size < sizeof(struct nlmsghdr)) {
                printstr(tcp, addr, size);
                return;
        }
-       if (umove_or_printaddr(tcp, addr, &nlmsghdr))
-               return;
 
-       tprintf("{{len=%u, type=", nlmsghdr.nlmsg_len);
+       tprintf("{{len=%u, type=", nlmsghdr->nlmsg_len);
 
-       printxval(netlink_types, nlmsghdr.nlmsg_type, "NLMSG_???");
+       printxval(netlink_types, nlmsghdr->nlmsg_type, "NLMSG_???");
 
        tprints(", flags=");
-       printflags(netlink_flags, nlmsghdr.nlmsg_flags, "NLM_F_???");
+       printflags(netlink_flags, nlmsghdr->nlmsg_flags, "NLM_F_???");
        /* manage get/new requests */
 
-       tprintf(", seq=%u, pid=%u}", nlmsghdr.nlmsg_seq,
-               nlmsghdr.nlmsg_pid);
+       tprintf(", seq=%u, pid=%u}", nlmsghdr->nlmsg_seq,
+               nlmsghdr->nlmsg_pid);
 
-       if (size - sizeof(struct nlmsghdr) > 0) {
+       if (nlmsghdr->nlmsg_len - sizeof(struct nlmsghdr) > 0) {
                tprints(", ");
                printstr(tcp, addr + sizeof(struct nlmsghdr),
-                        size - sizeof(struct nlmsghdr));
+                        nlmsghdr->nlmsg_len - sizeof(struct nlmsghdr));
        }
 
        tprints("}");
 }
+
+void
+decode_netlink(struct tcb *tcp, unsigned long addr, unsigned long total_size) {
+       struct nlmsghdr nlmsghdr;
+       unsigned long elt, size = total_size;
+       int print_array = 0;
+
+       for (elt = 0; nlmsg_fetch(tcp, &nlmsghdr, addr, size);
+            addr = nlmsg_next(&nlmsghdr, addr, &size), elt++) {
+               if (elt == max_strlen && abbrev(tcp)) {
+                       tprints("...");
+                       break;
+               }
+               if (size != total_size) {
+                       tprints(", ");
+               } else if (NLMSG_ALIGN(nlmsghdr.nlmsg_len) < total_size) {
+                       print_array = 1;
+                       tprints("[");
+               }
+               decode_netlink_msg(tcp, &nlmsghdr, addr, size);
+       }
+       if (print_array) {
+               tprints("]");
+       }
+}
diff --git a/tests/netlink_parsing.c b/tests/netlink_parsing.c
index 3e7c983..657b05d 100644
--- a/tests/netlink_parsing.c
+++ b/tests/netlink_parsing.c
@@ -43,7 +43,7 @@
 static void
 send_query(const int fd)
 {
-       struct {
+       struct req {
                struct nlmsghdr nlh;
                char magic[4];
        } req = {
@@ -54,6 +54,14 @@ send_query(const int fd)
                },
                .magic = "abcd"
        };
+       struct {
+               struct req req1;
+               char padding[NLMSG_ALIGN(sizeof(req)) - sizeof(req)];
+               struct req req2;
+       } reqs = {
+               .req1 = req,
+               .req2 = req
+       };
 
        const void *const efault = tail_alloc(sizeof(struct nlmsghdr) - 1);
 
@@ -90,6 +98,15 @@ send_query(const int fd)
 
        printf("sendto(%d, %p, %u, MSG_DONTWAIT, NULL, 0) = -1 "
               "EFAULT (%m)\n", fd, efault, (unsigned) sizeof(struct nlmsghdr));
+
+       sendto(fd, &reqs, sizeof(reqs), MSG_DONTWAIT, NULL, 0);
+
+       printf("sendto(%d, [{{len=%u, type=NLMSG_NOOP, flags=NLM_F_REQUEST|0x%x"
+              ", seq=0, pid=0}, \"abcd\"}, {{len=%u, type=NLMSG_NOOP"
+              ", flags=NLM_F_REQUEST|0x%x, seq=0, pid=0}, \"abcd\"}], %u"
+              ", MSG_DONTWAIT, NULL, 0) = %u\n", fd, (unsigned) sizeof(req),
+              NLM_F_DUMP, (unsigned) sizeof(req), NLM_F_DUMP,
+              (unsigned) sizeof(reqs), (unsigned) sizeof(reqs));
 }
 
 int main(void)
-- 
2.8.3


------------------------------------------------------------------------------
Attend Shape: An AT&T Tech Expo July 15-16. Meet us at AT&T Park in San
Francisco, CA to explore cutting-edge tech and listen to tech luminaries
present their vision of the future. This family event has something for
everyone, including kids. Get more information and register today.
http://sdm.link/attshape
_______________________________________________
Strace-devel mailing list
Strace-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/strace-devel

Reply via email to