| 1 | /* $NetBSD: uipc_syscalls_40.c,v 1.12 2016/08/01 03:15:30 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.12 2016/08/01 03:15:30 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 oifreq ifr, *ifrp = NULL; |
| 38 | int space = 0, error = 0; |
| 39 | const int sz = (int)sizeof(ifr); |
| 40 | const bool docopy = ifc->ifc_req != NULL; |
| 41 | int s; |
| 42 | int bound; |
| 43 | struct psref psref; |
| 44 | |
| 45 | if (docopy) { |
| 46 | space = ifc->ifc_len; |
| 47 | ifrp = ifc->ifc_req; |
| 48 | } |
| 49 | |
| 50 | bound = curlwp_bind(); |
| 51 | s = pserialize_read_enter(); |
| 52 | IFNET_READER_FOREACH(ifp) { |
| 53 | struct ifaddr *ifa; |
| 54 | |
| 55 | psref_acquire(&psref, &ifp->if_psref, ifnet_psref_class); |
| 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_READER_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_READER_FOREACH(ifa, ifp) { |
| 76 | struct sockaddr *sa = ifa->ifa_addr; |
| 77 | struct psref psref_ifa; |
| 78 | |
| 79 | ifa_acquire(ifa, &psref_ifa); |
| 80 | pserialize_read_exit(s); |
| 81 | #ifdef COMPAT_OSOCK |
| 82 | if (cmd == OOSIOCGIFCONF) { |
| 83 | struct osockaddr *osa = |
| 84 | (struct osockaddr *)&ifr.ifr_addr; |
| 85 | /* |
| 86 | * If it does not fit, we don't bother with it |
| 87 | */ |
| 88 | if (sa->sa_len > sizeof(*osa)) { |
| 89 | s = pserialize_read_enter(); |
| 90 | ifa_release(ifa, &psref_ifa); |
| 91 | continue; |
| 92 | } |
| 93 | memcpy(&ifr.ifr_addr, sa, sa->sa_len); |
| 94 | osa->sa_family = sa->sa_family; |
| 95 | if (space >= sz) { |
| 96 | error = copyout(&ifr, ifrp, sz); |
| 97 | ifrp++; |
| 98 | } |
| 99 | } else |
| 100 | #endif |
| 101 | if (sa->sa_len <= sizeof(*sa)) { |
| 102 | memcpy(&ifr.ifr_addr, sa, sa->sa_len); |
| 103 | if (space >= sz) { |
| 104 | error = copyout(&ifr, ifrp, sz); |
| 105 | ifrp++; |
| 106 | } |
| 107 | } else { |
| 108 | space -= sa->sa_len - sizeof(*sa); |
| 109 | if (space >= sz) { |
| 110 | error = copyout(&ifr, ifrp, |
| 111 | sizeof(ifr.ifr_name)); |
| 112 | if (error == 0) { |
| 113 | error = copyout(sa, |
| 114 | &ifrp->ifr_addr, |
| 115 | sa->sa_len); |
| 116 | } |
| 117 | ifrp = (struct oifreq *) |
| 118 | (sa->sa_len + |
| 119 | (char *)&ifrp->ifr_addr); |
| 120 | } |
| 121 | } |
| 122 | s = pserialize_read_enter(); |
| 123 | ifa_release(ifa, &psref_ifa); |
| 124 | if (error != 0) |
| 125 | goto release_exit; |
| 126 | space -= sz; |
| 127 | } |
| 128 | |
| 129 | psref_release(&psref, &ifp->if_psref, ifnet_psref_class); |
| 130 | } |
| 131 | pserialize_read_exit(s); |
| 132 | curlwp_bindx(bound); |
| 133 | |
| 134 | if (docopy) |
| 135 | ifc->ifc_len -= space; |
| 136 | else |
| 137 | ifc->ifc_len = -space; |
| 138 | return (0); |
| 139 | |
| 140 | release_exit: |
| 141 | pserialize_read_exit(s); |
| 142 | psref_release(&psref, &ifp->if_psref, ifnet_psref_class); |
| 143 | curlwp_bindx(bound); |
| 144 | return error; |
| 145 | } |
| 146 | #endif |
| 147 | |