1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
|
/* $NetBSD: uipc_syscalls_40.c,v 1.24 2022/07/07 18:17:33 riastradh Exp $ */
/* written by Pavel Cahyna, 2006. Public domain. */
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: uipc_syscalls_40.c,v 1.24 2022/07/07 18:17:33 riastradh Exp $");
#if defined(_KERNEL_OPT)
#include "opt_compat_netbsd.h"
#endif
/*
* System call interface to the socket abstraction.
*/
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/msg.h>
#include <sys/sysctl.h>
#include <sys/syscallargs.h>
#include <sys/errno.h>
#include <sys/compat_stub.h>
#include <net/if.h>
#include <compat/sys/socket.h>
#include <compat/sys/sockio.h>
#include <compat/common/compat_mod.h>
/*
* Return interface configuration of system. List may be used in later
* ioctl's (above) to get other information.
*/
/*ARGSUSED*/
static int
compat_ifconf(u_long cmd, void *data)
{
struct oifconf *ifc = data;
struct ifnet *ifp;
struct oifreq ifr, *ifrp = NULL;
int space = 0, error = 0;
const int sz = (int)sizeof(ifr);
int s;
int bound;
struct psref psref;
switch (cmd) {
case OSIOCGIFCONF:
case OOSIOCGIFCONF:
break;
default:
return ENOSYS;
}
const bool docopy = ifc->ifc_req != NULL;
if (docopy) {
if (ifc->ifc_len < 0)
return EINVAL;
space = ifc->ifc_len;
ifrp = ifc->ifc_req;
}
memset(&ifr, 0, sizeof(ifr));
bound = curlwp_bind();
s = pserialize_read_enter();
IFNET_READER_FOREACH(ifp) {
struct ifaddr *ifa;
if_acquire(ifp, &psref);
pserialize_read_exit(s);
(void)strncpy(ifr.ifr_name, ifp->if_xname,
sizeof(ifr.ifr_name));
if (ifr.ifr_name[sizeof(ifr.ifr_name) - 1] != '\0') {
error = ENAMETOOLONG;
goto release_exit;
}
if (IFADDR_READER_EMPTY(ifp)) {
memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
if (space >= sz) {
error = copyout(&ifr, ifrp, sz);
if (error != 0)
goto release_exit;
ifrp++;
}
space -= sizeof(ifr);
goto next;
}
s = pserialize_read_enter();
IFADDR_READER_FOREACH(ifa, ifp) {
struct sockaddr *sa = ifa->ifa_addr;
struct psref psref_ifa;
ifa_acquire(ifa, &psref_ifa);
pserialize_read_exit(s);
#ifdef COMPAT_OSOCK
if (cmd == OOSIOCGIFCONF) {
struct osockaddr *osa =
(struct osockaddr *)&ifr.ifr_addr;
/*
* If it does not fit, we don't bother with it
*/
if (sa->sa_len > sizeof(*osa))
goto next_ifa;
memcpy(&ifr.ifr_addr, sa, sa->sa_len);
osa->sa_family = sa->sa_family;
if (space >= sz) {
error = copyout(&ifr, ifrp, sz);
ifrp++;
}
} else
#endif
if (sa->sa_len <= sizeof(*sa)) {
memcpy(&ifr.ifr_addr, sa, sa->sa_len);
if (space >= sz) {
error = copyout(&ifr, ifrp, sz);
ifrp++;
}
} else {
space -= sa->sa_len - sizeof(*sa);
if (space >= sz) {
error = copyout(&ifr.ifr_name, ifrp,
sizeof(ifr.ifr_name));
if (error == 0) {
error = copyout(sa,
&ifrp->ifr_addr,
sa->sa_len);
}
ifrp = (struct oifreq *)
(sa->sa_len +
(char *)&ifrp->ifr_addr);
}
}
if (error != 0) {
ifa_release(ifa, &psref_ifa);
goto release_exit;
}
space -= sz;
#ifdef COMPAT_OSOCK
next_ifa:
#endif
s = pserialize_read_enter();
ifa_release(ifa, &psref_ifa);
}
pserialize_read_exit(s);
next:
s = pserialize_read_enter();
if_release(ifp, &psref);
}
pserialize_read_exit(s);
curlwp_bindx(bound);
if (docopy)
ifc->ifc_len -= space;
else
ifc->ifc_len = -space;
return 0;
release_exit:
if_release(ifp, &psref);
curlwp_bindx(bound);
return error;
}
void
uipc_syscalls_40_init(void)
{
MODULE_HOOK_SET(uipc_syscalls_40_hook, compat_ifconf);
}
void
uipc_syscalls_40_fini(void)
{
MODULE_HOOK_UNSET(uipc_syscalls_40_hook);
}
|