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