Commit | Line | Data |
---|---|---|
785e10b7 | 1 | /* uipc_socket.c 4.33 82/03/12 */ |
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" |
c5ff2e32 BJ |
17 | #include "../net/in.h" |
18 | #include "../net/in_systm.h" | |
ce9d8eb4 | 19 | |
ce9d8eb4 | 20 | /* |
cc15ab5d BJ |
21 | * Socket support routines. |
22 | * | |
23 | * DEAL WITH INTERRUPT NOTIFICATION. | |
ce9d8eb4 | 24 | */ |
ce9d8eb4 BJ |
25 | |
26 | /* | |
27 | * Create a socket. | |
28 | */ | |
2b4b57cd | 29 | socreate(aso, type, asp, asa, options) |
ce9d8eb4 BJ |
30 | struct socket **aso; |
31 | int type; | |
2b4b57cd BJ |
32 | struct sockproto *asp; |
33 | struct sockaddr *asa; | |
92a533e6 | 34 | int options; |
ce9d8eb4 BJ |
35 | { |
36 | register struct protosw *prp; | |
37 | register struct socket *so; | |
38 | struct mbuf *m; | |
cc15ab5d | 39 | int pf, proto, error; |
2b4b57cd | 40 | COUNT(SOCREATE); |
ce9d8eb4 BJ |
41 | |
42 | /* | |
cc15ab5d BJ |
43 | * Use process standard protocol/protocol family if none |
44 | * specified by address argument. | |
ce9d8eb4 | 45 | */ |
2b4b57cd | 46 | if (asp == 0) { |
cc15ab5d | 47 | pf = PF_INET; /* should be u.u_protof */ |
ce9d8eb4 BJ |
48 | proto = 0; |
49 | } else { | |
2b4b57cd BJ |
50 | pf = asp->sp_family; |
51 | proto = asp->sp_protocol; | |
ce9d8eb4 | 52 | } |
cc15ab5d BJ |
53 | |
54 | /* | |
55 | * If protocol specified, look for it, otherwise | |
56 | * for a protocol of the correct type in the right family. | |
57 | */ | |
58 | if (proto) | |
59 | prp = pffindproto(pf, proto); | |
60 | else | |
61 | prp = pffindtype(pf, type); | |
62 | if (prp == 0) | |
63 | return (EPROTONOSUPPORT); | |
ce9d8eb4 BJ |
64 | |
65 | /* | |
66 | * Get a socket structure. | |
67 | */ | |
cc15ab5d | 68 | m = m_getclr(M_WAIT); |
ce9d8eb4 BJ |
69 | if (m == 0) |
70 | return (ENOBUFS); | |
ce9d8eb4 | 71 | so = mtod(m, struct socket *); |
92a533e6 | 72 | so->so_options = options; |
ce9d8eb4 BJ |
73 | |
74 | /* | |
cc15ab5d BJ |
75 | * Attach protocol to socket, initializing |
76 | * and reserving resources. | |
ce9d8eb4 BJ |
77 | */ |
78 | so->so_proto = prp; | |
b91acce4 BJ |
79 | error = (*prp->pr_usrreq)(so, PRU_ATTACH, 0, asa); |
80 | if (error) { | |
2752c877 | 81 | (void) m_free(dtom(so)); |
cc15ab5d | 82 | return (error); |
ce9d8eb4 BJ |
83 | } |
84 | *aso = so; | |
85 | return (0); | |
86 | } | |
87 | ||
ae921915 BJ |
88 | sofree(so) |
89 | struct socket *so; | |
90 | { | |
91 | ||
2b4b57cd | 92 | COUNT(SOFREE); |
4ad99bae BJ |
93 | if (so->so_pcb || (so->so_state & SS_USERGONE) == 0) |
94 | return; | |
95 | sbrelease(&so->so_snd); | |
96 | sbrelease(&so->so_rcv); | |
2752c877 | 97 | (void) m_free(dtom(so)); |
ae921915 BJ |
98 | } |
99 | ||
92a533e6 | 100 | /* |
cc15ab5d BJ |
101 | * Close a socket on last file table reference removal. |
102 | * Initiate disconnect if connected. | |
103 | * Free socket when disconnect complete. | |
89900a09 BJ |
104 | * |
105 | * THIS IS REALLY A UNIX INTERFACE ROUTINE | |
92a533e6 | 106 | */ |
89900a09 | 107 | soclose(so, exiting) |
92a533e6 | 108 | register struct socket *so; |
89900a09 | 109 | int exiting; |
92a533e6 | 110 | { |
cc15ab5d BJ |
111 | int s = splnet(); /* conservative */ |
112 | ||
2b4b57cd | 113 | COUNT(SOCLOSE); |
cc15ab5d BJ |
114 | if (so->so_pcb == 0) |
115 | goto discard; | |
116 | if (so->so_state & SS_ISCONNECTED) { | |
117 | if ((so->so_state & SS_ISDISCONNECTING) == 0) { | |
2b4b57cd | 118 | u.u_error = sodisconnect(so, (struct sockaddr *)0); |
cc15ab5d | 119 | if (u.u_error) { |
89900a09 BJ |
120 | if (exiting) |
121 | goto drop; | |
cc15ab5d BJ |
122 | splx(s); |
123 | return; | |
124 | } | |
125 | } | |
30b84e26 | 126 | if ((so->so_options & SO_DONTLINGER) == 0) { |
b8acc34d | 127 | if ((so->so_state & SS_ISDISCONNECTING) && |
89900a09 BJ |
128 | (so->so_options & SO_NONBLOCKING) && |
129 | exiting == 0) { | |
b8acc34d BJ |
130 | u.u_error = EINPROGRESS; |
131 | splx(s); | |
132 | return; | |
133 | } | |
89900a09 | 134 | /* should use tsleep here, for at most linger */ |
b8acc34d BJ |
135 | while (so->so_state & SS_ISCONNECTED) |
136 | sleep((caddr_t)&so->so_timeo, PZERO+1); | |
72857acf | 137 | } |
cc15ab5d | 138 | } |
89900a09 | 139 | drop: |
cc15ab5d BJ |
140 | u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_DETACH, 0, 0); |
141 | discard: | |
4ad99bae BJ |
142 | so->so_state |= SS_USERGONE; |
143 | sofree(so); | |
cc15ab5d | 144 | splx(s); |
92a533e6 BJ |
145 | } |
146 | ||
2b4b57cd BJ |
147 | sosplice(pso, so) |
148 | struct socket *pso, *so; | |
149 | { | |
150 | ||
151 | COUNT(SOSPLICE); | |
4c078bb2 | 152 | if (pso->so_proto->pr_family != PF_UNIX) { |
2b4b57cd BJ |
153 | struct socket *tso; |
154 | tso = pso; pso = so; so = tso; | |
155 | } | |
4c078bb2 | 156 | if (pso->so_proto->pr_family != PF_UNIX) |
2b4b57cd BJ |
157 | return (EOPNOTSUPP); |
158 | /* check types and buffer space */ | |
159 | /* merge buffers */ | |
160 | return (0); | |
161 | } | |
162 | ||
ae921915 | 163 | /*ARGSUSED*/ |
cc15ab5d | 164 | sostat(so, sb) |
92a533e6 | 165 | struct socket *so; |
cc15ab5d | 166 | struct stat *sb; |
92a533e6 BJ |
167 | { |
168 | ||
2b4b57cd | 169 | COUNT(SOSTAT); |
5e35cca3 BJ |
170 | bzero((caddr_t)sb, sizeof (*sb)); /* XXX */ |
171 | return (0); /* XXX */ | |
92a533e6 BJ |
172 | } |
173 | ||
2b4b57cd BJ |
174 | /* |
175 | * Accept connection on a socket. | |
176 | */ | |
177 | soaccept(so, asa) | |
178 | struct socket *so; | |
179 | struct sockaddr *asa; | |
180 | { | |
181 | int s = splnet(); | |
182 | int error; | |
183 | ||
184 | COUNT(SOACCEPT); | |
2b4b57cd BJ |
185 | if ((so->so_options & SO_ACCEPTCONN) == 0) { |
186 | error = EINVAL; /* XXX */ | |
187 | goto bad; | |
188 | } | |
92d06f69 BJ |
189 | if ((so->so_state & SS_CONNAWAITING) == 0) { |
190 | error = ENOTCONN; | |
191 | goto bad; | |
192 | } | |
193 | so->so_state &= ~SS_CONNAWAITING; | |
2b4b57cd BJ |
194 | error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, 0, (caddr_t)asa); |
195 | bad: | |
196 | splx(s); | |
197 | return (error); | |
198 | } | |
199 | ||
ce9d8eb4 | 200 | /* |
cc15ab5d BJ |
201 | * Connect socket to a specified address. |
202 | * If already connected or connecting, then avoid | |
203 | * the protocol entry, to keep its job simpler. | |
ce9d8eb4 | 204 | */ |
2b4b57cd | 205 | soconnect(so, asa) |
ce9d8eb4 | 206 | struct socket *so; |
2b4b57cd | 207 | struct sockaddr *asa; |
ce9d8eb4 | 208 | { |
cc15ab5d BJ |
209 | int s = splnet(); |
210 | int error; | |
ce9d8eb4 | 211 | |
2b4b57cd | 212 | COUNT(SOCONNECT); |
cc15ab5d BJ |
213 | if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) { |
214 | error = EISCONN; | |
215 | goto bad; | |
216 | } | |
2b4b57cd | 217 | error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 0, (caddr_t)asa); |
cc15ab5d BJ |
218 | bad: |
219 | splx(s); | |
220 | return (error); | |
ce9d8eb4 BJ |
221 | } |
222 | ||
223 | /* | |
cc15ab5d BJ |
224 | * Disconnect from a socket. |
225 | * Address parameter is from system call for later multicast | |
226 | * protocols. Check to make sure that connected and no disconnect | |
227 | * in progress (for protocol's sake), and then invoke protocol. | |
ce9d8eb4 | 228 | */ |
2b4b57cd | 229 | sodisconnect(so, asa) |
ce9d8eb4 | 230 | struct socket *so; |
2b4b57cd | 231 | struct sockaddr *asa; |
ce9d8eb4 | 232 | { |
cc15ab5d BJ |
233 | int s = splnet(); |
234 | int error; | |
ce9d8eb4 | 235 | |
2b4b57cd | 236 | COUNT(SODISCONNECT); |
cc15ab5d BJ |
237 | if ((so->so_state & SS_ISCONNECTED) == 0) { |
238 | error = ENOTCONN; | |
239 | goto bad; | |
ce9d8eb4 | 240 | } |
cc15ab5d BJ |
241 | if (so->so_state & SS_ISDISCONNECTING) { |
242 | error = EALREADY; | |
243 | goto bad; | |
ce9d8eb4 | 244 | } |
2b4b57cd | 245 | error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 0, asa); |
cc15ab5d BJ |
246 | bad: |
247 | splx(s); | |
248 | return (error); | |
ce9d8eb4 BJ |
249 | } |
250 | ||
cc15ab5d BJ |
251 | /* |
252 | * Send on a socket. | |
253 | * If send must go all at once and message is larger than | |
254 | * send buffering, then hard error. | |
255 | * Lock against other senders. | |
256 | * If must go all at once and not enough room now, then | |
257 | * inform user that this would block and do nothing. | |
258 | */ | |
2b4b57cd | 259 | sosend(so, asa) |
ce9d8eb4 | 260 | register struct socket *so; |
2b4b57cd | 261 | struct sockaddr *asa; |
ce9d8eb4 | 262 | { |
cc15ab5d BJ |
263 | struct mbuf *top = 0; |
264 | register struct mbuf *m, **mp = ⊤ | |
ae921915 BJ |
265 | register u_int len; |
266 | int error = 0, space, s; | |
ce9d8eb4 | 267 | |
2b4b57cd | 268 | COUNT(SOSEND); |
1bc8734a BJ |
269 | if (so->so_state & SS_CANTSENDMORE) { |
270 | psignal(u.u_procp, SIGPIPE); | |
cc15ab5d | 271 | return (EPIPE); |
1bc8734a | 272 | } |
cc15ab5d BJ |
273 | if (sosendallatonce(so) && u.u_count > so->so_snd.sb_hiwat) |
274 | return (EMSGSIZE); | |
30b84e26 | 275 | if ((so->so_snd.sb_flags & SB_LOCK) && (so->so_options & SO_NONBLOCKING)) |
cc15ab5d BJ |
276 | return (EWOULDBLOCK); |
277 | sblock(&so->so_snd); | |
278 | #define snderr(errno) { error = errno; splx(s); goto release; } | |
279 | ||
280 | s = splnet(); | |
281 | again: | |
4c078bb2 BJ |
282 | if (so->so_error) { |
283 | error = so->so_error; | |
284 | so->so_error = 0; | |
285 | splx(s); | |
286 | goto release; | |
287 | } | |
cc15ab5d BJ |
288 | if ((so->so_state & SS_ISCONNECTED) == 0) { |
289 | if (so->so_proto->pr_flags & PR_CONNREQUIRED) | |
290 | snderr(ENOTCONN); | |
2b4b57cd | 291 | if (asa == 0) |
cc15ab5d BJ |
292 | snderr(EDESTADDRREQ); |
293 | } | |
cc15ab5d | 294 | if (top) { |
2b4b57cd | 295 | error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, top, asa); |
cc15ab5d BJ |
296 | if (error) { |
297 | splx(s); | |
ce9d8eb4 BJ |
298 | goto release; |
299 | } | |
cc15ab5d BJ |
300 | top = 0; |
301 | mp = ⊤ | |
ce9d8eb4 | 302 | } |
b91acce4 BJ |
303 | if (u.u_count == 0) { |
304 | splx(s); | |
305 | goto release; | |
306 | } | |
50fc8df6 | 307 | space = sbspace(&so->so_snd); |
6fa47729 | 308 | if (space <= 0 || sosendallatonce(so) && space < u.u_count) { |
30b84e26 | 309 | if (so->so_options & SO_NONBLOCKING) |
cc15ab5d BJ |
310 | snderr(EWOULDBLOCK); |
311 | sbunlock(&so->so_snd); | |
312 | sbwait(&so->so_snd); | |
313 | splx(s); | |
ce9d8eb4 BJ |
314 | goto again; |
315 | } | |
cc15ab5d | 316 | splx(s); |
50fc8df6 | 317 | while (u.u_count && space > 0) { |
cc15ab5d BJ |
318 | MGET(m, 1); |
319 | if (m == NULL) { | |
320 | error = ENOBUFS; | |
321 | m_freem(top); | |
322 | goto release; | |
ce9d8eb4 | 323 | } |
c5ff2e32 | 324 | if (u.u_count >= CLBYTES && space >= CLBYTES) { |
cc15ab5d | 325 | register struct mbuf *p; |
c5ff2e32 | 326 | MCLGET(p, 1); |
cc15ab5d BJ |
327 | if (p == 0) |
328 | goto nopages; | |
329 | m->m_off = (int)p - (int)m; | |
c5ff2e32 | 330 | len = CLBYTES; |
cc15ab5d | 331 | } else { |
ce9d8eb4 | 332 | nopages: |
cc15ab5d BJ |
333 | m->m_off = MMINOFF; |
334 | len = MIN(MLEN, u.u_count); | |
ce9d8eb4 | 335 | } |
cc15ab5d BJ |
336 | iomove(mtod(m, caddr_t), len, B_WRITE); |
337 | m->m_len = len; | |
338 | *mp = m; | |
339 | mp = &m->m_next; | |
50fc8df6 | 340 | space = sbspace(&so->so_snd); |
ce9d8eb4 | 341 | } |
cc15ab5d BJ |
342 | s = splnet(); |
343 | goto again; | |
344 | ||
ce9d8eb4 | 345 | release: |
cc15ab5d | 346 | sbunlock(&so->so_snd); |
ce9d8eb4 BJ |
347 | return (error); |
348 | } | |
349 | ||
2b4b57cd | 350 | soreceive(so, asa) |
ce9d8eb4 | 351 | register struct socket *so; |
2b4b57cd | 352 | struct sockaddr *asa; |
ce9d8eb4 BJ |
353 | { |
354 | register struct mbuf *m, *n; | |
ae921915 | 355 | u_int len; |
edebca28 BJ |
356 | int eor, s, error = 0, cnt = u.u_count; |
357 | caddr_t base = u.u_base; | |
ce9d8eb4 | 358 | |
2b4b57cd | 359 | COUNT(SORECEIVE); |
cc15ab5d BJ |
360 | restart: |
361 | sblock(&so->so_rcv); | |
362 | s = splnet(); | |
363 | ||
364 | #define rcverr(errno) { error = errno; splx(s); goto release; } | |
ce9d8eb4 | 365 | if (so->so_rcv.sb_cc == 0) { |
4c078bb2 BJ |
366 | if (so->so_error) { |
367 | error = so->so_error; | |
368 | so->so_error = 0; | |
369 | splx(s); | |
370 | goto release; | |
371 | } | |
cc15ab5d BJ |
372 | if (so->so_state & SS_CANTRCVMORE) { |
373 | splx(s); | |
374 | goto release; | |
375 | } | |
196d84fd BJ |
376 | if ((so->so_state & SS_ISCONNECTED) == 0 && |
377 | (so->so_proto->pr_flags & PR_CONNREQUIRED)) | |
378 | rcverr(ENOTCONN); | |
30b84e26 | 379 | if (so->so_options & SO_NONBLOCKING) |
4c078bb2 | 380 | rcverr(EWOULDBLOCK); |
cc15ab5d | 381 | sbunlock(&so->so_rcv); |
2752c877 | 382 | sbwait(&so->so_rcv); |
a4f6d93d | 383 | splx(s); |
cc15ab5d | 384 | goto restart; |
ce9d8eb4 | 385 | } |
92a533e6 | 386 | m = so->so_rcv.sb_mb; |
ce9d8eb4 BJ |
387 | if (m == 0) |
388 | panic("receive"); | |
b031e888 | 389 | if (so->so_proto->pr_flags & PR_ADDR) { |
b031e888 BJ |
390 | if (m->m_len != sizeof (struct sockaddr)) |
391 | panic("soreceive addr"); | |
392 | if (asa) | |
393 | bcopy(mtod(m, caddr_t), (caddr_t)asa, sizeof (*asa)); | |
b031e888 BJ |
394 | so->so_rcv.sb_cc -= m->m_len; |
395 | so->so_rcv.sb_mbcnt -= MSIZE; | |
50fc8df6 | 396 | m = m_free(m); |
cc15ab5d BJ |
397 | if (m == 0) |
398 | panic("receive 2"); | |
50fc8df6 | 399 | so->so_rcv.sb_mb = m; |
cc15ab5d | 400 | } |
edebca28 BJ |
401 | so->so_state &= ~SS_RCVATMARK; |
402 | if (so->so_oobmark && cnt > so->so_oobmark) | |
403 | cnt = so->so_oobmark; | |
ce9d8eb4 BJ |
404 | eor = 0; |
405 | do { | |
edebca28 | 406 | len = MIN(m->m_len, cnt); |
ce9d8eb4 BJ |
407 | splx(s); |
408 | iomove(mtod(m, caddr_t), len, B_READ); | |
edebca28 | 409 | cnt -= len; |
ce9d8eb4 BJ |
410 | s = splnet(); |
411 | if (len == m->m_len) { | |
e495e1cc BJ |
412 | eor = (int)m->m_act; |
413 | sbfree(&so->so_rcv, m); | |
414 | so->so_rcv.sb_mb = m->m_next; | |
ce9d8eb4 BJ |
415 | MFREE(m, n); |
416 | } else { | |
417 | m->m_off += len; | |
418 | m->m_len -= len; | |
92a533e6 | 419 | so->so_rcv.sb_cc -= len; |
ce9d8eb4 | 420 | } |
edebca28 | 421 | } while ((m = so->so_rcv.sb_mb) && cnt && !eor); |
ce9d8eb4 BJ |
422 | if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0) |
423 | do { | |
ce9d8eb4 | 424 | if (m == 0) |
cc15ab5d BJ |
425 | panic("receive 3"); |
426 | sbfree(&so->so_rcv, m); | |
ce9d8eb4 BJ |
427 | eor = (int)m->m_act; |
428 | so->so_rcv.sb_mb = m->m_next; | |
429 | MFREE(m, n); | |
cc15ab5d | 430 | m = n; |
ce9d8eb4 | 431 | } while (eor == 0); |
cc15ab5d BJ |
432 | if ((so->so_proto->pr_flags & PR_WANTRCVD) && so->so_pcb) |
433 | (*so->so_proto->pr_usrreq)(so, PRU_RCVD, 0, 0); | |
edebca28 BJ |
434 | if (so->so_oobmark) { |
435 | so->so_oobmark -= u.u_base - base; | |
436 | if (so->so_oobmark == 0) | |
437 | so->so_state |= SS_RCVATMARK; | |
438 | } | |
cc15ab5d | 439 | release: |
ae921915 | 440 | sbunlock(&so->so_rcv); |
cc15ab5d | 441 | splx(s); |
ae921915 | 442 | return (error); |
92a533e6 BJ |
443 | } |
444 | ||
edebca28 BJ |
445 | sohasoutofband(so) |
446 | struct socket *so; | |
447 | { | |
448 | ||
449 | if (so->so_pgrp == 0) | |
450 | return; | |
451 | if (so->so_pgrp > 0) | |
452 | gsignal(so->so_pgrp, SIGURG); | |
0a0f7cbb BJ |
453 | else { |
454 | struct proc *p = pfind(-so->so_pgrp); | |
455 | ||
456 | if (p) | |
457 | psignal(p, SIGURG); | |
458 | } | |
edebca28 BJ |
459 | } |
460 | ||
ae921915 BJ |
461 | /*ARGSUSED*/ |
462 | soioctl(so, cmd, cmdp) | |
92a533e6 BJ |
463 | register struct socket *so; |
464 | int cmd; | |
465 | register caddr_t cmdp; | |
466 | { | |
467 | ||
2b4b57cd | 468 | COUNT(SOIOCTL); |
2156d53c | 469 | switch (cmd) { |
92a533e6 | 470 | |
30b84e26 BJ |
471 | case FIONBIO: { |
472 | int nbio; | |
473 | if (copyin(cmdp, (caddr_t)&nbio, sizeof (nbio))) { | |
474 | u.u_error = EFAULT; | |
475 | return; | |
476 | } | |
477 | if (nbio) | |
478 | so->so_options |= SO_NONBLOCKING; | |
479 | else | |
480 | so->so_options &= ~SO_NONBLOCKING; | |
481 | return; | |
482 | } | |
483 | ||
484 | case FIOASYNC: { | |
485 | int async; | |
486 | if (copyin(cmdp, (caddr_t)&async, sizeof (async))) { | |
487 | u.u_error = EFAULT; | |
488 | return; | |
489 | } | |
490 | if (async) | |
491 | ; | |
492 | else | |
493 | ; | |
494 | return; | |
495 | } | |
496 | ||
497 | case SIOCSKEEP: { | |
498 | int keep; | |
499 | if (copyin(cmdp, (caddr_t)&keep, sizeof (keep))) { | |
500 | u.u_error = EFAULT; | |
501 | return; | |
502 | } | |
503 | if (keep) | |
504 | so->so_options &= ~SO_NOKEEPALIVE; | |
505 | else | |
506 | so->so_options |= SO_NOKEEPALIVE; | |
507 | return; | |
508 | } | |
509 | ||
510 | case SIOCGKEEP: { | |
511 | int keep = (so->so_options & SO_NOKEEPALIVE) == 0; | |
512 | if (copyout((caddr_t)&keep, cmdp, sizeof (keep))) | |
513 | u.u_error = EFAULT; | |
514 | return; | |
515 | } | |
516 | ||
517 | case SIOCSLINGER: { | |
518 | int linger; | |
519 | if (copyin(cmdp, (caddr_t)&linger, sizeof (linger))) { | |
520 | u.u_error = EFAULT; | |
521 | return; | |
522 | } | |
523 | so->so_linger = linger; | |
524 | if (so->so_linger) | |
525 | so->so_options &= ~SO_DONTLINGER; | |
526 | else | |
527 | so->so_options |= SO_DONTLINGER; | |
528 | return; | |
529 | } | |
530 | ||
531 | case SIOCGLINGER: { | |
532 | int linger = so->so_linger; | |
533 | if (copyout((caddr_t)&linger, cmdp, sizeof (linger))) { | |
534 | u.u_error = EFAULT; | |
535 | return; | |
536 | } | |
537 | } | |
edebca28 BJ |
538 | case SIOCSPGRP: { |
539 | int pgrp; | |
540 | if (copyin(cmdp, (caddr_t)&pgrp, sizeof (pgrp))) { | |
541 | u.u_error = EFAULT; | |
542 | return; | |
543 | } | |
544 | so->so_pgrp = pgrp; | |
545 | return; | |
546 | } | |
547 | ||
548 | case SIOCGPGRP: { | |
549 | int pgrp = so->so_pgrp; | |
550 | if (copyout((caddr_t)&pgrp, cmdp, sizeof (pgrp))) { | |
551 | u.u_error = EFAULT; | |
552 | return; | |
553 | } | |
554 | } | |
30b84e26 | 555 | |
b8acc34d BJ |
556 | case SIOCDONE: { |
557 | int flags; | |
558 | if (copyin(cmdp, (caddr_t)&flags, sizeof (flags))) { | |
559 | u.u_error = EFAULT; | |
560 | return; | |
561 | } | |
30b84e26 | 562 | flags++; |
b8acc34d BJ |
563 | if (flags & FREAD) { |
564 | int s = splimp(); | |
565 | socantrcvmore(so); | |
566 | sbflush(&so->so_rcv); | |
785e10b7 | 567 | splx(s); |
b8acc34d BJ |
568 | } |
569 | if (flags & FWRITE) | |
c30cd845 | 570 | u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_SHUTDOWN, (struct mbuf *)0, 0); |
b8acc34d BJ |
571 | return; |
572 | } | |
573 | ||
edebca28 BJ |
574 | case SIOCSENDOOB: { |
575 | char oob; | |
576 | struct mbuf *m; | |
577 | if (copyin(cmdp, (caddr_t)&oob, sizeof (oob))) { | |
578 | u.u_error = EFAULT; | |
579 | return; | |
580 | } | |
581 | m = m_get(M_DONTWAIT); | |
582 | if (m == 0) { | |
583 | u.u_error = ENOBUFS; | |
584 | return; | |
585 | } | |
586 | m->m_off = MMINOFF; | |
587 | m->m_len = 1; | |
588 | *mtod(m, caddr_t) = oob; | |
589 | (*so->so_proto->pr_usrreq)(so, PRU_SENDOOB, m, 0); | |
590 | return; | |
591 | } | |
592 | ||
593 | case SIOCRCVOOB: { | |
594 | struct mbuf *m = m_get(M_DONTWAIT); | |
595 | if (m == 0) { | |
596 | u.u_error = ENOBUFS; | |
597 | return; | |
598 | } | |
599 | m->m_off = MMINOFF; *mtod(m, caddr_t) = 0; | |
600 | (*so->so_proto->pr_usrreq)(so, PRU_RCVOOB, m, 0); | |
601 | if (copyout(mtod(m, caddr_t), cmdp, sizeof (char))) { | |
602 | u.u_error = EFAULT; | |
603 | return; | |
604 | } | |
605 | m_free(m); | |
606 | return; | |
607 | } | |
608 | ||
609 | case SIOCATMARK: { | |
610 | int atmark = (so->so_state&SS_RCVATMARK) != 0; | |
611 | if (copyout((caddr_t)&atmark, cmdp, sizeof (atmark))) { | |
612 | u.u_error = EFAULT; | |
613 | return; | |
614 | } | |
615 | return; | |
616 | } | |
5e1eeba0 | 617 | /* type/protocol specific ioctls */ |
92a533e6 | 618 | } |
5e1eeba0 | 619 | u.u_error = EOPNOTSUPP; |
ce9d8eb4 | 620 | } |