Commit | Line | Data |
---|---|---|
90aaea96 | 1 | /* socket.c 4.43 82/07/21 */ |
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" |
ce9d8eb4 | 20 | |
ce9d8eb4 | 21 | /* |
cc15ab5d BJ |
22 | * Socket support routines. |
23 | * | |
24 | * DEAL WITH INTERRUPT NOTIFICATION. | |
ce9d8eb4 | 25 | */ |
ce9d8eb4 BJ |
26 | |
27 | /* | |
28 | * Create a socket. | |
29 | */ | |
2b4b57cd | 30 | socreate(aso, type, asp, asa, options) |
ce9d8eb4 BJ |
31 | struct socket **aso; |
32 | int type; | |
2b4b57cd BJ |
33 | struct sockproto *asp; |
34 | struct sockaddr *asa; | |
92a533e6 | 35 | int options; |
ce9d8eb4 BJ |
36 | { |
37 | register struct protosw *prp; | |
38 | register struct socket *so; | |
39 | struct mbuf *m; | |
cc15ab5d | 40 | int pf, proto, error; |
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; |
90aaea96 BJ |
73 | if (options & SO_ACCEPTCONN) { |
74 | so->so_q = so; | |
75 | so->so_q0 = so; | |
76 | so->so_qlimit = (so->so_options & SO_NEWFDONCONN) ? 5 : 1; | |
77 | } | |
62364f0e BJ |
78 | so->so_state = 0; |
79 | if (u.u_uid == 0) | |
80 | so->so_state = SS_PRIV; | |
ce9d8eb4 BJ |
81 | |
82 | /* | |
cc15ab5d BJ |
83 | * Attach protocol to socket, initializing |
84 | * and reserving resources. | |
ce9d8eb4 BJ |
85 | */ |
86 | so->so_proto = prp; | |
b91acce4 BJ |
87 | error = (*prp->pr_usrreq)(so, PRU_ATTACH, 0, asa); |
88 | if (error) { | |
90aaea96 | 89 | so->so_state |= SS_NOFDREF; |
de48daf3 | 90 | sofree(so); |
cc15ab5d | 91 | return (error); |
ce9d8eb4 BJ |
92 | } |
93 | *aso = so; | |
94 | return (0); | |
95 | } | |
96 | ||
ae921915 BJ |
97 | sofree(so) |
98 | struct socket *so; | |
99 | { | |
100 | ||
90aaea96 BJ |
101 | if (so->so_head) { |
102 | if (!soqremque(so, 0) && !soqremque(so, 1)) | |
103 | panic("sofree dq"); | |
104 | so->so_head = 0; | |
105 | } | |
106 | if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0) | |
4ad99bae BJ |
107 | return; |
108 | sbrelease(&so->so_snd); | |
109 | sbrelease(&so->so_rcv); | |
2752c877 | 110 | (void) m_free(dtom(so)); |
ae921915 BJ |
111 | } |
112 | ||
92a533e6 | 113 | /* |
cc15ab5d BJ |
114 | * Close a socket on last file table reference removal. |
115 | * Initiate disconnect if connected. | |
116 | * Free socket when disconnect complete. | |
92a533e6 | 117 | */ |
89900a09 | 118 | soclose(so, exiting) |
92a533e6 | 119 | register struct socket *so; |
89900a09 | 120 | int exiting; |
92a533e6 | 121 | { |
cc15ab5d | 122 | int s = splnet(); /* conservative */ |
90aaea96 | 123 | register struct socket *so2; |
cc15ab5d | 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 | */ | |
2b4b57cd | 254 | sosend(so, asa) |
ce9d8eb4 | 255 | register struct socket *so; |
2b4b57cd | 256 | struct sockaddr *asa; |
ce9d8eb4 | 257 | { |
cc15ab5d BJ |
258 | struct mbuf *top = 0; |
259 | register struct mbuf *m, **mp = ⊤ | |
ae921915 BJ |
260 | register u_int len; |
261 | int error = 0, space, s; | |
ce9d8eb4 | 262 | |
cc15ab5d BJ |
263 | if (sosendallatonce(so) && u.u_count > so->so_snd.sb_hiwat) |
264 | return (EMSGSIZE); | |
0f90f987 BJ |
265 | #ifdef notdef |
266 | /* NEED TO PREVENT BUSY WAITING IN SELECT FOR WRITING */ | |
62364f0e | 267 | if ((so->so_snd.sb_flags & SB_LOCK) && (so->so_state & SS_NBIO)) |
cc15ab5d | 268 | return (EWOULDBLOCK); |
0f90f987 BJ |
269 | #endif |
270 | restart: | |
cc15ab5d BJ |
271 | sblock(&so->so_snd); |
272 | #define snderr(errno) { error = errno; splx(s); goto release; } | |
273 | ||
cc15ab5d | 274 | again: |
0f90f987 BJ |
275 | s = splnet(); |
276 | if (so->so_state & SS_CANTSENDMORE) { | |
277 | psignal(u.u_procp, SIGPIPE); | |
278 | snderr(EPIPE); | |
279 | } | |
4c078bb2 BJ |
280 | if (so->so_error) { |
281 | error = so->so_error; | |
0f90f987 | 282 | so->so_error = 0; /* ??? */ |
4c078bb2 BJ |
283 | splx(s); |
284 | goto release; | |
285 | } | |
cc15ab5d BJ |
286 | if ((so->so_state & SS_ISCONNECTED) == 0) { |
287 | if (so->so_proto->pr_flags & PR_CONNREQUIRED) | |
288 | snderr(ENOTCONN); | |
2b4b57cd | 289 | if (asa == 0) |
cc15ab5d BJ |
290 | snderr(EDESTADDRREQ); |
291 | } | |
cc15ab5d | 292 | if (top) { |
2b4b57cd | 293 | error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, top, asa); |
0f90f987 | 294 | top = 0; |
cc15ab5d BJ |
295 | if (error) { |
296 | splx(s); | |
ce9d8eb4 BJ |
297 | goto release; |
298 | } | |
cc15ab5d | 299 | mp = ⊤ |
ce9d8eb4 | 300 | } |
b91acce4 BJ |
301 | if (u.u_count == 0) { |
302 | splx(s); | |
303 | goto release; | |
304 | } | |
50fc8df6 | 305 | space = sbspace(&so->so_snd); |
6fa47729 | 306 | if (space <= 0 || sosendallatonce(so) && space < u.u_count) { |
62364f0e | 307 | if (so->so_state & SS_NBIO) |
cc15ab5d BJ |
308 | snderr(EWOULDBLOCK); |
309 | sbunlock(&so->so_snd); | |
310 | sbwait(&so->so_snd); | |
311 | splx(s); | |
0f90f987 | 312 | goto restart; |
ce9d8eb4 | 313 | } |
cc15ab5d | 314 | splx(s); |
50fc8df6 | 315 | while (u.u_count && space > 0) { |
cc15ab5d BJ |
316 | MGET(m, 1); |
317 | if (m == NULL) { | |
0f90f987 | 318 | error = ENOBUFS; /* SIGPIPE? */ |
cc15ab5d | 319 | goto release; |
ce9d8eb4 | 320 | } |
c5ff2e32 | 321 | if (u.u_count >= CLBYTES && space >= CLBYTES) { |
cc15ab5d | 322 | register struct mbuf *p; |
c5ff2e32 | 323 | MCLGET(p, 1); |
cc15ab5d BJ |
324 | if (p == 0) |
325 | goto nopages; | |
326 | m->m_off = (int)p - (int)m; | |
c5ff2e32 | 327 | len = CLBYTES; |
cc15ab5d | 328 | } else { |
ce9d8eb4 | 329 | nopages: |
cc15ab5d BJ |
330 | m->m_off = MMINOFF; |
331 | len = MIN(MLEN, u.u_count); | |
ce9d8eb4 | 332 | } |
cc15ab5d BJ |
333 | iomove(mtod(m, caddr_t), len, B_WRITE); |
334 | m->m_len = len; | |
335 | *mp = m; | |
336 | mp = &m->m_next; | |
50fc8df6 | 337 | space = sbspace(&so->so_snd); |
ce9d8eb4 | 338 | } |
cc15ab5d BJ |
339 | goto again; |
340 | ||
ce9d8eb4 | 341 | release: |
cc15ab5d | 342 | sbunlock(&so->so_snd); |
0f90f987 BJ |
343 | if (top) |
344 | m_freem(top); | |
ce9d8eb4 BJ |
345 | return (error); |
346 | } | |
347 | ||
2b4b57cd | 348 | soreceive(so, asa) |
ce9d8eb4 | 349 | register struct socket *so; |
2b4b57cd | 350 | struct sockaddr *asa; |
ce9d8eb4 BJ |
351 | { |
352 | register struct mbuf *m, *n; | |
ae921915 | 353 | u_int len; |
edebca28 BJ |
354 | int eor, s, error = 0, cnt = u.u_count; |
355 | caddr_t base = u.u_base; | |
ce9d8eb4 | 356 | |
cc15ab5d BJ |
357 | restart: |
358 | sblock(&so->so_rcv); | |
359 | s = splnet(); | |
360 | ||
361 | #define rcverr(errno) { error = errno; splx(s); goto release; } | |
ce9d8eb4 | 362 | if (so->so_rcv.sb_cc == 0) { |
4c078bb2 BJ |
363 | if (so->so_error) { |
364 | error = so->so_error; | |
365 | so->so_error = 0; | |
366 | splx(s); | |
367 | goto release; | |
368 | } | |
cc15ab5d BJ |
369 | if (so->so_state & SS_CANTRCVMORE) { |
370 | splx(s); | |
371 | goto release; | |
372 | } | |
196d84fd BJ |
373 | if ((so->so_state & SS_ISCONNECTED) == 0 && |
374 | (so->so_proto->pr_flags & PR_CONNREQUIRED)) | |
375 | rcverr(ENOTCONN); | |
62364f0e | 376 | if (so->so_state & SS_NBIO) |
4c078bb2 | 377 | rcverr(EWOULDBLOCK); |
cc15ab5d | 378 | sbunlock(&so->so_rcv); |
2752c877 | 379 | sbwait(&so->so_rcv); |
a4f6d93d | 380 | splx(s); |
cc15ab5d | 381 | goto restart; |
ce9d8eb4 | 382 | } |
92a533e6 | 383 | m = so->so_rcv.sb_mb; |
ce9d8eb4 BJ |
384 | if (m == 0) |
385 | panic("receive"); | |
b031e888 | 386 | if (so->so_proto->pr_flags & PR_ADDR) { |
b031e888 BJ |
387 | if (m->m_len != sizeof (struct sockaddr)) |
388 | panic("soreceive addr"); | |
389 | if (asa) | |
390 | bcopy(mtod(m, caddr_t), (caddr_t)asa, sizeof (*asa)); | |
b031e888 BJ |
391 | so->so_rcv.sb_cc -= m->m_len; |
392 | so->so_rcv.sb_mbcnt -= MSIZE; | |
50fc8df6 | 393 | m = m_free(m); |
cc15ab5d BJ |
394 | if (m == 0) |
395 | panic("receive 2"); | |
50fc8df6 | 396 | so->so_rcv.sb_mb = m; |
cc15ab5d | 397 | } |
edebca28 BJ |
398 | so->so_state &= ~SS_RCVATMARK; |
399 | if (so->so_oobmark && cnt > so->so_oobmark) | |
400 | cnt = so->so_oobmark; | |
ce9d8eb4 BJ |
401 | eor = 0; |
402 | do { | |
edebca28 | 403 | len = MIN(m->m_len, cnt); |
ce9d8eb4 BJ |
404 | splx(s); |
405 | iomove(mtod(m, caddr_t), len, B_READ); | |
edebca28 | 406 | cnt -= len; |
ce9d8eb4 BJ |
407 | s = splnet(); |
408 | if (len == m->m_len) { | |
e495e1cc BJ |
409 | eor = (int)m->m_act; |
410 | sbfree(&so->so_rcv, m); | |
411 | so->so_rcv.sb_mb = m->m_next; | |
ce9d8eb4 BJ |
412 | MFREE(m, n); |
413 | } else { | |
414 | m->m_off += len; | |
415 | m->m_len -= len; | |
92a533e6 | 416 | so->so_rcv.sb_cc -= len; |
ce9d8eb4 | 417 | } |
edebca28 | 418 | } while ((m = so->so_rcv.sb_mb) && cnt && !eor); |
ce9d8eb4 BJ |
419 | if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0) |
420 | do { | |
ce9d8eb4 | 421 | if (m == 0) |
cc15ab5d BJ |
422 | panic("receive 3"); |
423 | sbfree(&so->so_rcv, m); | |
ce9d8eb4 BJ |
424 | eor = (int)m->m_act; |
425 | so->so_rcv.sb_mb = m->m_next; | |
426 | MFREE(m, n); | |
cc15ab5d | 427 | m = n; |
ce9d8eb4 | 428 | } while (eor == 0); |
cc15ab5d BJ |
429 | if ((so->so_proto->pr_flags & PR_WANTRCVD) && so->so_pcb) |
430 | (*so->so_proto->pr_usrreq)(so, PRU_RCVD, 0, 0); | |
edebca28 BJ |
431 | if (so->so_oobmark) { |
432 | so->so_oobmark -= u.u_base - base; | |
433 | if (so->so_oobmark == 0) | |
434 | so->so_state |= SS_RCVATMARK; | |
435 | } | |
cc15ab5d | 436 | release: |
ae921915 | 437 | sbunlock(&so->so_rcv); |
cc15ab5d | 438 | splx(s); |
ae921915 | 439 | return (error); |
92a533e6 BJ |
440 | } |
441 | ||
edebca28 BJ |
442 | sohasoutofband(so) |
443 | struct socket *so; | |
444 | { | |
445 | ||
446 | if (so->so_pgrp == 0) | |
447 | return; | |
448 | if (so->so_pgrp > 0) | |
449 | gsignal(so->so_pgrp, SIGURG); | |
0a0f7cbb BJ |
450 | else { |
451 | struct proc *p = pfind(-so->so_pgrp); | |
452 | ||
453 | if (p) | |
454 | psignal(p, SIGURG); | |
455 | } | |
edebca28 BJ |
456 | } |
457 | ||
ae921915 BJ |
458 | /*ARGSUSED*/ |
459 | soioctl(so, cmd, cmdp) | |
92a533e6 BJ |
460 | register struct socket *so; |
461 | int cmd; | |
462 | register caddr_t cmdp; | |
463 | { | |
464 | ||
2156d53c | 465 | switch (cmd) { |
92a533e6 | 466 | |
30b84e26 BJ |
467 | case FIONBIO: { |
468 | int nbio; | |
469 | if (copyin(cmdp, (caddr_t)&nbio, sizeof (nbio))) { | |
470 | u.u_error = EFAULT; | |
471 | return; | |
472 | } | |
473 | if (nbio) | |
62364f0e | 474 | so->so_state |= SS_NBIO; |
30b84e26 | 475 | else |
62364f0e | 476 | so->so_state &= ~SS_NBIO; |
30b84e26 BJ |
477 | return; |
478 | } | |
479 | ||
480 | case FIOASYNC: { | |
481 | int async; | |
482 | if (copyin(cmdp, (caddr_t)&async, sizeof (async))) { | |
483 | u.u_error = EFAULT; | |
484 | return; | |
485 | } | |
486 | if (async) | |
62364f0e | 487 | so->so_state |= SS_ASYNC; |
30b84e26 | 488 | else |
62364f0e | 489 | so->so_state &= ~SS_ASYNC; |
30b84e26 BJ |
490 | return; |
491 | } | |
492 | ||
493 | case SIOCSKEEP: { | |
494 | int keep; | |
495 | if (copyin(cmdp, (caddr_t)&keep, sizeof (keep))) { | |
496 | u.u_error = EFAULT; | |
497 | return; | |
498 | } | |
499 | if (keep) | |
9d2f171f | 500 | so->so_options &= ~SO_KEEPALIVE; |
90aaea96 BJ |
501 | else |
502 | so->so_options |= SO_KEEPALIVE; | |
30b84e26 BJ |
503 | return; |
504 | } | |
505 | ||
506 | case SIOCGKEEP: { | |
62364f0e | 507 | int keep = (so->so_options & SO_KEEPALIVE) != 0; |
30b84e26 BJ |
508 | if (copyout((caddr_t)&keep, cmdp, sizeof (keep))) |
509 | u.u_error = EFAULT; | |
510 | return; | |
511 | } | |
512 | ||
513 | case SIOCSLINGER: { | |
514 | int linger; | |
515 | if (copyin(cmdp, (caddr_t)&linger, sizeof (linger))) { | |
516 | u.u_error = EFAULT; | |
517 | return; | |
518 | } | |
519 | so->so_linger = linger; | |
520 | if (so->so_linger) | |
521 | so->so_options &= ~SO_DONTLINGER; | |
522 | else | |
523 | so->so_options |= SO_DONTLINGER; | |
524 | return; | |
525 | } | |
526 | ||
527 | case SIOCGLINGER: { | |
528 | int linger = so->so_linger; | |
529 | if (copyout((caddr_t)&linger, cmdp, sizeof (linger))) { | |
530 | u.u_error = EFAULT; | |
531 | return; | |
532 | } | |
533 | } | |
edebca28 BJ |
534 | case SIOCSPGRP: { |
535 | int pgrp; | |
536 | if (copyin(cmdp, (caddr_t)&pgrp, sizeof (pgrp))) { | |
537 | u.u_error = EFAULT; | |
538 | return; | |
539 | } | |
540 | so->so_pgrp = pgrp; | |
541 | return; | |
542 | } | |
543 | ||
544 | case SIOCGPGRP: { | |
545 | int pgrp = so->so_pgrp; | |
546 | if (copyout((caddr_t)&pgrp, cmdp, sizeof (pgrp))) { | |
547 | u.u_error = EFAULT; | |
548 | return; | |
549 | } | |
550 | } | |
30b84e26 | 551 | |
b8acc34d BJ |
552 | case SIOCDONE: { |
553 | int flags; | |
554 | if (copyin(cmdp, (caddr_t)&flags, sizeof (flags))) { | |
555 | u.u_error = EFAULT; | |
556 | return; | |
557 | } | |
30b84e26 | 558 | flags++; |
b8acc34d BJ |
559 | if (flags & FREAD) { |
560 | int s = splimp(); | |
561 | socantrcvmore(so); | |
562 | sbflush(&so->so_rcv); | |
785e10b7 | 563 | splx(s); |
b8acc34d BJ |
564 | } |
565 | if (flags & FWRITE) | |
c30cd845 | 566 | u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_SHUTDOWN, (struct mbuf *)0, 0); |
b8acc34d BJ |
567 | return; |
568 | } | |
569 | ||
edebca28 BJ |
570 | case SIOCSENDOOB: { |
571 | char oob; | |
572 | struct mbuf *m; | |
573 | if (copyin(cmdp, (caddr_t)&oob, sizeof (oob))) { | |
574 | u.u_error = EFAULT; | |
575 | return; | |
576 | } | |
577 | m = m_get(M_DONTWAIT); | |
578 | if (m == 0) { | |
579 | u.u_error = ENOBUFS; | |
580 | return; | |
581 | } | |
582 | m->m_off = MMINOFF; | |
583 | m->m_len = 1; | |
584 | *mtod(m, caddr_t) = oob; | |
585 | (*so->so_proto->pr_usrreq)(so, PRU_SENDOOB, m, 0); | |
586 | return; | |
587 | } | |
588 | ||
589 | case SIOCRCVOOB: { | |
590 | struct mbuf *m = m_get(M_DONTWAIT); | |
591 | if (m == 0) { | |
592 | u.u_error = ENOBUFS; | |
593 | return; | |
594 | } | |
595 | m->m_off = MMINOFF; *mtod(m, caddr_t) = 0; | |
596 | (*so->so_proto->pr_usrreq)(so, PRU_RCVOOB, m, 0); | |
597 | if (copyout(mtod(m, caddr_t), cmdp, sizeof (char))) { | |
598 | u.u_error = EFAULT; | |
599 | return; | |
600 | } | |
601 | m_free(m); | |
602 | return; | |
603 | } | |
604 | ||
605 | case SIOCATMARK: { | |
606 | int atmark = (so->so_state&SS_RCVATMARK) != 0; | |
607 | if (copyout((caddr_t)&atmark, cmdp, sizeof (atmark))) { | |
608 | u.u_error = EFAULT; | |
609 | return; | |
610 | } | |
611 | return; | |
612 | } | |
2a4251c4 SL |
613 | |
614 | /* routing table update calls */ | |
615 | case SIOCADDRT: | |
616 | case SIOCDELRT: | |
617 | case SIOCCHGRT: { | |
618 | struct rtentry route; | |
2a4251c4 SL |
619 | if (!suser()) |
620 | return; | |
2a4251c4 SL |
621 | if (copyin(cmdp, (caddr_t)&route, sizeof (route))) { |
622 | u.u_error = EFAULT; | |
623 | return; | |
624 | } | |
625 | u.u_error = rtrequest(cmd, &route); | |
626 | return; | |
627 | } | |
628 | ||
5e1eeba0 | 629 | /* type/protocol specific ioctls */ |
92a533e6 | 630 | } |
5e1eeba0 | 631 | u.u_error = EOPNOTSUPP; |
ce9d8eb4 | 632 | } |