uipc_syscalls_40.c revision 1.17
1/* $NetBSD: uipc_syscalls_40.c,v 1.17 2019/01/27 02:08:39 pgoyette 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.17 2019/01/27 02:08:39 pgoyette 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 if (docopy) { 60 space = ifc->ifc_len; 61 ifrp = ifc->ifc_req; 62 } 63 64 bound = curlwp_bind(); 65 s = pserialize_read_enter(); 66 IFNET_READER_FOREACH(ifp) { 67 struct ifaddr *ifa; 68 69 if_acquire(ifp, &psref); 70 pserialize_read_exit(s); 71 72 (void)strncpy(ifr.ifr_name, ifp->if_xname, 73 sizeof(ifr.ifr_name)); 74 if (ifr.ifr_name[sizeof(ifr.ifr_name) - 1] != '\0') { 75 error = ENAMETOOLONG; 76 goto release_exit; 77 } 78 if (IFADDR_READER_EMPTY(ifp)) { 79 memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr)); 80 if (space >= sz) { 81 error = copyout(&ifr, ifrp, sz); 82 if (error != 0) 83 goto release_exit; 84 ifrp++; 85 } 86 space -= sizeof(ifr); 87 goto next; 88 } 89 90 s = pserialize_read_enter(); 91 IFADDR_READER_FOREACH(ifa, ifp) { 92 struct sockaddr *sa = ifa->ifa_addr; 93 struct psref psref_ifa; 94 95 ifa_acquire(ifa, &psref_ifa); 96 pserialize_read_exit(s); 97#ifdef COMPAT_OSOCK 98 if (cmd == OOSIOCGIFCONF) { 99 struct osockaddr *osa = 100 (struct osockaddr *)&ifr.ifr_addr; 101 /* 102 * If it does not fit, we don't bother with it 103 */ 104 if (sa->sa_len > sizeof(*osa)) 105 goto next_ifa; 106 memcpy(&ifr.ifr_addr, sa, sa->sa_len); 107 osa->sa_family = sa->sa_family; 108 if (space >= sz) { 109 error = copyout(&ifr, ifrp, sz); 110 ifrp++; 111 } 112 } else 113#endif 114 if (sa->sa_len <= sizeof(*sa)) { 115 memcpy(&ifr.ifr_addr, sa, sa->sa_len); 116 if (space >= sz) { 117 error = copyout(&ifr, ifrp, sz); 118 ifrp++; 119 } 120 } else { 121 space -= sa->sa_len - sizeof(*sa); 122 if (space >= sz) { 123 error = copyout(&ifr, ifrp, 124 sizeof(ifr.ifr_name)); 125 if (error == 0) { 126 error = copyout(sa, 127 &ifrp->ifr_addr, 128 sa->sa_len); 129 } 130 ifrp = (struct oifreq *) 131 (sa->sa_len + 132 (char *)&ifrp->ifr_addr); 133 } 134 } 135 if (error != 0) { 136 ifa_release(ifa, &psref_ifa); 137 goto release_exit; 138 } 139 space -= sz; 140 141#ifdef COMPAT_OSOCK 142 next_ifa: 143#endif 144 s = pserialize_read_enter(); 145 ifa_release(ifa, &psref_ifa); 146 } 147 pserialize_read_exit(s); 148 149 next: 150 s = pserialize_read_enter(); 151 if_release(ifp, &psref); 152 } 153 pserialize_read_exit(s); 154 curlwp_bindx(bound); 155 156 if (docopy) 157 ifc->ifc_len -= space; 158 else 159 ifc->ifc_len = -space; 160 return (0); 161 162release_exit: 163 if_release(ifp, &psref); 164 curlwp_bindx(bound); 165 return error; 166} 167 168void 169uipc_syscalls_40_init(void) 170{ 171 172 MODULE_SET_HOOK(uipc_syscalls_40_hook, "uipc40", compat_ifconf); 173} 174 175void 176uipc_syscalls_40_fini(void) 177{ 178 179 MODULE_UNSET_HOOK(uipc_syscalls_40_hook); 180} 181