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.10 (Berkeley) 05/30/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 71 #ifdef ARGO_DEBUG 72 /* 73 * CALLED FROM: 74 * anywhere you want to debug... 75 * FUNCTION and ARGUMENTS: 76 * print (str) followed by the control info in the mbufs of an mbuf chain (n) 77 */ 78 void 79 dump_mbuf(n, str) 80 struct mbuf *n; 81 char *str; 82 { 83 struct mbuf *nextrecord; 84 85 printf("dump %s\n", str); 86 87 if( n == MNULL) { 88 printf("EMPTY:\n"); 89 return; 90 } 91 92 for(;n;) { 93 nextrecord = n->m_act; 94 printf("RECORD:\n"); 95 while (n) { 96 printf("%x : Len %x Data %x A %x Nx %x Tp %x\n", 97 n, n->m_len, n->m_data, n->m_act, n->m_next, n->m_type); 98 #ifdef notdef 99 { 100 register char *p = mtod(n, char *); 101 register int i; 102 103 printf("data: "); 104 for(i=0; i < n->m_len; i++ ) { 105 if(i%8 == 0) 106 printf("\n"); 107 printf("0x%x ", *(p+i)); 108 } 109 printf("\n"); 110 } 111 #endif notdef 112 if( n->m_next == n ) { 113 printf("LOOP!\n"); 114 return; 115 } 116 n = n->m_next; 117 } 118 n = nextrecord; 119 } 120 printf("\n"); 121 } 122 123 #endif ARGO_DEBUG 124 125 /* 126 * CALLED FROM: 127 * tp_usrreq(), PRU_RCVOOB 128 * FUNCTION and ARGUMENTS: 129 * Copy data from the expedited data socket buffer into 130 * the pre-allocated mbuf m. 131 * There is an isomorphism between XPD TPDUs and expedited data TSDUs. 132 * XPD tpdus are limited to 16 bytes of data so they fit in one mbuf. 133 * RETURN VALUE: 134 * EINVAL if debugging is on and a disaster has occurred 135 * ENOTCONN if the socket isn't connected 136 * EWOULDBLOCK if the socket is in non-blocking mode and there's no 137 * xpd data in the buffer 138 * E* whatever is returned from the fsm. 139 */ 140 tp_rcvoob(tpcb, so, m, outflags, inflags) 141 struct tp_pcb *tpcb; 142 register struct socket *so; 143 register struct mbuf *m; 144 int *outflags; 145 int inflags; 146 { 147 register struct mbuf *n; 148 register struct sockbuf *sb = &so->so_rcv; 149 struct tp_event E; 150 int error = 0; 151 register struct mbuf **nn; 152 153 IFDEBUG(D_XPD) 154 printf("PRU_RCVOOB, sostate 0x%x\n", so->so_state); 155 ENDDEBUG 156 157 /* if you use soreceive */ 158 if (m==MNULL) 159 return ENOBUFS; 160 161 restart: 162 if ((((so->so_state & SS_ISCONNECTED) == 0) 163 || (so->so_state & SS_ISDISCONNECTING) != 0) && 164 (so->so_proto->pr_flags & PR_CONNREQUIRED)) { 165 return ENOTCONN; 166 } 167 168 /* Take the first mbuf off the chain. 169 * Each XPD TPDU gives you a complete TSDU so the chains don't get 170 * coalesced, but one TSDU may span several mbufs. 171 * Nevertheless, since n should have a most 16 bytes, it 172 * will fit into m. (size was checked in tp_input() ) 173 */ 174 175 /* 176 * Code for excision of OOB data should be added to 177 * uipc_socket2.c (like sbappend). 178 */ 179 180 sblock(sb); 181 for (nn = &sb->sb_mb; n = *nn; nn = &n->m_act) 182 if (n->m_type == MT_OOBDATA) 183 break; 184 185 if (n == 0) { 186 ASSERT( (tpcb->tp_flags & TPF_DISC_DATA_IN) == 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 error = DoEvent(T_DETACH); 401 if (tpcb->tp_state == TP_CLOSED) { 402 free((caddr_t)tpcb, M_PCB); 403 tpcb = 0; 404 } 405 break; 406 407 case PRU_SHUTDOWN: 408 /* recv end may have been released; local credit might be zero */ 409 case PRU_DISCONNECT: 410 E.ATTR(T_DISC_req).e_reason = E_TP_NORMAL_DISC; 411 error = DoEvent(T_DISC_req); 412 break; 413 414 case PRU_BIND: 415 error = (tpcb->tp_nlproto->nlp_pcbbind)( so->so_pcb, nam ); 416 if (error == 0) { 417 (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen, 418 tpcb->tp_lsuffix, TP_LOCAL ); 419 } 420 break; 421 422 case PRU_LISTEN: 423 if( tpcb->tp_lsuffixlen == 0) { 424 if( error = (tpcb->tp_nlproto->nlp_pcbbind)(so->so_pcb, MNULL) ) 425 break; 426 (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen, 427 tpcb->tp_lsuffix, TP_LOCAL ); 428 } 429 IFDEBUG(D_TPISO) 430 if(tpcb->tp_state != TP_CLOSED) 431 printf("LISTEN ERROR: state 0x%x\n", tpcb->tp_state); 432 ENDDEBUG 433 error = DoEvent(T_LISTEN_req); 434 break; 435 436 case PRU_CONNECT2: 437 error = EOPNOTSUPP; /* for unix domain sockets */ 438 break; 439 440 case PRU_CONNECT: 441 IFTRACE(D_CONN) 442 tptraceTPCB(TPPTmisc, 443 "PRU_CONNECT: so 0x%x *SHORT_LSUFXP(tpcb) 0x%x lsuflen 0x%x, class 0x%x", 444 tpcb->tp_sock, *SHORT_LSUFXP(tpcb), tpcb->tp_lsuffixlen, 445 tpcb->tp_class); 446 ENDTRACE 447 IFDEBUG(D_CONN) 448 printf("PRU_CONNECT: so *SHORT_LSUFXP(tpcb) 0x%x lsuflen 0x%x, class 0x%x", 449 tpcb->tp_sock, *SHORT_LSUFXP(tpcb), tpcb->tp_lsuffixlen, 450 tpcb->tp_class); 451 ENDDEBUG 452 if( tpcb->tp_lsuffixlen == 0) { 453 if( error = (tpcb->tp_nlproto->nlp_pcbbind)(so->so_pcb, MNULL) ) { 454 IFDEBUG(D_CONN) 455 printf("pcbbind returns error 0x%x\n", error ); 456 ENDDEBUG 457 break; 458 } 459 (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen, 460 tpcb->tp_lsuffix, TP_LOCAL ); 461 } 462 463 IFDEBUG(D_CONN) 464 printf("isop 0x%x isop->isop_socket offset 12 :\n", tpcb->tp_npcb); 465 dump_buf( tpcb->tp_npcb, 16); 466 ENDDEBUG 467 if( error = tp_route_to( nam, tpcb, /* channel */0) ) 468 break; 469 IFDEBUG(D_CONN) 470 printf( 471 "PRU_CONNECT after tpcb 0x%x so 0x%x npcb 0x%x flags 0x%x\n", 472 tpcb, so, tpcb->tp_npcb, tpcb->tp_flags); 473 printf("isop 0x%x isop->isop_socket offset 12 :\n", tpcb->tp_npcb); 474 dump_buf( tpcb->tp_npcb, 16); 475 ENDDEBUG 476 if( tpcb->tp_fsuffixlen == 0) { 477 /* didn't set peer extended suffix */ 478 (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_fsuffixlen, 479 tpcb->tp_fsuffix, TP_FOREIGN ); 480 } 481 (void) (tpcb->tp_nlproto->nlp_mtu)(so, so->so_pcb, 482 &tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0); 483 if( tpcb->tp_state == TP_CLOSED) { 484 soisconnecting(so); 485 error = DoEvent(T_CONN_req); 486 } else { 487 (tpcb->tp_nlproto->nlp_pcbdisc)(so->so_pcb); 488 error = EISCONN; 489 } 490 IFPERF(tpcb) 491 u_int lsufx, fsufx; 492 lsufx = *(u_short *)(tpcb->tp_lsuffix); 493 fsufx = *(u_short *)(tpcb->tp_fsuffix); 494 495 tpmeas( tpcb->tp_lref, 496 TPtime_open | (tpcb->tp_xtd_format <<4 ), 497 &time, lsufx, fsufx, tpcb->tp_fref); 498 ENDPERF 499 break; 500 501 case PRU_ACCEPT: 502 (tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_FOREIGN); 503 IFDEBUG(D_REQUEST) 504 printf("ACCEPT PEERADDDR:"); 505 dump_buf(mtod(nam, char *), nam->m_len); 506 ENDDEBUG 507 IFPERF(tpcb) 508 u_int lsufx, fsufx; 509 lsufx = *(u_short *)(tpcb->tp_lsuffix); 510 fsufx = *(u_short *)(tpcb->tp_fsuffix); 511 512 tpmeas( tpcb->tp_lref, TPtime_open, 513 &time, lsufx, fsufx, tpcb->tp_fref); 514 ENDPERF 515 break; 516 517 case PRU_RCVD: 518 if (so->so_state & SS_ISCONFIRMING) { 519 if (tpcb->tp_state == TP_CONFIRMING) 520 error = tp_confirm(tpcb); 521 break; 522 } 523 IFTRACE(D_DATA) 524 tptraceTPCB(TPPTmisc, 525 "RCVD BF: lcredit sent_lcdt cc hiwat \n", 526 tpcb->tp_lcredit, tpcb->tp_sent_lcdt, 527 so->so_rcv.sb_cc, so->so_rcv.sb_hiwat); 528 LOCAL_CREDIT(tpcb); 529 tptraceTPCB(TPPTmisc, 530 "PRU_RCVD AF sbspace lcredit hiwat cc", 531 sbspace(&so->so_rcv), tpcb->tp_lcredit, 532 so->so_rcv.sb_cc, so->so_rcv.sb_hiwat); 533 ENDTRACE 534 IFDEBUG(D_REQUEST) 535 printf("RCVD: cc %d space %d hiwat %d\n", 536 so->so_rcv.sb_cc, sbspace(&so->so_rcv), 537 so->so_rcv.sb_hiwat); 538 ENDDEBUG 539 if (((int)nam) & MSG_OOB) 540 error = DoEvent(T_USR_Xrcvd); 541 else 542 error = DoEvent(T_USR_rcvd); 543 break; 544 545 case PRU_RCVOOB: 546 if ((so->so_state & SS_ISCONNECTED) == 0) { 547 error = ENOTCONN; 548 break; 549 } 550 if( ! tpcb->tp_xpd_service ) { 551 error = EOPNOTSUPP; 552 break; 553 } 554 /* kludge - nam is really flags here */ 555 error = tp_rcvoob(tpcb, so, m, outflags, (int)nam); 556 break; 557 558 case PRU_SEND: 559 case PRU_SENDOOB: 560 if (controlp) { 561 error = tp_snd_control(controlp, so, &m); 562 controlp = NULL; 563 if (error) 564 break; 565 } 566 if (so->so_state & SS_ISCONFIRMING) { 567 if (tpcb->tp_state == TP_CONFIRMING) 568 error = tp_confirm(tpcb); 569 if (m) { 570 if (error == 0 && m->m_len != 0) 571 error = ENOTCONN; 572 m_freem(m); 573 m = 0; 574 } 575 break; 576 } 577 if (m == 0) 578 break; 579 580 if (req == PRU_SENDOOB) { 581 if (tpcb->tp_xpd_service == 0) { 582 error = EOPNOTSUPP; 583 break; 584 } 585 error = tp_sendoob(tpcb, so, m, outflags); 586 break; 587 } 588 /* 589 * The protocol machine copies mbuf chains, 590 * prepends headers, assigns seq numbers, and 591 * puts the packets on the device. 592 * When they are acked they are removed from the socket buf. 593 * 594 * sosend calls this up until sbspace goes negative. 595 * Sbspace may be made negative by appending this mbuf chain, 596 * possibly by a whole cluster. 597 */ 598 { 599 register struct mbuf *n = m; 600 register struct sockbuf *sb = &so->so_snd; 601 int maxsize = tpcb->tp_l_tpdusize 602 - tp_headersize(DT_TPDU_type, tpcb) 603 - (tpcb->tp_use_checksum?4:0) ; 604 int totlen = n->m_pkthdr.len; 605 int mbufcnt = 0; 606 struct mbuf *nn; 607 608 /* 609 * Could have eotsdu and no data.(presently MUST have 610 * an mbuf though, even if its length == 0) 611 */ 612 if (n->m_flags & M_EOR) { 613 eotsdu = 1; 614 n->m_flags &= ~M_EOR; 615 } 616 IFPERF(tpcb) 617 PStat(tpcb, Nb_from_sess) += totlen; 618 tpmeas(tpcb->tp_lref, TPtime_from_session, 0, 0, 619 PStat(tpcb, Nb_from_sess), totlen); 620 ENDPERF 621 IFDEBUG(D_SYSCALL) 622 printf( 623 "PRU_SEND: eot %d before sbappend 0x%x len 0x%x to sb @ 0x%x\n", 624 eotsdu, m, totlen, sb); 625 dump_mbuf(sb->sb_mb, "so_snd.sb_mb"); 626 dump_mbuf(m, "m : to be added"); 627 ENDDEBUG 628 /* 629 * Pre-packetize the data in the sockbuf 630 * according to negotiated mtu. Do it here 631 * where we can safely wait for mbufs. 632 * 633 * This presumes knowledge of sockbuf conventions. 634 */ 635 if (n = sb->sb_mb) 636 while (n->m_act) 637 n = n->m_act; 638 if ((nn = n) && n->m_pkthdr.len < maxsize) { 639 u_int space = maxsize - n->m_pkthdr.len; 640 641 do { 642 if (n->m_flags & M_EOR) 643 goto on1; 644 } while (n->m_next && (n = n->m_next)); 645 if (totlen <= space) { 646 TPNagle1++; 647 n->m_next = m; 648 nn->m_pkthdr.len += totlen; 649 while (n = n->m_next) 650 sballoc(sb, n); 651 if (eotsdu) 652 nn->m_flags |= M_EOR; 653 goto on2; 654 } else { 655 /* 656 * Can't sleep here, because when you wake up 657 * packet you want to attach to may be gone! 658 */ 659 if (TNew && (n->m_next = m_copym(m, 0, space, M_NOWAIT))) { 660 nn->m_pkthdr.len += space; 661 TPNagle2++; 662 while (n = n->m_next) 663 sballoc(sb, n); 664 m_adj(m, space); 665 } 666 } 667 } 668 on1: mbufcnt++; 669 for (n = m; n->m_pkthdr.len > maxsize;) { 670 nn = m_copym(n, 0, maxsize, M_WAIT); 671 sbappendrecord(sb, nn); 672 m_adj(n, maxsize); 673 mbufcnt++; 674 } 675 if (eotsdu) 676 n->m_flags |= M_EOR; 677 sbappendrecord(sb, n); 678 on2: 679 IFTRACE(D_DATA) 680 tptraceTPCB(TPPTmisc, 681 "SEND BF: maxsize totlen mbufcnt eotsdu", 682 maxsize, totlen, mbufcnt, eotsdu); 683 ENDTRACE 684 IFDEBUG(D_SYSCALL) 685 printf("PRU_SEND: eot %d after sbappend 0x%x mbufcnt 0x%x\n", 686 eotsdu, n, mbufcnt); 687 dump_mbuf(sb->sb_mb, "so_snd.sb_mb"); 688 ENDDEBUG 689 error = DoEvent(T_DATA_req); 690 IFDEBUG(D_SYSCALL) 691 printf("PRU_SEND: after driver error 0x%x \n",error); 692 printf("so_snd 0x%x cc 0t%d mbcnt 0t%d\n", 693 sb, sb->sb_cc, sb->sb_mbcnt); 694 dump_mbuf(sb->sb_mb, "so_snd.sb_mb after driver"); 695 ENDDEBUG 696 } 697 break; 698 699 case PRU_SOCKADDR: 700 (tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_LOCAL); 701 break; 702 703 case PRU_PEERADDR: 704 (tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_FOREIGN); 705 break; 706 707 case PRU_CONTROL: 708 error = EOPNOTSUPP; 709 break; 710 711 case PRU_PROTOSEND: 712 case PRU_PROTORCV: 713 case PRU_SENSE: 714 case PRU_SLOWTIMO: 715 case PRU_FASTTIMO: 716 error = EOPNOTSUPP; 717 break; 718 719 default: 720 #ifdef ARGO_DEBUG 721 printf("tp_usrreq UNKNOWN PRU %d\n", req); 722 #endif ARGO_DEBUG 723 error = EOPNOTSUPP; 724 } 725 726 IFDEBUG(D_REQUEST) 727 printf("%s, so 0x%x, tpcb 0x%x, error %d, state %d\n", 728 "returning from tp_usrreq", so, tpcb, error, 729 tpcb ? 0 : tpcb->tp_state); 730 ENDDEBUG 731 IFTRACE(D_REQUEST) 732 tptraceTPCB(TPPTusrreq, "END req so m state [", req, so, m, 733 tpcb?0:tpcb->tp_state); 734 ENDTRACE 735 if (controlp) { 736 m_freem(controlp); 737 printf("control data unexpectedly retained in tp_usrreq()"); 738 } 739 splx(s); 740 return error; 741 } 742 tp_ltrace(so, uio) 743 struct socket *so; 744 struct uio *uio; 745 { 746 IFTRACE(D_DATA) 747 register struct tp_pcb *tpcb = sototpcb(so); 748 if (tpcb) { 749 tptraceTPCB(TPPTmisc, "sosend so resid iovcnt", so, 750 uio->uio_resid, uio->uio_iovcnt, 0); 751 } 752 ENDTRACE 753 } 754 755 tp_confirm(tpcb) 756 register struct tp_pcb *tpcb; 757 { 758 struct tp_event E; 759 if (tpcb->tp_state == TP_CONFIRMING) 760 return DoEvent(T_ACPT_req); 761 printf("Tp confirm called when not confirming; tpcb 0x%x, state 0x%x\n", 762 tpcb, tpcb->tp_state); 763 return 0; 764 } 765 766 /* 767 * Process control data sent with sendmsg() 768 */ 769 tp_snd_control(m, so, data) 770 struct mbuf *m; 771 struct socket *so; 772 register struct mbuf **data; 773 { 774 register struct cmsghdr *ch; 775 int error = 0; 776 777 if (m && m->m_len) { 778 ch = mtod(m, struct cmsghdr *); 779 m->m_len -= sizeof (*ch); 780 m->m_data += sizeof (*ch); 781 error = tp_ctloutput(PRCO_SETOPT, 782 so, ch->cmsg_level, ch->cmsg_type, &m); 783 if (ch->cmsg_type == TPOPT_DISC_DATA) { 784 if (data && *data) { 785 m_freem(*data); 786 *data = 0; 787 } 788 error = tp_usrreq(so, PRU_DISCONNECT, (struct mbuf *)0, 789 (caddr_t)0, (struct mbuf *)0); 790 } 791 } 792 if (m) 793 m_freem(m); 794 return error; 795 } 796