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) 06/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 } 821