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#if defined(__GLIBC__)
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#if defined(HAVE_LINUX_NETLINK_H)
59# include <linux/netlink.h>
60#endif
61#if defined(HAVE_LINUX_NETFILTER_ARP_ARP_TABLES_H)
62# include <linux/netfilter_arp/arp_tables.h>
63#endif
64#if defined(HAVE_LINUX_NETFILTER_BRIDGE_EBTABLES_H)
65# include <linux/netfilter_bridge/ebtables.h>
66#endif
67#if defined(HAVE_LINUX_NETFILTER_IPV4_IP_TABLES_H)
68# include <linux/netfilter_ipv4/ip_tables.h>
69#endif
70#if defined(HAVE_LINUX_NETFILTER_IPV6_IP6_TABLES_H)
71# include <linux/netfilter_ipv6/ip6_tables.h>
72#endif
73#if defined(HAVE_LINUX_IF_PACKET_H)
74# include <linux/if_packet.h>
75#endif
76#if defined(HAVE_LINUX_ICMP_H)
77# include <linux/icmp.h>
78#endif
79#ifdef HAVE_BLUETOOTH_BLUETOOTH_H
80# include <bluetooth/bluetooth.h>
81# include <bluetooth/hci.h>
82# include <bluetooth/l2cap.h>
83# include <bluetooth/rfcomm.h>
84# include <bluetooth/sco.h>
85#endif
86#ifndef PF_UNSPEC
87# define PF_UNSPEC AF_UNSPEC
88#endif
89
90#include "xlat/domains.h"
91#include "xlat/addrfams.h"
92#include "xlat/socktypes.h"
93#include "xlat/sock_type_flags.h"
94#ifndef SOCK_TYPE_MASK
95# define SOCK_TYPE_MASK 0xf
96#endif
97
98#include "xlat/socketlayers.h"
99
100#include "xlat/inet_protocols.h"
101
102#ifdef PF_NETLINK
103# if !defined NETLINK_SOCK_DIAG && defined NETLINK_INET_DIAG
104#  define NETLINK_SOCK_DIAG NETLINK_INET_DIAG
105# endif
106# include "xlat/netlink_protocols.h"
107#endif
108
109#if defined(HAVE_BLUETOOTH_BLUETOOTH_H)
110# include "xlat/bt_protocols.h"
111#endif
112
113#include "xlat/msg_flags.h"
114
115#if defined(AF_PACKET) /* from e.g. linux/if_packet.h */
116# include "xlat/af_packet_types.h"
117#endif
118
119static void
120print_ifindex(unsigned int ifindex)
121{
122#ifdef HAVE_IF_INDEXTONAME
123	char buf[IFNAMSIZ + 1];
124
125	if (if_indextoname(ifindex, buf)) {
126		tprints("if_nametoindex(");
127		print_quoted_string(buf, sizeof(buf), QUOTE_0_TERMINATED);
128		tprints(")");
129		return;
130	}
131#endif
132	tprintf("%u", ifindex);
133}
134
135typedef union {
136	char pad[128];
137	struct sockaddr sa;
138	struct sockaddr_in sin;
139	struct sockaddr_un sau;
140#ifdef HAVE_INET_NTOP
141	struct sockaddr_in6 sa6;
142#endif
143#if defined(AF_IPX)
144	struct sockaddr_ipx sipx;
145#endif
146#ifdef AF_PACKET
147	struct sockaddr_ll ll;
148#endif
149#ifdef AF_NETLINK
150	struct sockaddr_nl nl;
151#endif
152#ifdef HAVE_BLUETOOTH_BLUETOOTH_H
153	struct sockaddr_hci hci;
154	struct sockaddr_l2 l2;
155	struct sockaddr_rc rc;
156	struct sockaddr_sco sco;
157#endif
158} sockaddr_buf_t;
159
160static void
161print_sockaddr(struct tcb *tcp, const sockaddr_buf_t *addr, const int addrlen)
162{
163	tprints("{sa_family=");
164	printxval(addrfams, addr->sa.sa_family, "AF_???");
165	tprints(", ");
166
167	switch (addr->sa.sa_family) {
168	case AF_UNIX:
169		if (addrlen == 2) {
170			tprints("NULL");
171		} else if (addr->sau.sun_path[0]) {
172			tprints("sun_path=");
173			print_quoted_string(addr->sau.sun_path,
174					    sizeof(addr->sau.sun_path) + 1,
175					    QUOTE_0_TERMINATED);
176		} else {
177			tprints("sun_path=@");
178			print_quoted_string(addr->sau.sun_path + 1,
179					    sizeof(addr->sau.sun_path),
180					    QUOTE_0_TERMINATED);
181		}
182		break;
183	case AF_INET:
184		tprintf("sin_port=htons(%u), sin_addr=inet_addr(\"%s\")",
185			ntohs(addr->sin.sin_port), inet_ntoa(addr->sin.sin_addr));
186		break;
187#ifdef HAVE_INET_NTOP
188	case AF_INET6:
189		{
190			char string_addr[100];
191			inet_ntop(AF_INET6, &addr->sa6.sin6_addr,
192				  string_addr, sizeof(string_addr));
193			tprintf("sin6_port=htons(%u), inet_pton(AF_INET6"
194				", \"%s\", &sin6_addr), sin6_flowinfo=%u",
195				ntohs(addr->sa6.sin6_port), string_addr,
196				addr->sa6.sin6_flowinfo);
197# ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
198			tprints(", sin6_scope_id=");
199#  if defined IN6_IS_ADDR_LINKLOCAL && defined IN6_IS_ADDR_MC_LINKLOCAL
200			if (IN6_IS_ADDR_LINKLOCAL(&addr->sa6.sin6_addr)
201			    || IN6_IS_ADDR_MC_LINKLOCAL(&addr->sa6.sin6_addr))
202				print_ifindex(addr->sa6.sin6_scope_id);
203			else
204#  endif
205				tprintf("%u", addr->sa6.sin6_scope_id);
206# endif /* HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID */
207		}
208		break;
209#endif
210#if defined(AF_IPX)
211	case AF_IPX:
212		{
213			int i;
214			tprintf("sipx_port=htons(%u), ",
215					ntohs(addr->sipx.sipx_port));
216			/* Yes, I know, this does not look too
217			 * strace-ish, but otherwise the IPX
218			 * addresses just look monstrous...
219			 * Anyways, feel free if you don't like
220			 * this way.. :)
221			 */
222			tprintf("%08lx:", (unsigned long)ntohl(addr->sipx.sipx_network));
223			for (i = 0; i < IPX_NODE_LEN; i++)
224				tprintf("%02x", addr->sipx.sipx_node[i]);
225			tprintf("/[%02x]", addr->sipx.sipx_type);
226		}
227		break;
228#endif /* AF_IPX */
229#ifdef AF_PACKET
230	case AF_PACKET:
231		{
232			int i;
233			tprintf("proto=%#04x, if%d, pkttype=",
234					ntohs(addr->ll.sll_protocol),
235					addr->ll.sll_ifindex);
236			printxval(af_packet_types, addr->ll.sll_pkttype, "PACKET_???");
237			tprintf(", addr(%d)={%d, ",
238					addr->ll.sll_halen,
239					addr->ll.sll_hatype);
240			for (i = 0; i < addr->ll.sll_halen; i++)
241				tprintf("%02x", addr->ll.sll_addr[i]);
242		}
243		break;
244
245#endif /* AF_PACKET */
246#ifdef AF_NETLINK
247	case AF_NETLINK:
248		tprintf("pid=%d, groups=%08x", addr->nl.nl_pid, addr->nl.nl_groups);
249		break;
250#endif /* AF_NETLINK */
251#if defined(AF_BLUETOOTH) && defined(HAVE_BLUETOOTH_BLUETOOTH_H)
252	case AF_BLUETOOTH:
253		tprintf("{sco_bdaddr=%02X:%02X:%02X:%02X:%02X:%02X} or "
254			"{rc_bdaddr=%02X:%02X:%02X:%02X:%02X:%02X, rc_channel=%d} or "
255			"{l2_psm=htobs(%d), l2_bdaddr=%02X:%02X:%02X:%02X:%02X:%02X, l2_cid=htobs(%d)} or "
256			"{hci_dev=htobs(%d)}",
257			addr->sco.sco_bdaddr.b[0], addr->sco.sco_bdaddr.b[1],
258			addr->sco.sco_bdaddr.b[2], addr->sco.sco_bdaddr.b[3],
259			addr->sco.sco_bdaddr.b[4], addr->sco.sco_bdaddr.b[5],
260			addr->rc.rc_bdaddr.b[0], addr->rc.rc_bdaddr.b[1],
261			addr->rc.rc_bdaddr.b[2], addr->rc.rc_bdaddr.b[3],
262			addr->rc.rc_bdaddr.b[4], addr->rc.rc_bdaddr.b[5],
263			addr->rc.rc_channel,
264			btohs(addr->l2.l2_psm), addr->l2.l2_bdaddr.b[0],
265			addr->l2.l2_bdaddr.b[1], addr->l2.l2_bdaddr.b[2],
266			addr->l2.l2_bdaddr.b[3], addr->l2.l2_bdaddr.b[4],
267			addr->l2.l2_bdaddr.b[5], btohs(addr->l2.l2_cid),
268			btohs(addr->hci.hci_dev));
269		break;
270#endif /* AF_BLUETOOTH && HAVE_BLUETOOTH_BLUETOOTH_H */
271	/* AF_AX25 AF_APPLETALK AF_NETROM AF_BRIDGE AF_AAL5
272	AF_X25 AF_ROSE etc. still need to be done */
273
274	default:
275		tprints("sa_data=");
276		print_quoted_string(addr->sa.sa_data,
277				    sizeof(addr->sa.sa_data), 0);
278		break;
279	}
280	tprints("}");
281}
282
283void
284printsock(struct tcb *tcp, long addr, int addrlen)
285{
286	sockaddr_buf_t addrbuf;
287
288	if (addrlen < 2) {
289		printaddr(addr);
290		return;
291	}
292
293	if (addrlen > (int) sizeof(addrbuf))
294		addrlen = sizeof(addrbuf);
295
296	memset(&addrbuf, 0, sizeof(addrbuf));
297	if (umoven_or_printaddr(tcp, addr, addrlen, addrbuf.pad))
298		return;
299	addrbuf.pad[sizeof(addrbuf.pad) - 1] = '\0';
300
301	print_sockaddr(tcp, &addrbuf, addrlen);
302}
303
304#include "xlat/scmvals.h"
305#include "xlat/ip_cmsg_types.h"
306
307#if SUPPORTED_PERSONALITIES > 1 && SIZEOF_LONG > 4
308struct cmsghdr32 {
309	uint32_t cmsg_len;
310	int cmsg_level;
311	int cmsg_type;
312};
313#endif
314
315typedef union {
316	char *ptr;
317	struct cmsghdr *cmsg;
318#if SUPPORTED_PERSONALITIES > 1 && SIZEOF_LONG > 4
319	struct cmsghdr32 *cmsg32;
320#endif
321} union_cmsghdr;
322
323static void
324print_scm_rights(struct tcb *tcp, const void *cmsg_data,
325		 const size_t data_len)
326{
327	const int *fds = cmsg_data;
328	const char *end = (const char *) cmsg_data + data_len;
329	bool seen = false;
330
331	if (sizeof(*fds) > data_len)
332		return;
333
334	tprints(", [");
335	while ((const char *) fds < end) {
336		if (seen)
337			tprints(", ");
338		else
339			seen = true;
340		printfd(tcp, *fds++);
341	}
342	tprints("]");
343}
344
345static void
346print_scm_creds(struct tcb *tcp, const void *cmsg_data,
347		const size_t data_len)
348{
349	const struct ucred *uc = cmsg_data;
350
351	if (sizeof(*uc) > data_len)
352		return;
353
354	tprintf(", {pid=%u, uid=%u, gid=%u}",
355		(unsigned) uc->pid, (unsigned) uc->uid, (unsigned) uc->gid);
356}
357
358static void
359print_scm_security(struct tcb *tcp, const void *cmsg_data,
360		   const size_t data_len)
361{
362	if (!data_len)
363		return;
364
365	tprints(", ");
366	print_quoted_string(cmsg_data, data_len, 0);
367}
368
369static void
370print_cmsg_ip_pktinfo(struct tcb *tcp, const void *cmsg_data,
371		      const size_t data_len)
372{
373	const struct in_pktinfo *info = cmsg_data;
374
375	if (sizeof(*info) > data_len)
376		return;
377
378	tprints(", {ipi_ifindex=");
379	print_ifindex(info->ipi_ifindex);
380	tprintf(", ipi_spec_dst=inet_addr(\"%s\"), ipi_addr=inet_addr(\"%s\")}",
381		inet_ntoa(info->ipi_spec_dst), inet_ntoa(info->ipi_addr));
382}
383
384static void
385print_cmsg_ip_ttl(struct tcb *tcp, const void *cmsg_data,
386		  const size_t data_len)
387{
388	const unsigned int *ttl = cmsg_data;
389
390	if (sizeof(*ttl) > data_len)
391		return;
392
393	tprintf(", {ttl=%u}", *ttl);
394}
395
396static void
397print_cmsg_ip_tos(struct tcb *tcp, const void *cmsg_data,
398		  const size_t data_len)
399{
400	const uint8_t *tos = cmsg_data;
401
402	if (sizeof(*tos) > data_len)
403		return;
404
405	tprintf(", {tos=%x}", *tos);
406}
407
408static void
409print_cmsg_ip_checksum(struct tcb *tcp, const void *cmsg_data,
410		       const size_t data_len)
411{
412	const uint32_t *csum = cmsg_data;
413
414	if (sizeof(*csum) > data_len)
415		return;
416
417	tprintf(", {csum=%u}", *csum);
418}
419
420static void
421print_cmsg_ip_opts(struct tcb *tcp, const void *cmsg_data,
422		   const size_t data_len)
423{
424	const unsigned char *opts = cmsg_data;
425	size_t i;
426
427	if (!data_len)
428		return;
429
430	tprints(", {opts=0x");
431	for (i = 0; i < data_len; ++i)
432		tprintf("%02x", opts[i]);
433	tprints("}");
434}
435
436static void
437print_cmsg_ip_recverr(struct tcb *tcp, const void *cmsg_data,
438		      const size_t data_len)
439{
440	const struct {
441		uint32_t ee_errno;
442		uint8_t  ee_origin;
443		uint8_t  ee_type;
444		uint8_t  ee_code;
445		uint8_t  ee_pad;
446		uint32_t ee_info;
447		uint32_t ee_data;
448		struct sockaddr_in offender;
449	} *err = cmsg_data;
450
451	if (sizeof(*err) > data_len)
452		return;
453
454	tprintf(", {ee_errno=%u, ee_origin=%u, ee_type=%u, ee_code=%u"
455		", ee_info=%u, ee_data=%u, offender=",
456		err->ee_errno, err->ee_origin, err->ee_type,
457		err->ee_code, err->ee_info, err->ee_data);
458	print_sockaddr(tcp, (const void *) &err->offender,
459		sizeof(err->offender));
460	tprints("}");
461}
462
463static void
464print_cmsg_ip_origdstaddr(struct tcb *tcp, const void *cmsg_data,
465			  const size_t data_len)
466{
467	if (sizeof(struct sockaddr_in) > data_len)
468		return;
469
470	tprints(", ");
471	print_sockaddr(tcp, cmsg_data, data_len);
472}
473
474static void
475print_cmsg_type_data(struct tcb *tcp, const int cmsg_level, const int cmsg_type,
476		     const void *cmsg_data, const size_t data_len)
477{
478	switch (cmsg_level) {
479	case SOL_SOCKET:
480		printxval(scmvals, cmsg_type, "SCM_???");
481		switch (cmsg_type) {
482		case SCM_RIGHTS:
483			print_scm_rights(tcp, cmsg_data, data_len);
484			break;
485		case SCM_CREDENTIALS:
486			print_scm_creds(tcp, cmsg_data, data_len);
487			break;
488		case SCM_SECURITY:
489			print_scm_security(tcp, cmsg_data, data_len);
490			break;
491		}
492		break;
493	case SOL_IP:
494		printxval(ip_cmsg_types, cmsg_type, "IP_???");
495		switch (cmsg_type) {
496		case IP_PKTINFO:
497			print_cmsg_ip_pktinfo(tcp, cmsg_data, data_len);
498			break;
499		case IP_TTL:
500			print_cmsg_ip_ttl(tcp, cmsg_data, data_len);
501			break;
502		case IP_TOS:
503			print_cmsg_ip_tos(tcp, cmsg_data, data_len);
504			break;
505		case IP_RECVOPTS:
506		case IP_RETOPTS:
507			print_cmsg_ip_opts(tcp, cmsg_data, data_len);
508			break;
509		case IP_RECVERR:
510			print_cmsg_ip_recverr(tcp, cmsg_data, data_len);
511			break;
512		case IP_ORIGDSTADDR:
513			print_cmsg_ip_origdstaddr(tcp, cmsg_data, data_len);
514			break;
515		case IP_CHECKSUM:
516			print_cmsg_ip_checksum(tcp, cmsg_data, data_len);
517			break;
518		case SCM_SECURITY:
519			print_scm_security(tcp, cmsg_data, data_len);
520			break;
521		}
522		break;
523	default:
524		tprintf("%u", cmsg_type);
525	}
526}
527
528static void
529printcmsghdr(struct tcb *tcp, unsigned long addr, size_t len)
530{
531	const size_t cmsg_size =
532#if SUPPORTED_PERSONALITIES > 1 && SIZEOF_LONG > 4
533		(current_wordsize < sizeof(long)) ? sizeof(struct cmsghdr32) :
534#endif
535			sizeof(struct cmsghdr);
536
537	char *buf = len < cmsg_size ? NULL : malloc(len);
538	if (!buf || umoven(tcp, addr, len, buf) < 0) {
539		tprints(", msg_control=");
540		printaddr(addr);
541		free(buf);
542		return;
543	}
544
545	union_cmsghdr u = { .ptr = buf };
546
547	tprints(", [");
548	while (len >= cmsg_size) {
549		size_t cmsg_len =
550#if SUPPORTED_PERSONALITIES > 1 && SIZEOF_LONG > 4
551			(current_wordsize < sizeof(long)) ? u.cmsg32->cmsg_len :
552#endif
553				u.cmsg->cmsg_len;
554		int cmsg_level =
555#if SUPPORTED_PERSONALITIES > 1 && SIZEOF_LONG > 4
556			(current_wordsize < sizeof(long)) ? u.cmsg32->cmsg_level :
557#endif
558				u.cmsg->cmsg_level;
559		int cmsg_type =
560#if SUPPORTED_PERSONALITIES > 1 && SIZEOF_LONG > 4
561			(current_wordsize < sizeof(long)) ? u.cmsg32->cmsg_type :
562#endif
563				u.cmsg->cmsg_type;
564
565		if (u.ptr != buf)
566			tprints(", ");
567		tprintf("{cmsg_len=%lu, cmsg_level=", (unsigned long) cmsg_len);
568		printxval(socketlayers, cmsg_level, "SOL_???");
569		tprints(", cmsg_type=");
570
571		if (cmsg_len > len)
572			cmsg_len = len;
573
574		print_cmsg_type_data(tcp, cmsg_level, cmsg_type,
575				     (const void *) (u.ptr + cmsg_size),
576				     cmsg_len > cmsg_size ? cmsg_len - cmsg_size: 0);
577		tprints("}");
578
579		if (cmsg_len < cmsg_size) {
580			len -= cmsg_size;
581			break;
582		}
583		cmsg_len = (cmsg_len + current_wordsize - 1) &
584			(size_t) ~(current_wordsize - 1);
585		if (cmsg_len >= len) {
586			len = 0;
587			break;
588		}
589		u.ptr += cmsg_len;
590		len -= cmsg_len;
591	}
592	if (len)
593		tprints(", ...");
594	tprints("]");
595	free(buf);
596}
597
598static void
599do_msghdr(struct tcb *tcp, struct msghdr *msg, unsigned long data_size)
600{
601	tprintf("{msg_name(%d)=", msg->msg_namelen);
602	printsock(tcp, (long)msg->msg_name, msg->msg_namelen);
603
604	tprintf(", msg_iov(%lu)=", (unsigned long)msg->msg_iovlen);
605	tprint_iov_upto(tcp, (unsigned long)msg->msg_iovlen,
606		   (unsigned long)msg->msg_iov, 1, data_size);
607
608#ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
609	tprintf(", msg_controllen=%lu", (unsigned long)msg->msg_controllen);
610	if (msg->msg_controllen)
611		printcmsghdr(tcp, (unsigned long) msg->msg_control,
612			     msg->msg_controllen);
613	tprints(", msg_flags=");
614	printflags(msg_flags, msg->msg_flags, "MSG_???");
615#else /* !HAVE_STRUCT_MSGHDR_MSG_CONTROL */
616	tprintf("msg_accrights=%#lx, msg_accrightslen=%u",
617		(unsigned long) msg->msg_accrights, msg->msg_accrightslen);
618#endif /* !HAVE_STRUCT_MSGHDR_MSG_CONTROL */
619	tprints("}");
620}
621
622struct msghdr32 {
623	uint32_t /* void* */    msg_name;
624	uint32_t /* socklen_t */msg_namelen;
625	uint32_t /* iovec* */   msg_iov;
626	uint32_t /* size_t */   msg_iovlen;
627	uint32_t /* void* */    msg_control;
628	uint32_t /* size_t */   msg_controllen;
629	uint32_t /* int */      msg_flags;
630};
631struct mmsghdr32 {
632	struct msghdr32         msg_hdr;
633	uint32_t /* unsigned */ msg_len;
634};
635
636#ifndef HAVE_STRUCT_MMSGHDR
637struct mmsghdr {
638	struct msghdr msg_hdr;
639	unsigned msg_len;
640};
641#endif
642
643#if SUPPORTED_PERSONALITIES > 1 && SIZEOF_LONG > 4
644static void
645copy_from_msghdr32(struct msghdr *to_msg, struct msghdr32 *from_msg32)
646{
647	to_msg->msg_name       = (void*)(long)from_msg32->msg_name;
648	to_msg->msg_namelen    =              from_msg32->msg_namelen;
649	to_msg->msg_iov        = (void*)(long)from_msg32->msg_iov;
650	to_msg->msg_iovlen     =              from_msg32->msg_iovlen;
651	to_msg->msg_control    = (void*)(long)from_msg32->msg_control;
652	to_msg->msg_controllen =              from_msg32->msg_controllen;
653	to_msg->msg_flags      =              from_msg32->msg_flags;
654}
655#endif
656
657static bool
658extractmsghdr(struct tcb *tcp, long addr, struct msghdr *msg)
659{
660#if SUPPORTED_PERSONALITIES > 1 && SIZEOF_LONG > 4
661	if (current_wordsize == 4) {
662		struct msghdr32 msg32;
663
664		if (umove(tcp, addr, &msg32) < 0)
665			return false;
666		copy_from_msghdr32(msg, &msg32);
667	} else
668#endif
669	if (umove(tcp, addr, msg) < 0)
670		return false;
671	return true;
672}
673
674static bool
675extractmmsghdr(struct tcb *tcp, long addr, unsigned int idx, struct mmsghdr *mmsg)
676{
677#if SUPPORTED_PERSONALITIES > 1 && SIZEOF_LONG > 4
678	if (current_wordsize == 4) {
679		struct mmsghdr32 mmsg32;
680
681		addr += sizeof(struct mmsghdr32) * idx;
682		if (umove(tcp, addr, &mmsg32) < 0)
683			return false;
684
685		copy_from_msghdr32(&mmsg->msg_hdr, &mmsg32.msg_hdr);
686		mmsg->msg_len = mmsg32.msg_len;
687	} else
688#endif
689	{
690		addr += sizeof(*mmsg) * idx;
691		if (umove(tcp, addr, mmsg) < 0)
692			return false;
693	}
694	return true;
695}
696
697static void
698printmsghdr(struct tcb *tcp, long addr, unsigned long data_size)
699{
700	struct msghdr msg;
701
702	if (verbose(tcp) && extractmsghdr(tcp, addr, &msg))
703		do_msghdr(tcp, &msg, data_size);
704	else
705		printaddr(addr);
706}
707
708void
709dumpiov_in_msghdr(struct tcb *tcp, long addr)
710{
711	struct msghdr msg;
712
713	if (extractmsghdr(tcp, addr, &msg))
714		dumpiov(tcp, msg.msg_iovlen, (long)msg.msg_iov);
715}
716
717static void
718printmmsghdr(struct tcb *tcp, long addr, unsigned int idx, unsigned long msg_len)
719{
720	struct mmsghdr mmsg;
721
722	if (extractmmsghdr(tcp, addr, idx, &mmsg)) {
723		tprints("{");
724		do_msghdr(tcp, &mmsg.msg_hdr, msg_len ? msg_len : mmsg.msg_len);
725		tprintf(", %u}", mmsg.msg_len);
726	}
727	else
728		printaddr(addr);
729}
730
731static void
732decode_mmsg(struct tcb *tcp, unsigned long msg_len)
733{
734	/* mmsgvec */
735	if (syserror(tcp)) {
736		printaddr(tcp->u_arg[1]);
737	} else {
738		unsigned int len = tcp->u_rval;
739		unsigned int i;
740
741		tprints("{");
742		for (i = 0; i < len; ++i) {
743			if (i)
744				tprints(", ");
745			printmmsghdr(tcp, tcp->u_arg[1], i, msg_len);
746		}
747		tprints("}");
748	}
749	/* vlen */
750	tprintf(", %u, ", (unsigned int) tcp->u_arg[2]);
751	/* flags */
752	printflags(msg_flags, tcp->u_arg[3], "MSG_???");
753}
754
755void
756dumpiov_in_mmsghdr(struct tcb *tcp, long addr)
757{
758	unsigned int len = tcp->u_rval;
759	unsigned int i;
760	struct mmsghdr mmsg;
761
762	for (i = 0; i < len; ++i) {
763		if (extractmmsghdr(tcp, addr, i, &mmsg)) {
764			tprintf(" = %lu buffers in vector %u\n",
765				(unsigned long)mmsg.msg_hdr.msg_iovlen, i);
766			dumpiov(tcp, mmsg.msg_hdr.msg_iovlen,
767				(long)mmsg.msg_hdr.msg_iov);
768		}
769	}
770}
771
772/*
773 * low bits of the socket type define real socket type,
774 * other bits are socket type flags.
775 */
776static void
777tprint_sock_type(int flags)
778{
779	const char *str = xlookup(socktypes, flags & SOCK_TYPE_MASK);
780
781	if (str) {
782		tprints(str);
783		flags &= ~SOCK_TYPE_MASK;
784		if (!flags)
785			return;
786		tprints("|");
787	}
788	printflags(sock_type_flags, flags, "SOCK_???");
789}
790
791SYS_FUNC(socket)
792{
793	printxval(domains, tcp->u_arg[0], "PF_???");
794	tprints(", ");
795	tprint_sock_type(tcp->u_arg[1]);
796	tprints(", ");
797	switch (tcp->u_arg[0]) {
798	case PF_INET:
799#ifdef PF_INET6
800	case PF_INET6:
801#endif
802		printxval(inet_protocols, tcp->u_arg[2], "IPPROTO_???");
803		break;
804#ifdef PF_IPX
805	case PF_IPX:
806		/* BTW: I don't believe this.. */
807		tprints("[");
808		printxval(domains, tcp->u_arg[2], "PF_???");
809		tprints("]");
810		break;
811#endif /* PF_IPX */
812#ifdef PF_NETLINK
813	case PF_NETLINK:
814		printxval(netlink_protocols, tcp->u_arg[2], "NETLINK_???");
815		break;
816#endif
817#if defined(PF_BLUETOOTH) && defined(HAVE_BLUETOOTH_BLUETOOTH_H)
818	case PF_BLUETOOTH:
819		printxval(bt_protocols, tcp->u_arg[2], "BTPROTO_???");
820		break;
821#endif
822	default:
823		tprintf("%lu", tcp->u_arg[2]);
824		break;
825	}
826
827	return RVAL_DECODED | RVAL_FD;
828}
829
830SYS_FUNC(bind)
831{
832	printfd(tcp, tcp->u_arg[0]);
833	tprints(", ");
834	printsock(tcp, tcp->u_arg[1], tcp->u_arg[2]);
835	tprintf(", %lu", tcp->u_arg[2]);
836
837	return RVAL_DECODED;
838}
839
840SYS_FUNC(listen)
841{
842	printfd(tcp, tcp->u_arg[0]);
843	tprints(", ");
844	tprintf("%lu", tcp->u_arg[1]);
845
846	return RVAL_DECODED;
847}
848
849static int
850do_sockname(struct tcb *tcp, int flags_arg)
851{
852	if (entering(tcp)) {
853		printfd(tcp, tcp->u_arg[0]);
854		tprints(", ");
855		return 0;
856	}
857
858	int len;
859	if (!tcp->u_arg[2] || !verbose(tcp) || syserror(tcp) ||
860	    umove(tcp, tcp->u_arg[2], &len) < 0) {
861		printaddr(tcp->u_arg[1]);
862		tprints(", ");
863		printaddr(tcp->u_arg[2]);
864	} else {
865		printsock(tcp, tcp->u_arg[1], len);
866		tprintf(", [%d]", len);
867	}
868
869	if (flags_arg >= 0) {
870		tprints(", ");
871		printflags(sock_type_flags, tcp->u_arg[flags_arg],
872			   "SOCK_???");
873	}
874	return 0;
875}
876
877SYS_FUNC(accept)
878{
879	do_sockname(tcp, -1);
880	return RVAL_FD;
881}
882
883SYS_FUNC(accept4)
884{
885	do_sockname(tcp, 3);
886	return RVAL_FD;
887}
888
889SYS_FUNC(send)
890{
891	printfd(tcp, tcp->u_arg[0]);
892	tprints(", ");
893	printstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
894	tprintf(", %lu, ", tcp->u_arg[2]);
895	/* flags */
896	printflags(msg_flags, tcp->u_arg[3], "MSG_???");
897
898	return RVAL_DECODED;
899}
900
901SYS_FUNC(sendto)
902{
903	printfd(tcp, tcp->u_arg[0]);
904	tprints(", ");
905	printstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
906	tprintf(", %lu, ", tcp->u_arg[2]);
907	/* flags */
908	printflags(msg_flags, tcp->u_arg[3], "MSG_???");
909	/* to address */
910	tprints(", ");
911	printsock(tcp, tcp->u_arg[4], tcp->u_arg[5]);
912	/* to length */
913	tprintf(", %lu", tcp->u_arg[5]);
914
915	return RVAL_DECODED;
916}
917
918SYS_FUNC(sendmsg)
919{
920	printfd(tcp, tcp->u_arg[0]);
921	tprints(", ");
922	printmsghdr(tcp, tcp->u_arg[1], (unsigned long) -1L);
923	/* flags */
924	tprints(", ");
925	printflags(msg_flags, tcp->u_arg[2], "MSG_???");
926
927	return RVAL_DECODED;
928}
929
930SYS_FUNC(sendmmsg)
931{
932	if (entering(tcp)) {
933		/* sockfd */
934		printfd(tcp, tcp->u_arg[0]);
935		tprints(", ");
936		if (!verbose(tcp)) {
937			tprintf("%#lx, %u, ",
938				tcp->u_arg[1], (unsigned int) tcp->u_arg[2]);
939			printflags(msg_flags, tcp->u_arg[3], "MSG_???");
940		}
941	} else {
942		if (verbose(tcp))
943			decode_mmsg(tcp, (unsigned long) -1L);
944	}
945	return 0;
946}
947
948SYS_FUNC(recv)
949{
950	if (entering(tcp)) {
951		printfd(tcp, tcp->u_arg[0]);
952		tprints(", ");
953	} else {
954		if (syserror(tcp))
955			printaddr(tcp->u_arg[1]);
956		else
957			printstr(tcp, tcp->u_arg[1], tcp->u_rval);
958
959		tprintf(", %lu, ", tcp->u_arg[2]);
960		printflags(msg_flags, tcp->u_arg[3], "MSG_???");
961	}
962	return 0;
963}
964
965SYS_FUNC(recvfrom)
966{
967	int fromlen;
968
969	if (entering(tcp)) {
970		printfd(tcp, tcp->u_arg[0]);
971		tprints(", ");
972	} else {
973		/* buf */
974		if (syserror(tcp)) {
975			printaddr(tcp->u_arg[1]);
976		} else {
977			printstr(tcp, tcp->u_arg[1], tcp->u_rval);
978		}
979		/* len */
980		tprintf(", %lu, ", tcp->u_arg[2]);
981		/* flags */
982		printflags(msg_flags, tcp->u_arg[3], "MSG_???");
983		tprints(", ");
984		if (syserror(tcp) || !tcp->u_arg[4] || !tcp->u_arg[5] ||
985		    umove(tcp, tcp->u_arg[5], &fromlen) < 0) {
986			/* from address, len */
987			printaddr(tcp->u_arg[4]);
988			tprints(", ");
989			printaddr(tcp->u_arg[5]);
990			return 0;
991		}
992		/* from address */
993		printsock(tcp, tcp->u_arg[4], fromlen);
994		/* from length */
995		tprintf(", [%u]", fromlen);
996	}
997	return 0;
998}
999
1000SYS_FUNC(recvmsg)
1001{
1002	if (entering(tcp)) {
1003		printfd(tcp, tcp->u_arg[0]);
1004		tprints(", ");
1005	} else {
1006		if (syserror(tcp))
1007			printaddr(tcp->u_arg[1]);
1008		else
1009			printmsghdr(tcp, tcp->u_arg[1], tcp->u_rval);
1010		/* flags */
1011		tprints(", ");
1012		printflags(msg_flags, tcp->u_arg[2], "MSG_???");
1013	}
1014	return 0;
1015}
1016
1017SYS_FUNC(recvmmsg)
1018{
1019	static char str[sizeof("left") + TIMESPEC_TEXT_BUFSIZE];
1020
1021	if (entering(tcp)) {
1022		printfd(tcp, tcp->u_arg[0]);
1023		tprints(", ");
1024		if (verbose(tcp)) {
1025			/* Abusing tcp->auxstr as temp storage.
1026			 * Will be used and cleared on syscall exit.
1027			 */
1028			tcp->auxstr = sprint_timespec(tcp, tcp->u_arg[4]);
1029		} else {
1030			tprintf("%#lx, %ld, ", tcp->u_arg[1], tcp->u_arg[2]);
1031			printflags(msg_flags, tcp->u_arg[3], "MSG_???");
1032			tprints(", ");
1033			print_timespec(tcp, tcp->u_arg[4]);
1034		}
1035		return 0;
1036	} else {
1037		if (verbose(tcp)) {
1038			decode_mmsg(tcp, 0);
1039			tprints(", ");
1040			/* timeout on entrance */
1041			tprints(tcp->auxstr);
1042			tcp->auxstr = NULL;
1043		}
1044		if (syserror(tcp))
1045			return 0;
1046		if (tcp->u_rval == 0) {
1047			tcp->auxstr = "Timeout";
1048			return RVAL_STR;
1049		}
1050		if (!verbose(tcp))
1051			return 0;
1052		/* timeout on exit */
1053		snprintf(str, sizeof(str), "left %s",
1054			 sprint_timespec(tcp, tcp->u_arg[4]));
1055		tcp->auxstr = str;
1056		return RVAL_STR;
1057	}
1058}
1059
1060#include "xlat/shutdown_modes.h"
1061
1062SYS_FUNC(shutdown)
1063{
1064	printfd(tcp, tcp->u_arg[0]);
1065	tprints(", ");
1066	printxval(shutdown_modes, tcp->u_arg[1], "SHUT_???");
1067
1068	return RVAL_DECODED;
1069}
1070
1071SYS_FUNC(getsockname)
1072{
1073	return do_sockname(tcp, -1);
1074}
1075
1076static void
1077printpair_fd(struct tcb *tcp, const int i0, const int i1)
1078{
1079	tprints("[");
1080	printfd(tcp, i0);
1081	tprints(", ");
1082	printfd(tcp, i1);
1083	tprints("]");
1084}
1085
1086static void
1087decode_pair_fd(struct tcb *tcp, const long addr)
1088{
1089	int pair[2];
1090
1091	if (umove_or_printaddr(tcp, addr, &pair))
1092		return;
1093
1094	printpair_fd(tcp, pair[0], pair[1]);
1095}
1096
1097static int
1098do_pipe(struct tcb *tcp, int flags_arg)
1099{
1100	if (exiting(tcp)) {
1101		if (syserror(tcp)) {
1102			printaddr(tcp->u_arg[0]);
1103		} else {
1104#ifdef HAVE_GETRVAL2
1105			if (flags_arg < 0) {
1106				printpair_fd(tcp, tcp->u_rval, getrval2(tcp));
1107			} else
1108#endif
1109				decode_pair_fd(tcp, tcp->u_arg[0]);
1110		}
1111		if (flags_arg >= 0) {
1112			tprints(", ");
1113			printflags(open_mode_flags, tcp->u_arg[flags_arg], "O_???");
1114		}
1115	}
1116	return 0;
1117}
1118
1119SYS_FUNC(pipe)
1120{
1121	return do_pipe(tcp, -1);
1122}
1123
1124SYS_FUNC(pipe2)
1125{
1126	return do_pipe(tcp, 1);
1127}
1128
1129SYS_FUNC(socketpair)
1130{
1131	if (entering(tcp)) {
1132		printxval(domains, tcp->u_arg[0], "PF_???");
1133		tprints(", ");
1134		tprint_sock_type(tcp->u_arg[1]);
1135		tprintf(", %lu", tcp->u_arg[2]);
1136	} else {
1137		tprints(", ");
1138		decode_pair_fd(tcp, tcp->u_arg[3]);
1139	}
1140	return 0;
1141}
1142
1143#include "xlat/sockoptions.h"
1144#include "xlat/sockipoptions.h"
1145#include "xlat/getsockipoptions.h"
1146#include "xlat/setsockipoptions.h"
1147#include "xlat/sockipv6options.h"
1148#include "xlat/getsockipv6options.h"
1149#include "xlat/setsockipv6options.h"
1150#include "xlat/sockipxoptions.h"
1151#include "xlat/sockrawoptions.h"
1152#include "xlat/sockpacketoptions.h"
1153#include "xlat/socksctpoptions.h"
1154#include "xlat/socktcpoptions.h"
1155
1156static void
1157print_sockopt_fd_level_name(struct tcb *tcp, int fd, int level, int name, bool is_getsockopt)
1158{
1159	printfd(tcp, fd);
1160	tprints(", ");
1161	printxval(socketlayers, level, "SOL_??");
1162	tprints(", ");
1163
1164	switch (level) {
1165	case SOL_SOCKET:
1166		printxval(sockoptions, name, "SO_???");
1167		break;
1168	case SOL_IP:
1169		printxvals(name, "IP_???", sockipoptions,
1170			is_getsockopt ? getsockipoptions : setsockipoptions, NULL);
1171		break;
1172	case SOL_IPV6:
1173		printxvals(name, "IPV6_???", sockipv6options,
1174			is_getsockopt ? getsockipv6options : setsockipv6options, NULL);
1175		break;
1176	case SOL_IPX:
1177		printxval(sockipxoptions, name, "IPX_???");
1178		break;
1179	case SOL_PACKET:
1180		printxval(sockpacketoptions, name, "PACKET_???");
1181		break;
1182	case SOL_TCP:
1183		printxval(socktcpoptions, name, "TCP_???");
1184		break;
1185	case SOL_SCTP:
1186		printxval(socksctpoptions, name, "SCTP_???");
1187		break;
1188	case SOL_RAW:
1189		printxval(sockrawoptions, name, "RAW_???");
1190		break;
1191
1192		/* Other SOL_* protocol levels still need work. */
1193
1194	default:
1195		tprintf("%u", name);
1196	}
1197
1198	tprints(", ");
1199}
1200
1201#ifdef SO_LINGER
1202static void
1203print_linger(struct tcb *tcp, long addr, int len)
1204{
1205	struct linger linger;
1206
1207	if (len != sizeof(linger) ||
1208	    umove(tcp, addr, &linger) < 0) {
1209		printaddr(addr);
1210		return;
1211	}
1212
1213	tprintf("{onoff=%d, linger=%d}",
1214		linger.l_onoff,
1215		linger.l_linger);
1216}
1217#endif /* SO_LINGER */
1218
1219#ifdef SO_PEERCRED
1220static void
1221print_ucred(struct tcb *tcp, long addr, int len)
1222{
1223	struct ucred uc;
1224
1225	if (len != sizeof(uc) ||
1226	    umove(tcp, addr, &uc) < 0) {
1227		printaddr(addr);
1228	} else {
1229		tprintf("{pid=%u, uid=%u, gid=%u}",
1230			(unsigned) uc.pid,
1231			(unsigned) uc.uid,
1232			(unsigned) uc.gid);
1233	}
1234}
1235#endif /* SO_PEERCRED */
1236
1237#ifdef PACKET_STATISTICS
1238static void
1239print_tpacket_stats(struct tcb *tcp, long addr, int len)
1240{
1241	struct tpacket_stats stats;
1242
1243	if (len != sizeof(stats) ||
1244	    umove(tcp, addr, &stats) < 0) {
1245		printaddr(addr);
1246	} else {
1247		tprintf("{packets=%u, drops=%u}",
1248			stats.tp_packets,
1249			stats.tp_drops);
1250	}
1251}
1252#endif /* PACKET_STATISTICS */
1253
1254#ifdef ICMP_FILTER
1255# include "xlat/icmpfilterflags.h"
1256
1257static void
1258print_icmp_filter(struct tcb *tcp, long addr, int len)
1259{
1260	struct icmp_filter	filter;
1261
1262	if (len != sizeof(filter) ||
1263	    umove(tcp, addr, &filter) < 0) {
1264		printaddr(addr);
1265		return;
1266	}
1267
1268	tprints("~(");
1269	printflags(icmpfilterflags, ~filter.data, "ICMP_???");
1270	tprints(")");
1271}
1272#endif /* ICMP_FILTER */
1273
1274static void
1275print_getsockopt(struct tcb *tcp, int level, int name, long addr, int len)
1276{
1277	if (addr && verbose(tcp))
1278	switch (level) {
1279	case SOL_SOCKET:
1280		switch (name) {
1281#ifdef SO_LINGER
1282		case SO_LINGER:
1283			print_linger(tcp, addr, len);
1284			goto done;
1285#endif
1286#ifdef SO_PEERCRED
1287		case SO_PEERCRED:
1288			print_ucred(tcp, addr, len);
1289			goto done;
1290#endif
1291		}
1292		break;
1293
1294	case SOL_PACKET:
1295		switch (name) {
1296#ifdef PACKET_STATISTICS
1297		case PACKET_STATISTICS:
1298			print_tpacket_stats(tcp, addr, len);
1299			goto done;
1300#endif
1301		}
1302		break;
1303
1304	case SOL_RAW:
1305		switch (name) {
1306#ifdef ICMP_FILTER
1307		case ICMP_FILTER:
1308			print_icmp_filter(tcp, addr, len);
1309			goto done;
1310#endif
1311		}
1312		break;
1313	}
1314
1315	/* default arg printing */
1316
1317	if (verbose(tcp)) {
1318		if (len == sizeof(int)) {
1319			printnum_int(tcp, addr, "%d");
1320		} else {
1321			printstr(tcp, addr, len);
1322		}
1323	} else {
1324		printaddr(addr);
1325	}
1326done:
1327	tprintf(", [%d]", len);
1328}
1329
1330SYS_FUNC(getsockopt)
1331{
1332	if (entering(tcp)) {
1333		print_sockopt_fd_level_name(tcp, tcp->u_arg[0],
1334					    tcp->u_arg[1], tcp->u_arg[2], true);
1335	} else {
1336		int len;
1337
1338		if (syserror(tcp) || umove(tcp, tcp->u_arg[4], &len) < 0) {
1339			tprintf("%#lx, %#lx",
1340				tcp->u_arg[3], tcp->u_arg[4]);
1341		} else {
1342			print_getsockopt(tcp, tcp->u_arg[1], tcp->u_arg[2],
1343					 tcp->u_arg[3], len);
1344		}
1345	}
1346	return 0;
1347}
1348
1349#ifdef IP_ADD_MEMBERSHIP
1350static void
1351print_mreq(struct tcb *tcp, long addr, unsigned int len)
1352{
1353	struct ip_mreq mreq;
1354
1355	if (len < sizeof(mreq)) {
1356		printstr(tcp, addr, len);
1357		return;
1358	}
1359	if (umove_or_printaddr(tcp, addr, &mreq))
1360		return;
1361
1362	tprints("{imr_multiaddr=inet_addr(");
1363	print_quoted_string(inet_ntoa(mreq.imr_multiaddr),
1364			    16, QUOTE_0_TERMINATED);
1365	tprints("), imr_interface=inet_addr(");
1366	print_quoted_string(inet_ntoa(mreq.imr_interface),
1367			    16, QUOTE_0_TERMINATED);
1368	tprints(")}");
1369}
1370#endif /* IP_ADD_MEMBERSHIP */
1371
1372#ifdef IPV6_ADD_MEMBERSHIP
1373static void
1374print_mreq6(struct tcb *tcp, long addr, unsigned int len)
1375{
1376	struct ipv6_mreq mreq;
1377
1378	if (len < sizeof(mreq))
1379		goto fail;
1380
1381	if (umove_or_printaddr(tcp, addr, &mreq))
1382		return;
1383
1384#ifdef HAVE_INET_NTOP
1385	const struct in6_addr *in6 = &mreq.ipv6mr_multiaddr;
1386	char address[INET6_ADDRSTRLEN];
1387
1388	if (!inet_ntop(AF_INET6, in6, address, sizeof(address)))
1389		goto fail;
1390
1391	tprints("{ipv6mr_multiaddr=inet_pton(");
1392	print_quoted_string(address, sizeof(address), QUOTE_0_TERMINATED);
1393	tprints("), ipv6mr_interface=");
1394	print_ifindex(mreq.ipv6mr_interface);
1395	tprints("}");
1396	return;
1397#endif /* HAVE_INET_NTOP */
1398
1399fail:
1400	printstr(tcp, addr, len);
1401}
1402#endif /* IPV6_ADD_MEMBERSHIP */
1403
1404#ifdef MCAST_JOIN_GROUP
1405static void
1406print_group_req(struct tcb *tcp, long addr, int len)
1407{
1408	struct group_req greq;
1409
1410	if (len != sizeof(greq) ||
1411	    umove(tcp, addr, &greq) < 0) {
1412		printaddr(addr);
1413		return;
1414	}
1415
1416	tprintf("{gr_interface=%u, gr_group=", greq.gr_interface);
1417	print_sockaddr(tcp, (const void *) &greq.gr_group,
1418		       sizeof(greq.gr_group));
1419	tprintf("}");
1420
1421}
1422#endif /* MCAST_JOIN_GROUP */
1423
1424#ifdef PACKET_RX_RING
1425static void
1426print_tpacket_req(struct tcb *tcp, long addr, int len)
1427{
1428	struct tpacket_req req;
1429
1430	if (len != sizeof(req) ||
1431	    umove(tcp, addr, &req) < 0) {
1432		printaddr(addr);
1433	} else {
1434		tprintf("{block_size=%u, block_nr=%u, "
1435			"frame_size=%u, frame_nr=%u}",
1436			req.tp_block_size,
1437			req.tp_block_nr,
1438			req.tp_frame_size,
1439			req.tp_frame_nr);
1440	}
1441}
1442#endif /* PACKET_RX_RING */
1443
1444#ifdef PACKET_ADD_MEMBERSHIP
1445# include "xlat/packet_mreq_type.h"
1446
1447static void
1448print_packet_mreq(struct tcb *tcp, long addr, int len)
1449{
1450	struct packet_mreq mreq;
1451
1452	if (len != sizeof(mreq) ||
1453	    umove(tcp, addr, &mreq) < 0) {
1454		printaddr(addr);
1455	} else {
1456		unsigned int i;
1457
1458		tprintf("{mr_ifindex=%u, mr_type=", mreq.mr_ifindex);
1459		printxval(packet_mreq_type, mreq.mr_type, "PACKET_MR_???");
1460		tprintf(", mr_alen=%u, mr_address=", mreq.mr_alen);
1461		if (mreq.mr_alen > ARRAY_SIZE(mreq.mr_address))
1462			mreq.mr_alen = ARRAY_SIZE(mreq.mr_address);
1463		for (i = 0; i < mreq.mr_alen; ++i)
1464			tprintf("%02x", mreq.mr_address[i]);
1465		tprints("}");
1466	}
1467}
1468#endif /* PACKET_ADD_MEMBERSHIP */
1469
1470static void
1471print_setsockopt(struct tcb *tcp, int level, int name, long addr, int len)
1472{
1473	if (addr && verbose(tcp))
1474	switch (level) {
1475	case SOL_SOCKET:
1476		switch (name) {
1477#ifdef SO_LINGER
1478		case SO_LINGER:
1479			print_linger(tcp, addr, len);
1480			goto done;
1481#endif
1482		}
1483		break;
1484
1485	case SOL_IP:
1486		switch (name) {
1487#ifdef IP_ADD_MEMBERSHIP
1488		case IP_ADD_MEMBERSHIP:
1489		case IP_DROP_MEMBERSHIP:
1490			print_mreq(tcp, addr, len);
1491			goto done;
1492#endif /* IP_ADD_MEMBERSHIP */
1493#ifdef MCAST_JOIN_GROUP
1494		case MCAST_JOIN_GROUP:
1495		case MCAST_LEAVE_GROUP:
1496			print_group_req(tcp, addr, len);
1497			goto done;
1498#endif /* MCAST_JOIN_GROUP */
1499		}
1500		break;
1501
1502	case SOL_IPV6:
1503		switch (name) {
1504#ifdef IPV6_ADD_MEMBERSHIP
1505		case IPV6_ADD_MEMBERSHIP:
1506		case IPV6_DROP_MEMBERSHIP:
1507# ifdef IPV6_JOIN_ANYCAST
1508		case IPV6_JOIN_ANYCAST:
1509# endif
1510# ifdef IPV6_LEAVE_ANYCAST
1511		case IPV6_LEAVE_ANYCAST:
1512# endif
1513			print_mreq6(tcp, addr, len);
1514			goto done;
1515#endif /* IPV6_ADD_MEMBERSHIP */
1516		}
1517		break;
1518
1519	case SOL_PACKET:
1520		switch (name) {
1521#ifdef PACKET_RX_RING
1522		case PACKET_RX_RING:
1523# ifdef PACKET_TX_RING
1524		case PACKET_TX_RING:
1525# endif
1526			print_tpacket_req(tcp, addr, len);
1527			goto done;
1528#endif /* PACKET_RX_RING */
1529#ifdef PACKET_ADD_MEMBERSHIP
1530		case PACKET_ADD_MEMBERSHIP:
1531		case PACKET_DROP_MEMBERSHIP:
1532			print_packet_mreq(tcp, addr, len);
1533			goto done;
1534#endif /* PACKET_ADD_MEMBERSHIP */
1535		}
1536		break;
1537
1538	case SOL_RAW:
1539		switch (name) {
1540#ifdef ICMP_FILTER
1541		case ICMP_FILTER:
1542			print_icmp_filter(tcp, addr, len);
1543			goto done;
1544#endif
1545		}
1546		break;
1547	}
1548
1549	/* default arg printing */
1550
1551	if (verbose(tcp)) {
1552		if (len == sizeof(int)) {
1553			printnum_int(tcp, addr, "%d");
1554		} else {
1555			printstr(tcp, addr, len);
1556		}
1557	} else {
1558		printaddr(addr);
1559	}
1560done:
1561	tprintf(", %d", len);
1562}
1563
1564SYS_FUNC(setsockopt)
1565{
1566	print_sockopt_fd_level_name(tcp, tcp->u_arg[0],
1567				    tcp->u_arg[1], tcp->u_arg[2], false);
1568	print_setsockopt(tcp, tcp->u_arg[1], tcp->u_arg[2],
1569			 tcp->u_arg[3], tcp->u_arg[4]);
1570
1571	return RVAL_DECODED;
1572}
1573