1 /*	$NetBSD: svr4_sockio.c,v 1.39 2016/07/20 07:37:51 ozaki-r Exp $	 */
2 
3 /*-
4  * Copyright (c) 1995, 2008 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Christos Zoulas.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: svr4_sockio.c,v 1.39 2016/07/20 07:37:51 ozaki-r Exp $");
34 
35 #include <sys/param.h>
36 #include <sys/proc.h>
37 #include <sys/systm.h>
38 #include <sys/file.h>
39 #include <sys/filedesc.h>
40 #include <sys/ioctl.h>
41 #include <sys/termios.h>
42 #include <sys/tty.h>
43 #include <sys/socket.h>
44 #include <sys/mount.h>
45 #include <net/if.h>
46 
47 #include <sys/syscallargs.h>
48 
49 #include <compat/sys/socket.h>
50 #include <compat/sys/sockio.h>
51 
52 #include <compat/svr4/svr4_types.h>
53 #include <compat/svr4/svr4_util.h>
54 #include <compat/svr4/svr4_signal.h>
55 #include <compat/svr4/svr4_lwp.h>
56 #include <compat/svr4/svr4_ucontext.h>
57 #include <compat/svr4/svr4_syscallargs.h>
58 #include <compat/svr4/svr4_stropts.h>
59 #include <compat/svr4/svr4_ioctl.h>
60 #include <compat/svr4/svr4_sockio.h>
61 
62 static int bsd_to_svr4_flags(int);
63 
64 #define bsd_to_svr4_flag(a) \
65 	if (bf & __CONCAT(I,a))	sf |= __CONCAT(SVR4_I,a)
66 
67 static int
bsd_to_svr4_flags(int bf)68 bsd_to_svr4_flags(int bf)
69 {
70 	int sf = 0;
71 	bsd_to_svr4_flag(FF_UP);
72 	bsd_to_svr4_flag(FF_BROADCAST);
73 	bsd_to_svr4_flag(FF_DEBUG);
74 	bsd_to_svr4_flag(FF_LOOPBACK);
75 	bsd_to_svr4_flag(FF_POINTOPOINT);
76 	bsd_to_svr4_flag(FF_NOTRAILERS);
77 	bsd_to_svr4_flag(FF_RUNNING);
78 	bsd_to_svr4_flag(FF_NOARP);
79 	bsd_to_svr4_flag(FF_PROMISC);
80 	bsd_to_svr4_flag(FF_ALLMULTI);
81 	bsd_to_svr4_flag(FF_MULTICAST);
82 	return sf;
83 }
84 
85 int
svr4_count_ifnum(struct ifnet * ifp)86 svr4_count_ifnum(struct ifnet *ifp)
87 {
88 	struct ifaddr *ifa;
89 	int ifnum = 0;
90 	int s = pserialize_read_enter();
91 
92 	IFADDR_READER_FOREACH(ifa, ifp)
93 		ifnum++;
94 
95 	pserialize_read_exit(s);
96 	return MAX(1, ifnum);
97 }
98 
99 int
svr4_sock_ioctl(file_t * fp,struct lwp * l,register_t * retval,int fd,u_long cmd,void * data)100 svr4_sock_ioctl(file_t *fp, struct lwp *l, register_t *retval,
101     int fd, u_long cmd, void *data)
102 {
103 	int error;
104 	int (*ctl)(file_t *, u_long,  void *) = fp->f_ops->fo_ioctl;
105 
106 	*retval = 0;
107 
108 	switch (cmd) {
109 	case SVR4_SIOCGLIFNUM:
110 		{
111 			struct ifnet *ifp;
112 			struct svr4_lifnum lifnum;
113 			int s;
114 
115 			error = copyin(data, &lifnum, sizeof(lifnum));
116 			if (error)
117 				return error;
118 
119 			lifnum.lifn_count = 0;
120 			/* XXX: We don't pay attention to family or flags */
121 			s = pserialize_read_enter();
122 			IFNET_READER_FOREACH(ifp)
123 				lifnum.lifn_count += svr4_count_ifnum(ifp);
124 			pserialize_read_exit(s);
125 
126 			DPRINTF(("SIOCGLIFNUM [family=%d,flags=%d,count=%d]\n",
127 			    lifnum.lifn_family, lifnum.lifn_flags,
128 			    lifnum.lifn_count));
129 			return copyout(&lifnum, data, sizeof(lifnum));
130 		}
131 
132 	case SVR4_SIOCGIFNUM:
133 		{
134 			struct ifnet *ifp;
135 			int ifnum = 0;
136 			int s;
137 
138 			/*
139 			 * This does not return the number of physical
140 			 * interfaces (if_index), but the number of interfaces
141 			 * + addresses like ifconf() does, because this number
142 			 * is used by code that will call SVR4_SIOCGIFCONF to
143 			 * find the space needed for SVR4_SIOCGIFCONF. So we
144 			 * count the number of ifreq entries that the next
145 			 * SVR4_SIOCGIFCONF will return. Maybe a more correct
146 			 * fix is to make SVR4_SIOCGIFCONF return only one
147 			 * entry per physical interface?
148 			 */
149 
150 			s = pserialize_read_enter();
151 			IFNET_READER_FOREACH(ifp)
152 				ifnum += svr4_count_ifnum(ifp);
153 			pserialize_read_exit(s);
154 
155 			DPRINTF(("SIOCGIFNUM %d\n", ifnum));
156 			return copyout(&ifnum, data, sizeof(ifnum));
157 		}
158 
159 	case SVR4_SIOCGIFFLAGS:
160 		{
161 			struct oifreq br;
162 			struct svr4_ifreq sr;
163 
164 			if ((error = copyin(data, &sr, sizeof(sr))) != 0)
165 				return error;
166 
167 			(void) strncpy(br.ifr_name, sr.svr4_ifr_name,
168 			    sizeof(br.ifr_name));
169 
170 			if ((error = (*ctl)(fp, SIOCGIFFLAGS, &br)) != 0) {
171 				DPRINTF(("SIOCGIFFLAGS %s: error %d\n",
172 					 sr.svr4_ifr_name, error));
173 				return error;
174 			}
175 
176 			sr.svr4_ifr_flags = bsd_to_svr4_flags(br.ifr_flags);
177 			DPRINTF(("SIOCGIFFLAGS %s = %x\n",
178 				sr.svr4_ifr_name, sr.svr4_ifr_flags));
179 			return copyout(&sr, data, sizeof(sr));
180 		}
181 
182 	case SVR4_SIOCGIFCONF:
183 		{
184 			struct svr4_ifconf sc;
185 
186 			if ((error = copyin(data, &sc, sizeof(sc))) != 0)
187 				return error;
188 
189 			DPRINTF(("ifreq %ld svr4_ifreq %ld ifc_len %d\n",
190 				(unsigned long)sizeof(struct oifreq),
191 				(unsigned long)sizeof(struct svr4_ifreq),
192 				sc.svr4_ifc_len));
193 
194 			if ((error = (*ctl)(fp, OOSIOCGIFCONF, &sc)) != 0)
195 				return error;
196 
197 			DPRINTF(("SIOCGIFCONF\n"));
198 			return 0;
199 		}
200 
201 
202 	default:
203 		DPRINTF(("Unknown svr4 sockio %lx\n", cmd));
204 		return 0;	/* ENOSYS really */
205 	}
206 }
207