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