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 <sys/stat.h>
34#include <sys/socket.h>
35#include <sys/uio.h>
36#include <sys/un.h>
37#include <netinet/in.h>
38#ifdef HAVE_NETINET_TCP_H
39# include <netinet/tcp.h>
40#endif
41#ifdef HAVE_NETINET_UDP_H
42# include <netinet/udp.h>
43#endif
44#ifdef HAVE_NETINET_SCTP_H
45# include <netinet/sctp.h>
46#endif
47#include <arpa/inet.h>
48#include <net/if.h>
49#include <asm/types.h>
50#ifdef HAVE_NETIPX_IPX_H
51# include <netipx/ipx.h>
52#else
53# include <linux/ipx.h>
54#endif
55
56#if defined(HAVE_LINUX_IP_VS_H)
57# include <linux/ip_vs.h>
58#endif
59#include "netlink.h"
60#if defined(HAVE_LINUX_NETFILTER_ARP_ARP_TABLES_H)
61# include <linux/netfilter_arp/arp_tables.h>
62#endif
63#if defined(HAVE_LINUX_NETFILTER_BRIDGE_EBTABLES_H)
64# include <linux/netfilter_bridge/ebtables.h>
65#endif
66#if defined(HAVE_LINUX_NETFILTER_IPV4_IP_TABLES_H)
67# include <linux/netfilter_ipv4/ip_tables.h>
68#endif
69#if defined(HAVE_LINUX_NETFILTER_IPV6_IP6_TABLES_H)
70# include <linux/netfilter_ipv6/ip6_tables.h>
71#endif
72#include <linux/if_packet.h>
73#include <linux/icmp.h>
74
75#include "xlat/socktypes.h"
76#include "xlat/sock_type_flags.h"
77#ifndef SOCK_TYPE_MASK
78# define SOCK_TYPE_MASK 0xf
79#endif
80
81#include "xlat/socketlayers.h"
82
83#include "xlat/inet_protocols.h"
84
85#ifdef HAVE_BLUETOOTH_BLUETOOTH_H
86# include <bluetooth/bluetooth.h>
87# include "xlat/bt_protocols.h"
88#endif
89
90void
91print_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
106static void
107decode_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, fd, 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 */
124static void
125tprint_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
139SYS_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
169SYS_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
180SYS_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
189static bool
190fetch_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
197static int
198decode_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
232SYS_FUNC(accept)
233{
234	return decode_sockname(tcp) | RVAL_FD;
235}
236
237SYS_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
249SYS_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
261SYS_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
279SYS_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
298SYS_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
352SYS_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
361SYS_FUNC(getsockname)
362{
363	return decode_sockname(tcp);
364}
365
366static void
367printpair_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
376static void
377decode_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
387static int
388do_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
400SYS_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
411SYS_FUNC(pipe2)
412{
413	return do_pipe(tcp, 1);
414}
415
416SYS_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
443static void
444print_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
489static void
490print_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
506static void
507print_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
524static void
525print_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
543static void
544print_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
563static void
564print_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	}
613done:
614	tprintf(", [%d]", len);
615}
616
617SYS_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
638static void
639print_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	tprintf("{imr_multiaddr=inet_addr(\"%s\")",
652		inet_ntoa(mreq.imr_multiaddr));
653	tprintf(", imr_interface=inet_addr(\"%s\")}",
654		inet_ntoa(mreq.imr_interface));
655}
656#endif /* IP_ADD_MEMBERSHIP */
657
658#ifdef IPV6_ADD_MEMBERSHIP
659static void
660print_mreq6(struct tcb *const tcp, const kernel_ulong_t addr,
661	    const unsigned int len)
662{
663	struct ipv6_mreq mreq;
664
665	if (len < sizeof(mreq)) {
666		printstrn(tcp, addr, len);
667		return;
668	}
669	if (umove_or_printaddr(tcp, addr, &mreq))
670		return;
671
672	tprints("{");
673	print_inet_addr(AF_INET6, &mreq.ipv6mr_multiaddr,
674			sizeof(mreq.ipv6mr_multiaddr), "ipv6mr_multiaddr");
675
676	tprints(", ipv6mr_interface=");
677	print_ifindex(mreq.ipv6mr_interface);
678	tprints("}");
679}
680#endif /* IPV6_ADD_MEMBERSHIP */
681
682#ifdef MCAST_JOIN_GROUP
683static void
684print_group_req(struct tcb *const tcp, const kernel_ulong_t addr, const int len)
685{
686	struct group_req greq;
687
688	if (len != sizeof(greq) ||
689	    umove(tcp, addr, &greq) < 0) {
690		printaddr(addr);
691		return;
692	}
693
694	tprintf("{gr_interface=%u, gr_group=", greq.gr_interface);
695	print_sockaddr(tcp, &greq.gr_group, sizeof(greq.gr_group));
696	tprints("}");
697
698}
699#endif /* MCAST_JOIN_GROUP */
700
701#ifdef PACKET_RX_RING
702static void
703print_tpacket_req(struct tcb *const tcp, const kernel_ulong_t addr, const int len)
704{
705	struct tpacket_req req;
706
707	if (len != sizeof(req) ||
708	    umove(tcp, addr, &req) < 0) {
709		printaddr(addr);
710	} else {
711		tprintf("{block_size=%u, block_nr=%u, "
712			"frame_size=%u, frame_nr=%u}",
713			req.tp_block_size,
714			req.tp_block_nr,
715			req.tp_frame_size,
716			req.tp_frame_nr);
717	}
718}
719#endif /* PACKET_RX_RING */
720
721#ifdef PACKET_ADD_MEMBERSHIP
722# include "xlat/packet_mreq_type.h"
723
724static void
725print_packet_mreq(struct tcb *const tcp, const kernel_ulong_t addr, const int len)
726{
727	struct packet_mreq mreq;
728
729	if (len != sizeof(mreq) ||
730	    umove(tcp, addr, &mreq) < 0) {
731		printaddr(addr);
732	} else {
733		unsigned int i;
734
735		tprintf("{mr_ifindex=%u, mr_type=", mreq.mr_ifindex);
736		printxval(packet_mreq_type, mreq.mr_type, "PACKET_MR_???");
737		tprintf(", mr_alen=%u, mr_address=", mreq.mr_alen);
738		if (mreq.mr_alen > ARRAY_SIZE(mreq.mr_address))
739			mreq.mr_alen = ARRAY_SIZE(mreq.mr_address);
740		for (i = 0; i < mreq.mr_alen; ++i)
741			tprintf("%02x", mreq.mr_address[i]);
742		tprints("}");
743	}
744}
745#endif /* PACKET_ADD_MEMBERSHIP */
746
747static void
748print_setsockopt(struct tcb *const tcp, const unsigned int level,
749		 const unsigned int name, const kernel_ulong_t addr,
750		 const int len)
751{
752	if (addr && verbose(tcp))
753	switch (level) {
754	case SOL_SOCKET:
755		switch (name) {
756		case SO_LINGER:
757			print_linger(tcp, addr, len);
758			goto done;
759		}
760		break;
761
762	case SOL_IP:
763		switch (name) {
764#ifdef IP_ADD_MEMBERSHIP
765		case IP_ADD_MEMBERSHIP:
766		case IP_DROP_MEMBERSHIP:
767			print_mreq(tcp, addr, len);
768			goto done;
769#endif /* IP_ADD_MEMBERSHIP */
770#ifdef MCAST_JOIN_GROUP
771		case MCAST_JOIN_GROUP:
772		case MCAST_LEAVE_GROUP:
773			print_group_req(tcp, addr, len);
774			goto done;
775#endif /* MCAST_JOIN_GROUP */
776		}
777		break;
778
779	case SOL_IPV6:
780		switch (name) {
781#ifdef IPV6_ADD_MEMBERSHIP
782		case IPV6_ADD_MEMBERSHIP:
783		case IPV6_DROP_MEMBERSHIP:
784# ifdef IPV6_JOIN_ANYCAST
785		case IPV6_JOIN_ANYCAST:
786# endif
787# ifdef IPV6_LEAVE_ANYCAST
788		case IPV6_LEAVE_ANYCAST:
789# endif
790			print_mreq6(tcp, addr, len);
791			goto done;
792#endif /* IPV6_ADD_MEMBERSHIP */
793		}
794		break;
795
796	case SOL_PACKET:
797		switch (name) {
798#ifdef PACKET_RX_RING
799		case PACKET_RX_RING:
800# ifdef PACKET_TX_RING
801		case PACKET_TX_RING:
802# endif
803			print_tpacket_req(tcp, addr, len);
804			goto done;
805#endif /* PACKET_RX_RING */
806#ifdef PACKET_ADD_MEMBERSHIP
807		case PACKET_ADD_MEMBERSHIP:
808		case PACKET_DROP_MEMBERSHIP:
809			print_packet_mreq(tcp, addr, len);
810			goto done;
811#endif /* PACKET_ADD_MEMBERSHIP */
812		}
813		break;
814
815	case SOL_RAW:
816		switch (name) {
817		case ICMP_FILTER:
818			print_icmp_filter(tcp, addr, len);
819			goto done;
820		}
821		break;
822	}
823
824	/* default arg printing */
825
826	if (verbose(tcp)) {
827		if (len == sizeof(int)) {
828			printnum_int(tcp, addr, "%d");
829		} else {
830			printstrn(tcp, addr, len);
831		}
832	} else {
833		printaddr(addr);
834	}
835done:
836	tprintf(", %d", len);
837}
838
839SYS_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
846	return RVAL_DECODED;
847}
848