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