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