uipc_syscalls_40.c revision 1.15.2.6 1 /* $NetBSD: uipc_syscalls_40.c,v 1.15.2.6 2018/04/12 22:33:41 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.6 2018/04/12 22:33:41 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 switch (cmd) {
48 case OSIOCGIFCONF:
49 case OOSIOCGIFCONF:
50 break;
51 default:
52 return ENOSYS;
53 }
54
55 if (docopy) {
56 space = ifc->ifc_len;
57 ifrp = ifc->ifc_req;
58 }
59
60 bound = curlwp_bind();
61 s = pserialize_read_enter();
62 IFNET_READER_FOREACH(ifp) {
63 struct ifaddr *ifa;
64
65 if_acquire(ifp, &psref);
66 pserialize_read_exit(s);
67
68 (void)strncpy(ifr.ifr_name, ifp->if_xname,
69 sizeof(ifr.ifr_name));
70 if (ifr.ifr_name[sizeof(ifr.ifr_name) - 1] != '\0') {
71 error = ENAMETOOLONG;
72 goto release_exit;
73 }
74 if (IFADDR_READER_EMPTY(ifp)) {
75 memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
76 if (space >= sz) {
77 error = copyout(&ifr, ifrp, sz);
78 if (error != 0)
79 goto release_exit;
80 ifrp++;
81 }
82 space -= sizeof(ifr);
83 goto next;
84 }
85
86 s = pserialize_read_enter();
87 IFADDR_READER_FOREACH(ifa, ifp) {
88 struct sockaddr *sa = ifa->ifa_addr;
89 struct psref psref_ifa;
90
91 ifa_acquire(ifa, &psref_ifa);
92 pserialize_read_exit(s);
93 #ifdef COMPAT_OSOCK
94 if (cmd == OOSIOCGIFCONF) {
95 struct osockaddr *osa =
96 (struct osockaddr *)&ifr.ifr_addr;
97 /*
98 * If it does not fit, we don't bother with it
99 */
100 if (sa->sa_len > sizeof(*osa))
101 goto next_ifa;
102 memcpy(&ifr.ifr_addr, sa, sa->sa_len);
103 osa->sa_family = sa->sa_family;
104 if (space >= sz) {
105 error = copyout(&ifr, ifrp, sz);
106 ifrp++;
107 }
108 } else
109 #endif
110 if (sa->sa_len <= sizeof(*sa)) {
111 memcpy(&ifr.ifr_addr, sa, sa->sa_len);
112 if (space >= sz) {
113 error = copyout(&ifr, ifrp, sz);
114 ifrp++;
115 }
116 } else {
117 space -= sa->sa_len - sizeof(*sa);
118 if (space >= sz) {
119 error = copyout(&ifr, ifrp,
120 sizeof(ifr.ifr_name));
121 if (error == 0) {
122 error = copyout(sa,
123 &ifrp->ifr_addr,
124 sa->sa_len);
125 }
126 ifrp = (struct oifreq *)
127 (sa->sa_len +
128 (char *)&ifrp->ifr_addr);
129 }
130 }
131 if (error != 0) {
132 ifa_release(ifa, &psref_ifa);
133 goto release_exit;
134 }
135 space -= sz;
136
137 #ifdef COMPAT_OSOCK
138 next_ifa:
139 #endif
140 s = pserialize_read_enter();
141 ifa_release(ifa, &psref_ifa);
142 }
143 pserialize_read_exit(s);
144
145 next:
146 s = pserialize_read_enter();
147 if_release(ifp, &psref);
148 }
149 pserialize_read_exit(s);
150 curlwp_bindx(bound);
151
152 if (docopy)
153 ifc->ifc_len -= space;
154 else
155 ifc->ifc_len = -space;
156 return (0);
157
158 release_exit:
159 if_release(ifp, &psref);
160 curlwp_bindx(bound);
161 return error;
162 }
163
164 void
165 if_40_init(void)
166 {
167
168 vec_compat_ifconf = compat_ifconf;
169 }
170
171 void
172 if_40_fini(void)
173 {
174
175 vec_compat_ifconf = (void *)enosys;
176 }
177