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