]> git.saurik.com Git - apple/xnu.git/blame_incremental - bsd/kern/sys_socket.c
xnu-123.5.tar.gz
[apple/xnu.git] / bsd / kern / sys_socket.c
... / ...
CommitLineData
1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22/*
23 * Copyright (c) 1982, 1986, 1990, 1993
24 * The Regents of the University of California. All rights reserved.
25 *
26 * Redistribution and use in source and binary forms, with or without
27 * modification, are permitted provided that the following conditions
28 * are met:
29 * 1. Redistributions of source code must retain the above copyright
30 * notice, this list of conditions and the following disclaimer.
31 * 2. Redistributions in binary form must reproduce the above copyright
32 * notice, this list of conditions and the following disclaimer in the
33 * documentation and/or other materials provided with the distribution.
34 * 3. All advertising materials mentioning features or use of this software
35 * must display the following acknowledgement:
36 * This product includes software developed by the University of
37 * California, Berkeley and its contributors.
38 * 4. Neither the name of the University nor the names of its contributors
39 * may be used to endorse or promote products derived from this software
40 * without specific prior written permission.
41 *
42 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
43 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
46 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
48 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
49 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
50 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
51 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
52 * SUCH DAMAGE.
53 *
54 * @(#)sys_socket.c 8.1 (Berkeley) 6/10/93
55 */
56
57#include <sys/param.h>
58#include <sys/systm.h>
59#include <sys/file.h>
60#include <sys/protosw.h>
61#include <sys/socket.h>
62#include <sys/socketvar.h>
63#include <sys/filio.h> /* XXX */
64#include <sys/sockio.h>
65#include <sys/stat.h>
66#include <sys/uio.h>
67#include <sys/filedesc.h>
68
69#include <net/if.h>
70#include <net/route.h>
71
72int soo_read __P((struct file *fp, struct uio *uio,
73 struct ucred *cred));
74int soo_write __P((struct file *fp, struct uio *uio,
75 struct ucred *cred));
76int soo_close __P((struct file *fp, struct proc *p));
77
78int soo_select __P((struct file *fp, int which, struct proc *p));
79
80struct fileops socketops =
81 { soo_read, soo_write, soo_ioctl, soo_select, soo_close };
82
83/* ARGSUSED */
84int
85soo_read(fp, uio, cred)
86 struct file *fp;
87 struct uio *uio;
88 struct ucred *cred;
89{
90 struct socket *so = (struct socket *)fp->f_data;
91 struct kextcb *kp;
92 int stat;
93 int (*fsoreceive) __P((struct socket *so,
94 struct sockaddr **paddr,
95 struct uio *uio, struct mbuf **mp0,
96 struct mbuf **controlp, int *flagsp));
97
98 thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
99 fsoreceive = so->so_proto->pr_usrreqs->pru_soreceive;
100 if (fsoreceive != soreceive)
101 { kp = sotokextcb(so);
102 while (kp)
103 { if (kp->e_soif && kp->e_soif->sf_soreceive)
104 (*kp->e_soif->sf_soreceive)(so, 0, &uio,
105 0, 0, 0, kp);
106 kp = kp->e_next;
107 }
108
109 }
110
111 stat = (*fsoreceive)(so, 0, uio, 0, 0, 0);
112 thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
113 return stat;
114}
115
116/* ARGSUSED */
117int
118soo_write(fp, uio, cred)
119 struct file *fp;
120 struct uio *uio;
121 struct ucred *cred;
122{
123 struct socket *so = (struct socket *)fp->f_data;
124 int (*fsosend) __P((struct socket *so, struct sockaddr *addr,
125 struct uio *uio, struct mbuf *top,
126 struct mbuf *control, int flags));
127 struct kextcb *kp;
128 int stat;
129
130 thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
131 fsosend = so->so_proto->pr_usrreqs->pru_sosend;
132 if (fsosend != sosend)
133 { kp = sotokextcb(so);
134 while (kp)
135 { if (kp->e_soif && kp->e_soif->sf_sosend)
136 (*kp->e_soif->sf_sosend)(so, 0, &uio,
137 0, 0, 0, kp);
138 kp = kp->e_next;
139 }
140 }
141
142 stat = (*fsosend)(so, 0, uio, 0, 0, 0);
143 thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
144 return stat;
145}
146
147int
148soo_ioctl(fp, cmd, data, p)
149 struct file *fp;
150 u_long cmd;
151 register caddr_t data;
152 struct proc *p;
153{
154 register struct socket *so = (struct socket *)fp->f_data;
155
156 struct sockopt sopt;
157 struct kextcb *kp;
158 int error = 0;
159 kp = sotokextcb(so);
160 sopt.sopt_level = cmd;
161 sopt.sopt_name = (int)data;
162 sopt.sopt_p = p;
163
164
165 thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
166
167 while (kp)
168 { if (kp->e_soif && kp->e_soif->sf_socontrol)
169 (*kp->e_soif->sf_socontrol)(so, &sopt, kp);
170 kp = kp->e_next;
171 }
172
173 switch (cmd) {
174
175 case FIONBIO:
176 if (*(int *)data)
177 so->so_state |= SS_NBIO;
178 else
179 so->so_state &= ~SS_NBIO;
180
181 thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
182 return (0);
183
184 case FIOASYNC:
185 if (*(int *)data) {
186 so->so_state |= SS_ASYNC;
187 so->so_rcv.sb_flags |= SB_ASYNC;
188 so->so_snd.sb_flags |= SB_ASYNC;
189 } else {
190 so->so_state &= ~SS_ASYNC;
191 so->so_rcv.sb_flags &= ~SB_ASYNC;
192 so->so_snd.sb_flags &= ~SB_ASYNC;
193 }
194 thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
195 return (0);
196
197 case FIONREAD:
198 *(int *)data = so->so_rcv.sb_cc;
199 thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
200 return (0);
201
202 case SIOCSPGRP:
203 so->so_pgid = *(int *)data;
204 thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
205 return (0);
206
207 case SIOCGPGRP:
208 *(int *)data = so->so_pgid;
209 thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
210 return (0);
211
212 case SIOCATMARK:
213 *(int *)data = (so->so_state&SS_RCVATMARK) != 0;
214 thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
215 return (0);
216
217 case SIOCSETOT: {
218 /*
219 * Set socket level options here and then call protocol
220 * specific routine.
221 */
222 struct socket *cloned_so = NULL;
223 int cloned_fd = *(int *)data;
224
225 /* let's make sure it's either -1 or a valid file descriptor */
226 if (cloned_fd != -1) {
227 struct file *cloned_fp;
228 error = getsock(p->p_fd, cloned_fd, &cloned_fp);
229 if (error) {
230 thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
231 return (error);
232 }
233
234 cloned_so = (struct socket *)cloned_fp->f_data;
235 }
236
237 /* Always set socket non-blocking for OT */
238 fp->f_flag |= FNONBLOCK;
239 so->so_state |= SS_NBIO;
240 so->so_options |= SO_DONTTRUNC | SO_WANTMORE;
241
242 if (cloned_so && so != cloned_so) {
243 /* Flags options */
244 so->so_options |= cloned_so->so_options & ~SO_ACCEPTCONN;
245
246 /* SO_LINGER */
247 if (so->so_options & SO_LINGER)
248 so->so_linger = cloned_so->so_linger;
249
250 /* SO_SNDBUF, SO_RCVBUF */
251 if (cloned_so->so_snd.sb_hiwat > 0) {
252 if (sbreserve(&so->so_snd, cloned_so->so_snd.sb_hiwat) == 0) {
253 error = ENOBUFS;
254 thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
255 return (error);
256 }
257 }
258 if (cloned_so->so_rcv.sb_hiwat > 0) {
259 if (sbreserve(&so->so_rcv, cloned_so->so_rcv.sb_hiwat) == 0) {
260 error = ENOBUFS;
261 thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
262 return (error);
263 }
264 }
265
266 /* SO_SNDLOWAT, SO_RCVLOWAT */
267 so->so_snd.sb_lowat =
268 (cloned_so->so_snd.sb_lowat > so->so_snd.sb_hiwat) ?
269 so->so_snd.sb_hiwat : cloned_so->so_snd.sb_lowat;
270 so->so_rcv.sb_lowat =
271 (cloned_so->so_rcv.sb_lowat > so->so_rcv.sb_hiwat) ?
272 so->so_rcv.sb_hiwat : cloned_so->so_rcv.sb_lowat;
273
274 /* SO_SNDTIMEO, SO_RCVTIMEO */
275 so->so_snd.sb_timeo = cloned_so->so_snd.sb_timeo;
276 so->so_rcv.sb_timeo = cloned_so->so_rcv.sb_timeo;
277 }
278
279 error = (*so->so_proto->pr_usrreqs->pru_control)(so, cmd, data, 0, p);
280 /* Just ignore protocols that do not understand it */
281 if (error == EOPNOTSUPP)
282 error = 0;
283
284 thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
285 return (error);
286 }
287 }
288 /*
289 * Interface/routing/protocol specific ioctls:
290 * interface and routing ioctls should have a
291 * different entry since a socket's unnecessary
292 */
293 if (IOCGROUP(cmd) == 'i')
294 error = ifioctl(so, cmd, data, p);
295 else
296 if (IOCGROUP(cmd) == 'r')
297 error = rtioctl(cmd, data, p);
298 else
299 error = (*so->so_proto->pr_usrreqs->pru_control)(so, cmd, data, 0, p);
300
301 thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
302 return error;
303}
304
305int
306soo_select(fp, which, p)
307 struct file *fp;
308 int which;
309 struct proc *p;
310{
311 register struct socket *so = (struct socket *)fp->f_data;
312 register int s = splnet();
313 int retnum=0;
314
315/* thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL); */
316
317 switch (which) {
318
319 case FREAD:
320 if (soreadable(so)) {
321 splx(s);
322 retnum = 1;
323 goto done;
324 }
325 selrecord(p, &so->so_rcv.sb_sel);
326 so->so_rcv.sb_flags |= SB_SEL;
327 break;
328
329 case FWRITE:
330 if (sowriteable(so)) {
331 splx(s);
332 retnum = 1;
333 goto done;
334 }
335 selrecord(p, &so->so_snd.sb_sel);
336 so->so_snd.sb_flags |= SB_SEL;
337 break;
338
339 case 0:
340 if (so->so_oobmark || (so->so_state & SS_RCVATMARK)) {
341 splx(s);
342 retnum = 1;
343 goto done;
344 }
345 selrecord(p, &so->so_rcv.sb_sel);
346 so->so_rcv.sb_flags |= SB_SEL;
347 break;
348 }
349 splx(s);
350done:
351/* thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL); */
352 return (retnum);
353}
354
355
356int
357soo_stat(so, ub)
358 register struct socket *so;
359 register struct stat *ub;
360{
361 int stat;
362
363 thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
364 bzero((caddr_t)ub, sizeof (*ub));
365 ub->st_mode = S_IFSOCK;
366 stat = (*so->so_proto->pr_usrreqs->pru_sense)(so, ub);
367 thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
368 return stat;
369}
370
371/* ARGSUSED */
372int
373soo_close(fp, p)
374 struct file *fp;
375 struct proc *p;
376{
377 int error = 0;
378
379 if (fp->f_data) {
380 thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
381 error = soclose((struct socket *)fp->f_data);
382 thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
383 }
384
385 fp->f_data = 0;
386 return (error);
387}