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.14 (Berkeley) 03/12/91 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 IFDEBUG(D_XPD) 188 printf("RCVOOB: empty queue!\n"); 189 ENDDEBUG 190 sbunlock(sb); 191 if (so->so_state & SS_NBIO) { 192 return EWOULDBLOCK; 193 } 194 sbwait(sb); 195 goto restart; 196 } 197 m->m_len = 0; 198 199 /* Assuming at most one xpd tpdu is in the buffer at once */ 200 while (n != MNULL) { 201 m->m_len += n->m_len; 202 bcopy(mtod(n, caddr_t), mtod(m, caddr_t), (unsigned)n->m_len); 203 m->m_data += n->m_len; /* so mtod() in bcopy() above gives right addr */ 204 n = n->m_next; 205 } 206 m->m_data = m->m_dat; 207 m->m_flags |= M_EOR; 208 209 IFDEBUG(D_XPD) 210 printf("tp_rcvoob: xpdlen 0x%x\n", m->m_len); 211 dump_mbuf(so->so_rcv.sb_mb, "RCVOOB: Rcv socketbuf"); 212 dump_mbuf(sb->sb_mb, "RCVOOB: Xrcv socketbuf"); 213 ENDDEBUG 214 215 if ((inflags & MSG_PEEK) == 0) { 216 n = *nn; 217 *nn = n->m_act; 218 sb->sb_cc -= m->m_len; 219 } 220 221 release: 222 sbunlock(sb); 223 224 IFTRACE(D_XPD) 225 tptraceTPCB(TPPTmisc, "PRU_RCVOOB @ release sb_cc m_len", 226 tpcb->tp_Xrcv.sb_cc, m->m_len, 0, 0); 227 ENDTRACE 228 if (error == 0) 229 error = DoEvent(T_USR_Xrcvd); 230 return error; 231 } 232 233 /* 234 * CALLED FROM: 235 * tp_usrreq(), PRU_SENDOOB 236 * FUNCTION and ARGUMENTS: 237 * Send what's in the mbuf chain (m) as an XPD TPDU. 238 * The mbuf may not contain more then 16 bytes of data. 239 * XPD TSDUs aren't segmented, so they translate into 240 * exactly one XPD TPDU, with EOT bit set. 241 * RETURN VALUE: 242 * EWOULDBLOCK if socket is in non-blocking mode and the previous 243 * xpd data haven't been acked yet. 244 * EMSGSIZE if trying to send > max-xpd bytes (16) 245 * ENOBUFS if ran out of mbufs 246 */ 247 tp_sendoob(tpcb, so, xdata, outflags) 248 struct tp_pcb *tpcb; 249 register struct socket *so; 250 register struct mbuf *xdata; 251 int *outflags; /* not used */ 252 { 253 /* 254 * Each mbuf chain represents a sequence # in the XPD seq space. 255 * The first one in the queue has sequence # tp_Xuna. 256 * When we add to the XPD queue, we stuff a zero-length 257 * mbuf (mark) into the DATA queue, with its sequence number in m_next 258 * to be assigned to this XPD tpdu, so data xfer can stop 259 * when it reaches the zero-length mbuf if this XPD TPDU hasn't 260 * yet been acknowledged. 261 */ 262 register struct sockbuf *sb = &(tpcb->tp_Xsnd); 263 register struct mbuf *xmark; 264 register int len=0; 265 struct tp_event E; 266 267 IFDEBUG(D_XPD) 268 printf("tp_sendoob:"); 269 if (xdata) 270 printf("xdata len 0x%x\n", xdata->m_len); 271 ENDDEBUG 272 /* DO NOT LOCK the Xsnd buffer!!!! You can have at MOST one 273 * socket buf locked at any time!!! (otherwise you might 274 * sleep() in sblock() w/ a signal pending and cause the 275 * system call to be aborted w/ a locked socketbuf, which 276 * is a problem. So the so_snd buffer lock 277 * (done in sosend()) serves as the lock for Xpd. 278 */ 279 if (sb->sb_mb) { /* Anything already in eXpedited data sockbuf? */ 280 if (so->so_state & SS_NBIO) { 281 return EWOULDBLOCK; 282 } 283 while (sb->sb_mb) { 284 sbunlock(&so->so_snd); /* already locked by sosend */ 285 sbwait(&so->so_snd); 286 sblock(&so->so_snd); /* sosend will unlock on return */ 287 } 288 } 289 290 if (xdata == (struct mbuf *)0) { 291 /* empty xpd packet */ 292 MGETHDR(xdata, M_WAIT, MT_OOBDATA); 293 if (xdata == NULL) { 294 return ENOBUFS; 295 } 296 xdata->m_len = 0; 297 xdata->m_pkthdr.len = 0; 298 } 299 IFDEBUG(D_XPD) 300 printf("tp_sendoob 1:"); 301 if (xdata) 302 printf("xdata len 0x%x\n", xdata->m_len); 303 ENDDEBUG 304 xmark = xdata; /* temporary use of variable xmark */ 305 while (xmark) { 306 len += xmark->m_len; 307 xmark = xmark->m_next; 308 } 309 if (len > TP_MAX_XPD_DATA) { 310 return EMSGSIZE; 311 } 312 IFDEBUG(D_XPD) 313 printf("tp_sendoob 2:"); 314 if (xdata) 315 printf("xdata len 0x%x\n", len); 316 ENDDEBUG 317 318 319 IFTRACE(D_XPD) 320 tptraceTPCB(TPPTmisc, "XPD mark m_next ", xdata->m_next, 0, 0, 0); 321 ENDTRACE 322 323 sbappendrecord(sb, xdata); 324 325 IFDEBUG(D_XPD) 326 printf("tp_sendoob len 0x%x\n", len); 327 dump_mbuf(so->so_snd.sb_mb, "XPD request Regular sndbuf:"); 328 dump_mbuf(tpcb->tp_Xsnd.sb_mb, "XPD request Xsndbuf:"); 329 ENDDEBUG 330 return DoEvent(T_XPD_req); 331 } 332 333 /* 334 * CALLED FROM: 335 * the socket routines 336 * FUNCTION and ARGUMENTS: 337 * Handles all "user requests" except the [gs]ockopts() requests. 338 * The argument (req) is the request type (PRU*), 339 * (m) is an mbuf chain, generally used for send and 340 * receive type requests only. 341 * (nam) is used for addresses usually, in particular for the bind request. 342 * 343 */ 344 /*ARGSUSED*/ 345 ProtoHook 346 tp_usrreq(so, req, m, nam, controlp) 347 struct socket *so; 348 u_int req; 349 struct mbuf *m, *nam, *controlp; 350 { 351 register struct tp_pcb *tpcb = sototpcb(so); 352 int s = splnet(); 353 int error = 0; 354 int flags, *outflags = &flags; 355 u_long eotsdu = 0; 356 struct tp_event E; 357 358 IFDEBUG(D_REQUEST) 359 printf("usrreq(0x%x,%d,0x%x,0x%x,0x%x)\n",so,req,m,nam,outflags); 360 if (so->so_error) 361 printf("WARNING!!! so->so_error is 0x%x\n", so->so_error); 362 ENDDEBUG 363 IFTRACE(D_REQUEST) 364 tptraceTPCB(TPPTusrreq, "req so m state [", req, so, m, 365 tpcb?tpcb->tp_state:0); 366 ENDTRACE 367 368 if ((u_int)tpcb == 0 && req != PRU_ATTACH) { 369 IFTRACE(D_REQUEST) 370 tptraceTPCB(TPPTusrreq, "req failed NO TPCB[", 0, 0, 0, 0); 371 ENDTRACE 372 splx(s); 373 return ENOTCONN; 374 } 375 376 switch (req) { 377 378 case PRU_ATTACH: 379 if (tpcb) { 380 error = EISCONN; 381 break; 382 } 383 if (error = tp_attach(so, so->so_proto->pr_domain->dom_family)) 384 break; 385 tpcb = sototpcb(so); 386 break; 387 388 case PRU_ABORT: /* called from close() */ 389 /* called for each incoming connect queued on the 390 * parent (accepting) socket 391 */ 392 if (tpcb->tp_state == TP_OPEN) { 393 E.ATTR(T_DISC_req).e_reason = E_TP_NO_SESSION; 394 error = DoEvent(T_DISC_req); /* pretend it was a close() */ 395 break; 396 } /* else DROP THROUGH */ 397 398 case PRU_DETACH: /* called from close() */ 399 /* called only after disconnect was called */ 400 if (tpcb->tp_state == TP_LISTENING) { 401 register struct tp_pcb **tt; 402 for (tt = &tp_listeners; *tt; tt = &((*tt)->tp_nextlisten)) 403 if (*tt == tpcb) 404 break; 405 if (*tt) 406 *tt = tpcb->tp_nextlisten; 407 else { 408 for (tt = &tp_intercepts; *tt; tt = &((*tt)->tp_nextlisten)) 409 if (*tt == tpcb) 410 break; 411 if (*tt) 412 *tt = tpcb->tp_nextlisten; 413 else 414 printf("tp_usrreq - detach: should panic\n"); 415 } 416 } 417 if (tpcb->tp_next) 418 remque(tpcb); 419 error = DoEvent(T_DETACH); 420 if (tpcb->tp_state == TP_CLOSED) { 421 free((caddr_t)tpcb, M_PCB); 422 tpcb = 0; 423 } 424 break; 425 426 case PRU_SHUTDOWN: 427 /* recv end may have been released; local credit might be zero */ 428 case PRU_DISCONNECT: 429 E.ATTR(T_DISC_req).e_reason = E_TP_NORMAL_DISC; 430 error = DoEvent(T_DISC_req); 431 break; 432 433 case PRU_BIND: 434 error = (tpcb->tp_nlproto->nlp_pcbbind)(so->so_pcb, nam); 435 if (error == 0) { 436 (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen, 437 tpcb->tp_lsuffix, TP_LOCAL); 438 } 439 break; 440 441 case PRU_LISTEN: 442 if (tpcb->tp_lsuffixlen == 0) { 443 if (error = (tpcb->tp_nlproto->nlp_pcbbind)(so->so_pcb, MNULL)) 444 break; 445 (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen, 446 tpcb->tp_lsuffix, TP_LOCAL); 447 } 448 if (tpcb->tp_next == 0) { 449 tpcb->tp_next = tpcb->tp_prev = tpcb; 450 tpcb->tp_nextlisten = tp_listeners; 451 tp_listeners = tpcb; 452 } 453 IFDEBUG(D_TPISO) 454 if (tpcb->tp_state != TP_CLOSED) 455 printf("LISTEN ERROR: state 0x%x\n", tpcb->tp_state); 456 ENDDEBUG 457 error = DoEvent(T_LISTEN_req); 458 break; 459 460 case PRU_CONNECT2: 461 error = EOPNOTSUPP; /* for unix domain sockets */ 462 break; 463 464 case PRU_CONNECT: 465 IFTRACE(D_CONN) 466 tptraceTPCB(TPPTmisc, 467 "PRU_CONNECT: so 0x%x *SHORT_LSUFXP(tpcb) 0x%x lsuflen 0x%x, class 0x%x", 468 tpcb->tp_sock, *SHORT_LSUFXP(tpcb), tpcb->tp_lsuffixlen, 469 tpcb->tp_class); 470 ENDTRACE 471 IFDEBUG(D_CONN) 472 printf("PRU_CONNECT: so *SHORT_LSUFXP(tpcb) 0x%x lsuflen 0x%x, class 0x%x", 473 tpcb->tp_sock, *SHORT_LSUFXP(tpcb), tpcb->tp_lsuffixlen, 474 tpcb->tp_class); 475 ENDDEBUG 476 if (tpcb->tp_lsuffixlen == 0) { 477 if (error = (tpcb->tp_nlproto->nlp_pcbbind)(so->so_pcb, MNULL)) { 478 IFDEBUG(D_CONN) 479 printf("pcbbind returns error 0x%x\n", error); 480 ENDDEBUG 481 break; 482 } 483 (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen, 484 tpcb->tp_lsuffix, TP_LOCAL); 485 } 486 487 IFDEBUG(D_CONN) 488 printf("isop 0x%x isop->isop_socket offset 12 :\n", tpcb->tp_npcb); 489 dump_buf(tpcb->tp_npcb, 16); 490 ENDDEBUG 491 if (error = tp_route_to(nam, tpcb, /* channel */0)) 492 break; 493 IFDEBUG(D_CONN) 494 printf( 495 "PRU_CONNECT after tpcb 0x%x so 0x%x npcb 0x%x flags 0x%x\n", 496 tpcb, so, tpcb->tp_npcb, tpcb->tp_flags); 497 printf("isop 0x%x isop->isop_socket offset 12 :\n", tpcb->tp_npcb); 498 dump_buf(tpcb->tp_npcb, 16); 499 ENDDEBUG 500 if (tpcb->tp_fsuffixlen == 0) { 501 /* didn't set peer extended suffix */ 502 (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_fsuffixlen, 503 tpcb->tp_fsuffix, TP_FOREIGN); 504 } 505 (void) (tpcb->tp_nlproto->nlp_mtu)(so, so->so_pcb, 506 &tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0); 507 if (tpcb->tp_state == TP_CLOSED) { 508 soisconnecting(so); 509 error = DoEvent(T_CONN_req); 510 } else { 511 (tpcb->tp_nlproto->nlp_pcbdisc)(so->so_pcb); 512 error = EISCONN; 513 } 514 IFPERF(tpcb) 515 u_int lsufx, fsufx; 516 lsufx = *(u_short *)(tpcb->tp_lsuffix); 517 fsufx = *(u_short *)(tpcb->tp_fsuffix); 518 519 tpmeas(tpcb->tp_lref, 520 TPtime_open | (tpcb->tp_xtd_format << 4), 521 &time, lsufx, fsufx, tpcb->tp_fref); 522 ENDPERF 523 break; 524 525 case PRU_ACCEPT: 526 (tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_FOREIGN); 527 IFDEBUG(D_REQUEST) 528 printf("ACCEPT PEERADDDR:"); 529 dump_buf(mtod(nam, char *), nam->m_len); 530 ENDDEBUG 531 IFPERF(tpcb) 532 u_int lsufx, fsufx; 533 lsufx = *(u_short *)(tpcb->tp_lsuffix); 534 fsufx = *(u_short *)(tpcb->tp_fsuffix); 535 536 tpmeas(tpcb->tp_lref, TPtime_open, 537 &time, lsufx, fsufx, tpcb->tp_fref); 538 ENDPERF 539 break; 540 541 case PRU_RCVD: 542 if (so->so_state & SS_ISCONFIRMING) { 543 if (tpcb->tp_state == TP_CONFIRMING) 544 error = tp_confirm(tpcb); 545 break; 546 } 547 IFTRACE(D_DATA) 548 tptraceTPCB(TPPTmisc, 549 "RCVD BF: lcredit sent_lcdt cc hiwat \n", 550 tpcb->tp_lcredit, tpcb->tp_sent_lcdt, 551 so->so_rcv.sb_cc, so->so_rcv.sb_hiwat); 552 LOCAL_CREDIT(tpcb); 553 tptraceTPCB(TPPTmisc, 554 "PRU_RCVD AF sbspace lcredit hiwat cc", 555 sbspace(&so->so_rcv), tpcb->tp_lcredit, 556 so->so_rcv.sb_cc, so->so_rcv.sb_hiwat); 557 ENDTRACE 558 IFDEBUG(D_REQUEST) 559 printf("RCVD: cc %d space %d hiwat %d\n", 560 so->so_rcv.sb_cc, sbspace(&so->so_rcv), 561 so->so_rcv.sb_hiwat); 562 ENDDEBUG 563 if (((int)nam) & MSG_OOB) 564 error = DoEvent(T_USR_Xrcvd); 565 else 566 error = DoEvent(T_USR_rcvd); 567 break; 568 569 case PRU_RCVOOB: 570 if ((so->so_state & SS_ISCONNECTED) == 0) { 571 error = ENOTCONN; 572 break; 573 } 574 if (! tpcb->tp_xpd_service) { 575 error = EOPNOTSUPP; 576 break; 577 } 578 /* kludge - nam is really flags here */ 579 error = tp_rcvoob(tpcb, so, m, outflags, (int)nam); 580 break; 581 582 case PRU_SEND: 583 case PRU_SENDOOB: 584 if (controlp) { 585 error = tp_snd_control(controlp, so, &m); 586 controlp = NULL; 587 if (error) 588 break; 589 } 590 if (so->so_state & SS_ISCONFIRMING) { 591 if (tpcb->tp_state == TP_CONFIRMING) 592 error = tp_confirm(tpcb); 593 if (m) { 594 if (error == 0 && m->m_len != 0) 595 error = ENOTCONN; 596 m_freem(m); 597 m = 0; 598 } 599 break; 600 } 601 if (m == 0) 602 break; 603 604 if (req == PRU_SENDOOB) { 605 if (tpcb->tp_xpd_service == 0) { 606 error = EOPNOTSUPP; 607 break; 608 } 609 error = tp_sendoob(tpcb, so, m, outflags); 610 break; 611 } 612 /* 613 * The protocol machine copies mbuf chains, 614 * prepends headers, assigns seq numbers, and 615 * puts the packets on the device. 616 * When they are acked they are removed from the socket buf. 617 * 618 * sosend calls this up until sbspace goes negative. 619 * Sbspace may be made negative by appending this mbuf chain, 620 * possibly by a whole cluster. 621 */ 622 { 623 register struct mbuf *n = m; 624 register struct sockbuf *sb = &so->so_snd; 625 int maxsize = tpcb->tp_l_tpdusize 626 - tp_headersize(DT_TPDU_type, tpcb) 627 - (tpcb->tp_use_checksum?4:0) ; 628 int totlen = n->m_pkthdr.len; 629 int mbufcnt = 0; 630 struct mbuf *nn; 631 632 /* 633 * Could have eotsdu and no data.(presently MUST have 634 * an mbuf though, even if its length == 0) 635 */ 636 if (n->m_flags & M_EOR) { 637 eotsdu = 1; 638 n->m_flags &= ~M_EOR; 639 } 640 IFPERF(tpcb) 641 PStat(tpcb, Nb_from_sess) += totlen; 642 tpmeas(tpcb->tp_lref, TPtime_from_session, 0, 0, 643 PStat(tpcb, Nb_from_sess), totlen); 644 ENDPERF 645 IFDEBUG(D_SYSCALL) 646 printf( 647 "PRU_SEND: eot %d before sbappend 0x%x len 0x%x to sb @ 0x%x\n", 648 eotsdu, m, totlen, sb); 649 dump_mbuf(sb->sb_mb, "so_snd.sb_mb"); 650 dump_mbuf(m, "m : to be added"); 651 ENDDEBUG 652 /* 653 * Pre-packetize the data in the sockbuf 654 * according to negotiated mtu. Do it here 655 * where we can safely wait for mbufs. 656 * 657 * This presumes knowledge of sockbuf conventions. 658 */ 659 if (n = sb->sb_mb) 660 while (n->m_act) 661 n = n->m_act; 662 if ((nn = n) && n->m_pkthdr.len < maxsize) { 663 u_int space = maxsize - n->m_pkthdr.len; 664 665 do { 666 if (n->m_flags & M_EOR) 667 goto on1; 668 } while (n->m_next && (n = n->m_next)); 669 if (totlen <= space) { 670 TPNagle1++; 671 n->m_next = m; 672 nn->m_pkthdr.len += totlen; 673 while (n = n->m_next) 674 sballoc(sb, n); 675 if (eotsdu) 676 nn->m_flags |= M_EOR; 677 goto on2; 678 } else { 679 /* 680 * Can't sleep here, because when you wake up 681 * packet you want to attach to may be gone! 682 */ 683 if (TNew && (n->m_next = m_copym(m, 0, space, M_NOWAIT))) { 684 nn->m_pkthdr.len += space; 685 TPNagle2++; 686 while (n = n->m_next) 687 sballoc(sb, n); 688 m_adj(m, space); 689 } 690 } 691 } 692 on1: mbufcnt++; 693 for (n = m; n->m_pkthdr.len > maxsize;) { 694 nn = m_copym(n, 0, maxsize, M_WAIT); 695 sbappendrecord(sb, nn); 696 m_adj(n, maxsize); 697 mbufcnt++; 698 } 699 if (eotsdu) 700 n->m_flags |= M_EOR; 701 sbappendrecord(sb, n); 702 on2: 703 IFTRACE(D_DATA) 704 tptraceTPCB(TPPTmisc, 705 "SEND BF: maxsize totlen mbufcnt eotsdu", 706 maxsize, totlen, mbufcnt, eotsdu); 707 ENDTRACE 708 IFDEBUG(D_SYSCALL) 709 printf("PRU_SEND: eot %d after sbappend 0x%x mbufcnt 0x%x\n", 710 eotsdu, n, mbufcnt); 711 dump_mbuf(sb->sb_mb, "so_snd.sb_mb"); 712 ENDDEBUG 713 error = DoEvent(T_DATA_req); 714 IFDEBUG(D_SYSCALL) 715 printf("PRU_SEND: after driver error 0x%x \n",error); 716 printf("so_snd 0x%x cc 0t%d mbcnt 0t%d\n", 717 sb, sb->sb_cc, sb->sb_mbcnt); 718 dump_mbuf(sb->sb_mb, "so_snd.sb_mb after driver"); 719 ENDDEBUG 720 } 721 break; 722 723 case PRU_SOCKADDR: 724 (tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_LOCAL); 725 break; 726 727 case PRU_PEERADDR: 728 (tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_FOREIGN); 729 break; 730 731 case PRU_CONTROL: 732 error = EOPNOTSUPP; 733 break; 734 735 case PRU_PROTOSEND: 736 case PRU_PROTORCV: 737 case PRU_SENSE: 738 case PRU_SLOWTIMO: 739 case PRU_FASTTIMO: 740 error = EOPNOTSUPP; 741 break; 742 743 default: 744 #ifdef ARGO_DEBUG 745 printf("tp_usrreq UNKNOWN PRU %d\n", req); 746 #endif ARGO_DEBUG 747 error = EOPNOTSUPP; 748 } 749 750 IFDEBUG(D_REQUEST) 751 printf("%s, so 0x%x, tpcb 0x%x, error %d, state %d\n", 752 "returning from tp_usrreq", so, tpcb, error, 753 tpcb ? 0 : tpcb->tp_state); 754 ENDDEBUG 755 IFTRACE(D_REQUEST) 756 tptraceTPCB(TPPTusrreq, "END req so m state [", req, so, m, 757 tpcb?0:tpcb->tp_state); 758 ENDTRACE 759 if (controlp) { 760 m_freem(controlp); 761 printf("control data unexpectedly retained in tp_usrreq()"); 762 } 763 splx(s); 764 return error; 765 } 766 tp_ltrace(so, uio) 767 struct socket *so; 768 struct uio *uio; 769 { 770 IFTRACE(D_DATA) 771 register struct tp_pcb *tpcb = sototpcb(so); 772 if (tpcb) { 773 tptraceTPCB(TPPTmisc, "sosend so resid iovcnt", so, 774 uio->uio_resid, uio->uio_iovcnt, 0); 775 } 776 ENDTRACE 777 } 778 779 tp_confirm(tpcb) 780 register struct tp_pcb *tpcb; 781 { 782 struct tp_event E; 783 if (tpcb->tp_state == TP_CONFIRMING) 784 return DoEvent(T_ACPT_req); 785 printf("Tp confirm called when not confirming; tpcb 0x%x, state 0x%x\n", 786 tpcb, tpcb->tp_state); 787 return 0; 788 } 789 790 /* 791 * Process control data sent with sendmsg() 792 */ 793 tp_snd_control(m, so, data) 794 struct mbuf *m; 795 struct socket *so; 796 register struct mbuf **data; 797 { 798 register struct cmsghdr *ch; 799 int error = 0; 800 801 if (m && m->m_len) { 802 ch = mtod(m, struct cmsghdr *); 803 m->m_len -= sizeof (*ch); 804 m->m_data += sizeof (*ch); 805 error = tp_ctloutput(PRCO_SETOPT, 806 so, ch->cmsg_level, ch->cmsg_type, &m); 807 if (ch->cmsg_type == TPOPT_DISC_DATA) { 808 if (data && *data) { 809 m_freem(*data); 810 *data = 0; 811 } 812 error = tp_usrreq(so, PRU_DISCONNECT, (struct mbuf *)0, 813 (caddr_t)0, (struct mbuf *)0); 814 } 815 } 816 if (m) 817 m_freem(m); 818 return error; 819 } 820