uipc_syscalls_40.c revision 1.24
1/* $NetBSD: uipc_syscalls_40.c,v 1.24 2022/07/07 18:17:33 riastradh 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.24 2022/07/07 18:17:33 riastradh 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 of system. List may be used in later 33 * ioctl's (above) to get other information. 34 */ 35/*ARGSUSED*/ 36static int 37compat_ifconf(u_long cmd, void *data) 38{ 39 struct oifconf *ifc = data; 40 struct ifnet *ifp; 41 struct oifreq ifr, *ifrp = NULL; 42 int space = 0, error = 0; 43 const int sz = (int)sizeof(ifr); 44 int s; 45 int bound; 46 struct psref psref; 47 48 switch (cmd) { 49 case OSIOCGIFCONF: 50 case OOSIOCGIFCONF: 51 break; 52 default: 53 return ENOSYS; 54 } 55 56 const bool docopy = ifc->ifc_req != NULL; 57 if (docopy) { 58 if (ifc->ifc_len < 0) 59 return EINVAL; 60 61 space = ifc->ifc_len; 62 ifrp = ifc->ifc_req; 63 } 64 memset(&ifr, 0, sizeof(ifr)); 65 66 bound = curlwp_bind(); 67 s = pserialize_read_enter(); 68 IFNET_READER_FOREACH(ifp) { 69 struct ifaddr *ifa; 70 71 if_acquire(ifp, &psref); 72 pserialize_read_exit(s); 73 74 (void)strncpy(ifr.ifr_name, ifp->if_xname, 75 sizeof(ifr.ifr_name)); 76 if (ifr.ifr_name[sizeof(ifr.ifr_name) - 1] != '\0') { 77 error = ENAMETOOLONG; 78 goto release_exit; 79 } 80 if (IFADDR_READER_EMPTY(ifp)) { 81 memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr)); 82 if (space >= sz) { 83 error = copyout(&ifr, ifrp, sz); 84 if (error != 0) 85 goto release_exit; 86 ifrp++; 87 } 88 space -= sizeof(ifr); 89 goto next; 90 } 91 92 s = pserialize_read_enter(); 93 IFADDR_READER_FOREACH(ifa, ifp) { 94 struct sockaddr *sa = ifa->ifa_addr; 95 struct psref psref_ifa; 96 97 ifa_acquire(ifa, &psref_ifa); 98 pserialize_read_exit(s); 99#ifdef COMPAT_OSOCK 100 if (cmd == OOSIOCGIFCONF) { 101 struct osockaddr *osa = 102 (struct osockaddr *)&ifr.ifr_addr; 103 /* 104 * If it does not fit, we don't bother with it 105 */ 106 if (sa->sa_len > sizeof(*osa)) 107 goto next_ifa; 108 memcpy(&ifr.ifr_addr, sa, sa->sa_len); 109 osa->sa_family = sa->sa_family; 110 if (space >= sz) { 111 error = copyout(&ifr, ifrp, sz); 112 ifrp++; 113 } 114 } else 115#endif 116 if (sa->sa_len <= sizeof(*sa)) { 117 memcpy(&ifr.ifr_addr, sa, sa->sa_len); 118 if (space >= sz) { 119 error = copyout(&ifr, ifrp, sz); 120 ifrp++; 121 } 122 } else { 123 space -= sa->sa_len - sizeof(*sa); 124 if (space >= sz) { 125 error = copyout(&ifr.ifr_name, ifrp, 126 sizeof(ifr.ifr_name)); 127 if (error == 0) { 128 error = copyout(sa, 129 &ifrp->ifr_addr, 130 sa->sa_len); 131 } 132 ifrp = (struct oifreq *) 133 (sa->sa_len + 134 (char *)&ifrp->ifr_addr); 135 } 136 } 137 if (error != 0) { 138 ifa_release(ifa, &psref_ifa); 139 goto release_exit; 140 } 141 space -= sz; 142 143#ifdef COMPAT_OSOCK 144 next_ifa: 145#endif 146 s = pserialize_read_enter(); 147 ifa_release(ifa, &psref_ifa); 148 } 149 pserialize_read_exit(s); 150 151 next: 152 s = pserialize_read_enter(); 153 if_release(ifp, &psref); 154 } 155 pserialize_read_exit(s); 156 curlwp_bindx(bound); 157 158 if (docopy) 159 ifc->ifc_len -= space; 160 else 161 ifc->ifc_len = -space; 162 return 0; 163 164release_exit: 165 if_release(ifp, &psref); 166 curlwp_bindx(bound); 167 return error; 168} 169 170void 171uipc_syscalls_40_init(void) 172{ 173 174 MODULE_HOOK_SET(uipc_syscalls_40_hook, compat_ifconf); 175} 176 177void 178uipc_syscalls_40_fini(void) 179{ 180 181 MODULE_HOOK_UNSET(uipc_syscalls_40_hook); 182} 183