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 * 33 * tp_usrreq(), the fellow that gets called from most of the socket code. 34 * Pretty straighforward. 35 * THe only really awful stuff here is the OOB processing, which is done 36 * wholly here. 37 * tp_rcvoob() and tp_sendoob() are contained here and called by tp_usrreq(). 38 */ 39 40 #ifndef lint 41 static char *rcsid = "$Header: tp_usrreq.c,v 5.4 88/11/18 17:29:18 nhall Exp $"; 42 #endif lint 43 44 #include "param.h" 45 #include "systm.h" 46 #include "user.h" 47 #include "mbuf.h" 48 #include "socket.h" 49 #include "socketvar.h" 50 #include "domain.h" 51 #include "protosw.h" 52 #include "errno.h" 53 54 #include "tp_param.h" 55 #include "tp_timer.h" 56 #include "tp_stat.h" 57 #include "tp_seq.h" 58 #include "tp_ip.h" 59 #include "tp_pcb.h" 60 #include "argo_debug.h" 61 #include "tp_trace.h" 62 #include "tp_meas.h" 63 #include "iso.h" 64 #include "iso_errno.h" 65 66 int tp_attach(), tp_driver(); 67 68 #ifdef ARGO_DEBUG 69 /* 70 * CALLED FROM: 71 * anywhere you want to debug... 72 * FUNCTION and ARGUMENTS: 73 * print (str) followed by the control info in the mbufs of an mbuf chain (n) 74 */ 75 void 76 dump_mbuf(n, str) 77 struct mbuf *n; 78 char *str; 79 { 80 struct mbuf *nextrecord; 81 82 printf("dump %s\n", str); 83 84 if( n == MNULL) { 85 printf("EMPTY:\n"); 86 return; 87 } 88 89 for(;n;) { 90 nextrecord = n->m_act; 91 printf("RECORD:\n"); 92 while (n) { 93 printf("%x : Len %x Data %x A %x Nx %x Tp %x\n", 94 n, n->m_len, n->m_data, n->m_act, n->m_next, n->m_type); 95 #ifdef notdef 96 { 97 register char *p = mtod(n, char *); 98 register int i; 99 100 printf("data: "); 101 for(i=0; i < n->m_len; i++ ) { 102 if(i%8 == 0) 103 printf("\n"); 104 printf("0x%x ", *(p+i)); 105 } 106 printf("\n"); 107 } 108 #endif notdef 109 if( n->m_next == n ) { 110 printf("LOOP!\n"); 111 return; 112 } 113 n = n->m_next; 114 } 115 n = nextrecord; 116 } 117 printf("\n"); 118 } 119 120 #endif ARGO_DEBUG 121 122 /* 123 * CALLED FROM: 124 * tp_usrreq(), PRU_RCVOOB 125 * FUNCTION and ARGUMENTS: 126 * Copy data from the expedited data socket buffer into 127 * the pre-allocated mbuf m. 128 * There is an isomorphism between XPD TPDUs and expedited data TSDUs. 129 * XPD tpdus are limited to 16 bytes of data so they fit in one mbuf. 130 * RETURN VALUE: 131 * EINVAL if debugging is on and a disaster has occurred 132 * ENOTCONN if the socket isn't connected 133 * EWOULDBLOCK if the socket is in non-blocking mode and there's no 134 * xpd data in the buffer 135 * E* whatever is returned from the fsm. 136 */ 137 tp_rcvoob(tpcb, so, m, outflags, inflags) 138 struct tp_pcb *tpcb; 139 register struct socket *so; 140 register struct mbuf *m; 141 int *outflags; 142 int inflags; 143 { 144 register struct mbuf *n; 145 register struct sockbuf *sb = &so->so_rcv; 146 struct tp_event E; 147 int error = 0; 148 register struct mbuf **nn; 149 150 IFDEBUG(D_XPD) 151 printf("PRU_RCVOOB, sostate 0x%x\n", so->so_state); 152 ENDDEBUG 153 154 /* if you use soreceive */ 155 if (m==MNULL) 156 return ENOBUFS; 157 158 restart: 159 sblock(sb); 160 161 if ((((so->so_state & SS_ISCONNECTED) == 0) 162 || (so->so_state & SS_ISDISCONNECTING) != 0) && 163 (so->so_proto->pr_flags & PR_CONNREQUIRED)) { 164 return ENOTCONN; 165 } 166 167 /* Take the first mbuf off the chain. 168 * Each XPD TPDU gives you a complete TSDU so the chains don't get 169 * coalesced, but one TSDU may span several mbufs. 170 * Nevertheless, since n should have a most 16 bytes, it 171 * will fit into m. (size was checked in tp_input() ) 172 */ 173 174 /* 175 * Code for excision of OOB data should be added to 176 * uipc_socket2.c (like sbappend). 177 */ 178 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 if (so->so_state & SS_NBIO) { 189 return EWOULDBLOCK; 190 } 191 sbunlock(sb); 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 oob_again: 271 /* DO NOT LOCK the Xsnd buffer!!!! You can have at MOST one 272 * socket buf locked at any time!!! (otherwise you might 273 * sleep() in sblock() w/ a signal pending and cause the 274 * system call to be aborted w/ a locked socketbuf, which 275 * is a problem. So the so_snd buffer lock 276 * (done in sosend()) serves as the lock for Xpd. 277 */ 278 if (sb->sb_mb) { /* anything already in this sockbuf? */ 279 if (so->so_state & SS_NBIO) { 280 return EWOULDBLOCK; 281 } 282 sbunlock(&so->so_snd); 283 sbwait(&so->so_snd); 284 sblock(&so->so_snd); 285 goto oob_again; 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 ", xmark->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 /* 333 * CALLED FROM: 334 * the socket routines 335 * FUNCTION and ARGUMENTS: 336 * Handles all "user requests" except the [gs]ockopts() requests. 337 * The argument (req) is the request type (PRU*), 338 * (m) is an mbuf chain, generally used for send and 339 * receive type requests only. 340 * (nam) is used for addresses usually, in particular for the bind request. 341 * 342 * The last argument (rights in most usrreq()s) has been stolen for 343 * returning flags values. Since rights can't be passed around w/ tp, 344 * this field is used only for RCVOOB user requests, and is assumed 345 * to be either 0 (as soreceive() would have it) or a ptr to the int flags 346 * (as recvv()'s version of soreceive() would have it 347 */ 348 /*ARGSUSED*/ 349 ProtoHook 350 tp_usrreq(so, req, m, nam, rightsp, controlp) 351 struct socket *so; 352 u_int req; 353 struct mbuf *m, *nam, *rightsp, *controlp; 354 { 355 register struct tp_pcb *tpcb = sototpcb(so); 356 int s = splnet(); 357 int error = 0; 358 int flags, *outflags = &flags; 359 u_long eotsdu = 0; 360 struct tp_event E; 361 362 IFDEBUG(D_REQUEST) 363 printf("usrreq(0x%x,%d,0x%x,0x%x,0x%x)\n",so,req,m,nam,outflags); 364 if(so->so_error) 365 printf("WARNING!!! so->so_error is 0x%x\n", so->so_error); 366 ENDDEBUG 367 IFTRACE(D_REQUEST) 368 tptraceTPCB(TPPTusrreq, "req so m state [", req, so, m, 369 tpcb?tpcb->tp_state:0); 370 ENDTRACE 371 372 if ((u_int)tpcb == 0 && req != PRU_ATTACH) { 373 IFTRACE(D_REQUEST) 374 tptraceTPCB(TPPTusrreq, "req failed NO TPCB[", 0, 0, 0, 0); 375 ENDTRACE 376 splx(s); 377 return ENOTCONN; 378 } 379 380 switch (req) { 381 382 case PRU_ATTACH: 383 if (tpcb) { 384 error = EISCONN; 385 break; 386 } 387 if( error = tp_attach(so, so->so_proto->pr_domain->dom_family ) ) 388 break; 389 tpcb = sototpcb(so); 390 break; 391 392 case PRU_ABORT: /* called from close() */ 393 /* called for each incoming connect queued on the 394 * parent (accepting) socket 395 */ 396 if( tpcb->tp_state == TP_OPEN ) { 397 E.ATTR(T_DISC_req).e_reason = E_TP_NO_SESSION; 398 error = DoEvent(T_DISC_req); /* pretend it was a close() */ 399 break; 400 } /* else DROP THROUGH */ 401 402 case PRU_DETACH: /* called from close() */ 403 /* called only after disconnect was called */ 404 error = DoEvent(T_DETACH); 405 if (tpcb->tp_state == TP_CLOSED) { 406 free((caddr_t)tpcb, M_PCB); 407 tpcb = 0; 408 } 409 break; 410 411 case PRU_SHUTDOWN: 412 /* recv end may have been released; local credit might be zero */ 413 case PRU_DISCONNECT: 414 E.ATTR(T_DISC_req).e_reason = E_TP_NORMAL_DISC; 415 error = DoEvent(T_DISC_req); 416 break; 417 418 case PRU_BIND: 419 error = (tpcb->tp_nlproto->nlp_pcbbind)( so->so_pcb, nam ); 420 if (error == 0) { 421 (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen, 422 tpcb->tp_lsuffix, TP_LOCAL ); 423 } 424 break; 425 426 case PRU_LISTEN: 427 if ( *SHORT_LSUFXP(tpcb) == (short)0 ) { 428 /* note: this suffix is independent of the extended suffix */ 429 if( error = (tpcb->tp_nlproto->nlp_pcbbind)(so->so_pcb, MNULL) ) 430 break; 431 } 432 if( tpcb->tp_lsuffixlen == 0) { 433 (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen, 434 tpcb->tp_lsuffix, TP_LOCAL ); 435 } 436 IFDEBUG(D_TPISO) 437 if(tpcb->tp_state != TP_CLOSED) 438 printf("LISTEN ERROR: state 0x%x\n", tpcb->tp_state); 439 ENDDEBUG 440 error = DoEvent(T_LISTEN_req); 441 break; 442 443 case PRU_CONNECT2: 444 error = EOPNOTSUPP; /* for unix domain sockets */ 445 break; 446 447 case PRU_CONNECT: 448 IFTRACE(D_CONN) 449 tptraceTPCB(TPPTmisc, 450 "PRU_CONNECT: so 0x%x *SHORT_LSUFXP(tpcb) 0x%x lsuflen 0x%x, class 0x%x", 451 tpcb->tp_sock, *SHORT_LSUFXP(tpcb), tpcb->tp_lsuffixlen, 452 tpcb->tp_class); 453 ENDTRACE 454 IFDEBUG(D_CONN) 455 printf("PRU_CONNECT: so *SHORT_LSUFXP(tpcb) 0x%x lsuflen 0x%x, class 0x%x", 456 tpcb->tp_sock, *SHORT_LSUFXP(tpcb), tpcb->tp_lsuffixlen, 457 tpcb->tp_class); 458 ENDDEBUG 459 if (*SHORT_LSUFXP(tpcb) == (short)0) { 460 /* no bind was done */ 461 /* note: this suffix is independent of the extended suffix */ 462 if( error = (tpcb->tp_nlproto->nlp_pcbbind)(so->so_pcb, MNULL) ) { 463 IFDEBUG(D_CONN) 464 printf("pcbbind returns error 0x%x\n", error ); 465 ENDDEBUG 466 break; 467 } 468 } 469 if( tpcb->tp_lsuffixlen == 0) { 470 (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen, 471 tpcb->tp_lsuffix, TP_LOCAL ); 472 } 473 474 IFDEBUG(D_CONN) 475 printf("isop 0x%x isop->isop_socket offset 12 :\n", tpcb->tp_npcb); 476 dump_buf( tpcb->tp_npcb, 16); 477 ENDDEBUG 478 if( error = tp_route_to( nam, tpcb, /* channel */0) ) 479 break; 480 IFDEBUG(D_CONN) 481 printf( 482 "PRU_CONNECT after tpcb 0x%x so 0x%x npcb 0x%x flags 0x%x\n", 483 tpcb, so, tpcb->tp_npcb, tpcb->tp_flags); 484 printf("isop 0x%x isop->isop_socket offset 12 :\n", tpcb->tp_npcb); 485 dump_buf( tpcb->tp_npcb, 16); 486 ENDDEBUG 487 if( tpcb->tp_fsuffixlen == 0) { 488 /* didn't set peer extended suffix */ 489 (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_fsuffixlen, 490 tpcb->tp_fsuffix, TP_FOREIGN ); 491 } 492 (void) (tpcb->tp_nlproto->nlp_mtu)(so, so->so_pcb, 493 &tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0); 494 if( tpcb->tp_state == TP_CLOSED) { 495 soisconnecting(so); 496 error = DoEvent(T_CONN_req); 497 } else { 498 (tpcb->tp_nlproto->nlp_pcbdisc)(so->so_pcb); 499 error = EISCONN; 500 } 501 IFPERF(tpcb) 502 u_int lsufx, fsufx; 503 lsufx = *(u_int *)(tpcb->tp_lsuffix); 504 fsufx = *(u_int *)(tpcb->tp_fsuffix); 505 506 tpmeas( tpcb->tp_lref, 507 TPtime_open | (tpcb->tp_xtd_format <<4 ), 508 &time, lsufx, fsufx, tpcb->tp_fref); 509 ENDPERF 510 break; 511 512 case PRU_ACCEPT: 513 /* all this garbage is to keep accept from returning 514 * before the 3-way handshake is done in class 4. 515 * it'll have to be modified for other classes 516 */ 517 IFDEBUG(D_REQUEST) 518 printf("PRU_ACCEPT so_error 0x%x\n", so->so_error); 519 ENDDEBUG 520 so->so_error = 0; 521 if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTED)== 0) { 522 error = EWOULDBLOCK; 523 break; 524 } 525 while ((so->so_state & SS_ISCONNECTED) == 0 && so->so_error == 0) { 526 sleep((caddr_t)&so->so_timeo, PZERO+1); 527 } 528 if (so->so_error) { 529 error = so->so_error; 530 } else { 531 (tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_FOREIGN); 532 IFDEBUG(D_REQUEST) 533 printf("ACCEPT PEERADDDR:"); 534 dump_buf(mtod(nam, char *), nam->m_len); 535 ENDDEBUG 536 } 537 IFPERF(tpcb) 538 u_int lsufx, fsufx; 539 lsufx = *(u_int *)(tpcb->tp_lsuffix); 540 fsufx = *(u_int *)(tpcb->tp_fsuffix); 541 542 tpmeas( tpcb->tp_lref, TPtime_open, 543 &time, lsufx, fsufx, tpcb->tp_fref); 544 ENDPERF 545 break; 546 547 case PRU_RCVD: 548 IFTRACE(D_DATA) 549 tptraceTPCB(TPPTmisc, 550 "RCVD BF: lcredit sent_lcdt cc hiwat \n", 551 tpcb->tp_lcredit, tpcb->tp_sent_lcdt, 552 so->so_rcv.sb_cc, so->so_rcv.sb_hiwat); 553 LOCAL_CREDIT(tpcb); 554 tptraceTPCB(TPPTmisc, 555 "PRU_RCVD AF sbspace lcredit hiwat cc", 556 sbspace(&so->so_rcv), tpcb->tp_lcredit, 557 so->so_rcv.sb_cc, so->so_rcv.sb_hiwat); 558 ENDTRACE 559 IFDEBUG(D_REQUEST) 560 printf("RCVD: cc %d space %d hiwat %d\n", 561 so->so_rcv.sb_cc, sbspace(&so->so_rcv), 562 so->so_rcv.sb_hiwat); 563 ENDDEBUG 564 if (((int)nam) & MSG_OOB) 565 error = DoEvent(T_USR_Xrcvd); 566 else 567 error = DoEvent(T_USR_rcvd); 568 break; 569 570 case PRU_RCVOOB: 571 if ((so->so_state & SS_ISCONNECTED) == 0) { 572 error = ENOTCONN; 573 break; 574 } 575 if( ! tpcb->tp_xpd_service ) { 576 error = EOPNOTSUPP; 577 break; 578 } 579 /* kludge - nam is really flags here */ 580 error = tp_rcvoob(tpcb, so, m, outflags, (int)nam); 581 break; 582 583 case PRU_SENDOOB: 584 if (controlp && (error = tp_snd_control(controlp, so, &m))) 585 break; 586 if (m == 0) 587 break; 588 if (so->so_state & SS_ISCONFIRMING) 589 tp_confirm(); 590 if( ! tpcb->tp_xpd_service ) { 591 error = EOPNOTSUPP; 592 break; 593 } 594 error = tp_sendoob(tpcb, so, m, outflags); 595 break; 596 597 case PRU_SEND: 598 /* 599 * The protocol machine copies mbuf chains, 600 * prepends headers, assigns seq numbers, and 601 * puts the packets on the device. 602 * When they are acked they are removed from the socket buf. 603 * 604 * sosend calls this up until sbspace goes negative. 605 * Sbspace may be made negative by appending this mbuf chain, 606 * possibly by a whole cluster. 607 */ 608 if (controlp && (error = tp_snd_control(controlp, so, &m))) 609 break; 610 if (m == 0) 611 break; 612 if (so->so_state & SS_ISCONFIRMING) 613 tp_confirm(); 614 { 615 register struct mbuf *n = m; 616 register int len=0; 617 register struct sockbuf *sb = &so->so_snd; 618 int maxsize = tpcb->tp_l_tpdusize 619 - tp_headersize(DT_TPDU_type, tpcb) 620 - (tpcb->tp_use_checksum?4:0) ; 621 int totlen = n->m_pkthdr.len; 622 623 /* 624 * Could have eotsdu and no data.(presently MUST have 625 * an mbuf though, even if its length == 0) 626 */ 627 if (n->m_flags & M_EOR) 628 eotsdu = 1; 629 IFPERF(tpcb) 630 PStat(tpcb, Nb_from_sess) += totlen; 631 tpmeas(tpcb->tp_lref, TPtime_from_session, 0, 0, 632 PStat(tpcb, Nb_from_sess), totlen); 633 ENDPERF 634 IFDEBUG(D_SYSCALL) 635 printf( 636 "PRU_SEND: eot %d before sbappend 0x%x len 0x%x to sb @ 0x%x\n", 637 eotsdu, m,len, sb); 638 dump_mbuf(sb->sb_mb, "so_snd.sb_mb"); 639 dump_mbuf(m, "m : to be added"); 640 ENDDEBUG 641 /* 642 * Pre-packetize the data in the sockbuf 643 * according to negotiated mtu. Do it here 644 * where we can safely wait for mbufs. 645 */ 646 while (n->m_pkthdr.len > maxsize) { 647 struct mbuf *nn 648 = m_copym(n, 0, maxsize, M_WAIT); 649 if (eotsdu) 650 n->m_flags &= ~M_EOR; 651 sbappendrecord(sb, nn); 652 m_adj(n, maxsize); 653 } 654 sbappendrecord(sb, n); 655 IFDEBUG(D_SYSCALL) 656 printf("PRU_SEND: eot %d after sbappend 0x%x len 0x%x\n", 657 eotsdu, n, len); 658 dump_mbuf(sb->sb_mb, "so_snd.sb_mb"); 659 ENDDEBUG 660 error = DoEvent(T_DATA_req); 661 IFDEBUG(D_SYSCALL) 662 printf("PRU_SEND: after driver error 0x%x \n",error); 663 printf("so_snd 0x%x cc 0t%d mbcnt 0t%d\n", 664 sb, sb->sb_cc, sb->sb_mbcnt); 665 dump_mbuf(sb->sb_mb, "so_snd.sb_mb after driver"); 666 ENDDEBUG 667 } 668 break; 669 670 case PRU_SOCKADDR: 671 (tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_LOCAL); 672 break; 673 674 case PRU_PEERADDR: 675 if ((so->so_state & SS_ISCONNECTED) && 676 (so->so_state & SS_ISDISCONNECTING) == 0) { 677 (tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_FOREIGN); 678 IFDEBUG(D_REQUEST) 679 printf("PEERADDDR:"); 680 dump_buf(mtod(nam, char *), nam->m_len); 681 ENDDEBUG 682 } else 683 error = ENOTCONN; 684 break; 685 686 case PRU_CONTROL: 687 error = EOPNOTSUPP; 688 break; 689 690 case PRU_PROTOSEND: 691 case PRU_PROTORCV: 692 case PRU_SENSE: 693 case PRU_SLOWTIMO: 694 case PRU_FASTTIMO: 695 error = EOPNOTSUPP; 696 break; 697 698 default: 699 #ifdef ARGO_DEBUG 700 printf("tp_usrreq UNKNOWN PRU %d\n", req); 701 #endif ARGO_DEBUG 702 error = EOPNOTSUPP; 703 } 704 705 IFDEBUG(D_REQUEST) 706 printf("returning from tp_usrreq(so 0x%x) error 0x%x\n", so, error); 707 ENDDEBUG 708 IFTRACE(D_REQUEST) 709 tptraceTPCB(TPPTusrreq, "END req so m state [", req, so, m, 710 tpcb?0:tpcb->tp_state); 711 ENDTRACE 712 splx(s); 713 return error; 714 } 715 716 /* 717 * Stub for future negotiated confirmation of connections. 718 */ 719 tp_confirm() 720 { 721 } 722 723 /* 724 * Process control data sent with sendmsg() 725 */ 726 tp_snd_control(m0, so, data) 727 register struct mbuf *m0; 728 struct socket *so; 729 register struct mbuf **data; 730 { 731 register struct tp_control_hdr *ch; 732 struct mbuf *m; 733 int error = 0; 734 735 if (m0 && m0->m_len) { 736 ch = mtod(m0, struct tp_control_hdr *); 737 m0->m_len -= sizeof (*ch); 738 m0->m_data += sizeof (*ch); 739 m = m_copym(m0, 0, M_COPYALL, M_WAIT); 740 error = tp_ctloutput(PRCO_SETOPT, 741 so, ch->cmsg_level, ch->cmsg_type, &m); 742 if (m) 743 m_freem(m); 744 if (ch->cmsg_type == TPOPT_DISC_DATA) { 745 if (data && *data) { 746 m_freem(*data); 747 *data = 0; 748 } 749 m0 = 0; 750 error = tp_usrreq(so, PRU_DISCONNECT, m0, (caddr_t)0, m0, m0); 751 } 752 } 753 return error; 754 } 755