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 "dir.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 sblock(sb); 161 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 for (nn = &sb->sb_mb; n = *nn; nn = &n->m_act) 181 if (n->m_type == MT_OOBDATA) 182 break; 183 184 if (n == 0) { 185 ASSERT( (tpcb->tp_flags & TPF_DISC_DATA_IN) == 0 ); 186 IFDEBUG(D_XPD) 187 printf("RCVOOB: empty queue!\n"); 188 ENDDEBUG 189 if (so->so_state & SS_NBIO) { 190 return EWOULDBLOCK; 191 } 192 sbunlock(sb); 193 sbwait(sb); 194 goto restart; 195 } 196 m->m_len = 0; 197 198 /* Assuming at most one xpd tpdu is in the buffer at once */ 199 while ( n != MNULL ) { 200 m->m_len += n->m_len; 201 bcopy(mtod(n, caddr_t), mtod(m, caddr_t), (unsigned)n->m_len); 202 m->m_data += n->m_len; /* so mtod() in bcopy() above gives right addr */ 203 n = n->m_next; 204 } 205 m->m_data = m->m_dat; 206 m->m_flags |= M_EOR; 207 208 IFDEBUG(D_XPD) 209 printf("tp_rcvoob: xpdlen 0x%x\n", m->m_len); 210 dump_mbuf(so->so_rcv.sb_mb, "RCVOOB: Rcv socketbuf"); 211 dump_mbuf(sb->sb_mb, "RCVOOB: Xrcv socketbuf"); 212 ENDDEBUG 213 214 if( (inflags & MSG_PEEK) == 0 ) { 215 n = *nn; 216 *nn = n->m_act; 217 sb->sb_cc -= m->m_len; 218 } 219 220 release: 221 sbunlock(sb); 222 223 IFTRACE(D_XPD) 224 tptraceTPCB(TPPTmisc, "PRU_RCVOOB @ release sb_cc m_len", 225 tpcb->tp_Xrcv.sb_cc, m->m_len,0,0 ); 226 ENDTRACE 227 if (error == 0) 228 error = DoEvent(T_USR_Xrcvd); 229 return error; 230 } 231 232 /* 233 * CALLED FROM: 234 * tp_usrreq(), PRU_SENDOOB 235 * FUNCTION and ARGUMENTS: 236 * Send what's in the mbuf chain (m) as an XPD TPDU. 237 * The mbuf may not contain more then 16 bytes of data. 238 * XPD TSDUs aren't segmented, so they translate into 239 * exactly one XPD TPDU, with EOT bit set. 240 * RETURN VALUE: 241 * EWOULDBLOCK if socket is in non-blocking mode and the previous 242 * xpd data haven't been acked yet. 243 * EMSGSIZE if trying to send > max-xpd bytes (16) 244 * ENOBUFS if ran out of mbufs 245 */ 246 tp_sendoob(tpcb, so, xdata, outflags) 247 struct tp_pcb *tpcb; 248 register struct socket *so; 249 register struct mbuf *xdata; 250 int *outflags; /* not used */ 251 { 252 /* 253 * Each mbuf chain represents a sequence # in the XPD seq space. 254 * The first one in the queue has sequence # tp_Xuna. 255 * When we add to the XPD queue, we stuff a zero-length 256 * mbuf (mark) into the DATA queue, with its sequence number in m_next 257 * to be assigned to this XPD tpdu, so data xfer can stop 258 * when it reaches the zero-length mbuf if this XPD TPDU hasn't 259 * yet been acknowledged. 260 */ 261 register struct sockbuf *sb = &(tpcb->tp_Xsnd); 262 register struct mbuf *xmark; 263 register int len=0; 264 struct tp_event E; 265 266 IFDEBUG(D_XPD) 267 printf("tp_sendoob:"); 268 if(xdata) 269 printf("xdata len 0x%x\n", xdata->m_len); 270 ENDDEBUG 271 oob_again: 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 this sockbuf? */ 280 if (so->so_state & SS_NBIO) { 281 return EWOULDBLOCK; 282 } 283 sbunlock(&so->so_snd); 284 sbwait(&so->so_snd); 285 sblock(&so->so_snd); 286 goto oob_again; 287 } 288 289 if (xdata == (struct mbuf *)0) { 290 /* empty xpd packet */ 291 MGETHDR(xdata, M_WAIT, MT_OOBDATA); 292 if (xdata == NULL) { 293 return ENOBUFS; 294 } 295 xdata->m_len = 0; 296 xdata->m_pkthdr.len = 0; 297 } 298 IFDEBUG(D_XPD) 299 printf("tp_sendoob 1:"); 300 if(xdata) 301 printf("xdata len 0x%x\n", xdata->m_len); 302 ENDDEBUG 303 xmark = xdata; /* temporary use of variable xmark */ 304 while (xmark) { 305 len += xmark->m_len; 306 xmark = xmark->m_next; 307 } 308 if (len > TP_MAX_XPD_DATA) { 309 return EMSGSIZE; 310 } 311 IFDEBUG(D_XPD) 312 printf("tp_sendoob 2:"); 313 if(xdata) 314 printf("xdata len 0x%x\n", len); 315 ENDDEBUG 316 317 318 IFTRACE(D_XPD) 319 tptraceTPCB(TPPTmisc, "XPD mark m_next ", xmark->m_next, 0, 0, 0); 320 ENDTRACE 321 322 sbappendrecord(sb, xdata); 323 324 IFDEBUG(D_XPD) 325 printf("tp_sendoob len 0x%x\n", len); 326 dump_mbuf(so->so_snd.sb_mb, "XPD request Regular sndbuf:"); 327 dump_mbuf(tpcb->tp_Xsnd.sb_mb, "XPD request Xsndbuf:"); 328 ENDDEBUG 329 return DoEvent(T_XPD_req); 330 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 * The last argument (rights in most usrreq()s) has been stolen for 344 * returning flags values. Since rights can't be passed around w/ tp, 345 * this field is used only for RCVOOB user requests, and is assumed 346 * to be either 0 (as soreceive() would have it) or a ptr to the int flags 347 * (as recvv()'s version of soreceive() would have it 348 */ 349 /*ARGSUSED*/ 350 ProtoHook 351 tp_usrreq(so, req, m, nam, rightsp, controlp) 352 struct socket *so; 353 u_int req; 354 struct mbuf *m, *nam, *rightsp, *controlp; 355 { 356 register struct tp_pcb *tpcb = sototpcb(so); 357 int s = splnet(); 358 int error = 0; 359 int flags, *outflags = &flags; 360 u_long eotsdu = 0; 361 struct tp_event E; 362 363 IFDEBUG(D_REQUEST) 364 printf("usrreq(0x%x,%d,0x%x,0x%x,0x%x)\n",so,req,m,nam,outflags); 365 if(so->so_error) 366 printf("WARNING!!! so->so_error is 0x%x\n", so->so_error); 367 ENDDEBUG 368 IFTRACE(D_REQUEST) 369 tptraceTPCB(TPPTusrreq, "req so m state [", req, so, m, 370 tpcb?tpcb->tp_state:0); 371 ENDTRACE 372 373 if ((u_int)tpcb == 0 && req != PRU_ATTACH) { 374 IFTRACE(D_REQUEST) 375 tptraceTPCB(TPPTusrreq, "req failed NO TPCB[", 0, 0, 0, 0); 376 ENDTRACE 377 splx(s); 378 return ENOTCONN; 379 } 380 381 switch (req) { 382 383 case PRU_ATTACH: 384 if (tpcb) { 385 error = EISCONN; 386 break; 387 } 388 if( error = tp_attach(so, so->so_proto->pr_domain->dom_family ) ) 389 break; 390 tpcb = sototpcb(so); 391 break; 392 393 case PRU_ABORT: /* called from close() */ 394 /* called for each incoming connect queued on the 395 * parent (accepting) socket 396 */ 397 if( tpcb->tp_state == TP_OPEN ) { 398 E.ATTR(T_DISC_req).e_reason = E_TP_NO_SESSION; 399 error = DoEvent(T_DISC_req); /* pretend it was a close() */ 400 break; 401 } /* else DROP THROUGH */ 402 403 case PRU_DETACH: /* called from close() */ 404 /* called only after disconnect was called */ 405 error = DoEvent(T_DETACH); 406 if (tpcb->tp_state == TP_CLOSED) { 407 free((caddr_t)tpcb, M_PCB); 408 tpcb = 0; 409 } 410 break; 411 412 case PRU_SHUTDOWN: 413 /* recv end may have been released; local credit might be zero */ 414 case PRU_DISCONNECT: 415 E.ATTR(T_DISC_req).e_reason = E_TP_NORMAL_DISC; 416 error = DoEvent(T_DISC_req); 417 break; 418 419 case PRU_BIND: 420 error = (tpcb->tp_nlproto->nlp_pcbbind)( so->so_pcb, nam ); 421 if (error == 0) { 422 (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen, 423 tpcb->tp_lsuffix, TP_LOCAL ); 424 } 425 break; 426 427 case PRU_LISTEN: 428 if ( *SHORT_LSUFXP(tpcb) == (short)0 ) { 429 /* note: this suffix is independent of the extended suffix */ 430 if( error = (tpcb->tp_nlproto->nlp_pcbbind)(so->so_pcb, MNULL) ) 431 break; 432 } 433 if( tpcb->tp_lsuffixlen == 0) { 434 (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen, 435 tpcb->tp_lsuffix, TP_LOCAL ); 436 } 437 IFDEBUG(D_TPISO) 438 if(tpcb->tp_state != TP_CLOSED) 439 printf("LISTEN ERROR: state 0x%x\n", tpcb->tp_state); 440 ENDDEBUG 441 error = DoEvent(T_LISTEN_req); 442 break; 443 444 case PRU_CONNECT2: 445 error = EOPNOTSUPP; /* for unix domain sockets */ 446 break; 447 448 case PRU_CONNECT: 449 IFTRACE(D_CONN) 450 tptraceTPCB(TPPTmisc, 451 "PRU_CONNECT: so 0x%x *SHORT_LSUFXP(tpcb) 0x%x lsuflen 0x%x, class 0x%x", 452 tpcb->tp_sock, *SHORT_LSUFXP(tpcb), tpcb->tp_lsuffixlen, 453 tpcb->tp_class); 454 ENDTRACE 455 IFDEBUG(D_CONN) 456 printf("PRU_CONNECT: so *SHORT_LSUFXP(tpcb) 0x%x lsuflen 0x%x, class 0x%x", 457 tpcb->tp_sock, *SHORT_LSUFXP(tpcb), tpcb->tp_lsuffixlen, 458 tpcb->tp_class); 459 ENDDEBUG 460 if (*SHORT_LSUFXP(tpcb) == (short)0) { 461 /* no bind was done */ 462 /* note: this suffix is independent of the extended suffix */ 463 if( error = (tpcb->tp_nlproto->nlp_pcbbind)(so->so_pcb, MNULL) ) { 464 IFDEBUG(D_CONN) 465 printf("pcbbind returns error 0x%x\n", error ); 466 ENDDEBUG 467 break; 468 } 469 } 470 if( tpcb->tp_lsuffixlen == 0) { 471 (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen, 472 tpcb->tp_lsuffix, TP_LOCAL ); 473 } 474 475 IFDEBUG(D_CONN) 476 printf("isop 0x%x isop->isop_socket offset 12 :\n", tpcb->tp_npcb); 477 dump_buf( tpcb->tp_npcb, 16); 478 ENDDEBUG 479 if( error = tp_route_to( nam, tpcb, /* channel */0) ) 480 break; 481 IFDEBUG(D_CONN) 482 printf( 483 "PRU_CONNECT after tpcb 0x%x so 0x%x npcb 0x%x flags 0x%x\n", 484 tpcb, so, tpcb->tp_npcb, tpcb->tp_flags); 485 printf("isop 0x%x isop->isop_socket offset 12 :\n", tpcb->tp_npcb); 486 dump_buf( tpcb->tp_npcb, 16); 487 ENDDEBUG 488 if( tpcb->tp_fsuffixlen == 0) { 489 /* didn't set peer extended suffix */ 490 (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_fsuffixlen, 491 tpcb->tp_fsuffix, TP_FOREIGN ); 492 } 493 (void) (tpcb->tp_nlproto->nlp_mtu)(so, so->so_pcb, 494 &tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0); 495 if( tpcb->tp_state == TP_CLOSED) { 496 soisconnecting(so); 497 error = DoEvent(T_CONN_req); 498 } else { 499 (tpcb->tp_nlproto->nlp_pcbdisc)(so->so_pcb); 500 error = EISCONN; 501 } 502 IFPERF(tpcb) 503 u_int lsufx, fsufx; 504 lsufx = *(u_int *)(tpcb->tp_lsuffix); 505 fsufx = *(u_int *)(tpcb->tp_fsuffix); 506 507 tpmeas( tpcb->tp_lref, 508 TPtime_open | (tpcb->tp_xtd_format <<4 ), 509 &time, lsufx, fsufx, tpcb->tp_fref); 510 ENDPERF 511 break; 512 513 case PRU_ACCEPT: 514 /* all this garbage is to keep accept from returning 515 * before the 3-way handshake is done in class 4. 516 * it'll have to be modified for other classes 517 */ 518 IFDEBUG(D_REQUEST) 519 printf("PRU_ACCEPT so_error 0x%x\n", so->so_error); 520 ENDDEBUG 521 so->so_error = 0; 522 if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTED)== 0) { 523 error = EWOULDBLOCK; 524 break; 525 } 526 while ((so->so_state & SS_ISCONNECTED) == 0 && so->so_error == 0) { 527 sleep((caddr_t)&so->so_timeo, PZERO+1); 528 } 529 if (so->so_error) { 530 error = so->so_error; 531 } else { 532 (tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_FOREIGN); 533 IFDEBUG(D_REQUEST) 534 printf("ACCEPT PEERADDDR:"); 535 dump_buf(mtod(nam, char *), nam->m_len); 536 ENDDEBUG 537 } 538 IFPERF(tpcb) 539 u_int lsufx, fsufx; 540 lsufx = *(u_int *)(tpcb->tp_lsuffix); 541 fsufx = *(u_int *)(tpcb->tp_fsuffix); 542 543 tpmeas( tpcb->tp_lref, TPtime_open, 544 &time, lsufx, fsufx, tpcb->tp_fref); 545 ENDPERF 546 break; 547 548 case PRU_RCVD: 549 IFTRACE(D_DATA) 550 tptraceTPCB(TPPTmisc, 551 "RCVD BF: lcredit sent_lcdt cc hiwat \n", 552 tpcb->tp_lcredit, tpcb->tp_sent_lcdt, 553 so->so_rcv.sb_cc, so->so_rcv.sb_hiwat); 554 LOCAL_CREDIT(tpcb); 555 tptraceTPCB(TPPTmisc, 556 "PRU_RCVD AF sbspace lcredit hiwat cc", 557 sbspace(&so->so_rcv), tpcb->tp_lcredit, 558 so->so_rcv.sb_cc, so->so_rcv.sb_hiwat); 559 ENDTRACE 560 IFDEBUG(D_REQUEST) 561 printf("RCVD: cc %d space %d hiwat %d\n", 562 so->so_rcv.sb_cc, sbspace(&so->so_rcv), 563 so->so_rcv.sb_hiwat); 564 ENDDEBUG 565 if (((int)nam) & MSG_OOB) 566 error = DoEvent(T_USR_Xrcvd); 567 else 568 error = DoEvent(T_USR_rcvd); 569 break; 570 571 case PRU_RCVOOB: 572 if ((so->so_state & SS_ISCONNECTED) == 0) { 573 error = ENOTCONN; 574 break; 575 } 576 if( ! tpcb->tp_xpd_service ) { 577 error = EOPNOTSUPP; 578 break; 579 } 580 /* kludge - nam is really flags here */ 581 error = tp_rcvoob(tpcb, so, m, outflags, (int)nam); 582 break; 583 584 case PRU_SENDOOB: 585 if (controlp && (error = tp_snd_control(controlp, so, &m))) 586 break; 587 if (m == 0) 588 break; 589 if (so->so_state & SS_ISCONFIRMING) 590 tp_confirm(); 591 if( ! tpcb->tp_xpd_service ) { 592 error = EOPNOTSUPP; 593 break; 594 } 595 error = tp_sendoob(tpcb, so, m, outflags); 596 break; 597 598 case PRU_SEND: 599 /* 600 * The protocol machine copies mbuf chains, 601 * prepends headers, assigns seq numbers, and 602 * puts the packets on the device. 603 * When they are acked they are removed from the socket buf. 604 * 605 * sosend calls this up until sbspace goes negative. 606 * Sbspace may be made negative by appending this mbuf chain, 607 * possibly by a whole cluster. 608 */ 609 if (controlp && (error = tp_snd_control(controlp, so, &m))) 610 break; 611 if (m == 0) 612 break; 613 if (so->so_state & SS_ISCONFIRMING) 614 tp_confirm(); 615 { 616 register struct mbuf *n = m; 617 register int len=0; 618 register struct sockbuf *sb = &so->so_snd; 619 int maxsize = tpcb->tp_l_tpdusize 620 - tp_headersize(DT_TPDU_type, tpcb) 621 - (tpcb->tp_use_checksum?4:0) ; 622 int totlen = n->m_pkthdr.len; 623 624 /* 625 * Could have eotsdu and no data.(presently MUST have 626 * an mbuf though, even if its length == 0) 627 */ 628 if (n->m_flags & M_EOR) 629 eotsdu = 1; 630 IFPERF(tpcb) 631 PStat(tpcb, Nb_from_sess) += totlen; 632 tpmeas(tpcb->tp_lref, TPtime_from_session, 0, 0, 633 PStat(tpcb, Nb_from_sess), totlen); 634 ENDPERF 635 IFDEBUG(D_SYSCALL) 636 printf( 637 "PRU_SEND: eot %d before sbappend 0x%x len 0x%x to sb @ 0x%x\n", 638 eotsdu, m,len, sb); 639 dump_mbuf(sb->sb_mb, "so_snd.sb_mb"); 640 dump_mbuf(m, "m : to be added"); 641 ENDDEBUG 642 /* 643 * Pre-packetize the data in the sockbuf 644 * according to negotiated mtu. Do it here 645 * where we can safely wait for mbufs. 646 */ 647 while (n->m_pkthdr.len > maxsize) { 648 struct mbuf *nn 649 = m_copym(n, 0, maxsize, M_WAIT); 650 if (eotsdu) 651 n->m_flags &= ~M_EOR; 652 sbappendrecord(sb, nn); 653 m_adj(n, maxsize); 654 } 655 sbappendrecord(sb, n); 656 IFDEBUG(D_SYSCALL) 657 printf("PRU_SEND: eot %d after sbappend 0x%x len 0x%x\n", 658 eotsdu, n, len); 659 dump_mbuf(sb->sb_mb, "so_snd.sb_mb"); 660 ENDDEBUG 661 error = DoEvent(T_DATA_req); 662 IFDEBUG(D_SYSCALL) 663 printf("PRU_SEND: after driver error 0x%x \n",error); 664 printf("so_snd 0x%x cc 0t%d mbcnt 0t%d\n", 665 sb, sb->sb_cc, sb->sb_mbcnt); 666 dump_mbuf(sb->sb_mb, "so_snd.sb_mb after driver"); 667 ENDDEBUG 668 } 669 break; 670 671 case PRU_SOCKADDR: 672 (tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_LOCAL); 673 break; 674 675 case PRU_PEERADDR: 676 if ((so->so_state & SS_ISCONNECTED) && 677 (so->so_state & SS_ISDISCONNECTING) == 0) { 678 (tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_FOREIGN); 679 IFDEBUG(D_REQUEST) 680 printf("PEERADDDR:"); 681 dump_buf(mtod(nam, char *), nam->m_len); 682 ENDDEBUG 683 } else 684 error = ENOTCONN; 685 break; 686 687 case PRU_CONTROL: 688 error = EOPNOTSUPP; 689 break; 690 691 case PRU_PROTOSEND: 692 case PRU_PROTORCV: 693 case PRU_SENSE: 694 case PRU_SLOWTIMO: 695 case PRU_FASTTIMO: 696 error = EOPNOTSUPP; 697 break; 698 699 default: 700 #ifdef ARGO_DEBUG 701 printf("tp_usrreq UNKNOWN PRU %d\n", req); 702 #endif ARGO_DEBUG 703 error = EOPNOTSUPP; 704 } 705 706 IFDEBUG(D_REQUEST) 707 printf("returning from tp_usrreq(so 0x%x) error 0x%x\n", so, error); 708 ENDDEBUG 709 IFTRACE(D_REQUEST) 710 tptraceTPCB(TPPTusrreq, "END req so m state [", req, so, m, 711 tpcb?0:tpcb->tp_state); 712 ENDTRACE 713 splx(s); 714 return error; 715 } 716 717 /* 718 * Stub for future negotiated confirmation of connections. 719 */ 720 tp_confirm() 721 { 722 } 723 724 /* 725 * Process control data sent with sendmsg() 726 */ 727 tp_snd_control(m0, so, data) 728 register struct mbuf *m0; 729 struct socket *so; 730 register struct mbuf **data; 731 { 732 register struct tp_control_hdr *ch; 733 struct mbuf *m; 734 int error = 0; 735 736 if (m0 && m0->m_len) { 737 ch = mtod(m0, struct tp_control_hdr *); 738 m0->m_len -= sizeof (*ch); 739 m0->m_data += sizeof (*ch); 740 m = m_copym(m0, 0, M_COPYALL, M_WAIT); 741 error = tp_ctloutput(PRCO_SETOPT, 742 so, ch->cmsg_level, ch->cmsg_type, &m); 743 if (m) 744 m_freem(m); 745 if (ch->cmsg_type == TPOPT_DISC_DATA) { 746 if (data && *data) { 747 m_freem(*data); 748 *data = 0; 749 } 750 m0 = 0; 751 error = tp_usrreq(so, PRU_DISCONNECT, m0, (caddr_t)0, m0, m0); 752 } 753 } 754 return error; 755 } 756