Commit | Line | Data |
---|---|---|
4f083fd7 | 1 | /* uipc_socket.c 4.64 82/11/13 */ |
ce9d8eb4 BJ |
2 | |
3 | #include "../h/param.h" | |
92a533e6 | 4 | #include "../h/systm.h" |
ce9d8eb4 BJ |
5 | #include "../h/dir.h" |
6 | #include "../h/user.h" | |
92a533e6 BJ |
7 | #include "../h/proc.h" |
8 | #include "../h/file.h" | |
ce9d8eb4 | 9 | #include "../h/inode.h" |
92a533e6 | 10 | #include "../h/buf.h" |
ce9d8eb4 | 11 | #include "../h/mbuf.h" |
92a533e6 BJ |
12 | #include "../h/protosw.h" |
13 | #include "../h/socket.h" | |
14 | #include "../h/socketvar.h" | |
ae921915 | 15 | #include "../h/stat.h" |
b8acc34d | 16 | #include "../h/ioctl.h" |
32a43ee2 | 17 | #include "../h/uio.h" |
3a35e7af | 18 | #include "../net/route.h" |
ce9d8eb4 | 19 | |
ce9d8eb4 | 20 | /* |
cf012934 BJ |
21 | * Socket operation routines. |
22 | * These routines are called by the routines in | |
23 | * sys_socket.c or from a system process, and | |
24 | * implement the semantics of socket operations by | |
25 | * switching out to the protocol specific routines. | |
ce9d8eb4 | 26 | */ |
ce9d8eb4 | 27 | |
a8d3bf7f | 28 | /*ARGSUSED*/ |
cf012934 | 29 | socreate(dom, aso, type, proto, opt) |
ce9d8eb4 | 30 | struct socket **aso; |
cf012934 BJ |
31 | int type, proto; |
32 | struct socketopt *opt; | |
ce9d8eb4 BJ |
33 | { |
34 | register struct protosw *prp; | |
35 | register struct socket *so; | |
36 | struct mbuf *m; | |
4f083fd7 | 37 | int error; |
cc15ab5d | 38 | |
cc15ab5d | 39 | if (proto) |
4f083fd7 | 40 | prp = pffindproto(dom, proto); |
cc15ab5d | 41 | else |
4f083fd7 | 42 | prp = pffindtype(dom, type); |
cc15ab5d BJ |
43 | if (prp == 0) |
44 | return (EPROTONOSUPPORT); | |
cf012934 BJ |
45 | if (prp->pr_type != type) |
46 | return (EPROTOTYPE); | |
cc15ab5d | 47 | m = m_getclr(M_WAIT); |
ce9d8eb4 BJ |
48 | if (m == 0) |
49 | return (ENOBUFS); | |
ce9d8eb4 | 50 | so = mtod(m, struct socket *); |
cf012934 | 51 | so->so_options = 0; |
62364f0e | 52 | so->so_state = 0; |
4f083fd7 | 53 | so->so_type = type; |
62364f0e BJ |
54 | if (u.u_uid == 0) |
55 | so->so_state = SS_PRIV; | |
ce9d8eb4 | 56 | so->so_proto = prp; |
cf012934 BJ |
57 | error = (*prp->pr_usrreq)(so, PRU_ATTACH, |
58 | (struct mbuf *)0, (struct mbuf *)0, (struct socketopt *)0); | |
b91acce4 | 59 | if (error) { |
90aaea96 | 60 | so->so_state |= SS_NOFDREF; |
de48daf3 | 61 | sofree(so); |
cc15ab5d | 62 | return (error); |
ce9d8eb4 BJ |
63 | } |
64 | *aso = so; | |
65 | return (0); | |
66 | } | |
67 | ||
cf012934 BJ |
68 | sobind(so, nam, opt) |
69 | struct socket *so; | |
70 | struct mbuf *nam; | |
71 | struct socketopt *opt; | |
72 | { | |
73 | int s = splnet(); | |
74 | int error; | |
75 | ||
76 | error = | |
77 | (*so->so_proto->pr_usrreq)(so, PRU_BIND, | |
78 | (struct mbuf *)0, nam, opt); | |
79 | splx(s); | |
80 | return (error); | |
81 | } | |
82 | ||
83 | solisten(so, backlog) | |
84 | struct socket *so; | |
85 | int backlog; | |
86 | { | |
87 | int s = splnet(); | |
88 | int error; | |
89 | ||
90 | error = (*so->so_proto->pr_usrreq)(so, PRU_LISTEN, | |
91 | (struct mbuf *)0, (struct mbuf *)0, (struct socketopt *)0); | |
92 | if (error) { | |
93 | splx(s); | |
94 | return (error); | |
95 | } | |
96 | if (so->so_q == 0) { | |
97 | so->so_q = so; | |
98 | so->so_q0 = so; | |
99 | so->so_options |= SO_ACCEPTCONN; | |
100 | } | |
101 | if (backlog < 0) | |
102 | backlog = 0; | |
103 | so->so_qlimit = backlog < 5 ? backlog : 5; | |
104 | so->so_options |= SO_NEWFDONCONN; | |
105 | return (0); | |
106 | } | |
107 | ||
ae921915 BJ |
108 | sofree(so) |
109 | struct socket *so; | |
110 | { | |
111 | ||
90aaea96 BJ |
112 | if (so->so_head) { |
113 | if (!soqremque(so, 0) && !soqremque(so, 1)) | |
114 | panic("sofree dq"); | |
115 | so->so_head = 0; | |
116 | } | |
117 | if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0) | |
4ad99bae BJ |
118 | return; |
119 | sbrelease(&so->so_snd); | |
120 | sbrelease(&so->so_rcv); | |
2752c877 | 121 | (void) m_free(dtom(so)); |
ae921915 BJ |
122 | } |
123 | ||
92a533e6 | 124 | /* |
cc15ab5d BJ |
125 | * Close a socket on last file table reference removal. |
126 | * Initiate disconnect if connected. | |
127 | * Free socket when disconnect complete. | |
92a533e6 | 128 | */ |
89900a09 | 129 | soclose(so, exiting) |
92a533e6 | 130 | register struct socket *so; |
89900a09 | 131 | int exiting; |
92a533e6 | 132 | { |
cc15ab5d | 133 | int s = splnet(); /* conservative */ |
5a1f132a | 134 | int error; |
cc15ab5d | 135 | |
90aaea96 BJ |
136 | if (so->so_options & SO_ACCEPTCONN) { |
137 | while (so->so_q0 != so) | |
5a1f132a | 138 | (void) soclose(so->so_q0, 1); |
90aaea96 | 139 | while (so->so_q != so) |
5a1f132a | 140 | (void) soclose(so->so_q, 1); |
90aaea96 | 141 | } |
cc15ab5d BJ |
142 | if (so->so_pcb == 0) |
143 | goto discard; | |
1ee9e088 BJ |
144 | if (exiting) |
145 | so->so_options |= SO_KEEPALIVE; | |
cc15ab5d BJ |
146 | if (so->so_state & SS_ISCONNECTED) { |
147 | if ((so->so_state & SS_ISDISCONNECTING) == 0) { | |
ac76a23d | 148 | error = sodisconnect(so, (struct mbuf *)0); |
5a1f132a | 149 | if (error) { |
89900a09 BJ |
150 | if (exiting) |
151 | goto drop; | |
cc15ab5d | 152 | splx(s); |
5a1f132a | 153 | return (error); |
cc15ab5d BJ |
154 | } |
155 | } | |
30b84e26 | 156 | if ((so->so_options & SO_DONTLINGER) == 0) { |
b8acc34d | 157 | if ((so->so_state & SS_ISDISCONNECTING) && |
62364f0e | 158 | (so->so_state & SS_NBIO) && |
5a1f132a BJ |
159 | exiting == 0) |
160 | return (EINPROGRESS); | |
89900a09 | 161 | /* should use tsleep here, for at most linger */ |
b8acc34d BJ |
162 | while (so->so_state & SS_ISCONNECTED) |
163 | sleep((caddr_t)&so->so_timeo, PZERO+1); | |
72857acf | 164 | } |
cc15ab5d | 165 | } |
89900a09 | 166 | drop: |
37c0974a | 167 | if (so->so_pcb) { |
5a1f132a | 168 | error = (*so->so_proto->pr_usrreq)(so, PRU_DETACH, |
cf012934 | 169 | (struct mbuf *)0, (struct mbuf *)0, (struct socketopt *)0); |
5a1f132a | 170 | if (exiting == 0 && error) { |
37c0974a | 171 | splx(s); |
5a1f132a | 172 | return (error); |
37c0974a SL |
173 | } |
174 | } | |
cc15ab5d | 175 | discard: |
90aaea96 | 176 | so->so_state |= SS_NOFDREF; |
4ad99bae | 177 | sofree(so); |
cc15ab5d | 178 | splx(s); |
5a1f132a | 179 | return (0); |
92a533e6 BJ |
180 | } |
181 | ||
ae921915 | 182 | /*ARGSUSED*/ |
0cc4f3e6 | 183 | sostat(so, ub) |
92a533e6 | 184 | struct socket *so; |
0cc4f3e6 | 185 | struct stat *ub; |
92a533e6 | 186 | { |
0cc4f3e6 | 187 | struct stat sb; |
92a533e6 | 188 | |
0cc4f3e6 | 189 | bzero((caddr_t)&sb, sizeof (sb)); /* XXX */ |
4f083fd7 | 190 | (void) copyout((caddr_t)&sb, (caddr_t)ub, sizeof (sb));/* XXX */ |
5e35cca3 | 191 | return (0); /* XXX */ |
92a533e6 BJ |
192 | } |
193 | ||
cf012934 | 194 | soaccept(so, nam, opt) |
2b4b57cd | 195 | struct socket *so; |
cf012934 BJ |
196 | struct mbuf *nam; |
197 | struct socketopt *opt; | |
2b4b57cd BJ |
198 | { |
199 | int s = splnet(); | |
200 | int error; | |
201 | ||
cf012934 BJ |
202 | error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, |
203 | (struct mbuf *)0, nam, opt); | |
2b4b57cd BJ |
204 | splx(s); |
205 | return (error); | |
206 | } | |
207 | ||
cf012934 | 208 | soconnect(so, nam, opt) |
ce9d8eb4 | 209 | struct socket *so; |
cf012934 BJ |
210 | struct mbuf *nam; |
211 | struct socketopt *opt; | |
ce9d8eb4 | 212 | { |
cc15ab5d BJ |
213 | int s = splnet(); |
214 | int error; | |
ce9d8eb4 | 215 | |
cc15ab5d BJ |
216 | if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) { |
217 | error = EISCONN; | |
218 | goto bad; | |
219 | } | |
cf012934 BJ |
220 | error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, |
221 | (struct mbuf *)0, nam, opt); | |
cc15ab5d BJ |
222 | bad: |
223 | splx(s); | |
224 | return (error); | |
ce9d8eb4 BJ |
225 | } |
226 | ||
cf012934 | 227 | sodisconnect(so, nam) |
ce9d8eb4 | 228 | struct socket *so; |
cf012934 | 229 | struct mbuf *nam; |
ce9d8eb4 | 230 | { |
cc15ab5d BJ |
231 | int s = splnet(); |
232 | int error; | |
ce9d8eb4 | 233 | |
cc15ab5d BJ |
234 | if ((so->so_state & SS_ISCONNECTED) == 0) { |
235 | error = ENOTCONN; | |
236 | goto bad; | |
ce9d8eb4 | 237 | } |
cc15ab5d BJ |
238 | if (so->so_state & SS_ISDISCONNECTING) { |
239 | error = EALREADY; | |
240 | goto bad; | |
ce9d8eb4 | 241 | } |
cf012934 BJ |
242 | error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, |
243 | (struct mbuf *)0, nam, (struct socketopt *)0); | |
cc15ab5d BJ |
244 | bad: |
245 | splx(s); | |
246 | return (error); | |
ce9d8eb4 BJ |
247 | } |
248 | ||
cc15ab5d BJ |
249 | /* |
250 | * Send on a socket. | |
251 | * If send must go all at once and message is larger than | |
252 | * send buffering, then hard error. | |
253 | * Lock against other senders. | |
254 | * If must go all at once and not enough room now, then | |
255 | * inform user that this would block and do nothing. | |
256 | */ | |
970108c7 | 257 | sosend(so, nam, uio, flags) |
ce9d8eb4 | 258 | register struct socket *so; |
cf012934 | 259 | struct mbuf *nam; |
5699bf69 | 260 | struct uio *uio; |
970108c7 | 261 | int flags; |
ce9d8eb4 | 262 | { |
cc15ab5d BJ |
263 | struct mbuf *top = 0; |
264 | register struct mbuf *m, **mp = ⊤ | |
5a1f132a | 265 | register int len; |
ae921915 | 266 | int error = 0, space, s; |
ce9d8eb4 | 267 | |
5699bf69 | 268 | if (sosendallatonce(so) && uio->uio_resid > so->so_snd.sb_hiwat) |
cc15ab5d | 269 | return (EMSGSIZE); |
0f90f987 | 270 | restart: |
cc15ab5d BJ |
271 | sblock(&so->so_snd); |
272 | #define snderr(errno) { error = errno; splx(s); goto release; } | |
273 | ||
c7256358 | 274 | u.u_ru.ru_msgsnd++; |
cc15ab5d | 275 | again: |
0f90f987 BJ |
276 | s = splnet(); |
277 | if (so->so_state & SS_CANTSENDMORE) { | |
278 | psignal(u.u_procp, SIGPIPE); | |
279 | snderr(EPIPE); | |
280 | } | |
4c078bb2 BJ |
281 | if (so->so_error) { |
282 | error = so->so_error; | |
0f90f987 | 283 | so->so_error = 0; /* ??? */ |
4c078bb2 BJ |
284 | splx(s); |
285 | goto release; | |
286 | } | |
cc15ab5d BJ |
287 | if ((so->so_state & SS_ISCONNECTED) == 0) { |
288 | if (so->so_proto->pr_flags & PR_CONNREQUIRED) | |
289 | snderr(ENOTCONN); | |
cf012934 | 290 | if (nam == 0) |
cc15ab5d BJ |
291 | snderr(EDESTADDRREQ); |
292 | } | |
cc15ab5d | 293 | if (top) { |
970108c7 BJ |
294 | error = (*so->so_proto->pr_usrreq)(so, |
295 | (flags & SOF_OOB) ? PRU_SENDOOB : PRU_SEND, | |
cf012934 | 296 | top, (caddr_t)nam, (struct socketopt *)0); |
0f90f987 | 297 | top = 0; |
cc15ab5d BJ |
298 | if (error) { |
299 | splx(s); | |
ce9d8eb4 BJ |
300 | goto release; |
301 | } | |
cc15ab5d | 302 | mp = ⊤ |
ce9d8eb4 | 303 | } |
5699bf69 | 304 | if (uio->uio_resid == 0) { |
b91acce4 BJ |
305 | splx(s); |
306 | goto release; | |
307 | } | |
970108c7 BJ |
308 | if (flags & SOF_OOB) |
309 | space = 1024; | |
310 | else { | |
311 | space = sbspace(&so->so_snd); | |
312 | if (space <= 0 || | |
313 | sosendallatonce(so) && space < uio->uio_resid) { | |
314 | if (so->so_state & SS_NBIO) | |
315 | snderr(EWOULDBLOCK); | |
316 | sbunlock(&so->so_snd); | |
317 | sbwait(&so->so_snd); | |
318 | splx(s); | |
319 | goto restart; | |
320 | } | |
ce9d8eb4 | 321 | } |
cc15ab5d | 322 | splx(s); |
5699bf69 BJ |
323 | while (uio->uio_resid > 0 && space > 0) { |
324 | register struct iovec *iov = uio->uio_iov; | |
325 | ||
326 | if (iov->iov_len == 0) { | |
327 | uio->uio_iov++; | |
328 | uio->uio_iovcnt--; | |
329 | if (uio->uio_iovcnt < 0) | |
330 | panic("sosend"); | |
331 | continue; | |
332 | } | |
cc15ab5d BJ |
333 | MGET(m, 1); |
334 | if (m == NULL) { | |
0f90f987 | 335 | error = ENOBUFS; /* SIGPIPE? */ |
cc15ab5d | 336 | goto release; |
ce9d8eb4 | 337 | } |
5699bf69 | 338 | if (iov->iov_len >= CLBYTES && space >= CLBYTES) { |
cc15ab5d | 339 | register struct mbuf *p; |
c5ff2e32 | 340 | MCLGET(p, 1); |
cc15ab5d BJ |
341 | if (p == 0) |
342 | goto nopages; | |
343 | m->m_off = (int)p - (int)m; | |
c5ff2e32 | 344 | len = CLBYTES; |
cc15ab5d | 345 | } else { |
ce9d8eb4 | 346 | nopages: |
5699bf69 | 347 | len = MIN(MLEN, iov->iov_len); |
ce9d8eb4 | 348 | } |
39d536e6 | 349 | (void) uiomove(mtod(m, caddr_t), len, UIO_WRITE, uio); |
cc15ab5d BJ |
350 | m->m_len = len; |
351 | *mp = m; | |
352 | mp = &m->m_next; | |
970108c7 BJ |
353 | if (flags & SOF_OOB) |
354 | space -= len; | |
355 | else | |
356 | space = sbspace(&so->so_snd); | |
ce9d8eb4 | 357 | } |
cc15ab5d BJ |
358 | goto again; |
359 | ||
ce9d8eb4 | 360 | release: |
cc15ab5d | 361 | sbunlock(&so->so_snd); |
0f90f987 BJ |
362 | if (top) |
363 | m_freem(top); | |
ce9d8eb4 BJ |
364 | return (error); |
365 | } | |
366 | ||
970108c7 | 367 | soreceive(so, aname, uio, flags) |
ce9d8eb4 | 368 | register struct socket *so; |
cf012934 | 369 | struct mbuf **aname; |
32a43ee2 | 370 | struct uio *uio; |
970108c7 | 371 | int flags; |
ce9d8eb4 BJ |
372 | { |
373 | register struct mbuf *m, *n; | |
5a1f132a | 374 | int len; |
970108c7 BJ |
375 | int eor, s, error = 0, moff, tomark; |
376 | ||
377 | if (flags & SOF_OOB) { | |
a8d3bf7f BJ |
378 | m = m_get(M_WAIT); |
379 | error = (*so->so_proto->pr_usrreq)(so, PRU_RCVOOB, | |
970108c7 | 380 | m, (struct mbuf *)0, (struct socketopt *)0); |
a8d3bf7f | 381 | if (error) |
5a1f132a | 382 | return (error); |
970108c7 BJ |
383 | len = uio->uio_resid; |
384 | do { | |
385 | if (len > m->m_len) | |
386 | len = m->m_len; | |
a8d3bf7f | 387 | error = |
a29f7995 | 388 | uiomove(mtod(m, caddr_t), (int)len, UIO_READ, uio); |
970108c7 | 389 | m = m_free(m); |
a8d3bf7f | 390 | } while (uio->uio_resid && error == 0 && m); |
970108c7 | 391 | if (m) |
39d536e6 | 392 | m_freem(m); |
a8d3bf7f | 393 | return (error); |
970108c7 | 394 | } |
ce9d8eb4 | 395 | |
cc15ab5d BJ |
396 | restart: |
397 | sblock(&so->so_rcv); | |
398 | s = splnet(); | |
37d8f813 | 399 | SBCHECK(&so->so_rcv, "soreceive restart"); |
cc15ab5d BJ |
400 | |
401 | #define rcverr(errno) { error = errno; splx(s); goto release; } | |
ce9d8eb4 | 402 | if (so->so_rcv.sb_cc == 0) { |
4c078bb2 BJ |
403 | if (so->so_error) { |
404 | error = so->so_error; | |
405 | so->so_error = 0; | |
406 | splx(s); | |
407 | goto release; | |
408 | } | |
cc15ab5d BJ |
409 | if (so->so_state & SS_CANTRCVMORE) { |
410 | splx(s); | |
411 | goto release; | |
412 | } | |
196d84fd BJ |
413 | if ((so->so_state & SS_ISCONNECTED) == 0 && |
414 | (so->so_proto->pr_flags & PR_CONNREQUIRED)) | |
415 | rcverr(ENOTCONN); | |
62364f0e | 416 | if (so->so_state & SS_NBIO) |
4c078bb2 | 417 | rcverr(EWOULDBLOCK); |
cc15ab5d | 418 | sbunlock(&so->so_rcv); |
2752c877 | 419 | sbwait(&so->so_rcv); |
a4f6d93d | 420 | splx(s); |
cc15ab5d | 421 | goto restart; |
ce9d8eb4 | 422 | } |
c7256358 | 423 | u.u_ru.ru_msgrcv++; |
92a533e6 | 424 | m = so->so_rcv.sb_mb; |
ce9d8eb4 BJ |
425 | if (m == 0) |
426 | panic("receive"); | |
e435773e | 427 | SBCHECK(&so->so_snd, "soreceive havecc"); |
b031e888 | 428 | if (so->so_proto->pr_flags & PR_ADDR) { |
970108c7 BJ |
429 | if ((flags & SOF_PREVIEW) == 0) { |
430 | so->so_rcv.sb_cc -= m->m_len; | |
431 | so->so_rcv.sb_mbcnt -= MSIZE; | |
432 | } | |
cf012934 | 433 | if (aname) { |
970108c7 BJ |
434 | if (flags & SOF_PREVIEW) |
435 | *aname = m_copy(m, 0, m->m_len); | |
436 | else | |
437 | *aname = m; | |
cf012934 BJ |
438 | m = m->m_next; |
439 | (*aname)->m_next = 0; | |
440 | } else | |
970108c7 BJ |
441 | if (flags & SOF_PREVIEW) |
442 | m = m->m_next; | |
443 | else | |
444 | m = m_free(m); | |
cc15ab5d BJ |
445 | if (m == 0) |
446 | panic("receive 2"); | |
e435773e BJ |
447 | if ((flags & SOF_PREVIEW) == 0) |
448 | so->so_rcv.sb_mb = m; | |
449 | SBCHECK(&so->so_snd, "soreceive afteraddr"); | |
cc15ab5d | 450 | } |
ce9d8eb4 | 451 | eor = 0; |
970108c7 BJ |
452 | moff = 0; |
453 | tomark = so->so_oobmark; | |
ce9d8eb4 | 454 | do { |
5699bf69 | 455 | if (uio->uio_resid <= 0) |
32a43ee2 | 456 | break; |
5699bf69 | 457 | len = uio->uio_resid; |
32a43ee2 | 458 | so->so_state &= ~SS_RCVATMARK; |
970108c7 BJ |
459 | if (tomark && len > tomark) |
460 | len = tomark; | |
e435773e | 461 | if (moff+len > m->m_len - moff) |
970108c7 | 462 | len = m->m_len - moff; |
ce9d8eb4 | 463 | splx(s); |
a8d3bf7f | 464 | error = |
a29f7995 | 465 | uiomove(mtod(m, caddr_t) + moff, (int)len, UIO_READ, uio); |
ce9d8eb4 BJ |
466 | s = splnet(); |
467 | if (len == m->m_len) { | |
e495e1cc | 468 | eor = (int)m->m_act; |
970108c7 BJ |
469 | if (flags & SOF_PREVIEW) |
470 | m = m->m_next; | |
471 | else { | |
472 | sbfree(&so->so_rcv, m); | |
473 | MFREE(m, n); | |
474 | m = n; | |
e435773e | 475 | so->so_rcv.sb_mb = m; |
970108c7 BJ |
476 | } |
477 | moff = 0; | |
ce9d8eb4 | 478 | } else { |
970108c7 BJ |
479 | if (flags & SOF_PREVIEW) |
480 | moff += len; | |
481 | else { | |
482 | m->m_off += len; | |
483 | m->m_len -= len; | |
484 | so->so_rcv.sb_cc -= len; | |
485 | } | |
ce9d8eb4 | 486 | } |
970108c7 | 487 | if ((flags & SOF_PREVIEW) == 0 && so->so_oobmark) { |
32a43ee2 BJ |
488 | so->so_oobmark -= len; |
489 | if (so->so_oobmark == 0) { | |
490 | so->so_state |= SS_RCVATMARK; | |
491 | break; | |
492 | } | |
493 | } | |
970108c7 BJ |
494 | if (tomark) { |
495 | tomark -= len; | |
496 | if (tomark == 0) | |
497 | break; | |
498 | } | |
e435773e | 499 | SBCHECK(&so->so_snd, "soreceive rcvloop"); |
a8d3bf7f | 500 | } while (m && error == 0 && !eor); |
970108c7 BJ |
501 | if (flags & SOF_PREVIEW) |
502 | goto release; | |
ce9d8eb4 BJ |
503 | if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0) |
504 | do { | |
ce9d8eb4 | 505 | if (m == 0) |
cc15ab5d BJ |
506 | panic("receive 3"); |
507 | sbfree(&so->so_rcv, m); | |
ce9d8eb4 BJ |
508 | eor = (int)m->m_act; |
509 | so->so_rcv.sb_mb = m->m_next; | |
510 | MFREE(m, n); | |
cc15ab5d | 511 | m = n; |
e435773e | 512 | SBCHECK(&so->so_snd, "soreceive atomicloop"); |
ce9d8eb4 | 513 | } while (eor == 0); |
cc15ab5d | 514 | if ((so->so_proto->pr_flags & PR_WANTRCVD) && so->so_pcb) |
cf012934 BJ |
515 | (*so->so_proto->pr_usrreq)(so, PRU_RCVD, |
516 | (struct mbuf *)0, (struct mbuf *)0, (struct socketopt *)0); | |
cc15ab5d | 517 | release: |
ae921915 | 518 | sbunlock(&so->so_rcv); |
cc15ab5d | 519 | splx(s); |
ae921915 | 520 | return (error); |
92a533e6 BJ |
521 | } |
522 | ||
edebca28 BJ |
523 | sohasoutofband(so) |
524 | struct socket *so; | |
525 | { | |
526 | ||
527 | if (so->so_pgrp == 0) | |
528 | return; | |
529 | if (so->so_pgrp > 0) | |
530 | gsignal(so->so_pgrp, SIGURG); | |
0a0f7cbb BJ |
531 | else { |
532 | struct proc *p = pfind(-so->so_pgrp); | |
533 | ||
534 | if (p) | |
535 | psignal(p, SIGURG); | |
536 | } | |
edebca28 BJ |
537 | } |
538 | ||
ae921915 | 539 | /*ARGSUSED*/ |
4b72e2f9 | 540 | soioctl(so, cmd, data) |
92a533e6 BJ |
541 | register struct socket *so; |
542 | int cmd; | |
4b72e2f9 | 543 | register char *data; |
92a533e6 BJ |
544 | { |
545 | ||
2156d53c | 546 | switch (cmd) { |
92a533e6 | 547 | |
4b72e2f9 SL |
548 | case FIONBIO: |
549 | if (*(int *)data) | |
62364f0e | 550 | so->so_state |= SS_NBIO; |
30b84e26 | 551 | else |
62364f0e | 552 | so->so_state &= ~SS_NBIO; |
a8d3bf7f | 553 | break; |
30b84e26 | 554 | |
4b72e2f9 SL |
555 | case FIOASYNC: |
556 | if (*(int *)data) | |
62364f0e | 557 | so->so_state |= SS_ASYNC; |
30b84e26 | 558 | else |
62364f0e | 559 | so->so_state &= ~SS_ASYNC; |
a8d3bf7f | 560 | break; |
30b84e26 | 561 | |
4b72e2f9 SL |
562 | case SIOCSKEEP: |
563 | if (*(int *)data) | |
9d2f171f | 564 | so->so_options &= ~SO_KEEPALIVE; |
90aaea96 BJ |
565 | else |
566 | so->so_options |= SO_KEEPALIVE; | |
a8d3bf7f | 567 | break; |
30b84e26 | 568 | |
4b72e2f9 SL |
569 | case SIOCGKEEP: |
570 | *(int *)data = (so->so_options & SO_KEEPALIVE) != 0; | |
a8d3bf7f | 571 | break; |
30b84e26 | 572 | |
4b72e2f9 SL |
573 | case SIOCSLINGER: |
574 | so->so_linger = *(int *)data; | |
30b84e26 BJ |
575 | if (so->so_linger) |
576 | so->so_options &= ~SO_DONTLINGER; | |
577 | else | |
578 | so->so_options |= SO_DONTLINGER; | |
a8d3bf7f | 579 | break; |
30b84e26 | 580 | |
4b72e2f9 SL |
581 | case SIOCGLINGER: |
582 | *(int *)data = so->so_linger; | |
a8d3bf7f | 583 | break; |
edebca28 | 584 | |
4b72e2f9 SL |
585 | case SIOCSPGRP: |
586 | so->so_pgrp = *(int *)data; | |
a8d3bf7f | 587 | break; |
4b72e2f9 SL |
588 | |
589 | case SIOCGPGRP: | |
590 | *(int *)data = so->so_pgrp; | |
a8d3bf7f | 591 | break; |
30b84e26 | 592 | |
b8acc34d | 593 | case SIOCDONE: { |
4b72e2f9 SL |
594 | int flags = *(int *)data; |
595 | ||
30b84e26 | 596 | flags++; |
b8acc34d BJ |
597 | if (flags & FREAD) { |
598 | int s = splimp(); | |
599 | socantrcvmore(so); | |
600 | sbflush(&so->so_rcv); | |
785e10b7 | 601 | splx(s); |
b8acc34d BJ |
602 | } |
603 | if (flags & FWRITE) | |
47b7bdd9 | 604 | return ((*so->so_proto->pr_usrreq)(so, PRU_SHUTDOWN, |
cf012934 | 605 | (struct mbuf *)0, (struct mbuf *)0, |
47b7bdd9 | 606 | (struct socketopt *)0)); |
a8d3bf7f | 607 | break; |
b8acc34d BJ |
608 | } |
609 | ||
edebca28 | 610 | case SIOCSENDOOB: { |
4b72e2f9 | 611 | char oob = *(char *)data; |
970108c7 | 612 | struct mbuf *m = m_get(M_DONTWAIT); |
4b72e2f9 | 613 | |
a8d3bf7f BJ |
614 | if (m == 0) |
615 | return (ENOBUFS); | |
970108c7 | 616 | m->m_len = 1; |
4b72e2f9 | 617 | *mtod(m, char *) = oob; |
47b7bdd9 BJ |
618 | return ((*so->so_proto->pr_usrreq)(so, PRU_SENDOOB, |
619 | m, (struct mbuf *)0, (struct socketopt *)0)); | |
edebca28 BJ |
620 | } |
621 | ||
622 | case SIOCRCVOOB: { | |
970108c7 | 623 | struct mbuf *m = m_get(M_WAIT); |
4b72e2f9 | 624 | |
a8d3bf7f BJ |
625 | if (m == 0) |
626 | return (ENOBUFS); | |
970108c7 | 627 | *mtod(m, caddr_t) = 0; |
cf012934 BJ |
628 | (*so->so_proto->pr_usrreq)(so, PRU_RCVOOB, |
629 | m, (struct mbuf *)0, (struct socketopt *)0); | |
4b72e2f9 SL |
630 | *(char *)data = *mtod(m, char *); |
631 | (void) m_free(m); | |
a8d3bf7f | 632 | break; |
edebca28 BJ |
633 | } |
634 | ||
4b72e2f9 SL |
635 | case SIOCATMARK: |
636 | *(int *)data = (so->so_state&SS_RCVATMARK) != 0; | |
a8d3bf7f | 637 | break; |
2a4251c4 SL |
638 | |
639 | /* routing table update calls */ | |
640 | case SIOCADDRT: | |
641 | case SIOCDELRT: | |
2a4251c4 | 642 | if (!suser()) |
47b7bdd9 BJ |
643 | return (u.u_error); /* XXX */ |
644 | return (rtrequest(cmd, (struct rtentry *)data)); | |
2a4251c4 | 645 | |
5e1eeba0 | 646 | /* type/protocol specific ioctls */ |
a8d3bf7f BJ |
647 | default: |
648 | return (ENOTTY); | |
92a533e6 | 649 | } |
a8d3bf7f | 650 | return (0); |
ce9d8eb4 | 651 | } |