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