|
|
1.1 ! root 1: /*********************************************************** ! 2: Copyright IBM Corporation 1987 ! 3: ! 4: All Rights Reserved ! 5: ! 6: Permission to use, copy, modify, and distribute this software and its ! 7: documentation for any purpose and without fee is hereby granted, ! 8: provided that the above copyright notice appear in all copies and that ! 9: both that copyright notice and this permission notice appear in ! 10: supporting documentation, and that the name of IBM not be ! 11: used in advertising or publicity pertaining to distribution of the ! 12: software without specific, written prior permission. ! 13: ! 14: IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ! 15: ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL ! 16: IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ! 17: ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, ! 18: WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ! 19: ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS ! 20: SOFTWARE. ! 21: ! 22: ******************************************************************/ ! 23: ! 24: /* ! 25: * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison ! 26: */ ! 27: /* ! 28: * ARGO TP ! 29: * ! 30: * $Header: tp_usrreq.c,v 5.4 88/11/18 17:29:18 nhall Exp $ ! 31: * $Source: /usr/argo/sys/netiso/RCS/tp_usrreq.c,v $ ! 32: * @(#)tp_usrreq.c 7.13 (Berkeley) 6/29/90 ! 33: * ! 34: * tp_usrreq(), the fellow that gets called from most of the socket code. ! 35: * Pretty straighforward. ! 36: * THe only really awful stuff here is the OOB processing, which is done ! 37: * wholly here. ! 38: * tp_rcvoob() and tp_sendoob() are contained here and called by tp_usrreq(). ! 39: */ ! 40: ! 41: #ifndef lint ! 42: static char *rcsid = "$Header: tp_usrreq.c,v 5.4 88/11/18 17:29:18 nhall Exp $"; ! 43: #endif lint ! 44: ! 45: #include "param.h" ! 46: #include "systm.h" ! 47: #include "user.h" ! 48: #include "mbuf.h" ! 49: #include "socket.h" ! 50: #include "socketvar.h" ! 51: #include "domain.h" ! 52: #include "protosw.h" ! 53: #include "errno.h" ! 54: ! 55: #include "tp_param.h" ! 56: #include "tp_timer.h" ! 57: #include "tp_stat.h" ! 58: #include "tp_seq.h" ! 59: #include "tp_ip.h" ! 60: #include "tp_pcb.h" ! 61: #include "argo_debug.h" ! 62: #include "tp_trace.h" ! 63: #include "tp_meas.h" ! 64: #include "iso.h" ! 65: #include "iso_errno.h" ! 66: ! 67: int tp_attach(), tp_driver(); ! 68: int TNew; ! 69: int TPNagle1, TPNagle2; ! 70: struct tp_pcb *tp_listeners, *tp_intercepts; ! 71: ! 72: #ifdef ARGO_DEBUG ! 73: /* ! 74: * CALLED FROM: ! 75: * anywhere you want to debug... ! 76: * FUNCTION and ARGUMENTS: ! 77: * print (str) followed by the control info in the mbufs of an mbuf chain (n) ! 78: */ ! 79: void ! 80: dump_mbuf(n, str) ! 81: struct mbuf *n; ! 82: char *str; ! 83: { ! 84: struct mbuf *nextrecord; ! 85: ! 86: printf("dump %s\n", str); ! 87: ! 88: if (n == MNULL) { ! 89: printf("EMPTY:\n"); ! 90: return; ! 91: } ! 92: ! 93: while (n) { ! 94: nextrecord = n->m_act; ! 95: printf("RECORD:\n"); ! 96: while (n) { ! 97: printf("%x : Len %x Data %x A %x Nx %x Tp %x\n", ! 98: n, n->m_len, n->m_data, n->m_act, n->m_next, n->m_type); ! 99: #ifdef notdef ! 100: { ! 101: register char *p = mtod(n, char *); ! 102: register int i; ! 103: ! 104: printf("data: "); ! 105: for (i = 0; i < n->m_len; i++) { ! 106: if (i%8 == 0) ! 107: printf("\n"); ! 108: printf("0x%x ", *(p+i)); ! 109: } ! 110: printf("\n"); ! 111: } ! 112: #endif notdef ! 113: if (n->m_next == n) { ! 114: printf("LOOP!\n"); ! 115: return; ! 116: } ! 117: n = n->m_next; ! 118: } ! 119: n = nextrecord; ! 120: } ! 121: printf("\n"); ! 122: } ! 123: ! 124: #endif ARGO_DEBUG ! 125: ! 126: /* ! 127: * CALLED FROM: ! 128: * tp_usrreq(), PRU_RCVOOB ! 129: * FUNCTION and ARGUMENTS: ! 130: * Copy data from the expedited data socket buffer into ! 131: * the pre-allocated mbuf m. ! 132: * There is an isomorphism between XPD TPDUs and expedited data TSDUs. ! 133: * XPD tpdus are limited to 16 bytes of data so they fit in one mbuf. ! 134: * RETURN VALUE: ! 135: * EINVAL if debugging is on and a disaster has occurred ! 136: * ENOTCONN if the socket isn't connected ! 137: * EWOULDBLOCK if the socket is in non-blocking mode and there's no ! 138: * xpd data in the buffer ! 139: * E* whatever is returned from the fsm. ! 140: */ ! 141: tp_rcvoob(tpcb, so, m, outflags, inflags) ! 142: struct tp_pcb *tpcb; ! 143: register struct socket *so; ! 144: register struct mbuf *m; ! 145: int *outflags; ! 146: int inflags; ! 147: { ! 148: register struct mbuf *n; ! 149: register struct sockbuf *sb = &so->so_rcv; ! 150: struct tp_event E; ! 151: int error = 0; ! 152: register struct mbuf **nn; ! 153: ! 154: IFDEBUG(D_XPD) ! 155: printf("PRU_RCVOOB, sostate 0x%x\n", so->so_state); ! 156: ENDDEBUG ! 157: ! 158: /* if you use soreceive */ ! 159: if (m == MNULL) ! 160: return ENOBUFS; ! 161: ! 162: restart: ! 163: if ((((so->so_state & SS_ISCONNECTED) == 0) ! 164: || (so->so_state & SS_ISDISCONNECTING) != 0) && ! 165: (so->so_proto->pr_flags & PR_CONNREQUIRED)) { ! 166: return ENOTCONN; ! 167: } ! 168: ! 169: /* Take the first mbuf off the chain. ! 170: * Each XPD TPDU gives you a complete TSDU so the chains don't get ! 171: * coalesced, but one TSDU may span several mbufs. ! 172: * Nevertheless, since n should have a most 16 bytes, it ! 173: * will fit into m. (size was checked in tp_input() ) ! 174: */ ! 175: ! 176: /* ! 177: * Code for excision of OOB data should be added to ! 178: * uipc_socket2.c (like sbappend). ! 179: */ ! 180: ! 181: sblock(sb); ! 182: for (nn = &sb->sb_mb; n = *nn; nn = &n->m_act) ! 183: if (n->m_type == MT_OOBDATA) ! 184: break; ! 185: ! 186: if (n == 0) { ! 187: ASSERT((tpcb->tp_flags & TPF_DISC_DATA_IN) == 0); ! 188: IFDEBUG(D_XPD) ! 189: printf("RCVOOB: empty queue!\n"); ! 190: ENDDEBUG ! 191: sbunlock(sb); ! 192: if (so->so_state & SS_NBIO) { ! 193: return EWOULDBLOCK; ! 194: } ! 195: sbwait(sb); ! 196: goto restart; ! 197: } ! 198: m->m_len = 0; ! 199: ! 200: /* Assuming at most one xpd tpdu is in the buffer at once */ ! 201: while (n != MNULL) { ! 202: m->m_len += n->m_len; ! 203: bcopy(mtod(n, caddr_t), mtod(m, caddr_t), (unsigned)n->m_len); ! 204: m->m_data += n->m_len; /* so mtod() in bcopy() above gives right addr */ ! 205: n = n->m_next; ! 206: } ! 207: m->m_data = m->m_dat; ! 208: m->m_flags |= M_EOR; ! 209: ! 210: IFDEBUG(D_XPD) ! 211: printf("tp_rcvoob: xpdlen 0x%x\n", m->m_len); ! 212: dump_mbuf(so->so_rcv.sb_mb, "RCVOOB: Rcv socketbuf"); ! 213: dump_mbuf(sb->sb_mb, "RCVOOB: Xrcv socketbuf"); ! 214: ENDDEBUG ! 215: ! 216: if ((inflags & MSG_PEEK) == 0) { ! 217: n = *nn; ! 218: *nn = n->m_act; ! 219: sb->sb_cc -= m->m_len; ! 220: } ! 221: ! 222: release: ! 223: sbunlock(sb); ! 224: ! 225: IFTRACE(D_XPD) ! 226: tptraceTPCB(TPPTmisc, "PRU_RCVOOB @ release sb_cc m_len", ! 227: tpcb->tp_Xrcv.sb_cc, m->m_len, 0, 0); ! 228: ENDTRACE ! 229: if (error == 0) ! 230: error = DoEvent(T_USR_Xrcvd); ! 231: return error; ! 232: } ! 233: ! 234: /* ! 235: * CALLED FROM: ! 236: * tp_usrreq(), PRU_SENDOOB ! 237: * FUNCTION and ARGUMENTS: ! 238: * Send what's in the mbuf chain (m) as an XPD TPDU. ! 239: * The mbuf may not contain more then 16 bytes of data. ! 240: * XPD TSDUs aren't segmented, so they translate into ! 241: * exactly one XPD TPDU, with EOT bit set. ! 242: * RETURN VALUE: ! 243: * EWOULDBLOCK if socket is in non-blocking mode and the previous ! 244: * xpd data haven't been acked yet. ! 245: * EMSGSIZE if trying to send > max-xpd bytes (16) ! 246: * ENOBUFS if ran out of mbufs ! 247: */ ! 248: tp_sendoob(tpcb, so, xdata, outflags) ! 249: struct tp_pcb *tpcb; ! 250: register struct socket *so; ! 251: register struct mbuf *xdata; ! 252: int *outflags; /* not used */ ! 253: { ! 254: /* ! 255: * Each mbuf chain represents a sequence # in the XPD seq space. ! 256: * The first one in the queue has sequence # tp_Xuna. ! 257: * When we add to the XPD queue, we stuff a zero-length ! 258: * mbuf (mark) into the DATA queue, with its sequence number in m_next ! 259: * to be assigned to this XPD tpdu, so data xfer can stop ! 260: * when it reaches the zero-length mbuf if this XPD TPDU hasn't ! 261: * yet been acknowledged. ! 262: */ ! 263: register struct sockbuf *sb = &(tpcb->tp_Xsnd); ! 264: register struct mbuf *xmark; ! 265: register int len=0; ! 266: struct tp_event E; ! 267: ! 268: IFDEBUG(D_XPD) ! 269: printf("tp_sendoob:"); ! 270: if (xdata) ! 271: printf("xdata len 0x%x\n", xdata->m_len); ! 272: ENDDEBUG ! 273: /* DO NOT LOCK the Xsnd buffer!!!! You can have at MOST one ! 274: * socket buf locked at any time!!! (otherwise you might ! 275: * sleep() in sblock() w/ a signal pending and cause the ! 276: * system call to be aborted w/ a locked socketbuf, which ! 277: * is a problem. So the so_snd buffer lock ! 278: * (done in sosend()) serves as the lock for Xpd. ! 279: */ ! 280: if (sb->sb_mb) { /* Anything already in eXpedited data sockbuf? */ ! 281: if (so->so_state & SS_NBIO) { ! 282: return EWOULDBLOCK; ! 283: } ! 284: while (sb->sb_mb) { ! 285: sbunlock(&so->so_snd); /* already locked by sosend */ ! 286: sbwait(&so->so_snd); ! 287: sblock(&so->so_snd); /* sosend will unlock on return */ ! 288: } ! 289: } ! 290: ! 291: if (xdata == (struct mbuf *)0) { ! 292: /* empty xpd packet */ ! 293: MGETHDR(xdata, M_WAIT, MT_OOBDATA); ! 294: if (xdata == NULL) { ! 295: return ENOBUFS; ! 296: } ! 297: xdata->m_len = 0; ! 298: xdata->m_pkthdr.len = 0; ! 299: } ! 300: IFDEBUG(D_XPD) ! 301: printf("tp_sendoob 1:"); ! 302: if (xdata) ! 303: printf("xdata len 0x%x\n", xdata->m_len); ! 304: ENDDEBUG ! 305: xmark = xdata; /* temporary use of variable xmark */ ! 306: while (xmark) { ! 307: len += xmark->m_len; ! 308: xmark = xmark->m_next; ! 309: } ! 310: if (len > TP_MAX_XPD_DATA) { ! 311: return EMSGSIZE; ! 312: } ! 313: IFDEBUG(D_XPD) ! 314: printf("tp_sendoob 2:"); ! 315: if (xdata) ! 316: printf("xdata len 0x%x\n", len); ! 317: ENDDEBUG ! 318: ! 319: ! 320: IFTRACE(D_XPD) ! 321: tptraceTPCB(TPPTmisc, "XPD mark m_next ", xdata->m_next, 0, 0, 0); ! 322: ENDTRACE ! 323: ! 324: sbappendrecord(sb, xdata); ! 325: ! 326: IFDEBUG(D_XPD) ! 327: printf("tp_sendoob len 0x%x\n", len); ! 328: dump_mbuf(so->so_snd.sb_mb, "XPD request Regular sndbuf:"); ! 329: dump_mbuf(tpcb->tp_Xsnd.sb_mb, "XPD request Xsndbuf:"); ! 330: ENDDEBUG ! 331: return DoEvent(T_XPD_req); ! 332: } ! 333: ! 334: /* ! 335: * CALLED FROM: ! 336: * the socket routines ! 337: * FUNCTION and ARGUMENTS: ! 338: * Handles all "user requests" except the [gs]ockopts() requests. ! 339: * The argument (req) is the request type (PRU*), ! 340: * (m) is an mbuf chain, generally used for send and ! 341: * receive type requests only. ! 342: * (nam) is used for addresses usually, in particular for the bind request. ! 343: * ! 344: */ ! 345: /*ARGSUSED*/ ! 346: ProtoHook ! 347: tp_usrreq(so, req, m, nam, controlp) ! 348: struct socket *so; ! 349: u_int req; ! 350: struct mbuf *m, *nam, *controlp; ! 351: { ! 352: register struct tp_pcb *tpcb = sototpcb(so); ! 353: int s = splnet(); ! 354: int error = 0; ! 355: int flags, *outflags = &flags; ! 356: u_long eotsdu = 0; ! 357: struct tp_event E; ! 358: ! 359: IFDEBUG(D_REQUEST) ! 360: printf("usrreq(0x%x,%d,0x%x,0x%x,0x%x)\n",so,req,m,nam,outflags); ! 361: if (so->so_error) ! 362: printf("WARNING!!! so->so_error is 0x%x\n", so->so_error); ! 363: ENDDEBUG ! 364: IFTRACE(D_REQUEST) ! 365: tptraceTPCB(TPPTusrreq, "req so m state [", req, so, m, ! 366: tpcb?tpcb->tp_state:0); ! 367: ENDTRACE ! 368: ! 369: if ((u_int)tpcb == 0 && req != PRU_ATTACH) { ! 370: IFTRACE(D_REQUEST) ! 371: tptraceTPCB(TPPTusrreq, "req failed NO TPCB[", 0, 0, 0, 0); ! 372: ENDTRACE ! 373: splx(s); ! 374: return ENOTCONN; ! 375: } ! 376: ! 377: switch (req) { ! 378: ! 379: case PRU_ATTACH: ! 380: if (tpcb) { ! 381: error = EISCONN; ! 382: break; ! 383: } ! 384: if (error = tp_attach(so, so->so_proto->pr_domain->dom_family)) ! 385: break; ! 386: tpcb = sototpcb(so); ! 387: break; ! 388: ! 389: case PRU_ABORT: /* called from close() */ ! 390: /* called for each incoming connect queued on the ! 391: * parent (accepting) socket ! 392: */ ! 393: if (tpcb->tp_state == TP_OPEN) { ! 394: E.ATTR(T_DISC_req).e_reason = E_TP_NO_SESSION; ! 395: error = DoEvent(T_DISC_req); /* pretend it was a close() */ ! 396: break; ! 397: } /* else DROP THROUGH */ ! 398: ! 399: case PRU_DETACH: /* called from close() */ ! 400: /* called only after disconnect was called */ ! 401: if (tpcb->tp_state == TP_LISTENING) { ! 402: register struct tp_pcb **tt; ! 403: for (tt = &tp_listeners; *tt; tt = &((*tt)->tp_nextlisten)) ! 404: if (*tt == tpcb) ! 405: break; ! 406: if (*tt) ! 407: *tt = tpcb->tp_nextlisten; ! 408: else { ! 409: for (tt = &tp_intercepts; *tt; tt = &((*tt)->tp_nextlisten)) ! 410: if (*tt == tpcb) ! 411: break; ! 412: if (*tt) ! 413: *tt = tpcb->tp_nextlisten; ! 414: else ! 415: printf("tp_usrreq - detach: should panic\n"); ! 416: } ! 417: } ! 418: if (tpcb->tp_next) ! 419: remque(tpcb); ! 420: error = DoEvent(T_DETACH); ! 421: if (tpcb->tp_state == TP_CLOSED) { ! 422: free((caddr_t)tpcb, M_PCB); ! 423: tpcb = 0; ! 424: } ! 425: break; ! 426: ! 427: case PRU_SHUTDOWN: ! 428: /* recv end may have been released; local credit might be zero */ ! 429: case PRU_DISCONNECT: ! 430: E.ATTR(T_DISC_req).e_reason = E_TP_NORMAL_DISC; ! 431: error = DoEvent(T_DISC_req); ! 432: break; ! 433: ! 434: case PRU_BIND: ! 435: error = (tpcb->tp_nlproto->nlp_pcbbind)(so->so_pcb, nam); ! 436: if (error == 0) { ! 437: (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen, ! 438: tpcb->tp_lsuffix, TP_LOCAL); ! 439: } ! 440: break; ! 441: ! 442: case PRU_LISTEN: ! 443: if (tpcb->tp_lsuffixlen == 0) { ! 444: if (error = (tpcb->tp_nlproto->nlp_pcbbind)(so->so_pcb, MNULL)) ! 445: break; ! 446: (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen, ! 447: tpcb->tp_lsuffix, TP_LOCAL); ! 448: } ! 449: if (tpcb->tp_next == 0) { ! 450: tpcb->tp_next = tpcb->tp_prev = tpcb; ! 451: tpcb->tp_nextlisten = tp_listeners; ! 452: tp_listeners = tpcb; ! 453: } ! 454: IFDEBUG(D_TPISO) ! 455: if (tpcb->tp_state != TP_CLOSED) ! 456: printf("LISTEN ERROR: state 0x%x\n", tpcb->tp_state); ! 457: ENDDEBUG ! 458: error = DoEvent(T_LISTEN_req); ! 459: break; ! 460: ! 461: case PRU_CONNECT2: ! 462: error = EOPNOTSUPP; /* for unix domain sockets */ ! 463: break; ! 464: ! 465: case PRU_CONNECT: ! 466: IFTRACE(D_CONN) ! 467: tptraceTPCB(TPPTmisc, ! 468: "PRU_CONNECT: so 0x%x *SHORT_LSUFXP(tpcb) 0x%x lsuflen 0x%x, class 0x%x", ! 469: tpcb->tp_sock, *SHORT_LSUFXP(tpcb), tpcb->tp_lsuffixlen, ! 470: tpcb->tp_class); ! 471: ENDTRACE ! 472: IFDEBUG(D_CONN) ! 473: printf("PRU_CONNECT: so *SHORT_LSUFXP(tpcb) 0x%x lsuflen 0x%x, class 0x%x", ! 474: tpcb->tp_sock, *SHORT_LSUFXP(tpcb), tpcb->tp_lsuffixlen, ! 475: tpcb->tp_class); ! 476: ENDDEBUG ! 477: if (tpcb->tp_lsuffixlen == 0) { ! 478: if (error = (tpcb->tp_nlproto->nlp_pcbbind)(so->so_pcb, MNULL)) { ! 479: IFDEBUG(D_CONN) ! 480: printf("pcbbind returns error 0x%x\n", error); ! 481: ENDDEBUG ! 482: break; ! 483: } ! 484: (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen, ! 485: tpcb->tp_lsuffix, TP_LOCAL); ! 486: } ! 487: ! 488: IFDEBUG(D_CONN) ! 489: printf("isop 0x%x isop->isop_socket offset 12 :\n", tpcb->tp_npcb); ! 490: dump_buf(tpcb->tp_npcb, 16); ! 491: ENDDEBUG ! 492: if (error = tp_route_to(nam, tpcb, /* channel */0)) ! 493: break; ! 494: IFDEBUG(D_CONN) ! 495: printf( ! 496: "PRU_CONNECT after tpcb 0x%x so 0x%x npcb 0x%x flags 0x%x\n", ! 497: tpcb, so, tpcb->tp_npcb, tpcb->tp_flags); ! 498: printf("isop 0x%x isop->isop_socket offset 12 :\n", tpcb->tp_npcb); ! 499: dump_buf(tpcb->tp_npcb, 16); ! 500: ENDDEBUG ! 501: if (tpcb->tp_fsuffixlen == 0) { ! 502: /* didn't set peer extended suffix */ ! 503: (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_fsuffixlen, ! 504: tpcb->tp_fsuffix, TP_FOREIGN); ! 505: } ! 506: (void) (tpcb->tp_nlproto->nlp_mtu)(so, so->so_pcb, ! 507: &tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0); ! 508: if (tpcb->tp_state == TP_CLOSED) { ! 509: soisconnecting(so); ! 510: error = DoEvent(T_CONN_req); ! 511: } else { ! 512: (tpcb->tp_nlproto->nlp_pcbdisc)(so->so_pcb); ! 513: error = EISCONN; ! 514: } ! 515: IFPERF(tpcb) ! 516: u_int lsufx, fsufx; ! 517: lsufx = *(u_short *)(tpcb->tp_lsuffix); ! 518: fsufx = *(u_short *)(tpcb->tp_fsuffix); ! 519: ! 520: tpmeas(tpcb->tp_lref, ! 521: TPtime_open | (tpcb->tp_xtd_format << 4), ! 522: &time, lsufx, fsufx, tpcb->tp_fref); ! 523: ENDPERF ! 524: break; ! 525: ! 526: case PRU_ACCEPT: ! 527: (tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_FOREIGN); ! 528: IFDEBUG(D_REQUEST) ! 529: printf("ACCEPT PEERADDDR:"); ! 530: dump_buf(mtod(nam, char *), nam->m_len); ! 531: ENDDEBUG ! 532: IFPERF(tpcb) ! 533: u_int lsufx, fsufx; ! 534: lsufx = *(u_short *)(tpcb->tp_lsuffix); ! 535: fsufx = *(u_short *)(tpcb->tp_fsuffix); ! 536: ! 537: tpmeas(tpcb->tp_lref, TPtime_open, ! 538: &time, lsufx, fsufx, tpcb->tp_fref); ! 539: ENDPERF ! 540: break; ! 541: ! 542: case PRU_RCVD: ! 543: if (so->so_state & SS_ISCONFIRMING) { ! 544: if (tpcb->tp_state == TP_CONFIRMING) ! 545: error = tp_confirm(tpcb); ! 546: break; ! 547: } ! 548: IFTRACE(D_DATA) ! 549: tptraceTPCB(TPPTmisc, ! 550: "RCVD BF: lcredit sent_lcdt cc hiwat \n", ! 551: tpcb->tp_lcredit, tpcb->tp_sent_lcdt, ! 552: so->so_rcv.sb_cc, so->so_rcv.sb_hiwat); ! 553: LOCAL_CREDIT(tpcb); ! 554: tptraceTPCB(TPPTmisc, ! 555: "PRU_RCVD AF sbspace lcredit hiwat cc", ! 556: sbspace(&so->so_rcv), tpcb->tp_lcredit, ! 557: so->so_rcv.sb_cc, so->so_rcv.sb_hiwat); ! 558: ENDTRACE ! 559: IFDEBUG(D_REQUEST) ! 560: printf("RCVD: cc %d space %d hiwat %d\n", ! 561: so->so_rcv.sb_cc, sbspace(&so->so_rcv), ! 562: so->so_rcv.sb_hiwat); ! 563: ENDDEBUG ! 564: if (((int)nam) & MSG_OOB) ! 565: error = DoEvent(T_USR_Xrcvd); ! 566: else ! 567: error = DoEvent(T_USR_rcvd); ! 568: break; ! 569: ! 570: case PRU_RCVOOB: ! 571: if ((so->so_state & SS_ISCONNECTED) == 0) { ! 572: error = ENOTCONN; ! 573: break; ! 574: } ! 575: if (! tpcb->tp_xpd_service) { ! 576: error = EOPNOTSUPP; ! 577: break; ! 578: } ! 579: /* kludge - nam is really flags here */ ! 580: error = tp_rcvoob(tpcb, so, m, outflags, (int)nam); ! 581: break; ! 582: ! 583: case PRU_SEND: ! 584: case PRU_SENDOOB: ! 585: if (controlp) { ! 586: error = tp_snd_control(controlp, so, &m); ! 587: controlp = NULL; ! 588: if (error) ! 589: break; ! 590: } ! 591: if (so->so_state & SS_ISCONFIRMING) { ! 592: if (tpcb->tp_state == TP_CONFIRMING) ! 593: error = tp_confirm(tpcb); ! 594: if (m) { ! 595: if (error == 0 && m->m_len != 0) ! 596: error = ENOTCONN; ! 597: m_freem(m); ! 598: m = 0; ! 599: } ! 600: break; ! 601: } ! 602: if (m == 0) ! 603: break; ! 604: ! 605: if (req == PRU_SENDOOB) { ! 606: if (tpcb->tp_xpd_service == 0) { ! 607: error = EOPNOTSUPP; ! 608: break; ! 609: } ! 610: error = tp_sendoob(tpcb, so, m, outflags); ! 611: break; ! 612: } ! 613: /* ! 614: * The protocol machine copies mbuf chains, ! 615: * prepends headers, assigns seq numbers, and ! 616: * puts the packets on the device. ! 617: * When they are acked they are removed from the socket buf. ! 618: * ! 619: * sosend calls this up until sbspace goes negative. ! 620: * Sbspace may be made negative by appending this mbuf chain, ! 621: * possibly by a whole cluster. ! 622: */ ! 623: { ! 624: register struct mbuf *n = m; ! 625: register struct sockbuf *sb = &so->so_snd; ! 626: int maxsize = tpcb->tp_l_tpdusize ! 627: - tp_headersize(DT_TPDU_type, tpcb) ! 628: - (tpcb->tp_use_checksum?4:0) ; ! 629: int totlen = n->m_pkthdr.len; ! 630: int mbufcnt = 0; ! 631: struct mbuf *nn; ! 632: ! 633: /* ! 634: * Could have eotsdu and no data.(presently MUST have ! 635: * an mbuf though, even if its length == 0) ! 636: */ ! 637: if (n->m_flags & M_EOR) { ! 638: eotsdu = 1; ! 639: n->m_flags &= ~M_EOR; ! 640: } ! 641: IFPERF(tpcb) ! 642: PStat(tpcb, Nb_from_sess) += totlen; ! 643: tpmeas(tpcb->tp_lref, TPtime_from_session, 0, 0, ! 644: PStat(tpcb, Nb_from_sess), totlen); ! 645: ENDPERF ! 646: IFDEBUG(D_SYSCALL) ! 647: printf( ! 648: "PRU_SEND: eot %d before sbappend 0x%x len 0x%x to sb @ 0x%x\n", ! 649: eotsdu, m, totlen, sb); ! 650: dump_mbuf(sb->sb_mb, "so_snd.sb_mb"); ! 651: dump_mbuf(m, "m : to be added"); ! 652: ENDDEBUG ! 653: /* ! 654: * Pre-packetize the data in the sockbuf ! 655: * according to negotiated mtu. Do it here ! 656: * where we can safely wait for mbufs. ! 657: * ! 658: * This presumes knowledge of sockbuf conventions. ! 659: */ ! 660: if (n = sb->sb_mb) ! 661: while (n->m_act) ! 662: n = n->m_act; ! 663: if ((nn = n) && n->m_pkthdr.len < maxsize) { ! 664: u_int space = maxsize - n->m_pkthdr.len; ! 665: ! 666: do { ! 667: if (n->m_flags & M_EOR) ! 668: goto on1; ! 669: } while (n->m_next && (n = n->m_next)); ! 670: if (totlen <= space) { ! 671: TPNagle1++; ! 672: n->m_next = m; ! 673: nn->m_pkthdr.len += totlen; ! 674: while (n = n->m_next) ! 675: sballoc(sb, n); ! 676: if (eotsdu) ! 677: nn->m_flags |= M_EOR; ! 678: goto on2; ! 679: } else { ! 680: /* ! 681: * Can't sleep here, because when you wake up ! 682: * packet you want to attach to may be gone! ! 683: */ ! 684: if (TNew && (n->m_next = m_copym(m, 0, space, M_NOWAIT))) { ! 685: nn->m_pkthdr.len += space; ! 686: TPNagle2++; ! 687: while (n = n->m_next) ! 688: sballoc(sb, n); ! 689: m_adj(m, space); ! 690: } ! 691: } ! 692: } ! 693: on1: mbufcnt++; ! 694: for (n = m; n->m_pkthdr.len > maxsize;) { ! 695: nn = m_copym(n, 0, maxsize, M_WAIT); ! 696: sbappendrecord(sb, nn); ! 697: m_adj(n, maxsize); ! 698: mbufcnt++; ! 699: } ! 700: if (eotsdu) ! 701: n->m_flags |= M_EOR; ! 702: sbappendrecord(sb, n); ! 703: on2: ! 704: IFTRACE(D_DATA) ! 705: tptraceTPCB(TPPTmisc, ! 706: "SEND BF: maxsize totlen mbufcnt eotsdu", ! 707: maxsize, totlen, mbufcnt, eotsdu); ! 708: ENDTRACE ! 709: IFDEBUG(D_SYSCALL) ! 710: printf("PRU_SEND: eot %d after sbappend 0x%x mbufcnt 0x%x\n", ! 711: eotsdu, n, mbufcnt); ! 712: dump_mbuf(sb->sb_mb, "so_snd.sb_mb"); ! 713: ENDDEBUG ! 714: error = DoEvent(T_DATA_req); ! 715: IFDEBUG(D_SYSCALL) ! 716: printf("PRU_SEND: after driver error 0x%x \n",error); ! 717: printf("so_snd 0x%x cc 0t%d mbcnt 0t%d\n", ! 718: sb, sb->sb_cc, sb->sb_mbcnt); ! 719: dump_mbuf(sb->sb_mb, "so_snd.sb_mb after driver"); ! 720: ENDDEBUG ! 721: } ! 722: break; ! 723: ! 724: case PRU_SOCKADDR: ! 725: (tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_LOCAL); ! 726: break; ! 727: ! 728: case PRU_PEERADDR: ! 729: (tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_FOREIGN); ! 730: break; ! 731: ! 732: case PRU_CONTROL: ! 733: error = EOPNOTSUPP; ! 734: break; ! 735: ! 736: case PRU_PROTOSEND: ! 737: case PRU_PROTORCV: ! 738: case PRU_SENSE: ! 739: case PRU_SLOWTIMO: ! 740: case PRU_FASTTIMO: ! 741: error = EOPNOTSUPP; ! 742: break; ! 743: ! 744: default: ! 745: #ifdef ARGO_DEBUG ! 746: printf("tp_usrreq UNKNOWN PRU %d\n", req); ! 747: #endif ARGO_DEBUG ! 748: error = EOPNOTSUPP; ! 749: } ! 750: ! 751: IFDEBUG(D_REQUEST) ! 752: printf("%s, so 0x%x, tpcb 0x%x, error %d, state %d\n", ! 753: "returning from tp_usrreq", so, tpcb, error, ! 754: tpcb ? 0 : tpcb->tp_state); ! 755: ENDDEBUG ! 756: IFTRACE(D_REQUEST) ! 757: tptraceTPCB(TPPTusrreq, "END req so m state [", req, so, m, ! 758: tpcb?0:tpcb->tp_state); ! 759: ENDTRACE ! 760: if (controlp) { ! 761: m_freem(controlp); ! 762: printf("control data unexpectedly retained in tp_usrreq()"); ! 763: } ! 764: splx(s); ! 765: return error; ! 766: } ! 767: tp_ltrace(so, uio) ! 768: struct socket *so; ! 769: struct uio *uio; ! 770: { ! 771: IFTRACE(D_DATA) ! 772: register struct tp_pcb *tpcb = sototpcb(so); ! 773: if (tpcb) { ! 774: tptraceTPCB(TPPTmisc, "sosend so resid iovcnt", so, ! 775: uio->uio_resid, uio->uio_iovcnt, 0); ! 776: } ! 777: ENDTRACE ! 778: } ! 779: ! 780: tp_confirm(tpcb) ! 781: register struct tp_pcb *tpcb; ! 782: { ! 783: struct tp_event E; ! 784: if (tpcb->tp_state == TP_CONFIRMING) ! 785: return DoEvent(T_ACPT_req); ! 786: printf("Tp confirm called when not confirming; tpcb 0x%x, state 0x%x\n", ! 787: tpcb, tpcb->tp_state); ! 788: return 0; ! 789: } ! 790: ! 791: /* ! 792: * Process control data sent with sendmsg() ! 793: */ ! 794: tp_snd_control(m, so, data) ! 795: struct mbuf *m; ! 796: struct socket *so; ! 797: register struct mbuf **data; ! 798: { ! 799: register struct cmsghdr *ch; ! 800: int error = 0; ! 801: ! 802: if (m && m->m_len) { ! 803: ch = mtod(m, struct cmsghdr *); ! 804: m->m_len -= sizeof (*ch); ! 805: m->m_data += sizeof (*ch); ! 806: error = tp_ctloutput(PRCO_SETOPT, ! 807: so, ch->cmsg_level, ch->cmsg_type, &m); ! 808: if (ch->cmsg_type == TPOPT_DISC_DATA) { ! 809: if (data && *data) { ! 810: m_freem(*data); ! 811: *data = 0; ! 812: } ! 813: error = tp_usrreq(so, PRU_DISCONNECT, (struct mbuf *)0, ! 814: (caddr_t)0, (struct mbuf *)0); ! 815: } ! 816: } ! 817: if (m) ! 818: m_freem(m); ! 819: return error; ! 820: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.