(root)/
strace-6.5/
tests-m32/
ioctl_sock.c
       1  /*
       2   * Check decoding of SIOC* ioctl commands.
       3   *
       4   * Copyright (c) 2020-2021 The strace developers.
       5   * All rights reserved.
       6   *
       7   * SPDX-License-Identifier: GPL-2.0-or-later
       8   */
       9  
      10  #include "tests.h"
      11  #include <errno.h>
      12  #include <stdio.h>
      13  #include <string.h>
      14  #include <unistd.h>
      15  #include <sys/ioctl.h>
      16  #include <sys/socket.h>
      17  #include <net/if.h>
      18  #include <arpa/inet.h>
      19  #include <linux/sockios.h>
      20  
      21  static const char *errstr;
      22  
      23  static int
      24  do_ioctl(int fd, kernel_ulong_t cmd, kernel_ulong_t arg)
      25  {
      26  	int rc = ioctl(fd, cmd, arg);
      27  	errstr = sprintrc(rc);
      28  
      29  	return rc;
      30  }
      31  
      32  static int
      33  do_ioctl_ptr(int fd, kernel_ulong_t cmd, const void *arg)
      34  {
      35  	return do_ioctl(fd, cmd, (uintptr_t) arg);
      36  }
      37  
      38  static void
      39  test_ptr(void)
      40  {
      41  	const char *const efault = tail_alloc(1) + 1;
      42  
      43  	static const struct {
      44  		uint32_t cmd;
      45  		const char *str;
      46  	} cmd[] = {
      47  		{ ARG_STR(FIOSETOWN) },
      48  		{ ARG_STR(SIOCSPGRP) },
      49  		{ ARG_STR(FIOGETOWN) },
      50  		{ ARG_STR(SIOCGPGRP) },
      51  		{ ARG_STR(SIOCATMARK) },
      52  #ifdef SIOCGSTAMP_OLD
      53  		{ ARG_STR(SIOCGSTAMP_OLD) },
      54  #endif
      55  #ifdef SIOCGSTAMP_NEW
      56  		{ ARG_STR(SIOCGSTAMP_NEW) },
      57  #endif
      58  #ifdef SIOCGSTAMPNS_OLD
      59  		{ ARG_STR(SIOCGSTAMPNS_OLD) },
      60  #endif
      61  #ifdef SIOCGSTAMPNS_NEW
      62  		{ ARG_STR(SIOCGSTAMPNS_NEW) },
      63  #endif
      64  		{ ARG_STR(SIOCADDRT) },
      65  		{ ARG_STR(SIOCDELRT) },
      66  		{ ARG_STR(SIOCRTMSG) },
      67  		{ ARG_STR(SIOCGIFNAME) },
      68  		{ ARG_STR(SIOCSIFLINK) },
      69  		{ ARG_STR(SIOCGIFCONF) },
      70  		{ ARG_STR(SIOCGIFFLAGS) },
      71  		{ ARG_STR(SIOCSIFFLAGS) },
      72  		{ ARG_STR(SIOCGIFADDR) },
      73  		{ ARG_STR(SIOCSIFADDR) },
      74  		{ ARG_STR(SIOCGIFDSTADDR) },
      75  		{ ARG_STR(SIOCSIFDSTADDR) },
      76  		{ ARG_STR(SIOCGIFBRDADDR) },
      77  		{ ARG_STR(SIOCSIFBRDADDR) },
      78  		{ ARG_STR(SIOCGIFNETMASK) },
      79  		{ ARG_STR(SIOCSIFNETMASK) },
      80  		{ ARG_STR(SIOCGIFMETRIC) },
      81  		{ ARG_STR(SIOCSIFMETRIC) },
      82  		{ ARG_STR(SIOCGIFMEM) },
      83  		{ ARG_STR(SIOCSIFMEM) },
      84  		{ ARG_STR(SIOCGIFMTU) },
      85  		{ ARG_STR(SIOCSIFMTU) },
      86  		{ ARG_STR(SIOCSIFNAME) },
      87  		{ ARG_STR(SIOCSIFHWADDR) },
      88  		{ ARG_STR(SIOCGIFENCAP) },
      89  		{ ARG_STR(SIOCSIFENCAP) },
      90  		{ ARG_STR(SIOCGIFHWADDR) },
      91  		{ ARG_STR(SIOCGIFSLAVE) },
      92  		{ ARG_STR(SIOCSIFSLAVE) },
      93  		{ ARG_STR(SIOCADDMULTI) },
      94  		{ ARG_STR(SIOCDELMULTI) },
      95  		{ ARG_STR(SIOCGIFINDEX) },
      96  		{ ARG_STR(SIOCSIFPFLAGS) },
      97  		{ ARG_STR(SIOCGIFPFLAGS) },
      98  		{ ARG_STR(SIOCDIFADDR) },
      99  		{ ARG_STR(SIOCSIFHWBROADCAST) },
     100  		{ ARG_STR(SIOCGIFCOUNT) },
     101  		{ ARG_STR(SIOCGIFBR) },
     102  		{ ARG_STR(SIOCSIFBR) },
     103  		{ ARG_STR(SIOCGIFTXQLEN) },
     104  		{ ARG_STR(SIOCSIFTXQLEN) },
     105  		{ ARG_STR(SIOCETHTOOL) },
     106  		{ ARG_STR(SIOCGMIIPHY) },
     107  		{ ARG_STR(SIOCGMIIREG) },
     108  		{ ARG_STR(SIOCSMIIREG) },
     109  		{ ARG_STR(SIOCWANDEV) },
     110  #ifdef SIOCOUTQNSD
     111  		{ ARG_STR(SIOCOUTQNSD) },
     112  #endif
     113  #ifdef SIOCGSKNS
     114  		{ ARG_STR(SIOCGSKNS) },
     115  #endif
     116  		{ ARG_STR(SIOCDARP) },
     117  		{ ARG_STR(SIOCGARP) },
     118  		{ ARG_STR(SIOCSARP) },
     119  		{ ARG_STR(SIOCDRARP) },
     120  		{ ARG_STR(SIOCGRARP) },
     121  		{ ARG_STR(SIOCSRARP) },
     122  		{ ARG_STR(SIOCGIFMAP) },
     123  		{ ARG_STR(SIOCSIFMAP) },
     124  		{ ARG_STR(SIOCADDDLCI) },
     125  		{ ARG_STR(SIOCDELDLCI) },
     126  		{ ARG_STR(SIOCGIFVLAN) },
     127  		{ ARG_STR(SIOCSIFVLAN) },
     128  		{ ARG_STR(SIOCBONDENSLAVE) },
     129  		{ ARG_STR(SIOCBONDRELEASE) },
     130  		{ ARG_STR(SIOCBONDSETHWADDR) },
     131  		{ ARG_STR(SIOCBONDSLAVEINFOQUERY) },
     132  		{ ARG_STR(SIOCBONDINFOQUERY) },
     133  		{ ARG_STR(SIOCBONDCHANGEACTIVE) },
     134  		{ ARG_STR(SIOCBRADDBR) },
     135  		{ ARG_STR(SIOCBRDELBR) },
     136  		{ ARG_STR(SIOCBRADDIF) },
     137  		{ ARG_STR(SIOCBRDELIF) },
     138  #ifdef SIOCSHWTSTAMP
     139  		{ ARG_STR(SIOCSHWTSTAMP) },
     140  #endif
     141  #ifdef SIOCGHWTSTAMP
     142  		{ ARG_STR(SIOCGHWTSTAMP) },
     143  #endif
     144  	},
     145  	unknown_cmd[] = {
     146  		{ _IO(0x89, 0xff), "_IOC(_IOC_NONE, 0x89, 0xff, 0)" }
     147  	};
     148  
     149  	for (size_t i = 0; i < ARRAY_SIZE(cmd); ++i) {
     150  		do_ioctl(-1, cmd[i].cmd, 0);
     151  		printf("ioctl(%d, %s, NULL) = %s\n",
     152  		       -1, cmd[i].str, errstr);
     153  
     154  		do_ioctl_ptr(-1, cmd[i].cmd, efault);
     155  		printf("ioctl(%d, %s, %p) = %s\n",
     156  		       -1, cmd[i].str, efault, errstr);
     157  	}
     158  
     159  	for (size_t i = 0; i < ARRAY_SIZE(unknown_cmd); ++i) {
     160  		do_ioctl(-1, unknown_cmd[i].cmd, 0);
     161  		printf("ioctl(%d, %s, 0) = %s\n",
     162  		       -1, unknown_cmd[i].str, errstr);
     163  
     164  		do_ioctl_ptr(-1, unknown_cmd[i].cmd, efault);
     165  		printf("ioctl(%d, %s, %p) = %s\n",
     166  		       -1, unknown_cmd[i].str, efault, errstr);
     167  	}
     168  }
     169  
     170  static void
     171  test_int(const int fd)
     172  {
     173  	TAIL_ALLOC_OBJECT_CONST_PTR(int, p_int);
     174  	pid_t pid = getpid();
     175  
     176  	const struct {
     177  		uint32_t cmd;
     178  		const char *str;
     179  		int val;
     180  	} cmd[] = {
     181  		{ ARG_STR(FIOGETOWN), -1 },
     182  		{ ARG_STR(FIOSETOWN), pid },
     183  		{ ARG_STR(SIOCATMARK), -1 },
     184  		{ ARG_STR(SIOCGPGRP), -1 },
     185  		{ ARG_STR(SIOCSPGRP), pid },
     186  		{ ARG_STR(SIOCSIFENCAP), -1 },
     187  	};
     188  
     189  	for (size_t i = 0; i < ARRAY_SIZE(cmd); ++i) {
     190  		*p_int = cmd[i].val;
     191  
     192  		do_ioctl_ptr(fd, cmd[i].cmd, p_int + 1);
     193  		printf("ioctl(%d, %s, %p) = %s\n",
     194  		       fd, cmd[i].str, p_int + 1, errstr);
     195  
     196  		do_ioctl_ptr(fd, cmd[i].cmd, p_int);
     197  		printf("ioctl(%d, %s, [%d]) = %s\n",
     198  		       fd, cmd[i].str, *p_int, errstr);
     199  	}
     200  }
     201  
     202  static void
     203  test_str(void)
     204  {
     205  	char *const buf = tail_alloc(IFNAMSIZ);
     206  
     207  	static const struct {
     208  		uint32_t cmd;
     209  		const char *str;
     210  	} cmd[] = {
     211  		{ ARG_STR(SIOCBRADDBR) },
     212  		{ ARG_STR(SIOCBRDELBR) },
     213  	};
     214  
     215  	for (size_t i = 0; i < ARRAY_SIZE(cmd); ++i) {
     216  		fill_memory_ex(buf, IFNAMSIZ, '0', 10);
     217  		do_ioctl_ptr(-1, cmd[i].cmd, buf + 1);
     218  		printf("ioctl(%d, %s, %p) = %s\n",
     219  		       -1, cmd[i].str, buf + 1, errstr);
     220  
     221  		do_ioctl_ptr(-1, cmd[i].cmd, buf);
     222  		printf("ioctl(%d, %s, \"%.*s\"...) = %s\n",
     223  		       -1, cmd[i].str, IFNAMSIZ, buf, errstr);
     224  
     225  		buf[IFNAMSIZ - 1] = '\0';
     226  		do_ioctl_ptr(-1, cmd[i].cmd, buf);
     227  		printf("ioctl(%d, %s, \"%s\") = %s\n",
     228  		       -1, cmd[i].str, buf, errstr);
     229  	}
     230  }
     231  
     232  static void
     233  test_ifreq(const int fd)
     234  {
     235  	TAIL_ALLOC_OBJECT_CONST_PTR(struct ifreq, ifr);
     236  
     237  #define SRC_IFR_INT(name, val0, val1)					\
     238  	static const struct ifreq src_ ## name[] = {			\
     239  		{ .name = val0 },					\
     240  		{ .name = val1 }					\
     241  	};								\
     242  	char str0_ ## name[sizeof(int) * 3];				\
     243  	snprintf(str0_ ## name, sizeof(str0_ ## name), "%d", val0);	\
     244  	char str1_ ## name[sizeof(int) * 3];				\
     245  	snprintf(str1_ ## name, sizeof(str1_ ## name), "%d", val1);	\
     246  	const char *const str_ ## name[] = {				\
     247  		str0_ ## name,						\
     248  		str1_ ## name						\
     249  	}								\
     250  /* End of SRC_IFR_INT definition.  */
     251  
     252  	SRC_IFR_INT(ifr_metric, 0x1defaced, 0xfacefed1);
     253  	SRC_IFR_INT(ifr_mtu, 0x2defaced, 0xfacefed2);
     254  	SRC_IFR_INT(ifr_qlen, 0x3defaced, 0xfacefed3);
     255  
     256  #define SRC_IFR_FLAG(name, valid_flags,   valid_str,			\
     257  			 invalid_flags, invalid_str)			\
     258  	static const struct ifreq src_ ## name[] = {			\
     259  		{ .name = valid_flags },				\
     260  		{ .name = invalid_flags }				\
     261  	};								\
     262  	static const char *const str_ ## name[] = {			\
     263  		valid_str,						\
     264  		invalid_str,						\
     265  	}								\
     266  /* End of SRC_IFR_FLAG definition.  */
     267  
     268  	SRC_IFR_FLAG(ifr_flags,
     269  		     0xffff, XLAT_KNOWN(0xffff,
     270  					"IFF_UP|"
     271  					"IFF_BROADCAST|"
     272  					"IFF_DEBUG|"
     273  					"IFF_LOOPBACK|"
     274  					"IFF_POINTOPOINT|"
     275  					"IFF_NOTRAILERS|"
     276  					"IFF_RUNNING|"
     277  					"IFF_NOARP|"
     278  					"IFF_PROMISC|"
     279  					"IFF_ALLMULTI|"
     280  					"IFF_MASTER|"
     281  					"IFF_SLAVE|"
     282  					"IFF_MULTICAST|"
     283  					"IFF_PORTSEL|"
     284  					"IFF_AUTOMEDIA|"
     285  					"IFF_DYNAMIC"),
     286  		     0, "0");
     287  
     288  #define SRC_IFR_STRING(name)						\
     289  	struct ifreq src_ ## name[2];					\
     290  	fill_memory_ex(src_ ## name[0].name,				\
     291  		       sizeof(src_ ## name[0].name),			\
     292  		       'a', 'z' - 'a' + 1);				\
     293  	memcpy(src_ ## name[1].name, src_ ## name[0].name,		\
     294  	       sizeof(src_ ## name[1].name) - 1);			\
     295  	src_ ## name[1].name[sizeof(src_ ## name[1].name) - 1] = '\0';	\
     296  	char str0_ ## name[sizeof(src_ ## name[0].name) + 5];		\
     297  	snprintf(str0_ ## name, sizeof(str0_ ## name),			\
     298  		 "\"%.*s\"...",						\
     299  		 (int) sizeof(src_ ## name[0].name) - 1,		\
     300  		 src_ ## name[0].name);					\
     301  	char str1_ ## name[sizeof(src_ ## name[1].name) + 2];		\
     302  	snprintf(str1_ ## name, sizeof(str1_ ## name),			\
     303  		 "\"%s\"", src_ ## name[1].name);			\
     304  	const char *const str_ ## name[] = {				\
     305  		str0_ ## name,						\
     306  		str1_ ## name						\
     307  	}								\
     308  /* End of SRC_IFR_STRING definition.  */
     309  
     310  	SRC_IFR_STRING(ifr_newname);
     311  	SRC_IFR_STRING(ifr_slave);
     312  
     313  #define SRC_IFR_ADDR(name, port)					\
     314  	const struct sockaddr_in src_in_ ## name = {			\
     315  		.sin_family = AF_INET,					\
     316  		.sin_addr.s_addr = htonl(INADDR_LOOPBACK),		\
     317  		.sin_port = htons(port)					\
     318  	};								\
     319  	struct ifreq src_ ## name[2];					\
     320  	memcpy(&src_ ## name[0].name, &src_in_ ## name,			\
     321  	       sizeof(src_in_ ## name));				\
     322  	memset(&src_ ## name[1], 0, sizeof(src_ ## name[1]));		\
     323  	char str_in_ ## name[256];					\
     324  	snprintf(str_in_ ## name, sizeof(str_in_ ## name),		\
     325  		 "{sa_family=AF_INET, sin_port=htons(%u)"		\
     326  		 ", sin_addr=inet_addr(\"%s\")}",			\
     327  		 ntohs((src_in_ ## name).sin_port),			\
     328  		 inet_ntoa((src_in_ ## name).sin_addr));		\
     329  	const char *const str_ ## name[] = {				\
     330  		str_in_ ## name, NULL					\
     331  	}								\
     332  /* End of SRC_IFR_ADDR definition.  */
     333  
     334  	SRC_IFR_ADDR(ifr_addr, 0x1bad);
     335  	SRC_IFR_ADDR(ifr_dstaddr, 0x2bad);
     336  	SRC_IFR_ADDR(ifr_broadaddr, 0x3bad);
     337  	SRC_IFR_ADDR(ifr_netmask, 0x4bad);
     338  
     339  #define SRC_IFR_HWADDR(name)						\
     340  	struct ifreq src_ ## name[2];					\
     341  	fill_memory(src_ ## name, sizeof(src_ ## name));		\
     342  	src_ ## name[0].name.sa_family = 1;				\
     343  	char str_hw_ ## name[256];					\
     344  	snprintf(str_hw_ ## name, sizeof(str_hw_ ## name),		\
     345  		 "{sa_family=ARPHRD_ETHER"				\
     346  		 ", sa_data=%02x:%02x:%02x:%02x:%02x:%02x}",		\
     347  		 (uint8_t) src_ ## name[0].name.sa_data[0],		\
     348  		 (uint8_t) src_ ## name[0].name.sa_data[1],		\
     349  		 (uint8_t) src_ ## name[0].name.sa_data[2],		\
     350  		 (uint8_t) src_ ## name[0].name.sa_data[3],		\
     351  		 (uint8_t) src_ ## name[0].name.sa_data[4],		\
     352  		 (uint8_t) src_ ## name[0].name.sa_data[5]);		\
     353  	const char *const str_ ## name[] = {				\
     354  		str_hw_ ## name, NULL					\
     355  	}								\
     356  /* End of SRC_IFR_HWADDR definition.  */
     357  
     358  	SRC_IFR_HWADDR(ifr_hwaddr);
     359  
     360  #define SRC_IFR_MAP(name)						\
     361  	struct ifreq src_ ## name[2];					\
     362  	fill_memory(src_ ## name, sizeof(src_ ## name));		\
     363  	char str_map_ ## name[256];					\
     364  	snprintf(str_map_ ## name, sizeof(str_map_ ## name),		\
     365  		 "{mem_start=%#lx, mem_end=%#lx, base_addr=%#x"		\
     366  		 ", irq=%#x, dma=%#x, port=%#x}",			\
     367  		 src_ ## name[0].name.mem_start,			\
     368  		 src_ ## name[0].name.mem_end,				\
     369  		 src_ ## name[0].name.base_addr,			\
     370  		 src_ ## name[0].name.irq,				\
     371  		 src_ ## name[0].name.dma,				\
     372  		 src_ ## name[0].name.port);				\
     373  	const char *const str_ ## name[] = {				\
     374  		str_map_ ## name, NULL					\
     375  	}								\
     376  /* End of SRC_IFR_MAP definition.  */
     377  
     378  	SRC_IFR_MAP(ifr_map);
     379  
     380  	const struct {
     381  		const uint32_t cmd;
     382  		const char *const str;
     383  		const char *const name;
     384  		const struct ifreq src_addr[2];
     385  		const char *const src_str[2];
     386  	} cmd[] = {
     387  #define ARG_IFREQ(name)				\
     388  	#name,					\
     389  	{ src_ ## name[0], src_ ## name[1]},	\
     390  	{ str_ ## name[0], str_ ## name[1]},	\
     391  /* End of ARG_IFREQ definition.  */
     392  
     393  		{ ARG_STR(SIOCSIFADDR),		ARG_IFREQ(ifr_addr) },
     394  		{ ARG_STR(SIOCSIFBRDADDR),	ARG_IFREQ(ifr_broadaddr) },
     395  		{ ARG_STR(SIOCSIFDSTADDR),	ARG_IFREQ(ifr_dstaddr) },
     396  		{ ARG_STR(SIOCSIFFLAGS),	ARG_IFREQ(ifr_flags) },
     397  		{ ARG_STR(SIOCSIFHWADDR),	ARG_IFREQ(ifr_hwaddr) },
     398  		{ ARG_STR(SIOCSIFHWBROADCAST),	ARG_IFREQ(ifr_hwaddr) },
     399  		{ ARG_STR(SIOCADDMULTI),	ARG_IFREQ(ifr_hwaddr) },
     400  		{ ARG_STR(SIOCDELMULTI),	ARG_IFREQ(ifr_hwaddr) },
     401  		{ ARG_STR(SIOCSIFMAP),		ARG_IFREQ(ifr_map) },
     402  		{ ARG_STR(SIOCSIFMETRIC),	ARG_IFREQ(ifr_metric) },
     403  		{ ARG_STR(SIOCSIFMTU),		ARG_IFREQ(ifr_mtu) },
     404  		{ ARG_STR(SIOCSIFNAME),		ARG_IFREQ(ifr_newname) },
     405  		{ ARG_STR(SIOCSIFNETMASK),	ARG_IFREQ(ifr_netmask) },
     406  		{ ARG_STR(SIOCSIFSLAVE),	ARG_IFREQ(ifr_slave) },
     407  		{ ARG_STR(SIOCSIFTXQLEN),	ARG_IFREQ(ifr_qlen) },
     408  	};
     409  
     410  	for (size_t i = 0; i < ARRAY_SIZE(cmd); ++i) {
     411  		do_ioctl_ptr(-1, cmd[i].cmd, (char *) ifr + 1);
     412  		printf("ioctl(%d, %s, %p) = %s\n",
     413  		       -1, cmd[i].str, (char *) ifr + 1, errstr);
     414  
     415  		for (size_t j = 0; j < ARRAY_SIZE(cmd[i].src_addr); ++j) {
     416  			if (!cmd[i].src_str[j])
     417  				continue;
     418  			memcpy(ifr, &cmd[i].src_addr[j], sizeof(*ifr));
     419  			fill_memory_ex(ifr->ifr_name, sizeof(ifr->ifr_name),
     420  				       '0', 10);
     421  			do_ioctl_ptr(-1, cmd[i].cmd, ifr);
     422  			printf("ioctl(%d, %s, {ifr_name=\"%.*s\"..., %s=%s})"
     423  			       " = %s\n",
     424  			       -1, cmd[i].str, IFNAMSIZ - 1, ifr->ifr_name,
     425  			       cmd[i].name, cmd[i].src_str[j], errstr);
     426  
     427  			ifr->ifr_name[IFNAMSIZ - 1] = '\0';
     428  			do_ioctl_ptr(-1, cmd[i].cmd, ifr);
     429  			printf("ioctl(%d, %s, {ifr_name=\"%s\", %s=%s}) = %s\n",
     430  			       -1, cmd[i].str, ifr->ifr_name,
     431  			       cmd[i].name, cmd[i].src_str[j], errstr);
     432  		}
     433  	}
     434  
     435  	memset(ifr, 0, sizeof(*ifr));
     436  	strcpy(ifr->ifr_name, "lo");
     437  	if (do_ioctl_ptr(fd, SIOCGIFINDEX, ifr)) {
     438  		printf("ioctl(%d, %s, {ifr_name=\"%s\"}) = %s\n",
     439  		       fd, "SIOCGIFINDEX", ifr->ifr_name, errstr);
     440  		ifr->ifr_ifindex = 1;
     441  	} else {
     442  		printf("ioctl(%d, %s, {ifr_name=\"%s\", ifr_ifindex=%d})"
     443  		       " = %s\n",
     444  		       fd, "SIOCGIFINDEX", ifr->ifr_name, ifr->ifr_ifindex,
     445  		       errstr);
     446  	}
     447  
     448  	int ifindex = ifr->ifr_ifindex;
     449  
     450  	do_ioctl_ptr(-1, SIOCGIFNAME, ifr);
     451  	printf("ioctl(%d, %s, {ifr_ifindex=%d}) = %s\n",
     452  	       -1, "SIOCGIFNAME", ifr->ifr_ifindex, errstr);
     453  
     454  	if (do_ioctl_ptr(fd, SIOCGIFNAME, ifr))
     455  		printf("ioctl(%d, %s, {ifr_ifindex=%d}) = %s\n",
     456  		       fd, "SIOCGIFNAME", ifr->ifr_ifindex, errstr);
     457  	else
     458  		printf("ioctl(%d, %s, {ifr_ifindex=%d, ifr_name=\"%s\"})"
     459  		       " = %s\n",
     460  		       fd, "SIOCGIFNAME", ifr->ifr_ifindex, ifr->ifr_name,
     461  		       errstr);
     462  
     463  	static const struct {
     464  		const uint32_t cmd;
     465  		const char *const str;
     466  	} ifindex_cmd[] = {
     467  		{ ARG_STR(SIOCBRADDIF) },
     468  		{ ARG_STR(SIOCBRDELIF) },
     469  	};
     470  
     471  	for (size_t i = 0; i < ARRAY_SIZE(ifindex_cmd); ++i) {
     472  		ifr->ifr_ifindex = ifindex;
     473  		do_ioctl_ptr(-1, ifindex_cmd[i].cmd, ifr);
     474  		printf("ioctl(%d, %s, {ifr_ifindex=%s}) = %s\n",
     475  		       -1, ifindex_cmd[i].str, IFINDEX_LO_STR, errstr);
     476  	}
     477  }
     478  
     479  int
     480  main(void)
     481  {
     482  	const int fd = socket(AF_INET, SOCK_STREAM, 0);
     483  	if (fd < 0)
     484  		perror_msg_and_skip("socket AF_INET");
     485  
     486  	test_ptr();
     487  	test_int(fd);
     488  	test_str();
     489  	test_ifreq(fd);
     490  
     491  	puts("+++ exited with 0 +++");
     492  	return 0;
     493  }