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