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.15 (Berkeley) 04/26/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 (tpcb->tp_state == TP_CONFIRMING) && 592 (error = tp_confirm(tpcb))) 593 break; 594 if (req == PRU_SENDOOB) { 595 error = (tpcb->tp_xpd_service == 0) ? 596 EOPNOTSUPP : tp_sendoob(tpcb, so, m, outflags); 597 break; 598 } 599 if (m == 0) 600 break; 601 if (m->m_flags & M_EOR) { 602 eotsdu = 1; 603 m->m_flags &= ~M_EOR; 604 } 605 if (eotsdu == 0 && m->m_pkthdr.len == 0) 606 break; 607 if (tpcb->tp_state != TP_AKWAIT && tpcb->tp_state != TP_OPEN) { 608 error = ENOTCONN; 609 break; 610 } 611 /* 612 * The protocol machine copies mbuf chains, 613 * prepends headers, assigns seq numbers, and 614 * puts the packets on the device. 615 * When they are acked they are removed from the socket buf. 616 * 617 * sosend calls this up until sbspace goes negative. 618 * Sbspace may be made negative by appending this mbuf chain, 619 * possibly by a whole cluster. 620 */ 621 { 622 register struct mbuf *n = m; 623 register struct sockbuf *sb = &so->so_snd; 624 int maxsize = tpcb->tp_l_tpdusize 625 - tp_headersize(DT_TPDU_type, tpcb) 626 - (tpcb->tp_use_checksum?4:0) ; 627 int totlen = n->m_pkthdr.len; 628 int mbufcnt = 0; 629 struct mbuf *nn; 630 631 /* 632 * Could have eotsdu and no data.(presently MUST have 633 * an mbuf though, even if its length == 0) 634 */ 635 IFPERF(tpcb) 636 PStat(tpcb, Nb_from_sess) += totlen; 637 tpmeas(tpcb->tp_lref, TPtime_from_session, 0, 0, 638 PStat(tpcb, Nb_from_sess), totlen); 639 ENDPERF 640 IFDEBUG(D_SYSCALL) 641 printf( 642 "PRU_SEND: eot %d before sbappend 0x%x len 0x%x to sb @ 0x%x\n", 643 eotsdu, m, totlen, sb); 644 dump_mbuf(sb->sb_mb, "so_snd.sb_mb"); 645 dump_mbuf(m, "m : to be added"); 646 ENDDEBUG 647 /* 648 * Pre-packetize the data in the sockbuf 649 * according to negotiated mtu. Do it here 650 * where we can safely wait for mbufs. 651 * 652 * This presumes knowledge of sockbuf conventions. 653 */ 654 if (n = sb->sb_mb) 655 while (n->m_act) 656 n = n->m_act; 657 if ((nn = n) && n->m_pkthdr.len < maxsize) { 658 u_int space = maxsize - n->m_pkthdr.len; 659 660 do { 661 if (n->m_flags & M_EOR) 662 goto on1; 663 } while (n->m_next && (n = n->m_next)); 664 if (totlen <= space) { 665 TPNagle1++; 666 n->m_next = m; 667 nn->m_pkthdr.len += totlen; 668 while (n = n->m_next) 669 sballoc(sb, n); 670 if (eotsdu) 671 nn->m_flags |= M_EOR; 672 goto on2; 673 } else { 674 /* 675 * Can't sleep here, because when you wake up 676 * packet you want to attach to may be gone! 677 */ 678 if (TNew && (n->m_next = m_copym(m, 0, space, M_NOWAIT))) { 679 nn->m_pkthdr.len += space; 680 TPNagle2++; 681 while (n = n->m_next) 682 sballoc(sb, n); 683 m_adj(m, space); 684 } 685 } 686 } 687 on1: mbufcnt++; 688 for (n = m; n->m_pkthdr.len > maxsize;) { 689 nn = m_copym(n, 0, maxsize, M_WAIT); 690 sbappendrecord(sb, nn); 691 m_adj(n, maxsize); 692 mbufcnt++; 693 } 694 if (eotsdu) 695 n->m_flags |= M_EOR; 696 sbappendrecord(sb, n); 697 on2: 698 IFTRACE(D_DATA) 699 tptraceTPCB(TPPTmisc, 700 "SEND BF: maxsize totlen mbufcnt eotsdu", 701 maxsize, totlen, mbufcnt, eotsdu); 702 ENDTRACE 703 IFDEBUG(D_SYSCALL) 704 printf("PRU_SEND: eot %d after sbappend 0x%x mbufcnt 0x%x\n", 705 eotsdu, n, mbufcnt); 706 dump_mbuf(sb->sb_mb, "so_snd.sb_mb"); 707 ENDDEBUG 708 if (tpcb->tp_state == TP_OPEN) 709 error = DoEvent(T_DATA_req); 710 IFDEBUG(D_SYSCALL) 711 printf("PRU_SEND: after driver error 0x%x \n",error); 712 printf("so_snd 0x%x cc 0t%d mbcnt 0t%d\n", 713 sb, sb->sb_cc, sb->sb_mbcnt); 714 dump_mbuf(sb->sb_mb, "so_snd.sb_mb after driver"); 715 ENDDEBUG 716 } 717 break; 718 719 case PRU_SOCKADDR: 720 (tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_LOCAL); 721 break; 722 723 case PRU_PEERADDR: 724 (tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_FOREIGN); 725 break; 726 727 case PRU_CONTROL: 728 error = EOPNOTSUPP; 729 break; 730 731 case PRU_PROTOSEND: 732 case PRU_PROTORCV: 733 case PRU_SENSE: 734 case PRU_SLOWTIMO: 735 case PRU_FASTTIMO: 736 error = EOPNOTSUPP; 737 break; 738 739 default: 740 #ifdef ARGO_DEBUG 741 printf("tp_usrreq UNKNOWN PRU %d\n", req); 742 #endif ARGO_DEBUG 743 error = EOPNOTSUPP; 744 } 745 746 IFDEBUG(D_REQUEST) 747 printf("%s, so 0x%x, tpcb 0x%x, error %d, state %d\n", 748 "returning from tp_usrreq", so, tpcb, error, 749 tpcb ? 0 : tpcb->tp_state); 750 ENDDEBUG 751 IFTRACE(D_REQUEST) 752 tptraceTPCB(TPPTusrreq, "END req so m state [", req, so, m, 753 tpcb?0:tpcb->tp_state); 754 ENDTRACE 755 if (controlp) { 756 m_freem(controlp); 757 printf("control data unexpectedly retained in tp_usrreq()"); 758 } 759 splx(s); 760 return error; 761 } 762 tp_ltrace(so, uio) 763 struct socket *so; 764 struct uio *uio; 765 { 766 IFTRACE(D_DATA) 767 register struct tp_pcb *tpcb = sototpcb(so); 768 if (tpcb) { 769 tptraceTPCB(TPPTmisc, "sosend so resid iovcnt", so, 770 uio->uio_resid, uio->uio_iovcnt, 0); 771 } 772 ENDTRACE 773 } 774 775 tp_confirm(tpcb) 776 register struct tp_pcb *tpcb; 777 { 778 struct tp_event E; 779 if (tpcb->tp_state == TP_CONFIRMING) 780 return DoEvent(T_ACPT_req); 781 printf("Tp confirm called when not confirming; tpcb 0x%x, state 0x%x\n", 782 tpcb, tpcb->tp_state); 783 return 0; 784 } 785 786 /* 787 * Process control data sent with sendmsg() 788 */ 789 tp_snd_control(m, so, data) 790 struct mbuf *m; 791 struct socket *so; 792 register struct mbuf **data; 793 { 794 register struct cmsghdr *ch; 795 int error = 0; 796 797 if (m && m->m_len) { 798 ch = mtod(m, struct cmsghdr *); 799 m->m_len -= sizeof (*ch); 800 m->m_data += sizeof (*ch); 801 error = tp_ctloutput(PRCO_SETOPT, 802 so, ch->cmsg_level, ch->cmsg_type, &m); 803 if (ch->cmsg_type == TPOPT_DISC_DATA) { 804 if (data && *data) { 805 m_freem(*data); 806 *data = 0; 807 } 808 error = tp_usrreq(so, PRU_DISCONNECT, (struct mbuf *)0, 809 (caddr_t)0, (struct mbuf *)0); 810 } 811 } 812 if (m) 813 m_freem(m); 814 return error; 815 } 816