1 /* $NetBSD: uipc_syscalls_40.c,v 1.9 2016/05/12 02:24:16 ozaki-r 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.9 2016/05/12 02:24:16 ozaki-r 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 #ifdef COMPAT_OIFREQ 25 /* 26 * Return interface configuration 27 * of system. List may be used 28 * in later ioctl's (above) to get 29 * other information. 30 */ 31 /*ARGSUSED*/ 32 int 33 compat_ifconf(u_long cmd, void *data) 34 { 35 struct oifconf *ifc = data; 36 struct ifnet *ifp; 37 struct ifaddr *ifa; 38 struct oifreq ifr, *ifrp = NULL; 39 int space = 0, error = 0; 40 const int sz = (int)sizeof(ifr); 41 const bool docopy = ifc->ifc_req != NULL; 42 int s; 43 int bound = curlwp->l_pflag & LP_BOUND; 44 struct psref psref; 45 46 if (docopy) { 47 space = ifc->ifc_len; 48 ifrp = ifc->ifc_req; 49 } 50 51 curlwp->l_pflag |= LP_BOUND; 52 s = pserialize_read_enter(); 53 IFNET_READER_FOREACH(ifp) { 54 psref_acquire(&psref, &ifp->if_psref, ifnet_psref_class); 55 pserialize_read_exit(s); 56 57 (void)strncpy(ifr.ifr_name, ifp->if_xname, 58 sizeof(ifr.ifr_name)); 59 if (ifr.ifr_name[sizeof(ifr.ifr_name) - 1] != '\0') { 60 error = ENAMETOOLONG; 61 goto release_exit; 62 } 63 if (IFADDR_EMPTY(ifp)) { 64 memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr)); 65 if (space >= sz) { 66 error = copyout(&ifr, ifrp, sz); 67 if (error != 0) 68 goto release_exit; 69 ifrp++; 70 } 71 space -= sizeof(ifr); 72 continue; 73 } 74 75 IFADDR_FOREACH(ifa, ifp) { 76 struct sockaddr *sa = ifa->ifa_addr; 77 #ifdef COMPAT_OSOCK 78 if (cmd == OOSIOCGIFCONF) { 79 struct osockaddr *osa = 80 (struct osockaddr *)&ifr.ifr_addr; 81 /* 82 * If it does not fit, we don't bother with it 83 */ 84 if (sa->sa_len > sizeof(*osa)) 85 continue; 86 memcpy(&ifr.ifr_addr, sa, sa->sa_len); 87 osa->sa_family = sa->sa_family; 88 if (space >= sz) { 89 error = copyout(&ifr, ifrp, sz); 90 ifrp++; 91 } 92 } else 93 #endif 94 if (sa->sa_len <= sizeof(*sa)) { 95 memcpy(&ifr.ifr_addr, sa, sa->sa_len); 96 if (space >= sz) { 97 error = copyout(&ifr, ifrp, sz); 98 ifrp++; 99 } 100 } else { 101 space -= sa->sa_len - sizeof(*sa); 102 if (space >= sz) { 103 error = copyout(&ifr, ifrp, 104 sizeof(ifr.ifr_name)); 105 if (error == 0) { 106 error = copyout(sa, 107 &ifrp->ifr_addr, 108 sa->sa_len); 109 } 110 ifrp = (struct oifreq *) 111 (sa->sa_len + 112 (char *)&ifrp->ifr_addr); 113 } 114 } 115 if (error != 0) 116 goto release_exit; 117 space -= sz; 118 } 119 120 s = pserialize_read_enter(); 121 psref_release(&psref, &ifp->if_psref, ifnet_psref_class); 122 } 123 pserialize_read_exit(s); 124 curlwp->l_pflag ^= bound ^ LP_BOUND; 125 126 if (docopy) 127 ifc->ifc_len -= space; 128 else 129 ifc->ifc_len = -space; 130 return (0); 131 132 release_exit: 133 psref_release(&psref, &ifp->if_psref, ifnet_psref_class); 134 curlwp->l_pflag ^= bound ^ LP_BOUND; 135 return error; 136 } 137 #endif 138