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*/ |
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 | 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 | |
140 | release_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 | |