uipc_syscalls_40.c revision 1.15 1 /* $NetBSD: uipc_syscalls_40.c,v 1.15 2017/11/22 15:25:34 martin 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 2017/11/22 15:25:34 martin 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 if_acquire(ifp, &psref);
56 pserialize_read_exit(s);
57
58 (void)strncpy(ifr.ifr_name, ifp->if_xname,
59 sizeof(ifr.ifr_name));
60 if (ifr.ifr_name[sizeof(ifr.ifr_name) - 1] != '\0') {
61 error = ENAMETOOLONG;
62 goto release_exit;
63 }
64 if (IFADDR_READER_EMPTY(ifp)) {
65 memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
66 if (space >= sz) {
67 error = copyout(&ifr, ifrp, sz);
68 if (error != 0)
69 goto release_exit;
70 ifrp++;
71 }
72 space -= sizeof(ifr);
73 goto next;
74 }
75
76 s = pserialize_read_enter();
77 IFADDR_READER_FOREACH(ifa, ifp) {
78 struct sockaddr *sa = ifa->ifa_addr;
79 struct psref psref_ifa;
80
81 ifa_acquire(ifa, &psref_ifa);
82 pserialize_read_exit(s);
83 #ifdef COMPAT_OSOCK
84 if (cmd == OOSIOCGIFCONF) {
85 struct osockaddr *osa =
86 (struct osockaddr *)&ifr.ifr_addr;
87 /*
88 * If it does not fit, we don't bother with it
89 */
90 if (sa->sa_len > sizeof(*osa))
91 goto next_ifa;
92 memcpy(&ifr.ifr_addr, sa, sa->sa_len);
93 osa->sa_family = sa->sa_family;
94 if (space >= sz) {
95 error = copyout(&ifr, ifrp, sz);
96 ifrp++;
97 }
98 } else
99 #endif
100 if (sa->sa_len <= sizeof(*sa)) {
101 memcpy(&ifr.ifr_addr, sa, sa->sa_len);
102 if (space >= sz) {
103 error = copyout(&ifr, ifrp, sz);
104 ifrp++;
105 }
106 } else {
107 space -= sa->sa_len - sizeof(*sa);
108 if (space >= sz) {
109 error = copyout(&ifr, ifrp,
110 sizeof(ifr.ifr_name));
111 if (error == 0) {
112 error = copyout(sa,
113 &ifrp->ifr_addr,
114 sa->sa_len);
115 }
116 ifrp = (struct oifreq *)
117 (sa->sa_len +
118 (char *)&ifrp->ifr_addr);
119 }
120 }
121 if (error != 0) {
122 ifa_release(ifa, &psref_ifa);
123 goto release_exit;
124 }
125 space -= sz;
126
127 #ifdef COMPAT_OSOCK
128 next_ifa:
129 #endif
130 s = pserialize_read_enter();
131 ifa_release(ifa, &psref_ifa);
132 }
133 pserialize_read_exit(s);
134
135 next:
136 s = pserialize_read_enter();
137 if_release(ifp, &psref);
138 }
139 pserialize_read_exit(s);
140 curlwp_bindx(bound);
141
142 if (docopy)
143 ifc->ifc_len -= space;
144 else
145 ifc->ifc_len = -space;
146 return (0);
147
148 release_exit:
149 if_release(ifp, &psref);
150 curlwp_bindx(bound);
151 return error;
152 }
153 #endif
154