Home | History | Annotate | Download | only in strace
      1 /*
      2  * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs (at) world.std.com>
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  * 3. The name of the author may not be used to endorse or promote products
     14  *    derived from this software without specific prior written permission.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26  */
     27 
     28 #include "defs.h"
     29 
     30 #include <sys/socket.h>
     31 #if defined ALPHA || defined SH || defined SH64
     32 # include <linux/ioctl.h>
     33 #endif
     34 #include <linux/sockios.h>
     35 #include <arpa/inet.h>
     36 #include <net/if.h>
     37 
     38 #include DEF_MPERS_TYPE(struct_ifconf)
     39 #include DEF_MPERS_TYPE(struct_ifreq)
     40 
     41 typedef struct ifconf struct_ifconf;
     42 typedef struct ifreq struct_ifreq;
     43 
     44 #include MPERS_DEFS
     45 
     46 #include "xlat/iffflags.h"
     47 
     48 #define PRINT_IFREQ_ADDR(tcp, ifr, sockaddr)					\
     49 	do {									\
     50 		tprints(#sockaddr "=");						\
     51 		print_sockaddr(tcp, &((ifr)->sockaddr),				\
     52 			       sizeof((ifr)->sockaddr));			\
     53 	} while (0)
     54 
     55 static void
     56 print_ifname(const char *ifname)
     57 {
     58 	print_quoted_string(ifname, IFNAMSIZ + 1, QUOTE_0_TERMINATED);
     59 }
     60 
     61 static void
     62 print_ifreq(struct tcb *const tcp, const unsigned int code,
     63 	    const kernel_ulong_t arg, const struct_ifreq *const ifr)
     64 {
     65 	switch (code) {
     66 	case SIOCSIFADDR:
     67 	case SIOCGIFADDR:
     68 		PRINT_IFREQ_ADDR(tcp, ifr, ifr_addr);
     69 		break;
     70 	case SIOCSIFDSTADDR:
     71 	case SIOCGIFDSTADDR:
     72 		PRINT_IFREQ_ADDR(tcp, ifr, ifr_dstaddr);
     73 		break;
     74 	case SIOCSIFBRDADDR:
     75 	case SIOCGIFBRDADDR:
     76 		PRINT_IFREQ_ADDR(tcp, ifr, ifr_broadaddr);
     77 		break;
     78 	case SIOCSIFNETMASK:
     79 	case SIOCGIFNETMASK:
     80 		PRINT_IFREQ_ADDR(tcp, ifr, ifr_netmask);
     81 		break;
     82 	case SIOCSIFHWADDR:
     83 	case SIOCGIFHWADDR: {
     84 		/* XXX Are there other hardware addresses
     85 		   than 6-byte MACs?  */
     86 		const unsigned char *bytes =
     87 			(unsigned char *) &ifr->ifr_hwaddr.sa_data;
     88 		tprintf("ifr_hwaddr=%02x:%02x:%02x:%02x:%02x:%02x",
     89 			bytes[0], bytes[1], bytes[2],
     90 			bytes[3], bytes[4], bytes[5]);
     91 		break;
     92 	}
     93 	case SIOCSIFFLAGS:
     94 	case SIOCGIFFLAGS:
     95 		tprints("ifr_flags=");
     96 		printflags(iffflags, (unsigned short) ifr->ifr_flags, "IFF_???");
     97 		break;
     98 	case SIOCSIFMETRIC:
     99 	case SIOCGIFMETRIC:
    100 		tprintf("ifr_metric=%d", ifr->ifr_metric);
    101 		break;
    102 	case SIOCSIFMTU:
    103 	case SIOCGIFMTU:
    104 		tprintf("ifr_mtu=%d", ifr->ifr_mtu);
    105 		break;
    106 	case SIOCSIFSLAVE:
    107 	case SIOCGIFSLAVE:
    108 		tprints("ifr_slave=");
    109 		print_ifname(ifr->ifr_slave);
    110 		break;
    111 	case SIOCSIFTXQLEN:
    112 	case SIOCGIFTXQLEN:
    113 		tprintf("ifr_qlen=%d", ifr->ifr_qlen);
    114 		break;
    115 	case SIOCSIFMAP:
    116 	case SIOCGIFMAP:
    117 		tprintf("ifr_map={mem_start=%#" PRI_klx ", "
    118 			"mem_end=%#" PRI_klx ", base_addr=%#x, "
    119 			"irq=%u, dma=%u, port=%u}",
    120 			(kernel_ulong_t) ifr->ifr_map.mem_start,
    121 			(kernel_ulong_t) ifr->ifr_map.mem_end,
    122 			(unsigned) ifr->ifr_map.base_addr,
    123 			(unsigned) ifr->ifr_map.irq,
    124 			(unsigned) ifr->ifr_map.dma,
    125 			(unsigned) ifr->ifr_map.port);
    126 		break;
    127 	}
    128 }
    129 
    130 static unsigned int
    131 print_ifc_len(int len)
    132 {
    133 	const unsigned int n = (unsigned int) len / sizeof(struct_ifreq);
    134 
    135 	if (len < 0 || n * sizeof(struct_ifreq) != (unsigned int) len)
    136 		tprintf("%d", len);
    137 	else
    138 		tprintf("%u * sizeof(struct ifreq)", n);
    139 
    140 	return n;
    141 }
    142 
    143 static bool
    144 print_ifconf_ifreq(struct tcb *tcp, void *elem_buf, size_t elem_size,
    145 		   void *dummy)
    146 {
    147 	struct_ifreq *ifr = elem_buf;
    148 
    149 	tprints("{ifr_name=");
    150 	print_ifname(ifr->ifr_name);
    151 	tprints(", ");
    152 	PRINT_IFREQ_ADDR(tcp, ifr, ifr_addr);
    153 	tprints("}");
    154 
    155 	return true;
    156 }
    157 
    158 /*
    159  * There are two different modes of operation:
    160  *
    161  * - Get buffer size.  In this case, the callee sets ifc_buf to NULL,
    162  *   and the kernel returns the buffer size in ifc_len.
    163  * - Get actual data.  In this case, the callee specifies the buffer address
    164  *   in ifc_buf and its size in ifc_len.  The kernel fills the buffer with
    165  *   the data, and its amount is returned in ifc_len.
    166  *
    167  * Note that, technically, the whole struct ifconf is overwritten,
    168  * so ifc_buf could be different on exit, but current ioctl handler
    169  * implementation does not touch it.
    170  */
    171 static int
    172 decode_ifconf(struct tcb *const tcp, const kernel_ulong_t addr)
    173 {
    174 	struct_ifconf *entering_ifc = NULL;
    175 	struct_ifconf *ifc =
    176 		entering(tcp) ? malloc(sizeof(*ifc)) : alloca(sizeof(*ifc));
    177 
    178 	if (exiting(tcp)) {
    179 		entering_ifc = get_tcb_priv_data(tcp);
    180 
    181 		if (!entering_ifc) {
    182 			error_msg("decode_ifconf: where is my ifconf?");
    183 			return 0;
    184 		}
    185 	}
    186 
    187 	if (!ifc || umove(tcp, addr, ifc) < 0) {
    188 		if (entering(tcp)) {
    189 			free(ifc);
    190 
    191 			tprints(", ");
    192 			printaddr(addr);
    193 		} else {
    194 			/*
    195 			 * We failed to fetch the structure on exiting syscall,
    196 			 * print whatever was fetched on entering syscall.
    197 			 */
    198 			if (!entering_ifc->ifc_buf)
    199 				print_ifc_len(entering_ifc->ifc_len);
    200 
    201 			tprints(", ifc_buf=");
    202 			printaddr(ptr_to_kulong(entering_ifc->ifc_buf));
    203 
    204 			tprints("}");
    205 		}
    206 
    207 		return RVAL_DECODED | 1;
    208 	}
    209 
    210 	if (entering(tcp)) {
    211 		tprints(", {ifc_len=");
    212 		if (ifc->ifc_buf)
    213 			print_ifc_len(ifc->ifc_len);
    214 
    215 		set_tcb_priv_data(tcp, ifc, free);
    216 
    217 		return 1;
    218 	}
    219 
    220 	/* exiting */
    221 
    222 	if (entering_ifc->ifc_buf && (entering_ifc->ifc_len != ifc->ifc_len))
    223 		tprints(" => ");
    224 	if (!entering_ifc->ifc_buf || (entering_ifc->ifc_len != ifc->ifc_len))
    225 		print_ifc_len(ifc->ifc_len);
    226 
    227 	tprints(", ifc_buf=");
    228 
    229 	if (!entering_ifc->ifc_buf || syserror(tcp)) {
    230 		printaddr(ptr_to_kulong(entering_ifc->ifc_buf));
    231 		if (entering_ifc->ifc_buf != ifc->ifc_buf) {
    232 			tprints(" => ");
    233 			printaddr(ptr_to_kulong(ifc->ifc_buf));
    234 		}
    235 	} else {
    236 		struct_ifreq ifr;
    237 
    238 		print_array(tcp, ptr_to_kulong(ifc->ifc_buf),
    239 			    ifc->ifc_len / sizeof(struct_ifreq),
    240 			    &ifr, sizeof(ifr),
    241 			    umoven_or_printaddr, print_ifconf_ifreq, NULL);
    242 	}
    243 
    244 	tprints("}");
    245 
    246 	return RVAL_DECODED | 1;
    247 }
    248 
    249 MPERS_PRINTER_DECL(int, sock_ioctl,
    250 		   struct tcb *tcp, const unsigned int code,
    251 		   const kernel_ulong_t arg)
    252 {
    253 	struct_ifreq ifr;
    254 
    255 	switch (code) {
    256 	case SIOCGIFCONF:
    257 		return decode_ifconf(tcp, arg);
    258 
    259 #ifdef SIOCBRADDBR
    260 	case SIOCBRADDBR:
    261 	case SIOCBRDELBR:
    262 		tprints(", ");
    263 		printstr(tcp, arg);
    264 		break;
    265 #endif
    266 
    267 #ifdef FIOSETOWN
    268 	case FIOSETOWN:
    269 #endif
    270 #ifdef SIOCSPGRP
    271 	case SIOCSPGRP:
    272 #endif
    273 		tprints(", ");
    274 		printnum_int(tcp, arg, "%d");
    275 		break;
    276 
    277 #ifdef FIOGETOWN
    278 	case FIOGETOWN:
    279 #endif
    280 #ifdef SIOCGPGRP
    281 	case SIOCGPGRP:
    282 #endif
    283 #ifdef SIOCATMARK
    284 	case SIOCATMARK:
    285 #endif
    286 		if (entering(tcp))
    287 			return 0;
    288 		tprints(", ");
    289 		printnum_int(tcp, arg, "%d");
    290 		break;
    291 
    292 #ifdef SIOCBRADDIF
    293 	case SIOCBRADDIF:
    294 #endif
    295 #ifdef SIOCBRDELIF
    296 	case SIOCBRDELIF:
    297 #endif
    298 		/* no arguments */
    299 		break;
    300 
    301 	case SIOCSIFNAME:
    302 	case SIOCSIFADDR:
    303 	case SIOCSIFDSTADDR:
    304 	case SIOCSIFBRDADDR:
    305 	case SIOCSIFNETMASK:
    306 	case SIOCSIFFLAGS:
    307 	case SIOCSIFMETRIC:
    308 	case SIOCSIFMTU:
    309 	case SIOCSIFSLAVE:
    310 	case SIOCSIFHWADDR:
    311 	case SIOCSIFTXQLEN:
    312 	case SIOCSIFMAP:
    313 		tprints(", ");
    314 		if (umove_or_printaddr(tcp, arg, &ifr))
    315 			break;
    316 
    317 		tprints("{ifr_name=");
    318 		print_ifname(ifr.ifr_name);
    319 		tprints(", ");
    320 		if (code == SIOCSIFNAME) {
    321 			tprints("ifr_newname=");
    322 			print_ifname(ifr.ifr_newname);
    323 		} else {
    324 			print_ifreq(tcp, code, arg, &ifr);
    325 		}
    326 		tprints("}");
    327 		break;
    328 
    329 	case SIOCGIFNAME:
    330 	case SIOCGIFINDEX:
    331 	case SIOCGIFADDR:
    332 	case SIOCGIFDSTADDR:
    333 	case SIOCGIFBRDADDR:
    334 	case SIOCGIFNETMASK:
    335 	case SIOCGIFFLAGS:
    336 	case SIOCGIFMETRIC:
    337 	case SIOCGIFMTU:
    338 	case SIOCGIFSLAVE:
    339 	case SIOCGIFHWADDR:
    340 	case SIOCGIFTXQLEN:
    341 	case SIOCGIFMAP:
    342 		if (entering(tcp)) {
    343 			tprints(", ");
    344 			if (umove_or_printaddr(tcp, arg, &ifr))
    345 				break;
    346 
    347 			if (SIOCGIFNAME == code) {
    348 				tprintf("{ifr_index=%d", ifr.ifr_ifindex);
    349 			} else {
    350 				tprints("{ifr_name=");
    351 				print_ifname(ifr.ifr_name);
    352 			}
    353 			return 1;
    354 		} else {
    355 			if (syserror(tcp)) {
    356 				tprints("}");
    357 				break;
    358 			}
    359 
    360 			tprints(", ");
    361 			if (umove(tcp, arg, &ifr) < 0) {
    362 				tprints("???}");
    363 				break;
    364 			}
    365 
    366 			if (SIOCGIFNAME == code) {
    367 				tprints("ifr_name=");
    368 				print_ifname(ifr.ifr_name);
    369 			} else {
    370 				print_ifreq(tcp, code, arg, &ifr);
    371 			}
    372 			tprints("}");
    373 			break;
    374 		}
    375 
    376 	default:
    377 		return RVAL_DECODED;
    378 	}
    379 
    380 	return RVAL_DECODED | 1;
    381 }
    382