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