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