1 /*- 2 * Copyright (c) 1991 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 * 7 * @(#)tp_usrreq.c 7.16 (Berkeley) 05/06/91 8 */ 9 10 /*********************************************************** 11 Copyright IBM Corporation 1987 12 13 All Rights Reserved 14 15 Permission to use, copy, modify, and distribute this software and its 16 documentation for any purpose and without fee is hereby granted, 17 provided that the above copyright notice appear in all copies and that 18 both that copyright notice and this permission notice appear in 19 supporting documentation, and that the name of IBM not be 20 used in advertising or publicity pertaining to distribution of the 21 software without specific, written prior permission. 22 23 IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 24 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 25 IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 26 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 27 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 28 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 29 SOFTWARE. 30 31 ******************************************************************/ 32 33 /* 34 * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison 35 */ 36 /* 37 * ARGO TP 38 * 39 * $Header: tp_usrreq.c,v 5.4 88/11/18 17:29:18 nhall Exp $ 40 * $Source: /usr/argo/sys/netiso/RCS/tp_usrreq.c,v $ 41 * 42 * tp_usrreq(), the fellow that gets called from most of the socket code. 43 * Pretty straighforward. 44 * THe only really awful stuff here is the OOB processing, which is done 45 * wholly here. 46 * tp_rcvoob() and tp_sendoob() are contained here and called by tp_usrreq(). 47 */ 48 49 #include "param.h" 50 #include "systm.h" 51 #include "user.h" 52 #include "mbuf.h" 53 #include "socket.h" 54 #include "socketvar.h" 55 #include "domain.h" 56 #include "protosw.h" 57 #include "errno.h" 58 59 #include "tp_param.h" 60 #include "tp_timer.h" 61 #include "tp_stat.h" 62 #include "tp_seq.h" 63 #include "tp_ip.h" 64 #include "tp_pcb.h" 65 #include "argo_debug.h" 66 #include "tp_trace.h" 67 #include "tp_meas.h" 68 #include "iso.h" 69 #include "iso_errno.h" 70 71 int tp_attach(), tp_driver(); 72 int TNew; 73 int TPNagle1, TPNagle2; 74 struct tp_pcb *tp_listeners, *tp_intercepts; 75 76 #ifdef ARGO_DEBUG 77 /* 78 * CALLED FROM: 79 * anywhere you want to debug... 80 * FUNCTION and ARGUMENTS: 81 * print (str) followed by the control info in the mbufs of an mbuf chain (n) 82 */ 83 void 84 dump_mbuf(n, str) 85 struct mbuf *n; 86 char *str; 87 { 88 struct mbuf *nextrecord; 89 90 printf("dump %s\n", str); 91 92 if (n == MNULL) { 93 printf("EMPTY:\n"); 94 return; 95 } 96 97 while (n) { 98 nextrecord = n->m_act; 99 printf("RECORD:\n"); 100 while (n) { 101 printf("%x : Len %x Data %x A %x Nx %x Tp %x\n", 102 n, n->m_len, n->m_data, n->m_act, n->m_next, n->m_type); 103 #ifdef notdef 104 { 105 register char *p = mtod(n, char *); 106 register int i; 107 108 printf("data: "); 109 for (i = 0; i < n->m_len; i++) { 110 if (i%8 == 0) 111 printf("\n"); 112 printf("0x%x ", *(p+i)); 113 } 114 printf("\n"); 115 } 116 #endif notdef 117 if (n->m_next == n) { 118 printf("LOOP!\n"); 119 return; 120 } 121 n = n->m_next; 122 } 123 n = nextrecord; 124 } 125 printf("\n"); 126 } 127 128 #endif ARGO_DEBUG 129 130 /* 131 * CALLED FROM: 132 * tp_usrreq(), PRU_RCVOOB 133 * FUNCTION and ARGUMENTS: 134 * Copy data from the expedited data socket buffer into 135 * the pre-allocated mbuf m. 136 * There is an isomorphism between XPD TPDUs and expedited data TSDUs. 137 * XPD tpdus are limited to 16 bytes of data so they fit in one mbuf. 138 * RETURN VALUE: 139 * EINVAL if debugging is on and a disaster has occurred 140 * ENOTCONN if the socket isn't connected 141 * EWOULDBLOCK if the socket is in non-blocking mode and there's no 142 * xpd data in the buffer 143 * E* whatever is returned from the fsm. 144 */ 145 tp_rcvoob(tpcb, so, m, outflags, inflags) 146 struct tp_pcb *tpcb; 147 register struct socket *so; 148 register struct mbuf *m; 149 int *outflags; 150 int inflags; 151 { 152 register struct mbuf *n; 153 register struct sockbuf *sb = &so->so_rcv; 154 struct tp_event E; 155 int error = 0; 156 register struct mbuf **nn; 157 158 IFDEBUG(D_XPD) 159 printf("PRU_RCVOOB, sostate 0x%x\n", so->so_state); 160 ENDDEBUG 161 162 /* if you use soreceive */ 163 if (m == MNULL) 164 return ENOBUFS; 165 166 restart: 167 if ((((so->so_state & SS_ISCONNECTED) == 0) 168 || (so->so_state & SS_ISDISCONNECTING) != 0) && 169 (so->so_proto->pr_flags & PR_CONNREQUIRED)) { 170 return ENOTCONN; 171 } 172 173 /* Take the first mbuf off the chain. 174 * Each XPD TPDU gives you a complete TSDU so the chains don't get 175 * coalesced, but one TSDU may span several mbufs. 176 * Nevertheless, since n should have a most 16 bytes, it 177 * will fit into m. (size was checked in tp_input() ) 178 */ 179 180 /* 181 * Code for excision of OOB data should be added to 182 * uipc_socket2.c (like sbappend). 183 */ 184 185 sblock(sb); 186 for (nn = &sb->sb_mb; n = *nn; nn = &n->m_act) 187 if (n->m_type == MT_OOBDATA) 188 break; 189 190 if (n == 0) { 191 IFDEBUG(D_XPD) 192 printf("RCVOOB: empty queue!\n"); 193 ENDDEBUG 194 sbunlock(sb); 195 if (so->so_state & SS_NBIO) { 196 return EWOULDBLOCK; 197 } 198 sbwait(sb); 199 goto restart; 200 } 201 m->m_len = 0; 202 203 /* Assuming at most one xpd tpdu is in the buffer at once */ 204 while (n != MNULL) { 205 m->m_len += n->m_len; 206 bcopy(mtod(n, caddr_t), mtod(m, caddr_t), (unsigned)n->m_len); 207 m->m_data += n->m_len; /* so mtod() in bcopy() above gives right addr */ 208 n = n->m_next; 209 } 210 m->m_data = m->m_dat; 211 m->m_flags |= M_EOR; 212 213 IFDEBUG(D_XPD) 214 printf("tp_rcvoob: xpdlen 0x%x\n", m->m_len); 215 dump_mbuf(so->so_rcv.sb_mb, "RCVOOB: Rcv socketbuf"); 216 dump_mbuf(sb->sb_mb, "RCVOOB: Xrcv socketbuf"); 217 ENDDEBUG 218 219 if ((inflags & MSG_PEEK) == 0) { 220 n = *nn; 221 *nn = n->m_act; 222 sb->sb_cc -= m->m_len; 223 } 224 225 release: 226 sbunlock(sb); 227 228 IFTRACE(D_XPD) 229 tptraceTPCB(TPPTmisc, "PRU_RCVOOB @ release sb_cc m_len", 230 tpcb->tp_Xrcv.sb_cc, m->m_len, 0, 0); 231 ENDTRACE 232 if (error == 0) 233 error = DoEvent(T_USR_Xrcvd); 234 return error; 235 } 236 237 /* 238 * CALLED FROM: 239 * tp_usrreq(), PRU_SENDOOB 240 * FUNCTION and ARGUMENTS: 241 * Send what's in the mbuf chain (m) as an XPD TPDU. 242 * The mbuf may not contain more then 16 bytes of data. 243 * XPD TSDUs aren't segmented, so they translate into 244 * exactly one XPD TPDU, with EOT bit set. 245 * RETURN VALUE: 246 * EWOULDBLOCK if socket is in non-blocking mode and the previous 247 * xpd data haven't been acked yet. 248 * EMSGSIZE if trying to send > max-xpd bytes (16) 249 * ENOBUFS if ran out of mbufs 250 */ 251 tp_sendoob(tpcb, so, xdata, outflags) 252 struct tp_pcb *tpcb; 253 register struct socket *so; 254 register struct mbuf *xdata; 255 int *outflags; /* not used */ 256 { 257 /* 258 * Each mbuf chain represents a sequence # in the XPD seq space. 259 * The first one in the queue has sequence # tp_Xuna. 260 * When we add to the XPD queue, we stuff a zero-length 261 * mbuf (mark) into the DATA queue, with its sequence number in m_next 262 * to be assigned to this XPD tpdu, so data xfer can stop 263 * when it reaches the zero-length mbuf if this XPD TPDU hasn't 264 * yet been acknowledged. 265 */ 266 register struct sockbuf *sb = &(tpcb->tp_Xsnd); 267 register struct mbuf *xmark; 268 register int len=0; 269 struct tp_event E; 270 271 IFDEBUG(D_XPD) 272 printf("tp_sendoob:"); 273 if (xdata) 274 printf("xdata len 0x%x\n", xdata->m_len); 275 ENDDEBUG 276 /* DO NOT LOCK the Xsnd buffer!!!! You can have at MOST one 277 * socket buf locked at any time!!! (otherwise you might 278 * sleep() in sblock() w/ a signal pending and cause the 279 * system call to be aborted w/ a locked socketbuf, which 280 * is a problem. So the so_snd buffer lock 281 * (done in sosend()) serves as the lock for Xpd. 282 */ 283 if (sb->sb_mb) { /* Anything already in eXpedited data sockbuf? */ 284 if (so->so_state & SS_NBIO) { 285 return EWOULDBLOCK; 286 } 287 while (sb->sb_mb) { 288 sbunlock(&so->so_snd); /* already locked by sosend */ 289 sbwait(&so->so_snd); 290 sblock(&so->so_snd); /* sosend will unlock on return */ 291 } 292 } 293 294 if (xdata == (struct mbuf *)0) { 295 /* empty xpd packet */ 296 MGETHDR(xdata, M_WAIT, MT_OOBDATA); 297 if (xdata == NULL) { 298 return ENOBUFS; 299 } 300 xdata->m_len = 0; 301 xdata->m_pkthdr.len = 0; 302 } 303 IFDEBUG(D_XPD) 304 printf("tp_sendoob 1:"); 305 if (xdata) 306 printf("xdata len 0x%x\n", xdata->m_len); 307 ENDDEBUG 308 xmark = xdata; /* temporary use of variable xmark */ 309 while (xmark) { 310 len += xmark->m_len; 311 xmark = xmark->m_next; 312 } 313 if (len > TP_MAX_XPD_DATA) { 314 return EMSGSIZE; 315 } 316 IFDEBUG(D_XPD) 317 printf("tp_sendoob 2:"); 318 if (xdata) 319 printf("xdata len 0x%x\n", len); 320 ENDDEBUG 321 322 323 IFTRACE(D_XPD) 324 tptraceTPCB(TPPTmisc, "XPD mark m_next ", xdata->m_next, 0, 0, 0); 325 ENDTRACE 326 327 sbappendrecord(sb, xdata); 328 329 IFDEBUG(D_XPD) 330 printf("tp_sendoob len 0x%x\n", len); 331 dump_mbuf(so->so_snd.sb_mb, "XPD request Regular sndbuf:"); 332 dump_mbuf(tpcb->tp_Xsnd.sb_mb, "XPD request Xsndbuf:"); 333 ENDDEBUG 334 return DoEvent(T_XPD_req); 335 } 336 337 /* 338 * CALLED FROM: 339 * the socket routines 340 * FUNCTION and ARGUMENTS: 341 * Handles all "user requests" except the [gs]ockopts() requests. 342 * The argument (req) is the request type (PRU*), 343 * (m) is an mbuf chain, generally used for send and 344 * receive type requests only. 345 * (nam) is used for addresses usually, in particular for the bind request. 346 * 347 */ 348 /*ARGSUSED*/ 349 ProtoHook 350 tp_usrreq(so, req, m, nam, controlp) 351 struct socket *so; 352 u_int req; 353 struct mbuf *m, *nam, *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 if (tpcb->tp_state == TP_LISTENING) { 405 register struct tp_pcb **tt; 406 for (tt = &tp_listeners; *tt; tt = &((*tt)->tp_nextlisten)) 407 if (*tt == tpcb) 408 break; 409 if (*tt) 410 *tt = tpcb->tp_nextlisten; 411 else { 412 for (tt = &tp_intercepts; *tt; tt = &((*tt)->tp_nextlisten)) 413 if (*tt == tpcb) 414 break; 415 if (*tt) 416 *tt = tpcb->tp_nextlisten; 417 else 418 printf("tp_usrreq - detach: should panic\n"); 419 } 420 } 421 if (tpcb->tp_next) 422 remque(tpcb); 423 error = DoEvent(T_DETACH); 424 if (tpcb->tp_state == TP_CLOSED) { 425 free((caddr_t)tpcb, M_PCB); 426 tpcb = 0; 427 } 428 break; 429 430 case PRU_SHUTDOWN: 431 /* recv end may have been released; local credit might be zero */ 432 case PRU_DISCONNECT: 433 E.ATTR(T_DISC_req).e_reason = E_TP_NORMAL_DISC; 434 error = DoEvent(T_DISC_req); 435 break; 436 437 case PRU_BIND: 438 error = (tpcb->tp_nlproto->nlp_pcbbind)(so->so_pcb, nam); 439 if (error == 0) { 440 (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen, 441 tpcb->tp_lsuffix, TP_LOCAL); 442 } 443 break; 444 445 case PRU_LISTEN: 446 if (tpcb->tp_lsuffixlen == 0) { 447 if (error = (tpcb->tp_nlproto->nlp_pcbbind)(so->so_pcb, MNULL)) 448 break; 449 (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen, 450 tpcb->tp_lsuffix, TP_LOCAL); 451 } 452 if (tpcb->tp_next == 0) { 453 tpcb->tp_next = tpcb->tp_prev = tpcb; 454 tpcb->tp_nextlisten = tp_listeners; 455 tp_listeners = tpcb; 456 } 457 IFDEBUG(D_TPISO) 458 if (tpcb->tp_state != TP_CLOSED) 459 printf("LISTEN ERROR: state 0x%x\n", tpcb->tp_state); 460 ENDDEBUG 461 error = DoEvent(T_LISTEN_req); 462 break; 463 464 case PRU_CONNECT2: 465 error = EOPNOTSUPP; /* for unix domain sockets */ 466 break; 467 468 case PRU_CONNECT: 469 IFTRACE(D_CONN) 470 tptraceTPCB(TPPTmisc, 471 "PRU_CONNECT: so 0x%x *SHORT_LSUFXP(tpcb) 0x%x lsuflen 0x%x, class 0x%x", 472 tpcb->tp_sock, *SHORT_LSUFXP(tpcb), tpcb->tp_lsuffixlen, 473 tpcb->tp_class); 474 ENDTRACE 475 IFDEBUG(D_CONN) 476 printf("PRU_CONNECT: so *SHORT_LSUFXP(tpcb) 0x%x lsuflen 0x%x, class 0x%x", 477 tpcb->tp_sock, *SHORT_LSUFXP(tpcb), tpcb->tp_lsuffixlen, 478 tpcb->tp_class); 479 ENDDEBUG 480 if (tpcb->tp_lsuffixlen == 0) { 481 if (error = (tpcb->tp_nlproto->nlp_pcbbind)(so->so_pcb, MNULL)) { 482 IFDEBUG(D_CONN) 483 printf("pcbbind returns error 0x%x\n", error); 484 ENDDEBUG 485 break; 486 } 487 (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_lsuffixlen, 488 tpcb->tp_lsuffix, TP_LOCAL); 489 } 490 491 IFDEBUG(D_CONN) 492 printf("isop 0x%x isop->isop_socket offset 12 :\n", tpcb->tp_npcb); 493 dump_buf(tpcb->tp_npcb, 16); 494 ENDDEBUG 495 if (error = tp_route_to(nam, tpcb, /* channel */0)) 496 break; 497 IFDEBUG(D_CONN) 498 printf( 499 "PRU_CONNECT after tpcb 0x%x so 0x%x npcb 0x%x flags 0x%x\n", 500 tpcb, so, tpcb->tp_npcb, tpcb->tp_flags); 501 printf("isop 0x%x isop->isop_socket offset 12 :\n", tpcb->tp_npcb); 502 dump_buf(tpcb->tp_npcb, 16); 503 ENDDEBUG 504 if (tpcb->tp_fsuffixlen == 0) { 505 /* didn't set peer extended suffix */ 506 (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, &tpcb->tp_fsuffixlen, 507 tpcb->tp_fsuffix, TP_FOREIGN); 508 } 509 (void) (tpcb->tp_nlproto->nlp_mtu)(so, so->so_pcb, 510 &tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0); 511 if (tpcb->tp_state == TP_CLOSED) { 512 soisconnecting(so); 513 error = DoEvent(T_CONN_req); 514 } else { 515 (tpcb->tp_nlproto->nlp_pcbdisc)(so->so_pcb); 516 error = EISCONN; 517 } 518 IFPERF(tpcb) 519 u_int lsufx, fsufx; 520 lsufx = *(u_short *)(tpcb->tp_lsuffix); 521 fsufx = *(u_short *)(tpcb->tp_fsuffix); 522 523 tpmeas(tpcb->tp_lref, 524 TPtime_open | (tpcb->tp_xtd_format << 4), 525 &time, lsufx, fsufx, tpcb->tp_fref); 526 ENDPERF 527 break; 528 529 case PRU_ACCEPT: 530 (tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_FOREIGN); 531 IFDEBUG(D_REQUEST) 532 printf("ACCEPT PEERADDDR:"); 533 dump_buf(mtod(nam, char *), nam->m_len); 534 ENDDEBUG 535 IFPERF(tpcb) 536 u_int lsufx, fsufx; 537 lsufx = *(u_short *)(tpcb->tp_lsuffix); 538 fsufx = *(u_short *)(tpcb->tp_fsuffix); 539 540 tpmeas(tpcb->tp_lref, TPtime_open, 541 &time, lsufx, fsufx, tpcb->tp_fref); 542 ENDPERF 543 break; 544 545 case PRU_RCVD: 546 if (so->so_state & SS_ISCONFIRMING) { 547 if (tpcb->tp_state == TP_CONFIRMING) 548 error = tp_confirm(tpcb); 549 break; 550 } 551 IFTRACE(D_DATA) 552 tptraceTPCB(TPPTmisc, 553 "RCVD BF: lcredit sent_lcdt cc hiwat \n", 554 tpcb->tp_lcredit, tpcb->tp_sent_lcdt, 555 so->so_rcv.sb_cc, so->so_rcv.sb_hiwat); 556 LOCAL_CREDIT(tpcb); 557 tptraceTPCB(TPPTmisc, 558 "PRU_RCVD AF sbspace lcredit hiwat cc", 559 sbspace(&so->so_rcv), tpcb->tp_lcredit, 560 so->so_rcv.sb_cc, so->so_rcv.sb_hiwat); 561 ENDTRACE 562 IFDEBUG(D_REQUEST) 563 printf("RCVD: cc %d space %d hiwat %d\n", 564 so->so_rcv.sb_cc, sbspace(&so->so_rcv), 565 so->so_rcv.sb_hiwat); 566 ENDDEBUG 567 if (((int)nam) & MSG_OOB) 568 error = DoEvent(T_USR_Xrcvd); 569 else 570 error = DoEvent(T_USR_rcvd); 571 break; 572 573 case PRU_RCVOOB: 574 if ((so->so_state & SS_ISCONNECTED) == 0) { 575 error = ENOTCONN; 576 break; 577 } 578 if (! tpcb->tp_xpd_service) { 579 error = EOPNOTSUPP; 580 break; 581 } 582 /* kludge - nam is really flags here */ 583 error = tp_rcvoob(tpcb, so, m, outflags, (int)nam); 584 break; 585 586 case PRU_SEND: 587 case PRU_SENDOOB: 588 if (controlp) { 589 error = tp_snd_control(controlp, so, &m); 590 controlp = NULL; 591 if (error) 592 break; 593 } 594 if ((so->so_state & SS_ISCONFIRMING) && 595 (tpcb->tp_state == TP_CONFIRMING) && 596 (error = tp_confirm(tpcb))) 597 break; 598 if (req == PRU_SENDOOB) { 599 error = (tpcb->tp_xpd_service == 0) ? 600 EOPNOTSUPP : tp_sendoob(tpcb, so, m, outflags); 601 break; 602 } 603 if (m == 0) 604 break; 605 if (m->m_flags & M_EOR) { 606 eotsdu = 1; 607 m->m_flags &= ~M_EOR; 608 } 609 if (eotsdu == 0 && m->m_pkthdr.len == 0) 610 break; 611 if (tpcb->tp_state != TP_AKWAIT && tpcb->tp_state != TP_OPEN) { 612 error = ENOTCONN; 613 break; 614 } 615 /* 616 * The protocol machine copies mbuf chains, 617 * prepends headers, assigns seq numbers, and 618 * puts the packets on the device. 619 * When they are acked they are removed from the socket buf. 620 * 621 * sosend calls this up until sbspace goes negative. 622 * Sbspace may be made negative by appending this mbuf chain, 623 * possibly by a whole cluster. 624 */ 625 { 626 register struct mbuf *n = m; 627 register struct sockbuf *sb = &so->so_snd; 628 int maxsize = tpcb->tp_l_tpdusize 629 - tp_headersize(DT_TPDU_type, tpcb) 630 - (tpcb->tp_use_checksum?4:0) ; 631 int totlen = n->m_pkthdr.len; 632 int mbufcnt = 0; 633 struct mbuf *nn; 634 635 /* 636 * Could have eotsdu and no data.(presently MUST have 637 * an mbuf though, even if its length == 0) 638 */ 639 IFPERF(tpcb) 640 PStat(tpcb, Nb_from_sess) += totlen; 641 tpmeas(tpcb->tp_lref, TPtime_from_session, 0, 0, 642 PStat(tpcb, Nb_from_sess), totlen); 643 ENDPERF 644 IFDEBUG(D_SYSCALL) 645 printf( 646 "PRU_SEND: eot %d before sbappend 0x%x len 0x%x to sb @ 0x%x\n", 647 eotsdu, m, totlen, sb); 648 dump_mbuf(sb->sb_mb, "so_snd.sb_mb"); 649 dump_mbuf(m, "m : to be added"); 650 ENDDEBUG 651 /* 652 * Pre-packetize the data in the sockbuf 653 * according to negotiated mtu. Do it here 654 * where we can safely wait for mbufs. 655 * 656 * This presumes knowledge of sockbuf conventions. 657 */ 658 if (n = sb->sb_mb) 659 while (n->m_act) 660 n = n->m_act; 661 if ((nn = n) && n->m_pkthdr.len < maxsize) { 662 u_int space = maxsize - n->m_pkthdr.len; 663 664 do { 665 if (n->m_flags & M_EOR) 666 goto on1; 667 } while (n->m_next && (n = n->m_next)); 668 if (totlen <= space) { 669 TPNagle1++; 670 n->m_next = m; 671 nn->m_pkthdr.len += totlen; 672 while (n = n->m_next) 673 sballoc(sb, n); 674 if (eotsdu) 675 nn->m_flags |= M_EOR; 676 goto on2; 677 } else { 678 /* 679 * Can't sleep here, because when you wake up 680 * packet you want to attach to may be gone! 681 */ 682 if (TNew && (n->m_next = m_copym(m, 0, space, M_NOWAIT))) { 683 nn->m_pkthdr.len += space; 684 TPNagle2++; 685 while (n = n->m_next) 686 sballoc(sb, n); 687 m_adj(m, space); 688 } 689 } 690 } 691 on1: mbufcnt++; 692 for (n = m; n->m_pkthdr.len > maxsize;) { 693 nn = m_copym(n, 0, maxsize, M_WAIT); 694 sbappendrecord(sb, nn); 695 m_adj(n, maxsize); 696 mbufcnt++; 697 } 698 if (eotsdu) 699 n->m_flags |= M_EOR; 700 sbappendrecord(sb, n); 701 on2: 702 IFTRACE(D_DATA) 703 tptraceTPCB(TPPTmisc, 704 "SEND BF: maxsize totlen mbufcnt eotsdu", 705 maxsize, totlen, mbufcnt, eotsdu); 706 ENDTRACE 707 IFDEBUG(D_SYSCALL) 708 printf("PRU_SEND: eot %d after sbappend 0x%x mbufcnt 0x%x\n", 709 eotsdu, n, mbufcnt); 710 dump_mbuf(sb->sb_mb, "so_snd.sb_mb"); 711 ENDDEBUG 712 if (tpcb->tp_state == TP_OPEN) 713 error = DoEvent(T_DATA_req); 714 IFDEBUG(D_SYSCALL) 715 printf("PRU_SEND: after driver error 0x%x \n",error); 716 printf("so_snd 0x%x cc 0t%d mbcnt 0t%d\n", 717 sb, sb->sb_cc, sb->sb_mbcnt); 718 dump_mbuf(sb->sb_mb, "so_snd.sb_mb after driver"); 719 ENDDEBUG 720 } 721 break; 722 723 case PRU_SOCKADDR: 724 (tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_LOCAL); 725 break; 726 727 case PRU_PEERADDR: 728 (tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, nam, TP_FOREIGN); 729 break; 730 731 case PRU_CONTROL: 732 error = EOPNOTSUPP; 733 break; 734 735 case PRU_PROTOSEND: 736 case PRU_PROTORCV: 737 case PRU_SENSE: 738 case PRU_SLOWTIMO: 739 case PRU_FASTTIMO: 740 error = EOPNOTSUPP; 741 break; 742 743 default: 744 #ifdef ARGO_DEBUG 745 printf("tp_usrreq UNKNOWN PRU %d\n", req); 746 #endif ARGO_DEBUG 747 error = EOPNOTSUPP; 748 } 749 750 IFDEBUG(D_REQUEST) 751 printf("%s, so 0x%x, tpcb 0x%x, error %d, state %d\n", 752 "returning from tp_usrreq", so, tpcb, error, 753 tpcb ? 0 : tpcb->tp_state); 754 ENDDEBUG 755 IFTRACE(D_REQUEST) 756 tptraceTPCB(TPPTusrreq, "END req so m state [", req, so, m, 757 tpcb?0:tpcb->tp_state); 758 ENDTRACE 759 if (controlp) { 760 m_freem(controlp); 761 printf("control data unexpectedly retained in tp_usrreq()"); 762 } 763 splx(s); 764 return error; 765 } 766 tp_ltrace(so, uio) 767 struct socket *so; 768 struct uio *uio; 769 { 770 IFTRACE(D_DATA) 771 register struct tp_pcb *tpcb = sototpcb(so); 772 if (tpcb) { 773 tptraceTPCB(TPPTmisc, "sosend so resid iovcnt", so, 774 uio->uio_resid, uio->uio_iovcnt, 0); 775 } 776 ENDTRACE 777 } 778 779 tp_confirm(tpcb) 780 register struct tp_pcb *tpcb; 781 { 782 struct tp_event E; 783 if (tpcb->tp_state == TP_CONFIRMING) 784 return DoEvent(T_ACPT_req); 785 printf("Tp confirm called when not confirming; tpcb 0x%x, state 0x%x\n", 786 tpcb, tpcb->tp_state); 787 return 0; 788 } 789 790 /* 791 * Process control data sent with sendmsg() 792 */ 793 tp_snd_control(m, so, data) 794 struct mbuf *m; 795 struct socket *so; 796 register struct mbuf **data; 797 { 798 register struct cmsghdr *ch; 799 int error = 0; 800 801 if (m && m->m_len) { 802 ch = mtod(m, struct cmsghdr *); 803 m->m_len -= sizeof (*ch); 804 m->m_data += sizeof (*ch); 805 error = tp_ctloutput(PRCO_SETOPT, 806 so, ch->cmsg_level, ch->cmsg_type, &m); 807 if (ch->cmsg_type == TPOPT_DISC_DATA) { 808 if (data && *data) { 809 m_freem(*data); 810 *data = 0; 811 } 812 error = tp_usrreq(so, PRU_DISCONNECT, (struct mbuf *)0, 813 (caddr_t)0, (struct mbuf *)0); 814 } 815 } 816 if (m) 817 m_freem(m); 818 return error; 819 } 820