1: /*
   2:  * Copyright (c) 1982, 1986 Regents of the University of California.
   3:  * All rights reserved.
   4:  *
   5:  * Redistribution and use in source and binary forms are permitted
   6:  * provided that this notice is preserved and that due credit is given
   7:  * to the University of California at Berkeley. The name of the University
   8:  * may not be used to endorse or promote products derived from this
   9:  * software without specific prior written permission. This software
  10:  * is provided ``as is'' without express or implied warranty.
  11:  *
  12:  *	@(#)uipc_socket.c	7.8.1 (2.11BSD GTE) 11/26/94
  13:  */
  14: 
  15: #include "param.h"
  16: #ifdef INET
  17: #include "user.h"
  18: #include "proc.h"
  19: #include "file.h"
  20: #include "mbuf.h"
  21: #include "domain.h"
  22: #include "protosw.h"
  23: #include "socket.h"
  24: #include "socketvar.h"
  25: #include "uio.h"
  26: 
  27: /*
  28:  * Socket operation routines.
  29:  * These routines are called by the routines in
  30:  * sys_socket.c or from a system process, and
  31:  * implement the semantics of socket operations by
  32:  * switching out to the protocol specific routines.
  33:  *
  34:  * TODO:
  35:  *	test socketpair
  36:  *	clean up async
  37:  *	out-of-band is a kludge
  38:  */
  39: /*ARGSUSED*/
  40: socreate(dom, aso, type, proto)
  41:     struct socket **aso;
  42:     register int type;
  43:     int proto;
  44: {
  45:     register struct protosw *prp;
  46:     register struct socket *so;
  47:     register struct mbuf *m;
  48:     register int error;
  49: 
  50:     if (proto)
  51:         prp = pffindproto(dom, proto, type);
  52:     else
  53:         prp = pffindtype(dom, type);
  54:     if (prp == 0)
  55:         return (EPROTONOSUPPORT);
  56:     if (prp->pr_type != type)
  57:         return (EPROTOTYPE);
  58:     m = m_getclr(M_WAIT, MT_SOCKET);
  59:     so = mtod(m, struct socket *);
  60:     so->so_options = 0;
  61:     so->so_state = 0;
  62:     so->so_type = type;
  63:     if (u.u_uid == 0)
  64:         so->so_state = SS_PRIV;
  65:     so->so_proto = prp;
  66:     error =
  67:         (*prp->pr_usrreq)(so, PRU_ATTACH,
  68:         (struct mbuf *)0, (struct mbuf *)proto, (struct mbuf *)0);
  69:     if (error) {
  70:         so->so_state |= SS_NOFDREF;
  71:         sofree(so);
  72:         return (error);
  73:     }
  74:     *aso = so;
  75:     return (0);
  76: }
  77: 
  78: sobind(so, nam)
  79:     struct socket *so;
  80:     struct mbuf *nam;
  81: {
  82:     int s = splnet();
  83:     int error;
  84: 
  85:     error =
  86:         (*so->so_proto->pr_usrreq)(so, PRU_BIND,
  87:         (struct mbuf *)0, nam, (struct mbuf *)0);
  88:     splx(s);
  89:     return (error);
  90: }
  91: 
  92: solisten(so, backlog)
  93:     register struct socket *so;
  94:     int backlog;
  95: {
  96:     int s = splnet(), error;
  97: 
  98:     error =
  99:         (*so->so_proto->pr_usrreq)(so, PRU_LISTEN,
 100:         (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0);
 101:     if (error) {
 102:         splx(s);
 103:         return (error);
 104:     }
 105:     if (so->so_q == 0) {
 106:         so->so_q = so;
 107:         so->so_q0 = so;
 108:         so->so_options |= SO_ACCEPTCONN;
 109:     }
 110:     if (backlog < 0)
 111:         backlog = 0;
 112:     so->so_qlimit = MIN(backlog, SOMAXCONN);
 113:     splx(s);
 114:     return (0);
 115: }
 116: 
 117: sofree(so)
 118:     register struct socket *so;
 119: {
 120: 
 121:     if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0)
 122:         return;
 123:     if (so->so_head) {
 124:         if (!soqremque(so, 0) && !soqremque(so, 1))
 125:             panic("sofree dq");
 126:         so->so_head = 0;
 127:     }
 128:     sbrelease(&so->so_snd);
 129:     sorflush(so);
 130:     (void) m_free(dtom(so));
 131: }
 132: 
 133: /*
 134:  * Close a socket on last file table reference removal.
 135:  * Initiate disconnect if connected.
 136:  * Free socket when disconnect complete.
 137:  */
 138: soclose(so)
 139:     register struct socket *so;
 140: {
 141:     int s = splnet();       /* conservative */
 142:     int error = 0;
 143: 
 144:     if (so->so_options & SO_ACCEPTCONN) {
 145:         while (so->so_q0 != so)
 146:             (void) soabort(so->so_q0);
 147:         while (so->so_q != so)
 148:             (void) soabort(so->so_q);
 149:     }
 150:     if (so->so_pcb == 0)
 151:         goto discard;
 152:     if (so->so_state & SS_ISCONNECTED) {
 153:         if ((so->so_state & SS_ISDISCONNECTING) == 0) {
 154:             error = sodisconnect(so);
 155:             if (error)
 156:                 goto drop;
 157:         }
 158:         if (so->so_options & SO_LINGER) {
 159:             if ((so->so_state & SS_ISDISCONNECTING) &&
 160:                 (so->so_state & SS_NBIO))
 161:                 goto drop;
 162:             while (so->so_state & SS_ISCONNECTED)
 163:                 SLEEP((caddr_t)&so->so_timeo, PZERO+1);
 164:         }
 165:     }
 166: drop:
 167:     if (so->so_pcb) {
 168:         int error2 =
 169:             (*so->so_proto->pr_usrreq)(so, PRU_DETACH,
 170:             (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0);
 171:         if (error == 0)
 172:             error = error2;
 173:     }
 174: discard:
 175:     if (so->so_state & SS_NOFDREF)
 176:         panic("soclose: NOFDREF");
 177:     so->so_state |= SS_NOFDREF;
 178:     sofree(so);
 179:     splx(s);
 180:     return(error);
 181: }
 182: 
 183: /*
 184:  * Must be called at splnet...
 185:  */
 186: soabort(so)
 187:     struct socket *so;
 188: {
 189: 
 190:     return (
 191:         (*so->so_proto->pr_usrreq)(so, PRU_ABORT,
 192:         (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0));
 193: }
 194: 
 195: soaccept(so, nam)
 196:     register struct socket *so;
 197:     struct mbuf *nam;
 198: {
 199:     int s = splnet();
 200:     int error;
 201: 
 202:     if ((so->so_state & SS_NOFDREF) == 0)
 203:         panic("soaccept: !NOFDREF");
 204:     so->so_state &= ~SS_NOFDREF;
 205:     error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT,
 206:         (struct mbuf *)0, nam, (struct mbuf *)0);
 207:     splx(s);
 208:     return (error);
 209: }
 210: 
 211: soconnect(so, nam)
 212:     register struct socket *so;
 213:     struct mbuf *nam;
 214: {
 215:     int s;
 216:     int error;
 217: 
 218: /*
 219:  * this is done here in supervisor mode since the kernel can't access the
 220:  * socket or its options.
 221: */
 222:     if (so->so_options & SO_ACCEPTCONN)
 223:         return (EOPNOTSUPP);
 224:     if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING))
 225:         return(EALREADY);
 226:     s = splnet();
 227:     /*
 228: 	 * If protocol is connection-based, can only connect once.
 229: 	 * Otherwise, if connected, try to disconnect first.
 230: 	 * This allows user to disconnect by connecting to, e.g.,
 231: 	 * a null address.
 232: 	 */
 233:     if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING) &&
 234:         ((so->so_proto->pr_flags & PR_CONNREQUIRED) ||
 235:         (error = sodisconnect(so))))
 236:         error = EISCONN;
 237:     else
 238:         error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT,
 239:             (struct mbuf *)0, nam, (struct mbuf *)0);
 240: /*
 241:  * this is done here because the kernel mode can't get at this info without
 242:  * a lot of trouble.
 243: */
 244:     if  (!error)
 245:         {
 246:         if  ((so->so_state & SS_NBIO) &&
 247:              (so->so_state & SS_ISCONNECTING))
 248:             error = EINPROGRESS;
 249:         }
 250:     else
 251:         so->so_state &= ~SS_ISCONNECTING;
 252:     splx(s);
 253:     return (error);
 254: }
 255: 
 256: soconnect2(so1, so2)
 257:     register struct socket *so1;
 258:     struct socket *so2;
 259: {
 260:     int s = splnet();
 261:     int error;
 262: 
 263:     error = (*so1->so_proto->pr_usrreq)(so1, PRU_CONNECT2,
 264:         (struct mbuf *)0, (struct mbuf *)so2, (struct mbuf *)0);
 265:     splx(s);
 266:     return (error);
 267: }
 268: 
 269: sodisconnect(so)
 270:     register struct socket *so;
 271: {
 272:     int s = splnet();
 273:     int error;
 274: 
 275:     if ((so->so_state & SS_ISCONNECTED) == 0) {
 276:         error = ENOTCONN;
 277:         goto bad;
 278:     }
 279:     if (so->so_state & SS_ISDISCONNECTING) {
 280:         error = EALREADY;
 281:         goto bad;
 282:     }
 283:     error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT,
 284:         (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0);
 285: bad:
 286:     splx(s);
 287:     return (error);
 288: }
 289: 
 290: /*
 291:  * Send on a socket.
 292:  * If send must go all at once and message is larger than
 293:  * send buffering, then hard error.
 294:  * Lock against other senders.
 295:  * If must go all at once and not enough room now, then
 296:  * inform user that this would block and do nothing.
 297:  * Otherwise, if nonblocking, send as much as possible.
 298:  */
 299: sosend(so, nam, uio, flags, rights)
 300:     register struct socket *so;
 301:     struct mbuf *nam;
 302:     register struct uio *uio;
 303:     int flags;
 304:     struct mbuf *rights;
 305: {
 306:     struct mbuf *top = 0;
 307:     register struct mbuf *m, **mp;
 308:     register int space;
 309:     int len, rlen = 0, error = 0, s, dontroute, first = 1;
 310: 
 311:     if (sosendallatonce(so) && uio->uio_resid > so->so_snd.sb_hiwat)
 312:         return (EMSGSIZE);
 313:     dontroute =
 314:         (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 &&
 315:         (so->so_proto->pr_flags & PR_ATOMIC);
 316:     u.u_ru.ru_msgsnd++;
 317:     if (rights)
 318:         rlen = rights->m_len;
 319: #define snderr(errno)   { error = errno; splx(s); goto release; }
 320: 
 321: restart:
 322:     sblock(&so->so_snd);
 323:     do {
 324:         s = splnet();
 325:         if (so->so_state & SS_CANTSENDMORE)
 326:             snderr(EPIPE);
 327:         if (so->so_error) {
 328:             error = so->so_error;
 329:             so->so_error = 0;           /* ??? */
 330:             splx(s);
 331:             goto release;
 332:         }
 333:         if ((so->so_state & SS_ISCONNECTED) == 0) {
 334:             if (so->so_proto->pr_flags & PR_CONNREQUIRED)
 335:                 snderr(ENOTCONN);
 336:             if (nam == 0)
 337:                 snderr(EDESTADDRREQ);
 338:         }
 339:         if (flags & MSG_OOB)
 340:             space = 1024;
 341:         else {
 342:             space = sbspace(&so->so_snd);
 343:             if (space <= rlen ||
 344:                (sosendallatonce(so) &&
 345:                 space < uio->uio_resid + rlen) ||
 346:                (uio->uio_resid >= CLBYTES && space < CLBYTES &&
 347:                so->so_snd.sb_cc >= CLBYTES &&
 348:                (so->so_state & SS_NBIO) == 0)) {
 349:                 if (so->so_state & SS_NBIO) {
 350:                     if (first)
 351:                         error = EWOULDBLOCK;
 352:                     splx(s);
 353:                     goto release;
 354:                 }
 355:                 sbunlock(&so->so_snd);
 356:                 sbwait(&so->so_snd);
 357:                 splx(s);
 358:                 goto restart;
 359:             }
 360:         }
 361:         splx(s);
 362:         mp = &top;
 363:         space -= rlen;
 364:         while (space > 0) {
 365:             MGET(m, M_WAIT, MT_DATA);
 366:             if (uio->uio_resid >= CLBYTES / 2 && space >= CLBYTES) {
 367:                 MCLGET(m);
 368:                 if (m->m_len != CLBYTES)
 369:                     goto nopages;
 370:                 len = MIN(CLBYTES, uio->uio_resid);
 371:                 space -= CLBYTES;
 372:             } else {
 373: nopages:
 374:                 len = MIN(MIN(MLEN, uio->uio_resid), space);
 375:                 space -= len;
 376:             }
 377:             error = uiomove(mtod(m, caddr_t), len, uio);
 378:             m->m_len = len;
 379:             *mp = m;
 380:             if (error)
 381:                 goto release;
 382:             mp = &m->m_next;
 383:             if (uio->uio_resid == 0)
 384:                 break;
 385:         }
 386:         if (dontroute)
 387:             so->so_options |= SO_DONTROUTE;
 388:         s = splnet();                   /* XXX */
 389:         error = (*so->so_proto->pr_usrreq)(so,
 390:             (flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND,
 391:             top, (caddr_t)nam, rights);
 392:         splx(s);
 393:         if (dontroute)
 394:             so->so_options &= ~SO_DONTROUTE;
 395:         rights = 0;
 396:         rlen = 0;
 397:         top = 0;
 398:         first = 0;
 399:         if (error)
 400:             break;
 401:     } while (uio->uio_resid);
 402: 
 403: release:
 404:     sbunlock(&so->so_snd);
 405:     if (top)
 406:         m_freem(top);
 407:     if (error == EPIPE)
 408:         NETPSIGNAL(u.u_procp, SIGPIPE);
 409:     return (error);
 410: }
 411: 
 412: /*
 413:  * Implement receive operations on a socket.
 414:  * We depend on the way that records are added to the sockbuf
 415:  * by sbappend*.  In particular, each record (mbufs linked through m_next)
 416:  * must begin with an address if the protocol so specifies,
 417:  * followed by an optional mbuf containing access rights if supported
 418:  * by the protocol, and then zero or more mbufs of data.
 419:  * In order to avoid blocking network interrupts for the entire time here,
 420:  * we splx() while doing the actual copy to user space.
 421:  * Although the sockbuf is locked, new data may still be appended,
 422:  * and thus we must maintain consistency of the sockbuf during that time.
 423:  */
 424: soreceive(so, aname, uio, flags, rightsp)
 425:     register struct socket *so;
 426:     struct mbuf **aname;
 427:     register struct uio *uio;
 428:     int flags;
 429:     struct mbuf **rightsp;
 430: {
 431:     register struct mbuf *m;
 432:     register int len, error = 0, s, offset;
 433:     struct protosw *pr = so->so_proto;
 434:     struct mbuf *nextrecord;
 435:     int moff;
 436: 
 437:     if (rightsp)
 438:         *rightsp = 0;
 439:     if (aname)
 440:         *aname = 0;
 441:     if (flags & MSG_OOB) {
 442:         m = m_get(M_WAIT, MT_DATA);
 443:         error = (*pr->pr_usrreq)(so, PRU_RCVOOB,
 444:             m, (struct mbuf *)(flags & MSG_PEEK), (struct mbuf *)0);
 445:         if (error)
 446:             goto bad;
 447:         do {
 448:             len = uio->uio_resid;
 449:             if (len > m->m_len)
 450:                 len = m->m_len;
 451:             error =
 452:                 uiomove(mtod(m, caddr_t), (int)len, uio);
 453:             m = m_free(m);
 454:         } while (uio->uio_resid && error == 0 && m);
 455: bad:
 456:         if (m)
 457:             m_freem(m);
 458:         return (error);
 459:     }
 460: 
 461: restart:
 462:     sblock(&so->so_rcv);
 463:     s = splnet();
 464: 
 465:     if (so->so_rcv.sb_cc == 0) {
 466:         if (so->so_error) {
 467:             error = so->so_error;
 468:             so->so_error = 0;
 469:             goto release;
 470:         }
 471:         if (so->so_state & SS_CANTRCVMORE)
 472:             goto release;
 473:         if ((so->so_state & SS_ISCONNECTED) == 0 &&
 474:             (so->so_proto->pr_flags & PR_CONNREQUIRED)) {
 475:             error = ENOTCONN;
 476:             goto release;
 477:         }
 478:         if (uio->uio_resid == 0)
 479:             goto release;
 480:         if (so->so_state & SS_NBIO) {
 481:             error = EWOULDBLOCK;
 482:             goto release;
 483:         }
 484:         sbunlock(&so->so_rcv);
 485:         sbwait(&so->so_rcv);
 486:         splx(s);
 487:         goto restart;
 488:     }
 489:     u.u_ru.ru_msgrcv++;
 490:     m = so->so_rcv.sb_mb;
 491:     if (m == 0)
 492:         panic("receive 1");
 493:     nextrecord = m->m_act;
 494:     if (pr->pr_flags & PR_ADDR) {
 495:         if (m->m_type != MT_SONAME)
 496:             panic("receive 1a");
 497:         if (flags & MSG_PEEK) {
 498:             if (aname)
 499:                 *aname = m_copy(m, 0, m->m_len);
 500:             m = m->m_next;
 501:         } else {
 502:             sbfree(&so->so_rcv, m);
 503:             if (aname) {
 504:                 *aname = m;
 505:                 m = m->m_next;
 506:                 (*aname)->m_next = 0;
 507:                 so->so_rcv.sb_mb = m;
 508:             } else {
 509:                 MFREE(m, so->so_rcv.sb_mb);
 510:                 m = so->so_rcv.sb_mb;
 511:             }
 512:             if (m)
 513:                 m->m_act = nextrecord;
 514:         }
 515:     }
 516:     if (m && m->m_type == MT_RIGHTS) {
 517:         if ((pr->pr_flags & PR_RIGHTS) == 0)
 518:             panic("receive 2");
 519:         if (flags & MSG_PEEK) {
 520:             if (rightsp)
 521:                 *rightsp = m_copy(m, 0, m->m_len);
 522:             m = m->m_next;
 523:         } else {
 524:             sbfree(&so->so_rcv, m);
 525:             if (rightsp) {
 526:                 *rightsp = m;
 527:                 so->so_rcv.sb_mb = m->m_next;
 528:                 m->m_next = 0;
 529:                 m = so->so_rcv.sb_mb;
 530:             } else {
 531:                 MFREE(m, so->so_rcv.sb_mb);
 532:                 m = so->so_rcv.sb_mb;
 533:             }
 534:             if (m)
 535:                 m->m_act = nextrecord;
 536:         }
 537:     }
 538:     moff = 0;
 539:     offset = 0;
 540:     while (m && uio->uio_resid && error == 0) {
 541:         if (m->m_type != MT_DATA && m->m_type != MT_HEADER)
 542:             panic("receive 3");
 543:         len = uio->uio_resid;
 544:         so->so_state &= ~SS_RCVATMARK;
 545:         if (so->so_oobmark && len > so->so_oobmark - offset)
 546:             len = so->so_oobmark - offset;
 547:         if (len > m->m_len - moff)
 548:             len = m->m_len - moff;
 549:         splx(s);
 550:         error = uiomove(mtod(m, caddr_t) + moff, (int)len, uio);
 551:         s = splnet();
 552:         if (len == m->m_len - moff) {
 553:             if (flags & MSG_PEEK) {
 554:                 m = m->m_next;
 555:                 moff = 0;
 556:             } else {
 557:                 nextrecord = m->m_act;
 558:                 sbfree(&so->so_rcv, m);
 559:                 MFREE(m, so->so_rcv.sb_mb);
 560:                 m = so->so_rcv.sb_mb;
 561:                 if (m)
 562:                     m->m_act = nextrecord;
 563:             }
 564:         } else {
 565:             if (flags & MSG_PEEK)
 566:                 moff += len;
 567:             else {
 568:                 m->m_off += len;
 569:                 m->m_len -= len;
 570:                 so->so_rcv.sb_cc -= len;
 571:             }
 572:         }
 573:         if (so->so_oobmark) {
 574:             if ((flags & MSG_PEEK) == 0) {
 575:                 so->so_oobmark -= len;
 576:                 if (so->so_oobmark == 0) {
 577:                     so->so_state |= SS_RCVATMARK;
 578:                     break;
 579:                 }
 580:             } else
 581:                 offset += len;
 582:         }
 583:     }
 584:     if ((flags & MSG_PEEK) == 0) {
 585:         if (m == 0)
 586:             so->so_rcv.sb_mb = nextrecord;
 587:         else if (pr->pr_flags & PR_ATOMIC)
 588:             (void) sbdroprecord(&so->so_rcv);
 589:         if (pr->pr_flags & PR_WANTRCVD && so->so_pcb)
 590:             (*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0,
 591:                 (struct mbuf *)0, (struct mbuf *)0);
 592:         if (error == 0 && rightsp && *rightsp &&
 593:             pr->pr_domain->dom_externalize)
 594:             error = (*pr->pr_domain->dom_externalize)(*rightsp);
 595:     }
 596: release:
 597:     sbunlock(&so->so_rcv);
 598:     splx(s);
 599:     return (error);
 600: }
 601: 
 602: soshutdown(so, how)
 603:     register struct socket *so;
 604:     register int how;
 605: {
 606:     register struct protosw *pr = so->so_proto;
 607: 
 608:     how++;
 609:     if (how & FREAD)
 610:         sorflush(so);
 611:     if (how & FWRITE)
 612:         return ((*pr->pr_usrreq)(so, PRU_SHUTDOWN,
 613:             (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0));
 614:     return (0);
 615: }
 616: 
 617: sorflush(so)
 618:     register struct socket *so;
 619: {
 620:     register struct sockbuf *sb = &so->so_rcv;
 621:     register struct protosw *pr = so->so_proto;
 622:     register int s;
 623:     struct sockbuf asb;
 624: 
 625:     sblock(sb);
 626:     s = splimp();
 627:     socantrcvmore(so);
 628:     sbunlock(sb);
 629:     asb = *sb;
 630:     bzero((caddr_t)sb, sizeof (*sb));
 631:     splx(s);
 632:     if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose)
 633:         (*pr->pr_domain->dom_dispose)(asb.sb_mb);
 634:     sbrelease(&asb);
 635: }
 636: 
 637: sosetopt(so, level, optname, m0)
 638:     register struct socket *so;
 639:     int level, optname;
 640:     struct mbuf *m0;
 641: {
 642:     int error = 0;
 643:     register struct mbuf *m = m0;
 644: 
 645: /* we make a copy because the kernel is faking the m0 mbuf and we have to
 646:  * have something for the m_free's to work with
 647: */
 648:     if (m0)
 649:         m = m0 = m_copy(m0, 0, M_COPYALL);
 650:     if (level != SOL_SOCKET) {
 651:         if (so->so_proto && so->so_proto->pr_ctloutput)
 652:             return ((*so->so_proto->pr_ctloutput)
 653:                   (PRCO_SETOPT, so, level, optname, &m0));
 654:         error = ENOPROTOOPT;
 655:     } else {
 656:         switch (optname) {
 657: 
 658:         case SO_LINGER:
 659:             if (m == NULL || m->m_len != sizeof (struct linger)) {
 660:                 error = EINVAL;
 661:                 goto bad;
 662:             }
 663:             so->so_linger = mtod(m, struct linger *)->l_linger;
 664:             /* fall thru... */
 665: 
 666:         case SO_DEBUG:
 667:         case SO_KEEPALIVE:
 668:         case SO_DONTROUTE:
 669:         case SO_USELOOPBACK:
 670:         case SO_BROADCAST:
 671:         case SO_REUSEADDR:
 672:         case SO_OOBINLINE:
 673:             if (m == NULL || m->m_len < sizeof (int)) {
 674:                 error = EINVAL;
 675:                 goto bad;
 676:             }
 677:             if (*mtod(m, int *))
 678:                 so->so_options |= optname;
 679:             else
 680:                 so->so_options &= ~optname;
 681:             break;
 682: 
 683:         case SO_SNDBUF:
 684:         case SO_RCVBUF:
 685:         case SO_SNDLOWAT:
 686:         case SO_RCVLOWAT:
 687:         case SO_SNDTIMEO:
 688:         case SO_RCVTIMEO:
 689:             if (m == NULL || m->m_len < sizeof (int)) {
 690:                 error = EINVAL;
 691:                 goto bad;
 692:             }
 693:             switch (optname) {
 694: 
 695:             case SO_SNDBUF:
 696:             case SO_RCVBUF:
 697:                 if (sbreserve(optname == SO_SNDBUF ? &so->so_snd :
 698:                     &so->so_rcv, *mtod(m, int *)) == 0) {
 699:                     error = ENOBUFS;
 700:                     goto bad;
 701:                 }
 702:                 break;
 703: 
 704:             case SO_SNDLOWAT:
 705:                 so->so_snd.sb_lowat = *mtod(m, int *);
 706:                 break;
 707:             case SO_RCVLOWAT:
 708:                 so->so_rcv.sb_lowat = *mtod(m, int *);
 709:                 break;
 710:             case SO_SNDTIMEO:
 711:                 so->so_snd.sb_timeo = *mtod(m, int *);
 712:                 break;
 713:             case SO_RCVTIMEO:
 714:                 so->so_rcv.sb_timeo = *mtod(m, int *);
 715:                 break;
 716:             }
 717:             break;
 718: 
 719:         default:
 720:             error = ENOPROTOOPT;
 721:             break;
 722:         }
 723:     }
 724: bad:
 725:     if (m)
 726:         (void) m_free(m);
 727:     return (error);
 728: }
 729: 
 730: sogetopt(so, level, optname, mp)
 731:     register struct socket *so;
 732:     int level, optname;
 733:     struct mbuf **mp;
 734: {
 735:     register struct mbuf *m;
 736: 
 737:     if (level != SOL_SOCKET) {
 738:         if (so->so_proto && so->so_proto->pr_ctloutput) {
 739:             return ((*so->so_proto->pr_ctloutput)
 740:                   (PRCO_GETOPT, so, level, optname, mp));
 741:         } else
 742:             return (ENOPROTOOPT);
 743:     } else {
 744:         m = m_get(M_WAIT, MT_SOOPTS);
 745:         m->m_len = sizeof (int);
 746: 
 747:         switch (optname) {
 748: 
 749:         case SO_LINGER:
 750:             m->m_len = sizeof (struct linger);
 751:             mtod(m, struct linger *)->l_onoff =
 752:                 so->so_options & SO_LINGER;
 753:             mtod(m, struct linger *)->l_linger = so->so_linger;
 754:             break;
 755: 
 756:         case SO_USELOOPBACK:
 757:         case SO_DONTROUTE:
 758:         case SO_DEBUG:
 759:         case SO_KEEPALIVE:
 760:         case SO_REUSEADDR:
 761:         case SO_BROADCAST:
 762:         case SO_OOBINLINE:
 763:             *mtod(m, int *) = so->so_options & optname;
 764:             break;
 765: 
 766:         case SO_TYPE:
 767:             *mtod(m, int *) = so->so_type;
 768:             break;
 769: 
 770:         case SO_ERROR:
 771:             *mtod(m, int *) = so->so_error;
 772:             so->so_error = 0;
 773:             break;
 774: 
 775:         case SO_SNDBUF:
 776:             *mtod(m, int *) = so->so_snd.sb_hiwat;
 777:             break;
 778: 
 779:         case SO_RCVBUF:
 780:             *mtod(m, int *) = so->so_rcv.sb_hiwat;
 781:             break;
 782: 
 783:         case SO_SNDLOWAT:
 784:             *mtod(m, int *) = so->so_snd.sb_lowat;
 785:             break;
 786: 
 787:         case SO_RCVLOWAT:
 788:             *mtod(m, int *) = so->so_rcv.sb_lowat;
 789:             break;
 790: 
 791:         case SO_SNDTIMEO:
 792:             *mtod(m, int *) = so->so_snd.sb_timeo;
 793:             break;
 794: 
 795:         case SO_RCVTIMEO:
 796:             *mtod(m, int *) = so->so_rcv.sb_timeo;
 797:             break;
 798: 
 799:         default:
 800:             (void)m_free(m);
 801:             return (ENOPROTOOPT);
 802:         }
 803:         *mp = m;
 804:         return (0);
 805:     }
 806: }
 807: 
 808: sohasoutofband(so)
 809:     register struct socket *so;
 810: {
 811: register struct proc *p;
 812: 
 813:     if (so->so_pgrp < 0)
 814:         GSIGNAL(-so->so_pgrp, SIGURG);
 815:     else if (so->so_pgrp > 0 &&
 816:         (p = (struct proc *)NETPFIND(so->so_pgrp)) != 0)
 817:         NETPSIGNAL(p, SIGURG);
 818:     if (so->so_rcv.sb_sel) {
 819:         SELWAKEUP(so->so_rcv.sb_sel,
 820:             (long)(so->so_rcv.sb_flags & SB_COLL));
 821:         so->so_rcv.sb_sel = 0;
 822:         so->so_rcv.sb_flags &= ~SB_COLL;
 823:     }
 824: }
 825: 
 826: /*
 827:  * this routine was extracted from the accept() call in uipc_sys.c to
 828:  * do the initial accept processing in the supervisor rather than copying
 829:  * the socket struct back and forth.
 830: */
 831: 
 832: soacc1(so)
 833: register struct socket  *so;
 834:     {
 835: 
 836:     if  ((so->so_options & SO_ACCEPTCONN) == 0)
 837:         return(u.u_error = EINVAL);
 838:     if  ((so->so_state & SS_NBIO) && so->so_qlen == 0)
 839:         return(u.u_error = EWOULDBLOCK);
 840:     while   (so->so_qlen == 0 && so->so_error == 0)
 841:         {
 842:         if  (so->so_state & SS_CANTRCVMORE)
 843:             {
 844:             so->so_error = ECONNABORTED;
 845:             break;
 846:             }
 847:         SLEEP(&so->so_timeo, PZERO+1);
 848:         }
 849:     if  (so->so_error)
 850:         {
 851:         u.u_error = so->so_error;
 852:         so->so_error = 0;
 853:         return(u.u_error);
 854:         }
 855:     return(0);
 856:     }
 857: 
 858: /*
 859:  * used to dequeue a connection request.  the panic on nothing left is
 860:  * done in the kernel when we return 0.
 861: */
 862: 
 863: struct socket *
 864: asoqremque(so, n)
 865:     struct  socket  *so;
 866:     int n;
 867:     {
 868: register struct socket  *aso;
 869: 
 870:     aso = so->so_q;
 871:     if  (soqremque(aso, n) == 0)
 872:         return(0);
 873:     return(aso);
 874:     }
 875: 
 876: /*
 877:  * this is the while loop from connect(), the setjmp has been done in
 878:  * kernel, so we just wait for isconnecting to go away.
 879: */
 880: 
 881: connwhile(so)
 882: register struct socket  *so;
 883:     {
 884: 
 885:     while   ((so->so_state & SS_ISCONNECTING) && so->so_error == 0)
 886:         SLEEP(&so->so_timeo, PZERO+1);
 887:     u.u_error = so->so_error;
 888:     so->so_error = 0;
 889:     so->so_state &= ~SS_ISCONNECTING;
 890:     return(u.u_error);
 891:     }
 892: 
 893: sogetnam(so, m)
 894:     register struct socket  *so;
 895:     struct  mbuf    *m;
 896:     {
 897:     return(u.u_error=(*so->so_proto->pr_usrreq)(so, PRU_SOCKADDR, 0, m, 0));
 898:     }
 899: 
 900: sogetpeer(so, m)
 901:     register struct socket *so;
 902:     struct  mbuf    *m;
 903:     {
 904: 
 905:     if  ((so->so_state & SS_ISCONNECTED) == 0)
 906:         return(u.u_error = ENOTCONN);
 907:     return(u.u_error=(*so->so_proto->pr_usrreq)(so, PRU_PEERADDR, 0, m, 0));
 908:     }
 909: #endif

Defined functions

asoqremque defined in line 863; used 2 times
connwhile defined in line 881; used 2 times
soabort defined in line 186; used 5 times
soacc1 defined in line 832; used 2 times
soaccept defined in line 195; used 2 times
sobind defined in line 78; used 2 times
soclose defined in line 138; used 2 times
soconnect defined in line 211; used 2 times
soconnect2 defined in line 256; used 2 times
socreate defined in line 40; used 2 times
sodisconnect defined in line 269; used 2 times
sogetnam defined in line 893; used 2 times
sogetopt defined in line 730; used 2 times
sogetpeer defined in line 900; used 2 times
solisten defined in line 92; used 2 times
soreceive defined in line 424; used 2 times
sorflush defined in line 617; used 2 times
sosend defined in line 299; used 2 times
sosetopt defined in line 637; used 2 times
soshutdown defined in line 602; used 2 times

Defined macros

snderr defined in line 319; used 3 times
Last modified: 1994-11-27
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 5999
Valid CSS Valid XHTML 1.0 Strict