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.5 (Berkeley) 09/22/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 (n && n->m_pkthdr.len < maxsize) { 634 int space = maxsize - n->m_pkthdr.len; 635 int eorseen = 0; 636 nn = n; 637 for (;; n = n->m_next) { 638 eorseen |= n->m_flags & M_EOR; 639 if (n->m_next == 0) 640 break; 641 } 642 if (eorseen) 643 goto on1; 644 if (m->m_pkthdr.len <= space) { 645 n->m_next = m; 646 if (eotsdu) 647 nn->m_flags |= M_EOR; 648 goto on2; 649 } else { 650 nn->m_next = m_copym(n, 0, space, M_WAIT); 651 m_adj(n, space); 652 } 653 } 654 on1: len++; 655 for (n = m; n->m_pkthdr.len > maxsize;) { 656 nn = m_copym(n, 0, len, M_WAIT); 657 sbappendrecord(sb, nn); 658 m_adj(n, maxsize); 659 len++; 660 } 661 if (eotsdu) 662 n->m_flags |= M_EOR; 663 sbappendrecord(sb, n); 664 on2: 665 IFTRACE(D_DATA) 666 tptraceTPCB(TPPTmisc, 667 "SEND BF: maxsize totlen frags eotsdu", 668 maxsize, totlen, len, eotsdu); 669 ENDTRACE 670 IFDEBUG(D_SYSCALL) 671 printf("PRU_SEND: eot %d after sbappend 0x%x len 0x%x\n", 672 eotsdu, n, len); 673 dump_mbuf(sb->sb_mb, "so_snd.sb_mb"); 674 ENDDEBUG 675 error = DoEvent(T_DATA_req); 676 IFDEBUG(D_SYSCALL) 677 printf("PRU_SEND: after driver error 0x%x \n",error); 678 printf("so_snd 0x%x cc 0t%d mbcnt 0t%d\n", 679 sb, sb->sb_cc, sb->sb_mbcnt); 680 dump_mbuf(sb->sb_mb, "so_snd.sb_mb after driver"); 681 ENDDEBUG 682 } 683 break; 684 685 case PRU_SOCKADDR: 686 (tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_LOCAL); 687 break; 688 689 case PRU_PEERADDR: 690 (tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_FOREIGN); 691 break; 692 693 case PRU_CONTROL: 694 error = EOPNOTSUPP; 695 break; 696 697 case PRU_PROTOSEND: 698 case PRU_PROTORCV: 699 case PRU_SENSE: 700 case PRU_SLOWTIMO: 701 case PRU_FASTTIMO: 702 error = EOPNOTSUPP; 703 break; 704 705 default: 706 #ifdef ARGO_DEBUG 707 printf("tp_usrreq UNKNOWN PRU %d\n", req); 708 #endif ARGO_DEBUG 709 error = EOPNOTSUPP; 710 } 711 712 IFDEBUG(D_REQUEST) 713 printf("%s, so 0x%x, tpcb 0x%x, error %d, state %d\n", 714 "returning from tp_usrreq", so, tpcb, error, 715 tpcb ? 0 : tpcb->tp_state); 716 ENDDEBUG 717 IFTRACE(D_REQUEST) 718 tptraceTPCB(TPPTusrreq, "END req so m state [", req, so, m, 719 tpcb?0:tpcb->tp_state); 720 ENDTRACE 721 splx(s); 722 return error; 723 } 724 tp_ltrace(so, uio) 725 struct socket *so; 726 struct uio *uio; 727 { 728 IFTRACE(D_DATA) 729 register struct tp_pcb *tpcb = sototpcb(so); 730 if (tpcb) { 731 tptraceTPCB(TPPTmisc, "sosend so resid iovcnt", so, 732 uio->uio_resid, uio->uio_iovcnt, 0); 733 } 734 ENDTRACE 735 } 736 737 tp_confirm(tpcb) 738 register struct tp_pcb *tpcb; 739 { 740 struct tp_event E; 741 if (tpcb->tp_state == TP_CONFIRMING) 742 return DoEvent(T_ACPT_req); 743 printf("Tp confirm called when not confirming; tpcb 0x%x, state 0x%x\n", 744 tpcb, tpcb->tp_state); 745 return 0; 746 } 747 748 /* 749 * Process control data sent with sendmsg() 750 */ 751 tp_snd_control(m0, so, data) 752 register struct mbuf *m0; 753 struct socket *so; 754 register struct mbuf **data; 755 { 756 register struct tp_control_hdr *ch; 757 struct mbuf *m; 758 int error = 0; 759 760 if (m0 && m0->m_len) { 761 ch = mtod(m0, struct tp_control_hdr *); 762 m0->m_len -= sizeof (*ch); 763 m0->m_data += sizeof (*ch); 764 m = m_copym(m0, 0, M_COPYALL, M_WAIT); 765 error = tp_ctloutput(PRCO_SETOPT, 766 so, ch->cmsg_level, ch->cmsg_type, &m); 767 if (m) 768 m_freem(m); 769 if (ch->cmsg_type == TPOPT_DISC_DATA) { 770 if (data && *data) { 771 m_freem(*data); 772 *data = 0; 773 } 774 m0 = 0; 775 error = tp_usrreq(so, PRU_DISCONNECT, m0, (caddr_t)0, m0, m0); 776 } 777 } 778 return error; 779 } 780