Commit | Line | Data |
---|---|---|
c7256358 | 1 | /* uipc_socket.c 4.49 82/09/04 */ |
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 | ||
c7256358 | 275 | u.u_ru.ru_msgsnd++; |
cc15ab5d | 276 | again: |
0f90f987 BJ |
277 | s = splnet(); |
278 | if (so->so_state & SS_CANTSENDMORE) { | |
279 | psignal(u.u_procp, SIGPIPE); | |
280 | snderr(EPIPE); | |
281 | } | |
4c078bb2 BJ |
282 | if (so->so_error) { |
283 | error = so->so_error; | |
0f90f987 | 284 | so->so_error = 0; /* ??? */ |
4c078bb2 BJ |
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); |
0f90f987 | 296 | top = 0; |
cc15ab5d BJ |
297 | if (error) { |
298 | splx(s); | |
ce9d8eb4 BJ |
299 | goto release; |
300 | } | |
cc15ab5d | 301 | mp = ⊤ |
ce9d8eb4 | 302 | } |
5699bf69 | 303 | if (uio->uio_resid == 0) { |
b91acce4 BJ |
304 | splx(s); |
305 | goto release; | |
306 | } | |
50fc8df6 | 307 | space = sbspace(&so->so_snd); |
5699bf69 | 308 | if (space <= 0 || sosendallatonce(so) && space < uio->uio_resid) { |
62364f0e | 309 | if (so->so_state & SS_NBIO) |
cc15ab5d BJ |
310 | snderr(EWOULDBLOCK); |
311 | sbunlock(&so->so_snd); | |
312 | sbwait(&so->so_snd); | |
313 | splx(s); | |
0f90f987 | 314 | goto restart; |
ce9d8eb4 | 315 | } |
cc15ab5d | 316 | splx(s); |
5699bf69 BJ |
317 | while (uio->uio_resid > 0 && space > 0) { |
318 | register struct iovec *iov = uio->uio_iov; | |
319 | ||
320 | if (iov->iov_len == 0) { | |
321 | uio->uio_iov++; | |
322 | uio->uio_iovcnt--; | |
323 | if (uio->uio_iovcnt < 0) | |
324 | panic("sosend"); | |
325 | continue; | |
326 | } | |
cc15ab5d BJ |
327 | MGET(m, 1); |
328 | if (m == NULL) { | |
0f90f987 | 329 | error = ENOBUFS; /* SIGPIPE? */ |
cc15ab5d | 330 | goto release; |
ce9d8eb4 | 331 | } |
5699bf69 | 332 | if (iov->iov_len >= CLBYTES && space >= CLBYTES) { |
cc15ab5d | 333 | register struct mbuf *p; |
c5ff2e32 | 334 | MCLGET(p, 1); |
cc15ab5d BJ |
335 | if (p == 0) |
336 | goto nopages; | |
337 | m->m_off = (int)p - (int)m; | |
c5ff2e32 | 338 | len = CLBYTES; |
cc15ab5d | 339 | } else { |
ce9d8eb4 | 340 | nopages: |
cc15ab5d | 341 | m->m_off = MMINOFF; |
5699bf69 | 342 | len = MIN(MLEN, iov->iov_len); |
ce9d8eb4 | 343 | } |
5699bf69 | 344 | uiomove(mtod(m, caddr_t), len, UIO_WRITE, uio); |
cc15ab5d BJ |
345 | m->m_len = len; |
346 | *mp = m; | |
347 | mp = &m->m_next; | |
50fc8df6 | 348 | space = sbspace(&so->so_snd); |
ce9d8eb4 | 349 | } |
cc15ab5d BJ |
350 | goto again; |
351 | ||
ce9d8eb4 | 352 | release: |
cc15ab5d | 353 | sbunlock(&so->so_snd); |
0f90f987 BJ |
354 | if (top) |
355 | m_freem(top); | |
ce9d8eb4 BJ |
356 | return (error); |
357 | } | |
358 | ||
32a43ee2 | 359 | soreceive(so, asa, uio) |
ce9d8eb4 | 360 | register struct socket *so; |
2b4b57cd | 361 | struct sockaddr *asa; |
32a43ee2 | 362 | struct uio *uio; |
ce9d8eb4 | 363 | { |
32a43ee2 | 364 | register struct iovec *iov; |
ce9d8eb4 | 365 | register struct mbuf *m, *n; |
ae921915 | 366 | u_int len; |
5699bf69 | 367 | int eor, s, error = 0; |
ce9d8eb4 | 368 | |
cc15ab5d BJ |
369 | restart: |
370 | sblock(&so->so_rcv); | |
371 | s = splnet(); | |
372 | ||
373 | #define rcverr(errno) { error = errno; splx(s); goto release; } | |
ce9d8eb4 | 374 | if (so->so_rcv.sb_cc == 0) { |
4c078bb2 BJ |
375 | if (so->so_error) { |
376 | error = so->so_error; | |
377 | so->so_error = 0; | |
378 | splx(s); | |
379 | goto release; | |
380 | } | |
cc15ab5d BJ |
381 | if (so->so_state & SS_CANTRCVMORE) { |
382 | splx(s); | |
383 | goto release; | |
384 | } | |
196d84fd BJ |
385 | if ((so->so_state & SS_ISCONNECTED) == 0 && |
386 | (so->so_proto->pr_flags & PR_CONNREQUIRED)) | |
387 | rcverr(ENOTCONN); | |
62364f0e | 388 | if (so->so_state & SS_NBIO) |
4c078bb2 | 389 | rcverr(EWOULDBLOCK); |
cc15ab5d | 390 | sbunlock(&so->so_rcv); |
2752c877 | 391 | sbwait(&so->so_rcv); |
a4f6d93d | 392 | splx(s); |
cc15ab5d | 393 | goto restart; |
ce9d8eb4 | 394 | } |
c7256358 | 395 | u.u_ru.ru_msgrcv++; |
92a533e6 | 396 | m = so->so_rcv.sb_mb; |
ce9d8eb4 BJ |
397 | if (m == 0) |
398 | panic("receive"); | |
b031e888 | 399 | if (so->so_proto->pr_flags & PR_ADDR) { |
b031e888 BJ |
400 | if (m->m_len != sizeof (struct sockaddr)) |
401 | panic("soreceive addr"); | |
402 | if (asa) | |
403 | bcopy(mtod(m, caddr_t), (caddr_t)asa, sizeof (*asa)); | |
b031e888 BJ |
404 | so->so_rcv.sb_cc -= m->m_len; |
405 | so->so_rcv.sb_mbcnt -= MSIZE; | |
50fc8df6 | 406 | m = m_free(m); |
cc15ab5d BJ |
407 | if (m == 0) |
408 | panic("receive 2"); | |
50fc8df6 | 409 | so->so_rcv.sb_mb = m; |
cc15ab5d | 410 | } |
ce9d8eb4 BJ |
411 | eor = 0; |
412 | do { | |
5699bf69 | 413 | if (uio->uio_resid <= 0) |
32a43ee2 | 414 | break; |
5699bf69 | 415 | len = uio->uio_resid; |
32a43ee2 BJ |
416 | so->so_state &= ~SS_RCVATMARK; |
417 | if (so->so_oobmark && len > so->so_oobmark) | |
418 | len = so->so_oobmark; | |
419 | if (len > m->m_len) | |
420 | len = m->m_len; | |
ce9d8eb4 | 421 | splx(s); |
5699bf69 | 422 | uiomove(mtod(m, caddr_t), (int)len, UIO_READ, uio); |
ce9d8eb4 BJ |
423 | s = splnet(); |
424 | if (len == m->m_len) { | |
e495e1cc BJ |
425 | eor = (int)m->m_act; |
426 | sbfree(&so->so_rcv, m); | |
427 | so->so_rcv.sb_mb = m->m_next; | |
ce9d8eb4 BJ |
428 | MFREE(m, n); |
429 | } else { | |
430 | m->m_off += len; | |
431 | m->m_len -= len; | |
92a533e6 | 432 | so->so_rcv.sb_cc -= len; |
ce9d8eb4 | 433 | } |
32a43ee2 BJ |
434 | if (so->so_oobmark) { |
435 | so->so_oobmark -= len; | |
436 | if (so->so_oobmark == 0) { | |
437 | so->so_state |= SS_RCVATMARK; | |
438 | break; | |
439 | } | |
440 | } | |
441 | } while ((m = so->so_rcv.sb_mb) && !eor); | |
ce9d8eb4 BJ |
442 | if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0) |
443 | do { | |
ce9d8eb4 | 444 | if (m == 0) |
cc15ab5d BJ |
445 | panic("receive 3"); |
446 | sbfree(&so->so_rcv, m); | |
ce9d8eb4 BJ |
447 | eor = (int)m->m_act; |
448 | so->so_rcv.sb_mb = m->m_next; | |
449 | MFREE(m, n); | |
cc15ab5d | 450 | m = n; |
ce9d8eb4 | 451 | } while (eor == 0); |
cc15ab5d BJ |
452 | if ((so->so_proto->pr_flags & PR_WANTRCVD) && so->so_pcb) |
453 | (*so->so_proto->pr_usrreq)(so, PRU_RCVD, 0, 0); | |
cc15ab5d | 454 | release: |
ae921915 | 455 | sbunlock(&so->so_rcv); |
cc15ab5d | 456 | splx(s); |
ae921915 | 457 | return (error); |
92a533e6 BJ |
458 | } |
459 | ||
edebca28 BJ |
460 | sohasoutofband(so) |
461 | struct socket *so; | |
462 | { | |
463 | ||
464 | if (so->so_pgrp == 0) | |
465 | return; | |
466 | if (so->so_pgrp > 0) | |
467 | gsignal(so->so_pgrp, SIGURG); | |
0a0f7cbb BJ |
468 | else { |
469 | struct proc *p = pfind(-so->so_pgrp); | |
470 | ||
471 | if (p) | |
472 | psignal(p, SIGURG); | |
473 | } | |
edebca28 BJ |
474 | } |
475 | ||
ae921915 | 476 | /*ARGSUSED*/ |
4b72e2f9 | 477 | soioctl(so, cmd, data) |
92a533e6 BJ |
478 | register struct socket *so; |
479 | int cmd; | |
4b72e2f9 | 480 | register char *data; |
92a533e6 BJ |
481 | { |
482 | ||
2156d53c | 483 | switch (cmd) { |
92a533e6 | 484 | |
4b72e2f9 SL |
485 | case FIONBIO: |
486 | if (*(int *)data) | |
62364f0e | 487 | so->so_state |= SS_NBIO; |
30b84e26 | 488 | else |
62364f0e | 489 | so->so_state &= ~SS_NBIO; |
30b84e26 | 490 | return; |
30b84e26 | 491 | |
4b72e2f9 SL |
492 | case FIOASYNC: |
493 | if (*(int *)data) | |
62364f0e | 494 | so->so_state |= SS_ASYNC; |
30b84e26 | 495 | else |
62364f0e | 496 | so->so_state &= ~SS_ASYNC; |
30b84e26 | 497 | return; |
30b84e26 | 498 | |
4b72e2f9 SL |
499 | case SIOCSKEEP: |
500 | if (*(int *)data) | |
9d2f171f | 501 | so->so_options &= ~SO_KEEPALIVE; |
90aaea96 BJ |
502 | else |
503 | so->so_options |= SO_KEEPALIVE; | |
30b84e26 | 504 | return; |
30b84e26 | 505 | |
4b72e2f9 SL |
506 | case SIOCGKEEP: |
507 | *(int *)data = (so->so_options & SO_KEEPALIVE) != 0; | |
30b84e26 | 508 | return; |
30b84e26 | 509 | |
4b72e2f9 SL |
510 | case SIOCSLINGER: |
511 | so->so_linger = *(int *)data; | |
30b84e26 BJ |
512 | if (so->so_linger) |
513 | so->so_options &= ~SO_DONTLINGER; | |
514 | else | |
515 | so->so_options |= SO_DONTLINGER; | |
516 | return; | |
30b84e26 | 517 | |
4b72e2f9 SL |
518 | case SIOCGLINGER: |
519 | *(int *)data = so->so_linger; | |
edebca28 | 520 | return; |
edebca28 | 521 | |
4b72e2f9 SL |
522 | case SIOCSPGRP: |
523 | so->so_pgrp = *(int *)data; | |
524 | return; | |
525 | ||
526 | case SIOCGPGRP: | |
527 | *(int *)data = so->so_pgrp; | |
528 | return; | |
30b84e26 | 529 | |
b8acc34d | 530 | case SIOCDONE: { |
4b72e2f9 SL |
531 | int flags = *(int *)data; |
532 | ||
30b84e26 | 533 | flags++; |
b8acc34d BJ |
534 | if (flags & FREAD) { |
535 | int s = splimp(); | |
536 | socantrcvmore(so); | |
537 | sbflush(&so->so_rcv); | |
785e10b7 | 538 | splx(s); |
b8acc34d BJ |
539 | } |
540 | if (flags & FWRITE) | |
c30cd845 | 541 | u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_SHUTDOWN, (struct mbuf *)0, 0); |
b8acc34d BJ |
542 | return; |
543 | } | |
544 | ||
edebca28 | 545 | case SIOCSENDOOB: { |
4b72e2f9 | 546 | char oob = *(char *)data; |
edebca28 | 547 | struct mbuf *m; |
4b72e2f9 | 548 | |
edebca28 BJ |
549 | m = m_get(M_DONTWAIT); |
550 | if (m == 0) { | |
551 | u.u_error = ENOBUFS; | |
552 | return; | |
553 | } | |
554 | m->m_off = MMINOFF; | |
4b72e2f9 SL |
555 | m->m_len = sizeof (char); |
556 | *mtod(m, char *) = oob; | |
edebca28 BJ |
557 | (*so->so_proto->pr_usrreq)(so, PRU_SENDOOB, m, 0); |
558 | return; | |
559 | } | |
560 | ||
561 | case SIOCRCVOOB: { | |
562 | struct mbuf *m = m_get(M_DONTWAIT); | |
4b72e2f9 | 563 | |
edebca28 BJ |
564 | if (m == 0) { |
565 | u.u_error = ENOBUFS; | |
566 | return; | |
567 | } | |
568 | m->m_off = MMINOFF; *mtod(m, caddr_t) = 0; | |
569 | (*so->so_proto->pr_usrreq)(so, PRU_RCVOOB, m, 0); | |
4b72e2f9 SL |
570 | *(char *)data = *mtod(m, char *); |
571 | (void) m_free(m); | |
edebca28 BJ |
572 | return; |
573 | } | |
574 | ||
4b72e2f9 SL |
575 | case SIOCATMARK: |
576 | *(int *)data = (so->so_state&SS_RCVATMARK) != 0; | |
edebca28 | 577 | return; |
2a4251c4 SL |
578 | |
579 | /* routing table update calls */ | |
580 | case SIOCADDRT: | |
581 | case SIOCDELRT: | |
2a4251c4 SL |
582 | if (!suser()) |
583 | return; | |
4b72e2f9 | 584 | u.u_error = rtrequest(cmd, (struct rtentry *)data); |
2a4251c4 | 585 | return; |
2a4251c4 | 586 | |
5e1eeba0 | 587 | /* type/protocol specific ioctls */ |
92a533e6 | 588 | } |
5e1eeba0 | 589 | u.u_error = EOPNOTSUPP; |
ce9d8eb4 | 590 | } |