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