Commit | Line | Data |
---|---|---|
9e87be97 | 1 | /* uipc_socket.c 4.74 83/05/18 */ |
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" |
22f36762 | 19 | #include "../net/if.h" |
ce9d8eb4 | 20 | |
ce9d8eb4 | 21 | /* |
cf012934 BJ |
22 | * Socket operation routines. |
23 | * These routines are called by the routines in | |
24 | * sys_socket.c or from a system process, and | |
25 | * implement the semantics of socket operations by | |
26 | * switching out to the protocol specific routines. | |
ce9d8eb4 | 27 | */ |
ce9d8eb4 | 28 | |
a8d3bf7f | 29 | /*ARGSUSED*/ |
98422daa | 30 | socreate(dom, aso, type, proto) |
ce9d8eb4 | 31 | struct socket **aso; |
cf012934 | 32 | int type, proto; |
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); | |
cce93e4b | 47 | m = m_getclr(M_WAIT, MT_SOCKET); |
ce9d8eb4 BJ |
48 | if (m == 0) |
49 | return (ENOBUFS); | |
ce9d8eb4 | 50 | so = mtod(m, struct socket *); |
98422daa | 51 | so->so_options = SO_LINGER; |
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 | 57 | error = (*prp->pr_usrreq)(so, PRU_ATTACH, |
98422daa | 58 | (struct mbuf *)0, (struct mbuf *)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 | ||
98422daa | 68 | sobind(so, nam) |
cf012934 BJ |
69 | struct socket *so; |
70 | struct mbuf *nam; | |
cf012934 BJ |
71 | { |
72 | int s = splnet(); | |
73 | int error; | |
74 | ||
75 | error = | |
98422daa | 76 | (*so->so_proto->pr_usrreq)(so, PRU_BIND, (struct mbuf *)0, nam); |
cf012934 BJ |
77 | splx(s); |
78 | return (error); | |
79 | } | |
80 | ||
81 | solisten(so, backlog) | |
82 | struct socket *so; | |
83 | int backlog; | |
84 | { | |
85 | int s = splnet(); | |
86 | int error; | |
87 | ||
88 | error = (*so->so_proto->pr_usrreq)(so, PRU_LISTEN, | |
98422daa | 89 | (struct mbuf *)0, (struct mbuf *)0); |
cf012934 BJ |
90 | if (error) { |
91 | splx(s); | |
92 | return (error); | |
93 | } | |
94 | if (so->so_q == 0) { | |
95 | so->so_q = so; | |
96 | so->so_q0 = so; | |
97 | so->so_options |= SO_ACCEPTCONN; | |
98 | } | |
99 | if (backlog < 0) | |
100 | backlog = 0; | |
5fe6f9d1 SL |
101 | #define SOMAXCONN 5 |
102 | so->so_qlimit = MIN(backlog, SOMAXCONN); | |
cf012934 | 103 | so->so_options |= SO_NEWFDONCONN; |
9e87be97 | 104 | splx(s); |
cf012934 BJ |
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) | |
26225f25 | 138 | (void) soabort(so->so_q0); |
90aaea96 | 139 | while (so->so_q != so) |
26225f25 | 140 | (void) soabort(so->so_q); |
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 | } | |
98422daa | 156 | if (so->so_options & SO_LINGER) { |
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, |
98422daa | 169 | (struct mbuf *)0, (struct mbuf *)0); |
5a1f132a | 170 | if (exiting == 0 && error) { |
37c0974a | 171 | splx(s); |
5a1f132a | 172 | return (error); |
37c0974a SL |
173 | } |
174 | } | |
cc15ab5d | 175 | discard: |
26225f25 SL |
176 | if (so->so_state & SS_NOFDREF) |
177 | panic("soclose: NOFDREF"); | |
90aaea96 | 178 | so->so_state |= SS_NOFDREF; |
4ad99bae | 179 | sofree(so); |
cc15ab5d | 180 | splx(s); |
5a1f132a | 181 | return (0); |
92a533e6 BJ |
182 | } |
183 | ||
26225f25 SL |
184 | /* |
185 | * Must be called at splnet... | |
186 | */ | |
187 | soabort(so) | |
188 | struct socket *so; | |
189 | { | |
190 | int error; | |
191 | ||
192 | error = (*so->so_proto->pr_usrreq)(so, PRU_ABORT, | |
193 | (struct mbuf *)0, (struct mbuf *)0); | |
194 | return (error); | |
195 | } | |
196 | ||
ae921915 | 197 | /*ARGSUSED*/ |
0cc4f3e6 | 198 | sostat(so, ub) |
92a533e6 | 199 | struct socket *so; |
0cc4f3e6 | 200 | struct stat *ub; |
92a533e6 | 201 | { |
0cc4f3e6 | 202 | struct stat sb; |
92a533e6 | 203 | |
0cc4f3e6 | 204 | bzero((caddr_t)&sb, sizeof (sb)); /* XXX */ |
4f083fd7 | 205 | (void) copyout((caddr_t)&sb, (caddr_t)ub, sizeof (sb));/* XXX */ |
5e35cca3 | 206 | return (0); /* XXX */ |
92a533e6 BJ |
207 | } |
208 | ||
98422daa | 209 | soaccept(so, nam) |
2b4b57cd | 210 | struct socket *so; |
cf012934 | 211 | struct mbuf *nam; |
2b4b57cd BJ |
212 | { |
213 | int s = splnet(); | |
214 | int error; | |
215 | ||
26225f25 SL |
216 | if ((so->so_state & SS_NOFDREF) == 0) |
217 | panic("soaccept: !NOFDREF"); | |
98422daa | 218 | so->so_state &= ~SS_NOFDREF; |
cf012934 | 219 | error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, |
98422daa | 220 | (struct mbuf *)0, nam); |
2b4b57cd BJ |
221 | splx(s); |
222 | return (error); | |
223 | } | |
224 | ||
98422daa | 225 | soconnect(so, nam) |
ce9d8eb4 | 226 | struct socket *so; |
cf012934 | 227 | struct mbuf *nam; |
ce9d8eb4 | 228 | { |
cc15ab5d BJ |
229 | int s = splnet(); |
230 | int error; | |
ce9d8eb4 | 231 | |
cc15ab5d BJ |
232 | if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) { |
233 | error = EISCONN; | |
234 | goto bad; | |
235 | } | |
cf012934 | 236 | error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, |
98422daa | 237 | (struct mbuf *)0, nam); |
cc15ab5d BJ |
238 | bad: |
239 | splx(s); | |
240 | return (error); | |
ce9d8eb4 BJ |
241 | } |
242 | ||
cf012934 | 243 | sodisconnect(so, nam) |
ce9d8eb4 | 244 | struct socket *so; |
cf012934 | 245 | struct mbuf *nam; |
ce9d8eb4 | 246 | { |
cc15ab5d BJ |
247 | int s = splnet(); |
248 | int error; | |
ce9d8eb4 | 249 | |
cc15ab5d BJ |
250 | if ((so->so_state & SS_ISCONNECTED) == 0) { |
251 | error = ENOTCONN; | |
252 | goto bad; | |
ce9d8eb4 | 253 | } |
cc15ab5d BJ |
254 | if (so->so_state & SS_ISDISCONNECTING) { |
255 | error = EALREADY; | |
256 | goto bad; | |
ce9d8eb4 | 257 | } |
cf012934 | 258 | error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, |
98422daa | 259 | (struct mbuf *)0, nam); |
cc15ab5d BJ |
260 | bad: |
261 | splx(s); | |
262 | return (error); | |
ce9d8eb4 BJ |
263 | } |
264 | ||
cc15ab5d BJ |
265 | /* |
266 | * Send on a socket. | |
267 | * If send must go all at once and message is larger than | |
268 | * send buffering, then hard error. | |
269 | * Lock against other senders. | |
270 | * If must go all at once and not enough room now, then | |
271 | * inform user that this would block and do nothing. | |
272 | */ | |
970108c7 | 273 | sosend(so, nam, uio, flags) |
ce9d8eb4 | 274 | register struct socket *so; |
cf012934 | 275 | struct mbuf *nam; |
5699bf69 | 276 | struct uio *uio; |
970108c7 | 277 | int flags; |
ce9d8eb4 | 278 | { |
cc15ab5d BJ |
279 | struct mbuf *top = 0; |
280 | register struct mbuf *m, **mp = ⊤ | |
5a1f132a | 281 | register int len; |
98422daa | 282 | int error = 0, space, s, dontroute; |
ce9d8eb4 | 283 | |
5699bf69 | 284 | if (sosendallatonce(so) && uio->uio_resid > so->so_snd.sb_hiwat) |
cc15ab5d | 285 | return (EMSGSIZE); |
98422daa SL |
286 | dontroute = (flags & SOF_DONTROUTE) && |
287 | (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 BJ |
315 | error = (*so->so_proto->pr_usrreq)(so, |
316 | (flags & SOF_OOB) ? PRU_SENDOOB : PRU_SEND, | |
98422daa SL |
317 | top, (caddr_t)nam); |
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 | } | |
970108c7 BJ |
331 | if (flags & SOF_OOB) |
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; | |
970108c7 BJ |
376 | if (flags & SOF_OOB) |
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 | ||
970108c7 | 390 | soreceive(so, aname, uio, flags) |
ce9d8eb4 | 391 | register struct socket *so; |
cf012934 | 392 | struct mbuf **aname; |
32a43ee2 | 393 | struct uio *uio; |
970108c7 | 394 | int flags; |
ce9d8eb4 BJ |
395 | { |
396 | register struct mbuf *m, *n; | |
5a1f132a | 397 | int len; |
970108c7 BJ |
398 | int eor, s, error = 0, moff, tomark; |
399 | ||
400 | if (flags & SOF_OOB) { | |
cce93e4b | 401 | m = m_get(M_WAIT, MT_DATA); |
5fe6f9d1 SL |
402 | if (m == NULL) |
403 | return (ENOBUFS); | |
a8d3bf7f | 404 | error = (*so->so_proto->pr_usrreq)(so, PRU_RCVOOB, |
98422daa | 405 | m, (struct mbuf *)0); |
a8d3bf7f | 406 | if (error) |
5fe6f9d1 | 407 | goto bad; |
970108c7 | 408 | do { |
5fe6f9d1 | 409 | len = uio->uio_resid; |
970108c7 BJ |
410 | if (len > m->m_len) |
411 | len = m->m_len; | |
a8d3bf7f | 412 | error = |
a29f7995 | 413 | uiomove(mtod(m, caddr_t), (int)len, UIO_READ, uio); |
970108c7 | 414 | m = m_free(m); |
a8d3bf7f | 415 | } while (uio->uio_resid && error == 0 && m); |
5fe6f9d1 | 416 | bad: |
970108c7 | 417 | if (m) |
39d536e6 | 418 | m_freem(m); |
a8d3bf7f | 419 | return (error); |
970108c7 | 420 | } |
ce9d8eb4 | 421 | |
cc15ab5d BJ |
422 | restart: |
423 | sblock(&so->so_rcv); | |
424 | s = splnet(); | |
425 | ||
426 | #define rcverr(errno) { error = errno; splx(s); goto release; } | |
ce9d8eb4 | 427 | if (so->so_rcv.sb_cc == 0) { |
4c078bb2 BJ |
428 | if (so->so_error) { |
429 | error = so->so_error; | |
430 | so->so_error = 0; | |
431 | splx(s); | |
432 | goto release; | |
433 | } | |
cc15ab5d BJ |
434 | if (so->so_state & SS_CANTRCVMORE) { |
435 | splx(s); | |
436 | goto release; | |
437 | } | |
196d84fd BJ |
438 | if ((so->so_state & SS_ISCONNECTED) == 0 && |
439 | (so->so_proto->pr_flags & PR_CONNREQUIRED)) | |
440 | rcverr(ENOTCONN); | |
62364f0e | 441 | if (so->so_state & SS_NBIO) |
4c078bb2 | 442 | rcverr(EWOULDBLOCK); |
cc15ab5d | 443 | sbunlock(&so->so_rcv); |
2752c877 | 444 | sbwait(&so->so_rcv); |
a4f6d93d | 445 | splx(s); |
cc15ab5d | 446 | goto restart; |
ce9d8eb4 | 447 | } |
c7256358 | 448 | u.u_ru.ru_msgrcv++; |
92a533e6 | 449 | m = so->so_rcv.sb_mb; |
ce9d8eb4 BJ |
450 | if (m == 0) |
451 | panic("receive"); | |
b031e888 | 452 | if (so->so_proto->pr_flags & PR_ADDR) { |
970108c7 BJ |
453 | if ((flags & SOF_PREVIEW) == 0) { |
454 | so->so_rcv.sb_cc -= m->m_len; | |
455 | so->so_rcv.sb_mbcnt -= MSIZE; | |
456 | } | |
cf012934 | 457 | if (aname) { |
5fe6f9d1 | 458 | if (flags & SOF_PREVIEW) { |
970108c7 | 459 | *aname = m_copy(m, 0, m->m_len); |
5fe6f9d1 SL |
460 | if (*aname == NULL) |
461 | panic("receive 2"); | |
462 | } else | |
970108c7 | 463 | *aname = m; |
cf012934 BJ |
464 | m = m->m_next; |
465 | (*aname)->m_next = 0; | |
466 | } else | |
970108c7 BJ |
467 | if (flags & SOF_PREVIEW) |
468 | m = m->m_next; | |
469 | else | |
470 | m = m_free(m); | |
cc15ab5d | 471 | if (m == 0) |
5fe6f9d1 | 472 | panic("receive 3"); |
e435773e BJ |
473 | if ((flags & SOF_PREVIEW) == 0) |
474 | so->so_rcv.sb_mb = m; | |
cc15ab5d | 475 | } |
ce9d8eb4 | 476 | eor = 0; |
970108c7 BJ |
477 | moff = 0; |
478 | tomark = so->so_oobmark; | |
ce9d8eb4 | 479 | do { |
5699bf69 | 480 | if (uio->uio_resid <= 0) |
32a43ee2 | 481 | break; |
5699bf69 | 482 | len = uio->uio_resid; |
32a43ee2 | 483 | so->so_state &= ~SS_RCVATMARK; |
970108c7 BJ |
484 | if (tomark && len > tomark) |
485 | len = tomark; | |
e435773e | 486 | if (moff+len > m->m_len - moff) |
970108c7 | 487 | len = m->m_len - moff; |
ce9d8eb4 | 488 | splx(s); |
a8d3bf7f | 489 | error = |
a29f7995 | 490 | uiomove(mtod(m, caddr_t) + moff, (int)len, UIO_READ, uio); |
ce9d8eb4 BJ |
491 | s = splnet(); |
492 | if (len == m->m_len) { | |
e495e1cc | 493 | eor = (int)m->m_act; |
970108c7 BJ |
494 | if (flags & SOF_PREVIEW) |
495 | m = m->m_next; | |
496 | else { | |
497 | sbfree(&so->so_rcv, m); | |
498 | MFREE(m, n); | |
499 | m = n; | |
e435773e | 500 | so->so_rcv.sb_mb = m; |
970108c7 BJ |
501 | } |
502 | moff = 0; | |
ce9d8eb4 | 503 | } else { |
970108c7 BJ |
504 | if (flags & SOF_PREVIEW) |
505 | moff += len; | |
506 | else { | |
507 | m->m_off += len; | |
508 | m->m_len -= len; | |
509 | so->so_rcv.sb_cc -= len; | |
510 | } | |
ce9d8eb4 | 511 | } |
970108c7 | 512 | if ((flags & SOF_PREVIEW) == 0 && so->so_oobmark) { |
32a43ee2 BJ |
513 | so->so_oobmark -= len; |
514 | if (so->so_oobmark == 0) { | |
515 | so->so_state |= SS_RCVATMARK; | |
516 | break; | |
517 | } | |
518 | } | |
970108c7 BJ |
519 | if (tomark) { |
520 | tomark -= len; | |
521 | if (tomark == 0) | |
522 | break; | |
523 | } | |
a8d3bf7f | 524 | } while (m && error == 0 && !eor); |
970108c7 BJ |
525 | if (flags & SOF_PREVIEW) |
526 | goto release; | |
ce9d8eb4 BJ |
527 | if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0) |
528 | do { | |
ce9d8eb4 | 529 | if (m == 0) |
5fe6f9d1 | 530 | panic("receive 4"); |
cc15ab5d | 531 | sbfree(&so->so_rcv, m); |
ce9d8eb4 BJ |
532 | eor = (int)m->m_act; |
533 | so->so_rcv.sb_mb = m->m_next; | |
534 | MFREE(m, n); | |
cc15ab5d | 535 | m = n; |
ce9d8eb4 | 536 | } while (eor == 0); |
cc15ab5d | 537 | if ((so->so_proto->pr_flags & PR_WANTRCVD) && so->so_pcb) |
cf012934 | 538 | (*so->so_proto->pr_usrreq)(so, PRU_RCVD, |
98422daa | 539 | (struct mbuf *)0, (struct mbuf *)0); |
cc15ab5d | 540 | release: |
ae921915 | 541 | sbunlock(&so->so_rcv); |
cc15ab5d | 542 | splx(s); |
ae921915 | 543 | return (error); |
92a533e6 BJ |
544 | } |
545 | ||
98422daa SL |
546 | soshutdown(so, how) |
547 | struct socket *so; | |
548 | int how; | |
549 | { | |
550 | ||
551 | how++; | |
552 | if (how & FREAD) { | |
553 | int s = splimp(); | |
554 | socantrcvmore(so); | |
555 | sbflush(&so->so_rcv); | |
556 | splx(s); | |
557 | } | |
558 | if (how & FWRITE) | |
559 | return ((*so->so_proto->pr_usrreq)(so, PRU_SHUTDOWN, | |
560 | (struct mbuf *)0, (struct mbuf *)0)); | |
561 | return (0); | |
562 | } | |
563 | ||
564 | sosetopt(so, level, optname, m) | |
565 | struct socket *so; | |
566 | int level, optname; | |
567 | struct mbuf *m; | |
568 | { | |
98422daa SL |
569 | |
570 | if (level != SOL_SOCKET) | |
571 | return (EINVAL); /* XXX */ | |
98422daa SL |
572 | switch (optname) { |
573 | ||
574 | case SO_DEBUG: | |
d2cba8de | 575 | case SO_KEEPALIVE: |
b4a3d4a7 SL |
576 | case SO_DONTROUTE: |
577 | case SO_USELOOPBACK: | |
578 | case SO_REUSEADDR: | |
579 | so->so_options |= optname; | |
d2cba8de SL |
580 | break; |
581 | ||
98422daa | 582 | case SO_LINGER: |
d2cba8de SL |
583 | if (m == NULL || m->m_len != sizeof (int)) |
584 | return (EINVAL); | |
98422daa | 585 | so->so_options |= SO_LINGER; |
d2cba8de | 586 | so->so_linger = *mtod(m, int *); |
98422daa SL |
587 | break; |
588 | ||
589 | case SO_DONTLINGER: | |
590 | so->so_options &= ~SO_LINGER; | |
591 | so->so_linger = 0; | |
592 | break; | |
593 | ||
98422daa SL |
594 | default: |
595 | return (EINVAL); | |
596 | } | |
597 | return (0); | |
598 | } | |
599 | ||
600 | sogetopt(so, level, optname, m) | |
601 | struct socket *so; | |
602 | int level, optname; | |
603 | struct mbuf *m; | |
604 | { | |
98422daa SL |
605 | |
606 | if (level != SOL_SOCKET) | |
607 | return (EINVAL); /* XXX */ | |
608 | switch (optname) { | |
609 | ||
610 | case SO_USELOOPBACK: | |
611 | case SO_DONTROUTE: | |
612 | case SO_DEBUG: | |
613 | case SO_KEEPALIVE: | |
614 | case SO_LINGER: | |
b4a3d4a7 | 615 | case SO_REUSEADDR: |
98422daa SL |
616 | if ((so->so_options & optname) == 0) |
617 | return (ENOPROTOOPT); | |
d2cba8de | 618 | if (optname == SO_LINGER && m != NULL) { |
98422daa SL |
619 | *mtod(m, int *) = so->so_linger; |
620 | m->m_len = sizeof (so->so_linger); | |
621 | } | |
622 | break; | |
623 | ||
624 | default: | |
625 | return (EINVAL); | |
626 | } | |
627 | return (0); | |
628 | } | |
629 | ||
edebca28 BJ |
630 | sohasoutofband(so) |
631 | struct socket *so; | |
632 | { | |
633 | ||
634 | if (so->so_pgrp == 0) | |
635 | return; | |
636 | if (so->so_pgrp > 0) | |
637 | gsignal(so->so_pgrp, SIGURG); | |
0a0f7cbb BJ |
638 | else { |
639 | struct proc *p = pfind(-so->so_pgrp); | |
640 | ||
641 | if (p) | |
642 | psignal(p, SIGURG); | |
643 | } | |
edebca28 BJ |
644 | } |
645 | ||
ae921915 | 646 | /*ARGSUSED*/ |
4b72e2f9 | 647 | soioctl(so, cmd, data) |
92a533e6 BJ |
648 | register struct socket *so; |
649 | int cmd; | |
4b72e2f9 | 650 | register char *data; |
92a533e6 BJ |
651 | { |
652 | ||
2156d53c | 653 | switch (cmd) { |
92a533e6 | 654 | |
4b72e2f9 SL |
655 | case FIONBIO: |
656 | if (*(int *)data) | |
62364f0e | 657 | so->so_state |= SS_NBIO; |
30b84e26 | 658 | else |
62364f0e | 659 | so->so_state &= ~SS_NBIO; |
a8d3bf7f | 660 | break; |
30b84e26 | 661 | |
4b72e2f9 SL |
662 | case FIOASYNC: |
663 | if (*(int *)data) | |
62364f0e | 664 | so->so_state |= SS_ASYNC; |
30b84e26 | 665 | else |
62364f0e | 666 | so->so_state &= ~SS_ASYNC; |
a8d3bf7f | 667 | break; |
30b84e26 | 668 | |
4b72e2f9 SL |
669 | case SIOCSPGRP: |
670 | so->so_pgrp = *(int *)data; | |
a8d3bf7f | 671 | break; |
4b72e2f9 SL |
672 | |
673 | case SIOCGPGRP: | |
674 | *(int *)data = so->so_pgrp; | |
a8d3bf7f | 675 | break; |
30b84e26 | 676 | |
4b72e2f9 SL |
677 | case SIOCATMARK: |
678 | *(int *)data = (so->so_state&SS_RCVATMARK) != 0; | |
a8d3bf7f | 679 | break; |
2a4251c4 SL |
680 | |
681 | /* routing table update calls */ | |
682 | case SIOCADDRT: | |
683 | case SIOCDELRT: | |
2a4251c4 | 684 | if (!suser()) |
5fe6f9d1 | 685 | return (u.u_error); |
47b7bdd9 | 686 | return (rtrequest(cmd, (struct rtentry *)data)); |
2a4251c4 | 687 | |
22f36762 SL |
688 | /* interface parameter requests */ |
689 | case SIOCSIFADDR: | |
690 | case SIOCSIFFLAGS: | |
9841d167 | 691 | case SIOCSIFDSTADDR: |
22f36762 SL |
692 | if (!suser()) |
693 | return (u.u_error); | |
694 | return (ifrequest(cmd, data)); | |
695 | ||
696 | case SIOCGIFADDR: | |
697 | case SIOCGIFFLAGS: | |
9841d167 | 698 | case SIOCGIFDSTADDR: |
22f36762 SL |
699 | return (ifrequest(cmd, data)); |
700 | ||
701 | case SIOCGIFCONF: | |
702 | return (ifconf(cmd, data)); | |
703 | ||
5e1eeba0 | 704 | /* type/protocol specific ioctls */ |
a8d3bf7f | 705 | default: |
5fe6f9d1 | 706 | return (ENOTTY); /* XXX */ |
92a533e6 | 707 | } |
a8d3bf7f | 708 | return (0); |
ce9d8eb4 | 709 | } |