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*/
32int
33compat_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
140release_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