uipc_syscalls_40.c revision 1.19
1/* $NetBSD: uipc_syscalls_40.c,v 1.19 2019/04/18 17:45:12 christos Exp $ */ 2 3/* written by Pavel Cahyna, 2006. Public domain. */ 4 5#include <sys/cdefs.h> 6__KERNEL_RCSID(0, "$NetBSD: uipc_syscalls_40.c,v 1.19 2019/04/18 17:45:12 christos Exp $"); 7 8#if defined(_KERNEL_OPT) 9#include "opt_compat_netbsd.h" 10#endif 11 12/* 13 * System call interface to the socket abstraction. 14 */ 15 16#include <sys/param.h> 17#include <sys/kernel.h> 18#include <sys/msg.h> 19#include <sys/sysctl.h> 20#include <sys/syscallargs.h> 21#include <sys/errno.h> 22#include <sys/compat_stub.h> 23 24#include <net/if.h> 25 26#include <compat/sys/socket.h> 27#include <compat/sys/sockio.h> 28 29#include <compat/common/compat_mod.h> 30 31/* 32 * Return interface configuration 33 * of system. List may be used 34 * in later ioctl's (above) to get 35 * other information. 36 */ 37/*ARGSUSED*/ 38static int 39compat_ifconf(u_long cmd, void *data) 40{ 41 struct oifconf *ifc = data; 42 struct ifnet *ifp; 43 struct oifreq ifr, *ifrp = NULL; 44 int space = 0, error = 0; 45 const int sz = (int)sizeof(ifr); 46 const bool docopy = ifc->ifc_req != NULL; 47 int s; 48 int bound; 49 struct psref psref; 50 51 switch (cmd) { 52 case OSIOCGIFCONF: 53 case OOSIOCGIFCONF: 54 break; 55 default: 56 return ENOSYS; 57 } 58 59 memset(&ifr, 0, sizeof(ifr)); 60 if (docopy) { 61 space = ifc->ifc_len; 62 ifrp = ifc->ifc_req; 63 } 64 65 bound = curlwp_bind(); 66 s = pserialize_read_enter(); 67 IFNET_READER_FOREACH(ifp) { 68 struct ifaddr *ifa; 69 70 if_acquire(ifp, &psref); 71 pserialize_read_exit(s); 72 73 (void)strncpy(ifr.ifr_name, ifp->if_xname, 74 sizeof(ifr.ifr_name)); 75 if (ifr.ifr_name[sizeof(ifr.ifr_name) - 1] != '\0') { 76 error = ENAMETOOLONG; 77 goto release_exit; 78 } 79 if (IFADDR_READER_EMPTY(ifp)) { 80 memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr)); 81 if (space >= sz) { 82 error = copyout(&ifr, ifrp, sz); 83 if (error != 0) 84 goto release_exit; 85 ifrp++; 86 } 87 space -= sizeof(ifr); 88 goto next; 89 } 90 91 s = pserialize_read_enter(); 92 IFADDR_READER_FOREACH(ifa, ifp) { 93 struct sockaddr *sa = ifa->ifa_addr; 94 struct psref psref_ifa; 95 96 ifa_acquire(ifa, &psref_ifa); 97 pserialize_read_exit(s); 98#ifdef COMPAT_OSOCK 99 if (cmd == OOSIOCGIFCONF) { 100 struct osockaddr *osa = 101 (struct osockaddr *)&ifr.ifr_addr; 102 /* 103 * If it does not fit, we don't bother with it 104 */ 105 if (sa->sa_len > sizeof(*osa)) 106 goto next_ifa; 107 memcpy(&ifr.ifr_addr, sa, sa->sa_len); 108 osa->sa_family = sa->sa_family; 109 if (space >= sz) { 110 error = copyout(&ifr, ifrp, sz); 111 ifrp++; 112 } 113 } else 114#endif 115 if (sa->sa_len <= sizeof(*sa)) { 116 memcpy(&ifr.ifr_addr, sa, sa->sa_len); 117 if (space >= sz) { 118 error = copyout(&ifr, ifrp, sz); 119 ifrp++; 120 } 121 } else { 122 space -= sa->sa_len - sizeof(*sa); 123 if (space >= sz) { 124 error = copyout(&ifr, ifrp, 125 sizeof(ifr.ifr_name)); 126 if (error == 0) { 127 error = copyout(sa, 128 &ifrp->ifr_addr, 129 sa->sa_len); 130 } 131 ifrp = (struct oifreq *) 132 (sa->sa_len + 133 (char *)&ifrp->ifr_addr); 134 } 135 } 136 if (error != 0) { 137 ifa_release(ifa, &psref_ifa); 138 goto release_exit; 139 } 140 space -= sz; 141 142#ifdef COMPAT_OSOCK 143 next_ifa: 144#endif 145 s = pserialize_read_enter(); 146 ifa_release(ifa, &psref_ifa); 147 } 148 pserialize_read_exit(s); 149 150 next: 151 s = pserialize_read_enter(); 152 if_release(ifp, &psref); 153 } 154 pserialize_read_exit(s); 155 curlwp_bindx(bound); 156 157 if (docopy) 158 ifc->ifc_len -= space; 159 else 160 ifc->ifc_len = -space; 161 return (0); 162 163release_exit: 164 if_release(ifp, &psref); 165 curlwp_bindx(bound); 166 return error; 167} 168 169void 170uipc_syscalls_40_init(void) 171{ 172 173 MODULE_HOOK_SET(uipc_syscalls_40_hook, "uipc40", compat_ifconf); 174} 175 176void 177uipc_syscalls_40_fini(void) 178{ 179 180 MODULE_HOOK_UNSET(uipc_syscalls_40_hook); 181} 182