]> granicus.if.org Git - strace/blob - net.c
tests: rewrite sigreturn syscall decoding check from match_grep to match_diff
[strace] / net.c
1 /*
2  * Copyright (c) 1991, 1992 Paul Kranenburg <pk@cs.few.eur.nl>
3  * Copyright (c) 1993 Branko Lankester <branko@hacktic.nl>
4  * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@world.std.com>
5  * Copyright (c) 1996-2000 Wichert Akkerman <wichert@cistron.nl>
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. The name of the author may not be used to endorse or promote products
17  *    derived from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include "defs.h"
32 #include <sys/stat.h>
33 #include <sys/socket.h>
34 #include <sys/uio.h>
35 #include <sys/un.h>
36 #include <netinet/in.h>
37 #ifdef HAVE_NETINET_TCP_H
38 # include <netinet/tcp.h>
39 #endif
40 #ifdef HAVE_NETINET_UDP_H
41 # include <netinet/udp.h>
42 #endif
43 #ifdef HAVE_NETINET_SCTP_H
44 # include <netinet/sctp.h>
45 #endif
46 #include <arpa/inet.h>
47 #include <net/if.h>
48 #include <asm/types.h>
49 #ifdef HAVE_NETIPX_IPX_H
50 # include <netipx/ipx.h>
51 #else
52 # include <linux/ipx.h>
53 #endif
54
55 #if defined(HAVE_LINUX_IP_VS_H)
56 # include <linux/ip_vs.h>
57 #endif
58 #include <linux/netlink.h>
59 #if defined(HAVE_LINUX_NETFILTER_ARP_ARP_TABLES_H)
60 # include <linux/netfilter_arp/arp_tables.h>
61 #endif
62 #if defined(HAVE_LINUX_NETFILTER_BRIDGE_EBTABLES_H)
63 # include <linux/netfilter_bridge/ebtables.h>
64 #endif
65 #if defined(HAVE_LINUX_NETFILTER_IPV4_IP_TABLES_H)
66 # include <linux/netfilter_ipv4/ip_tables.h>
67 #endif
68 #if defined(HAVE_LINUX_NETFILTER_IPV6_IP6_TABLES_H)
69 # include <linux/netfilter_ipv6/ip6_tables.h>
70 #endif
71 #include <linux/if_packet.h>
72 #include <linux/icmp.h>
73
74 #include "xlat/socktypes.h"
75 #include "xlat/sock_type_flags.h"
76 #ifndef SOCK_TYPE_MASK
77 # define SOCK_TYPE_MASK 0xf
78 #endif
79
80 #include "xlat/socketlayers.h"
81
82 #include "xlat/inet_protocols.h"
83 #include "xlat/netlink_protocols.h"
84
85 #ifdef HAVE_BLUETOOTH_BLUETOOTH_H
86 # include <bluetooth/bluetooth.h>
87 # include "xlat/bt_protocols.h"
88 #endif
89
90 void
91 print_ifindex(unsigned int ifindex)
92 {
93 #ifdef HAVE_IF_INDEXTONAME
94         char buf[IFNAMSIZ + 1];
95
96         if (if_indextoname(ifindex, buf)) {
97                 tprints("if_nametoindex(");
98                 print_quoted_string(buf, sizeof(buf), QUOTE_0_TERMINATED);
99                 tprints(")");
100                 return;
101         }
102 #endif
103         tprintf("%u", ifindex);
104 }
105
106 static void
107 decode_sockbuf(struct tcb *const tcp, const int fd, const kernel_ulong_t addr,
108                const kernel_ulong_t addrlen)
109 {
110
111         switch (verbose(tcp) ? getfdproto(tcp, fd) : SOCK_PROTO_UNKNOWN) {
112         case SOCK_PROTO_NETLINK:
113                 decode_netlink(tcp, addr, addrlen);
114                 break;
115         default:
116                 printstrn(tcp, addr, addrlen);
117         }
118 }
119
120 /*
121  * low bits of the socket type define real socket type,
122  * other bits are socket type flags.
123  */
124 static void
125 tprint_sock_type(unsigned int flags)
126 {
127         const char *str = xlookup(socktypes, flags & SOCK_TYPE_MASK);
128
129         if (str) {
130                 tprints(str);
131                 flags &= ~SOCK_TYPE_MASK;
132                 if (!flags)
133                         return;
134                 tprints("|");
135         }
136         printflags(sock_type_flags, flags, "SOCK_???");
137 }
138
139 SYS_FUNC(socket)
140 {
141         printxval(addrfams, tcp->u_arg[0], "AF_???");
142         tprints(", ");
143         tprint_sock_type(tcp->u_arg[1]);
144         tprints(", ");
145         switch (tcp->u_arg[0]) {
146         case AF_INET:
147         case AF_INET6:
148                 printxval(inet_protocols, tcp->u_arg[2], "IPPROTO_???");
149                 break;
150
151         case AF_NETLINK:
152                 printxval(netlink_protocols, tcp->u_arg[2], "NETLINK_???");
153                 break;
154
155 #ifdef HAVE_BLUETOOTH_BLUETOOTH_H
156         case AF_BLUETOOTH:
157                 printxval(bt_protocols, tcp->u_arg[2], "BTPROTO_???");
158                 break;
159 #endif
160
161         default:
162                 tprintf("%" PRI_klu, tcp->u_arg[2]);
163                 break;
164         }
165
166         return RVAL_DECODED | RVAL_FD;
167 }
168
169 SYS_FUNC(bind)
170 {
171         printfd(tcp, tcp->u_arg[0]);
172         tprints(", ");
173         const int addrlen = tcp->u_arg[2];
174         decode_sockaddr(tcp, tcp->u_arg[1], addrlen);
175         tprintf(", %d", addrlen);
176
177         return RVAL_DECODED;
178 }
179
180 SYS_FUNC(listen)
181 {
182         printfd(tcp, tcp->u_arg[0]);
183         tprints(", ");
184         tprintf("%" PRI_klu, tcp->u_arg[1]);
185
186         return RVAL_DECODED;
187 }
188
189 static bool
190 fetch_socklen(struct tcb *const tcp, int *const plen,
191               const kernel_ulong_t sockaddr, const kernel_ulong_t socklen)
192 {
193         return verbose(tcp) && sockaddr && socklen
194                && umove(tcp, socklen, plen) == 0;
195 }
196
197 static int
198 decode_sockname(struct tcb *tcp)
199 {
200         int ulen, rlen;
201
202         if (entering(tcp)) {
203                 printfd(tcp, tcp->u_arg[0]);
204                 tprints(", ");
205                 if (fetch_socklen(tcp, &ulen, tcp->u_arg[1], tcp->u_arg[2])) {
206                         set_tcb_priv_ulong(tcp, ulen);
207                         return 0;
208                 } else {
209                         printaddr(tcp->u_arg[1]);
210                         tprints(", ");
211                         printaddr(tcp->u_arg[2]);
212                         return RVAL_DECODED;
213                 }
214         }
215
216         ulen = get_tcb_priv_ulong(tcp);
217
218         if (syserror(tcp) || umove(tcp, tcp->u_arg[2], &rlen) < 0) {
219                 printaddr(tcp->u_arg[1]);
220                 tprintf(", [%d]", ulen);
221         } else {
222                 decode_sockaddr(tcp, tcp->u_arg[1], ulen > rlen ? rlen : ulen);
223                 if (ulen != rlen)
224                         tprintf(", [%d->%d]", ulen, rlen);
225                 else
226                         tprintf(", [%d]", rlen);
227         }
228
229         return RVAL_DECODED;
230 }
231
232 SYS_FUNC(accept)
233 {
234         return decode_sockname(tcp) | RVAL_FD;
235 }
236
237 SYS_FUNC(accept4)
238 {
239         int rc = decode_sockname(tcp);
240
241         if (rc & RVAL_DECODED) {
242                 tprints(", ");
243                 printflags(sock_type_flags, tcp->u_arg[3], "SOCK_???");
244         }
245
246         return rc | RVAL_FD;
247 }
248
249 SYS_FUNC(send)
250 {
251         printfd(tcp, tcp->u_arg[0]);
252         tprints(", ");
253         decode_sockbuf(tcp, tcp->u_arg[0], tcp->u_arg[1], tcp->u_arg[2]);
254         tprintf(", %" PRI_klu ", ", tcp->u_arg[2]);
255         /* flags */
256         printflags(msg_flags, tcp->u_arg[3], "MSG_???");
257
258         return RVAL_DECODED;
259 }
260
261 SYS_FUNC(sendto)
262 {
263         printfd(tcp, tcp->u_arg[0]);
264         tprints(", ");
265         decode_sockbuf(tcp, tcp->u_arg[0], tcp->u_arg[1], tcp->u_arg[2]);
266         tprintf(", %" PRI_klu ", ", tcp->u_arg[2]);
267         /* flags */
268         printflags(msg_flags, tcp->u_arg[3], "MSG_???");
269         /* to address */
270         const int addrlen = tcp->u_arg[5];
271         tprints(", ");
272         decode_sockaddr(tcp, tcp->u_arg[4], addrlen);
273         /* to length */
274         tprintf(", %d", addrlen);
275
276         return RVAL_DECODED;
277 }
278
279 SYS_FUNC(recv)
280 {
281         if (entering(tcp)) {
282                 printfd(tcp, tcp->u_arg[0]);
283                 tprints(", ");
284         } else {
285                 if (syserror(tcp)) {
286                         printaddr(tcp->u_arg[1]);
287                 } else {
288                         decode_sockbuf(tcp, tcp->u_arg[0], tcp->u_arg[1],
289                                      tcp->u_rval);
290                 }
291
292                 tprintf(", %" PRI_klu ", ", tcp->u_arg[2]);
293                 printflags(msg_flags, tcp->u_arg[3], "MSG_???");
294         }
295         return 0;
296 }
297
298 SYS_FUNC(recvfrom)
299 {
300         int ulen, rlen;
301
302         if (entering(tcp)) {
303                 printfd(tcp, tcp->u_arg[0]);
304                 tprints(", ");
305                 if (fetch_socklen(tcp, &ulen, tcp->u_arg[4], tcp->u_arg[5])) {
306                         set_tcb_priv_ulong(tcp, ulen);
307                 }
308         } else {
309                 /* buf */
310                 if (syserror(tcp)) {
311                         printaddr(tcp->u_arg[1]);
312                 } else {
313                         decode_sockbuf(tcp, tcp->u_arg[0], tcp->u_arg[1],
314                                      tcp->u_rval);
315                 }
316                 /* size */
317                 tprintf(", %" PRI_klu ", ", tcp->u_arg[2]);
318                 /* flags */
319                 printflags(msg_flags, tcp->u_arg[3], "MSG_???");
320                 tprints(", ");
321
322                 ulen = get_tcb_priv_ulong(tcp);
323
324                 if (!fetch_socklen(tcp, &rlen, tcp->u_arg[4], tcp->u_arg[5])) {
325                         /* from address */
326                         printaddr(tcp->u_arg[4]);
327                         tprints(", ");
328                         /* from length */
329                         printaddr(tcp->u_arg[5]);
330                         return 0;
331                 }
332                 if (syserror(tcp)) {
333                         /* from address */
334                         printaddr(tcp->u_arg[4]);
335                         /* from length */
336                         tprintf(", [%d]", ulen);
337                         return 0;
338                 }
339                 /* from address */
340                 decode_sockaddr(tcp, tcp->u_arg[4], ulen > rlen ? rlen : ulen);
341                 /* from length */
342                 if (ulen != rlen)
343                         tprintf(", [%d->%d]", ulen, rlen);
344                 else
345                         tprintf(", [%d]", rlen);
346         }
347         return 0;
348 }
349
350 #include "xlat/shutdown_modes.h"
351
352 SYS_FUNC(shutdown)
353 {
354         printfd(tcp, tcp->u_arg[0]);
355         tprints(", ");
356         printxval(shutdown_modes, tcp->u_arg[1], "SHUT_???");
357
358         return RVAL_DECODED;
359 }
360
361 SYS_FUNC(getsockname)
362 {
363         return decode_sockname(tcp);
364 }
365
366 static void
367 printpair_fd(struct tcb *tcp, const int i0, const int i1)
368 {
369         tprints("[");
370         printfd(tcp, i0);
371         tprints(", ");
372         printfd(tcp, i1);
373         tprints("]");
374 }
375
376 static void
377 decode_pair_fd(struct tcb *const tcp, const kernel_ulong_t addr)
378 {
379         int pair[2];
380
381         if (umove_or_printaddr(tcp, addr, &pair))
382                 return;
383
384         printpair_fd(tcp, pair[0], pair[1]);
385 }
386
387 static int
388 do_pipe(struct tcb *tcp, int flags_arg)
389 {
390         if (exiting(tcp)) {
391                 decode_pair_fd(tcp, tcp->u_arg[0]);
392                 if (flags_arg >= 0) {
393                         tprints(", ");
394                         printflags(open_mode_flags, tcp->u_arg[flags_arg], "O_???");
395                 }
396         }
397         return 0;
398 }
399
400 SYS_FUNC(pipe)
401 {
402 #ifdef HAVE_GETRVAL2
403         if (exiting(tcp) && !syserror(tcp))
404                 printpair_fd(tcp, tcp->u_rval, getrval2(tcp));
405         return 0;
406 #else
407         return do_pipe(tcp, -1);
408 #endif
409 }
410
411 SYS_FUNC(pipe2)
412 {
413         return do_pipe(tcp, 1);
414 }
415
416 SYS_FUNC(socketpair)
417 {
418         if (entering(tcp)) {
419                 printxval(addrfams, tcp->u_arg[0], "AF_???");
420                 tprints(", ");
421                 tprint_sock_type(tcp->u_arg[1]);
422                 tprintf(", %" PRI_klu, tcp->u_arg[2]);
423         } else {
424                 tprints(", ");
425                 decode_pair_fd(tcp, tcp->u_arg[3]);
426         }
427         return 0;
428 }
429
430 #include "xlat/sockoptions.h"
431 #include "xlat/sockipoptions.h"
432 #include "xlat/getsockipoptions.h"
433 #include "xlat/setsockipoptions.h"
434 #include "xlat/sockipv6options.h"
435 #include "xlat/getsockipv6options.h"
436 #include "xlat/setsockipv6options.h"
437 #include "xlat/sockipxoptions.h"
438 #include "xlat/sockrawoptions.h"
439 #include "xlat/sockpacketoptions.h"
440 #include "xlat/socksctpoptions.h"
441 #include "xlat/socktcpoptions.h"
442
443 static void
444 print_sockopt_fd_level_name(struct tcb *tcp, int fd, unsigned int level,
445                             unsigned int name, bool is_getsockopt)
446 {
447         printfd(tcp, fd);
448         tprints(", ");
449         printxval(socketlayers, level, "SOL_??");
450         tprints(", ");
451
452         switch (level) {
453         case SOL_SOCKET:
454                 printxval(sockoptions, name, "SO_???");
455                 break;
456         case SOL_IP:
457                 printxvals(name, "IP_???", sockipoptions,
458                         is_getsockopt ? getsockipoptions : setsockipoptions, NULL);
459                 break;
460         case SOL_IPV6:
461                 printxvals(name, "IPV6_???", sockipv6options,
462                         is_getsockopt ? getsockipv6options : setsockipv6options, NULL);
463                 break;
464         case SOL_IPX:
465                 printxval(sockipxoptions, name, "IPX_???");
466                 break;
467         case SOL_PACKET:
468                 printxval(sockpacketoptions, name, "PACKET_???");
469                 break;
470         case SOL_TCP:
471                 printxval(socktcpoptions, name, "TCP_???");
472                 break;
473         case SOL_SCTP:
474                 printxval(socksctpoptions, name, "SCTP_???");
475                 break;
476         case SOL_RAW:
477                 printxval(sockrawoptions, name, "RAW_???");
478                 break;
479
480                 /* Other SOL_* protocol levels still need work. */
481
482         default:
483                 tprintf("%u", name);
484         }
485
486         tprints(", ");
487 }
488
489 static void
490 print_linger(struct tcb *const tcp, const kernel_ulong_t addr, const int len)
491 {
492         struct linger linger;
493
494         if (len != sizeof(linger) ||
495             umove(tcp, addr, &linger) < 0) {
496                 printaddr(addr);
497                 return;
498         }
499
500         tprintf("{onoff=%d, linger=%d}",
501                 linger.l_onoff,
502                 linger.l_linger);
503 }
504
505 #ifdef SO_PEERCRED
506 static void
507 print_ucred(struct tcb *const tcp, const kernel_ulong_t addr, const int len)
508 {
509         struct ucred uc;
510
511         if (len != sizeof(uc) ||
512             umove(tcp, addr, &uc) < 0) {
513                 printaddr(addr);
514         } else {
515                 tprintf("{pid=%u, uid=%u, gid=%u}",
516                         (unsigned) uc.pid,
517                         (unsigned) uc.uid,
518                         (unsigned) uc.gid);
519         }
520 }
521 #endif /* SO_PEERCRED */
522
523 #ifdef PACKET_STATISTICS
524 static void
525 print_tpacket_stats(struct tcb *const tcp, const kernel_ulong_t addr,
526                     const int len)
527 {
528         struct tpacket_stats stats;
529
530         if (len != sizeof(stats) ||
531             umove(tcp, addr, &stats) < 0) {
532                 printaddr(addr);
533         } else {
534                 tprintf("{packets=%u, drops=%u}",
535                         stats.tp_packets,
536                         stats.tp_drops);
537         }
538 }
539 #endif /* PACKET_STATISTICS */
540
541 #include "xlat/icmpfilterflags.h"
542
543 static void
544 print_icmp_filter(struct tcb *const tcp, const kernel_ulong_t addr, int len)
545 {
546         struct icmp_filter filter = {};
547
548         if (len > (int) sizeof(filter))
549                 len = sizeof(filter);
550         else if (len <= 0) {
551                 printaddr(addr);
552                 return;
553         }
554
555         if (umoven_or_printaddr(tcp, addr, len, &filter))
556                 return;
557
558         tprints("~(");
559         printflags(icmpfilterflags, ~filter.data, "ICMP_???");
560         tprints(")");
561 }
562
563 static void
564 print_getsockopt(struct tcb *const tcp, const unsigned int level,
565                  const unsigned int name, const kernel_ulong_t addr,
566                  const int len)
567 {
568         if (addr && verbose(tcp))
569         switch (level) {
570         case SOL_SOCKET:
571                 switch (name) {
572                 case SO_LINGER:
573                         print_linger(tcp, addr, len);
574                         goto done;
575 #ifdef SO_PEERCRED
576                 case SO_PEERCRED:
577                         print_ucred(tcp, addr, len);
578                         goto done;
579 #endif
580                 }
581                 break;
582
583         case SOL_PACKET:
584                 switch (name) {
585 #ifdef PACKET_STATISTICS
586                 case PACKET_STATISTICS:
587                         print_tpacket_stats(tcp, addr, len);
588                         goto done;
589 #endif
590                 }
591                 break;
592
593         case SOL_RAW:
594                 switch (name) {
595                 case ICMP_FILTER:
596                         print_icmp_filter(tcp, addr, len);
597                         goto done;
598                 }
599                 break;
600         }
601
602         /* default arg printing */
603
604         if (verbose(tcp)) {
605                 if (len == sizeof(int)) {
606                         printnum_int(tcp, addr, "%d");
607                 } else {
608                         printstrn(tcp, addr, len);
609                 }
610         } else {
611                 printaddr(addr);
612         }
613 done:
614         tprintf(", [%d]", len);
615 }
616
617 SYS_FUNC(getsockopt)
618 {
619         if (entering(tcp)) {
620                 print_sockopt_fd_level_name(tcp, tcp->u_arg[0],
621                                             tcp->u_arg[1], tcp->u_arg[2], true);
622         } else {
623                 int len;
624
625                 if (syserror(tcp) || umove(tcp, tcp->u_arg[4], &len) < 0) {
626                         printaddr(tcp->u_arg[3]);
627                         tprints(", ");
628                         printaddr(tcp->u_arg[4]);
629                 } else {
630                         print_getsockopt(tcp, tcp->u_arg[1], tcp->u_arg[2],
631                                          tcp->u_arg[3], len);
632                 }
633         }
634         return 0;
635 }
636
637 #ifdef IP_ADD_MEMBERSHIP
638 static void
639 print_mreq(struct tcb *const tcp, const kernel_ulong_t addr,
640            const unsigned int len)
641 {
642         struct ip_mreq mreq;
643
644         if (len < sizeof(mreq)) {
645                 printstrn(tcp, addr, len);
646                 return;
647         }
648         if (umove_or_printaddr(tcp, addr, &mreq))
649                 return;
650
651         tprints("{imr_multiaddr=inet_addr(");
652         print_quoted_string(inet_ntoa(mreq.imr_multiaddr),
653                             16, QUOTE_0_TERMINATED);
654         tprints("), imr_interface=inet_addr(");
655         print_quoted_string(inet_ntoa(mreq.imr_interface),
656                             16, QUOTE_0_TERMINATED);
657         tprints(")}");
658 }
659 #endif /* IP_ADD_MEMBERSHIP */
660
661 #ifdef IPV6_ADD_MEMBERSHIP
662 static void
663 print_mreq6(struct tcb *const tcp, const kernel_ulong_t addr,
664             const unsigned int len)
665 {
666         struct ipv6_mreq mreq;
667
668         if (len < sizeof(mreq))
669                 goto fail;
670
671         if (umove_or_printaddr(tcp, addr, &mreq))
672                 return;
673
674         const struct in6_addr *in6 = &mreq.ipv6mr_multiaddr;
675         char address[INET6_ADDRSTRLEN];
676
677         if (!inet_ntop(AF_INET6, in6, address, sizeof(address)))
678                 goto fail;
679
680         tprints("{ipv6mr_multiaddr=inet_pton(");
681         print_quoted_string(address, sizeof(address), QUOTE_0_TERMINATED);
682         tprints("), ipv6mr_interface=");
683         print_ifindex(mreq.ipv6mr_interface);
684         tprints("}");
685         return;
686
687 fail:
688         printstrn(tcp, addr, len);
689 }
690 #endif /* IPV6_ADD_MEMBERSHIP */
691
692 #ifdef MCAST_JOIN_GROUP
693 static void
694 print_group_req(struct tcb *const tcp, const kernel_ulong_t addr, const int len)
695 {
696         struct group_req greq;
697
698         if (len != sizeof(greq) ||
699             umove(tcp, addr, &greq) < 0) {
700                 printaddr(addr);
701                 return;
702         }
703
704         tprintf("{gr_interface=%u, gr_group=", greq.gr_interface);
705         print_sockaddr(tcp, &greq.gr_group, sizeof(greq.gr_group));
706         tprints("}");
707
708 }
709 #endif /* MCAST_JOIN_GROUP */
710
711 #ifdef PACKET_RX_RING
712 static void
713 print_tpacket_req(struct tcb *const tcp, const kernel_ulong_t addr, const int len)
714 {
715         struct tpacket_req req;
716
717         if (len != sizeof(req) ||
718             umove(tcp, addr, &req) < 0) {
719                 printaddr(addr);
720         } else {
721                 tprintf("{block_size=%u, block_nr=%u, "
722                         "frame_size=%u, frame_nr=%u}",
723                         req.tp_block_size,
724                         req.tp_block_nr,
725                         req.tp_frame_size,
726                         req.tp_frame_nr);
727         }
728 }
729 #endif /* PACKET_RX_RING */
730
731 #ifdef PACKET_ADD_MEMBERSHIP
732 # include "xlat/packet_mreq_type.h"
733
734 static void
735 print_packet_mreq(struct tcb *const tcp, const kernel_ulong_t addr, const int len)
736 {
737         struct packet_mreq mreq;
738
739         if (len != sizeof(mreq) ||
740             umove(tcp, addr, &mreq) < 0) {
741                 printaddr(addr);
742         } else {
743                 unsigned int i;
744
745                 tprintf("{mr_ifindex=%u, mr_type=", mreq.mr_ifindex);
746                 printxval(packet_mreq_type, mreq.mr_type, "PACKET_MR_???");
747                 tprintf(", mr_alen=%u, mr_address=", mreq.mr_alen);
748                 if (mreq.mr_alen > ARRAY_SIZE(mreq.mr_address))
749                         mreq.mr_alen = ARRAY_SIZE(mreq.mr_address);
750                 for (i = 0; i < mreq.mr_alen; ++i)
751                         tprintf("%02x", mreq.mr_address[i]);
752                 tprints("}");
753         }
754 }
755 #endif /* PACKET_ADD_MEMBERSHIP */
756
757 static void
758 print_setsockopt(struct tcb *const tcp, const unsigned int level,
759                  const unsigned int name, const kernel_ulong_t addr,
760                  const int len)
761 {
762         if (addr && verbose(tcp))
763         switch (level) {
764         case SOL_SOCKET:
765                 switch (name) {
766                 case SO_LINGER:
767                         print_linger(tcp, addr, len);
768                         goto done;
769                 }
770                 break;
771
772         case SOL_IP:
773                 switch (name) {
774 #ifdef IP_ADD_MEMBERSHIP
775                 case IP_ADD_MEMBERSHIP:
776                 case IP_DROP_MEMBERSHIP:
777                         print_mreq(tcp, addr, len);
778                         goto done;
779 #endif /* IP_ADD_MEMBERSHIP */
780 #ifdef MCAST_JOIN_GROUP
781                 case MCAST_JOIN_GROUP:
782                 case MCAST_LEAVE_GROUP:
783                         print_group_req(tcp, addr, len);
784                         goto done;
785 #endif /* MCAST_JOIN_GROUP */
786                 }
787                 break;
788
789         case SOL_IPV6:
790                 switch (name) {
791 #ifdef IPV6_ADD_MEMBERSHIP
792                 case IPV6_ADD_MEMBERSHIP:
793                 case IPV6_DROP_MEMBERSHIP:
794 # ifdef IPV6_JOIN_ANYCAST
795                 case IPV6_JOIN_ANYCAST:
796 # endif
797 # ifdef IPV6_LEAVE_ANYCAST
798                 case IPV6_LEAVE_ANYCAST:
799 # endif
800                         print_mreq6(tcp, addr, len);
801                         goto done;
802 #endif /* IPV6_ADD_MEMBERSHIP */
803                 }
804                 break;
805
806         case SOL_PACKET:
807                 switch (name) {
808 #ifdef PACKET_RX_RING
809                 case PACKET_RX_RING:
810 # ifdef PACKET_TX_RING
811                 case PACKET_TX_RING:
812 # endif
813                         print_tpacket_req(tcp, addr, len);
814                         goto done;
815 #endif /* PACKET_RX_RING */
816 #ifdef PACKET_ADD_MEMBERSHIP
817                 case PACKET_ADD_MEMBERSHIP:
818                 case PACKET_DROP_MEMBERSHIP:
819                         print_packet_mreq(tcp, addr, len);
820                         goto done;
821 #endif /* PACKET_ADD_MEMBERSHIP */
822                 }
823                 break;
824
825         case SOL_RAW:
826                 switch (name) {
827                 case ICMP_FILTER:
828                         print_icmp_filter(tcp, addr, len);
829                         goto done;
830                 }
831                 break;
832         }
833
834         /* default arg printing */
835
836         if (verbose(tcp)) {
837                 if (len == sizeof(int)) {
838                         printnum_int(tcp, addr, "%d");
839                 } else {
840                         printstrn(tcp, addr, len);
841                 }
842         } else {
843                 printaddr(addr);
844         }
845 done:
846         tprintf(", %d", len);
847 }
848
849 SYS_FUNC(setsockopt)
850 {
851         print_sockopt_fd_level_name(tcp, tcp->u_arg[0],
852                                     tcp->u_arg[1], tcp->u_arg[2], false);
853         print_setsockopt(tcp, tcp->u_arg[1], tcp->u_arg[2],
854                          tcp->u_arg[3], tcp->u_arg[4]);
855
856         return RVAL_DECODED;
857 }