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 "../netiso/tp_param.h" 56 #include "../netiso/tp_timer.h" 57 #include "../netiso/tp_stat.h" 58 #include "../netiso/tp_seq.h" 59 #include "../netiso/tp_ip.h" 60 #include "../netiso/tp_pcb.h" 61 #include "../netiso/argo_debug.h" 62 #include "../netiso/tp_trace.h" 63 #include "../netiso/tp_meas.h" 64 #include "../netiso/iso.h" 65 #include "../netiso/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 Of %x A %x Nx %x Tp %x\n", 95 n, n->m_len, n->m_off, 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 static int 139 tp_rcvoob(tpcb, so, m, outflags, inflags) 140 struct tp_pcb *tpcb; 141 register struct socket *so; 142 register struct mbuf *m; 143 int *outflags; 144 int inflags; 145 { 146 register struct mbuf *n; 147 register struct sockbuf *sb = &tpcb->tp_Xrcv; 148 struct tp_event E; 149 int error = 0; 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 if ( sb->sb_cc == 0) { 169 ASSERT( (tpcb->tp_flags & TPF_DISC_DATA_IN) == 0 ); 170 IFDEBUG(D_XPD) 171 printf("RCVOOB: empty queue!\n"); 172 ENDDEBUG 173 if (so->so_state & SS_NBIO) { 174 return EWOULDBLOCK; 175 } 176 sbunlock(sb); 177 sbwait(sb); 178 goto restart; 179 } 180 /* Take the first mbuf off the chain. 181 * Each XPD TPDU gives you a complete TSDU so the chains don't get 182 * coalesced, but one TSDU may span several mbufs. 183 * Nevertheless, since n should have a most 16 bytes, it 184 * will fit into m. (size was checked in tp_input() ) 185 */ 186 187 n = sb->sb_mb; 188 ASSERT((n->m_type == TPMT_DATA) || 189 n->m_type == TPMT_IPHDR || n->m_type == TPMT_TPHDR); 190 191 /* 192 * mtod doesn't work for cluster-type mbufs, hence this disaster check: 193 */ 194 if( n->m_off > MMAXOFF ) 195 panic("tp_rcvoob: unexpected cluster "); 196 197 m->m_next = MNULL; 198 m->m_act = MNULL; 199 m->m_off = MMINOFF; 200 m->m_len = 0; 201 202 /* Assuming at most one xpd tpdu is in the buffer at once */ 203 while ( n != MNULL ) { 204 m->m_len += n->m_len; 205 bcopy(mtod(n, caddr_t), mtod(m, caddr_t), n->m_len); 206 m->m_off += n->m_len; /* so mtod() in bcopy() above gives right addr */ 207 n = n->m_next; 208 } 209 m->m_off = MMINOFF; /* restore it to its proper value */ 210 211 IFDEBUG(D_XPD) 212 printf("tp_rcvoob: xpdlen 0x%x\n", m->m_len); 213 dump_mbuf(so->so_rcv.sb_mb, "RCVOOB: Rcv socketbuf"); 214 dump_mbuf(sb->sb_mb, "RCVOOB: Xrcv socketbuf"); 215 ENDDEBUG 216 217 if( (inflags & MSG_PEEK) == 0 ) 218 sbdrop(sb, m->m_len); 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(outflags) 228 *outflags = MSG_OOB | MSG_EOTSDU | inflags; /* always on xpd recv */ 229 if (error == 0) 230 error = DoEvent(T_USR_Xrcvd); 231 return error; 232 } 233 234 /* 235 * CALLED FROM: 236 * tp_usrreq(), PRU_SENDOOB 237 * FUNCTION and ARGUMENTS: 238 * Send what's in the mbuf chain (m) as an XPD TPDU. 239 * The mbuf may not contain more then 16 bytes of data. 240 * XPD TSDUs aren't segmented, so they translate into 241 * exactly one XPD TPDU, with EOT bit set. 242 * RETURN VALUE: 243 * EWOULDBLOCK if socket is in non-blocking mode and the previous 244 * xpd data haven't been acked yet. 245 * EMSGSIZE if trying to send > max-xpd bytes (16) 246 * ENOBUFS if ran out of mbufs 247 */ 248 static int 249 tp_sendoob(tpcb, so, xdata, outflags) 250 struct tp_pcb *tpcb; 251 register struct socket *so; 252 register struct mbuf *xdata; 253 int *outflags; /* not used */ 254 { 255 /* 256 * Each mbuf chain represents a sequence # in the XPD seq space. 257 * The first one in the queue has sequence # tp_Xuna. 258 * When we add to the XPD queue, we stuff a zero-length 259 * mbuf (mark) into the DATA queue, with its sequence number in m_next 260 * to be assigned to this XPD tpdu, so data xfer can stop 261 * when it reaches the zero-length mbuf if this XPD TPDU hasn't 262 * yet been acknowledged. 263 */ 264 register struct sockbuf *sb = &(tpcb->tp_Xsnd); 265 register struct mbuf *xmark; 266 register int len=0; 267 struct tp_event E; 268 269 IFDEBUG(D_XPD) 270 printf("tp_sendoob:"); 271 if(xdata) 272 printf("xdata len 0x%x\n", xdata->m_len); 273 ENDDEBUG 274 oob_again: 275 /* DO NOT LOCK the Xsnd buffer!!!! You can have at MOST one 276 * socket buf locked at any time!!! (otherwise you might 277 * sleep() in sblock() w/ a signal pending and cause the 278 * system call to be aborted w/ a locked socketbuf, which 279 * is a problem. So the so_snd buffer lock 280 * (done in sosend()) serves as the lock for Xpd. 281 */ 282 if (sb->sb_mb) { /* anything already in this sockbuf? */ 283 if (so->so_state & SS_NBIO) { 284 return EWOULDBLOCK; 285 } 286 sbunlock(&so->so_snd); 287 sbwait(&so->so_snd); 288 sblock(&so->so_snd); 289 goto oob_again; 290 } 291 292 if (xdata == (struct mbuf *)0) { 293 /* empty xpd packet */ 294 MGET(xdata, M_WAIT, TPMT_DATA); 295 if (xdata == NULL) { 296 return ENOBUFS; 297 } 298 xdata->m_len = 0; 299 xdata->m_act = MNULL; 300 } 301 IFDEBUG(D_XPD) 302 printf("tp_sendoob 1:"); 303 if(xdata) 304 printf("xdata len 0x%x\n", xdata->m_len); 305 ENDDEBUG 306 xmark = xdata; /* temporary use of variable xmark */ 307 while (xmark) { 308 len += xmark->m_len; 309 xmark = xmark->m_next; 310 } 311 if (len > TP_MAX_XPD_DATA) { 312 return EMSGSIZE; 313 } 314 IFDEBUG(D_XPD) 315 printf("tp_sendoob 2:"); 316 if(xdata) 317 printf("xdata len 0x%x\n", len); 318 ENDDEBUG 319 320 /* stick an xpd mark in the normal data queue 321 * make sure we have enough mbufs before we stick anything into any queues 322 */ 323 MGET(xmark,M_WAIT, TPMT_XPD); 324 if (xmark == MNULL) { 325 return ENOBUFS; 326 } 327 xmark->m_len = 0; 328 xmark->m_act = MNULL; 329 330 { /* stash the xpd sequence number in the mark */ 331 SeqNum *Xuna = mtod(xmark, SeqNum *); 332 *Xuna = tpcb->tp_Xuna; 333 } 334 335 IFTRACE(D_XPD) 336 tptraceTPCB(TPPTmisc, "XPD mark m_next ", xmark->m_next, 0, 0, 0); 337 ENDTRACE 338 339 sbappendrecord(&so->so_snd, xmark); /* the mark */ 340 sbappendrecord(sb, xdata); 341 342 IFDEBUG(D_XPD) 343 printf("tp_sendoob len 0x%x\n", len); 344 dump_mbuf(so->so_snd.sb_mb, "XPD request Regular sndbuf:"); 345 dump_mbuf(tpcb->tp_Xsnd.sb_mb, "XPD request Xsndbuf:"); 346 ENDDEBUG 347 u.u_r.r_val1 += len; 348 return DoEvent(T_XPD_req); 349 350 } 351 352 /* 353 * CALLED FROM: 354 * the socket routines 355 * FUNCTION and ARGUMENTS: 356 * Handles all "user requests" except the [gs]ockopts() requests. 357 * The argument (req) is the request type (PRU*), 358 * (m) is an mbuf chain, generally used for send and 359 * receive type requests only. 360 * (nam) is used for addresses usually, in particular for the bind request. 361 * 362 * The last argument (rights in most usrreq()s) has been stolen for 363 * returning flags values. Since rights can't be passed around w/ tp, 364 * this field is used only for RCVOOB user requests, and is assumed 365 * to be either 0 (as soreceive() would have it) or a ptr to the int flags 366 * (as recvv()'s version of soreceive() would have it 367 */ 368 /*ARGSUSED*/ 369 ProtoHook 370 tp_usrreq(so, req, m, nam, rightsp, outflags) 371 struct socket *so; 372 u_int req; 373 struct mbuf *m, *nam, *rightsp /* not used */; 374 int *outflags; 375 { 376 register struct tp_pcb *tpcb = sototpcb(so); 377 int s = splnet(); 378 int error = 0; 379 u_long eotsdu = 0; 380 struct tp_event E; 381 382 IFDEBUG(D_REQUEST) 383 printf("usrreq(0x%x,%d,0x%x,0x%x,0x%x)\n",so,req,m,nam,outflags); 384 if(so->so_error) 385 printf("WARNING!!! so->so_error is 0x%x\n", so->so_error); 386 ENDDEBUG 387 IFTRACE(D_REQUEST) 388 tptraceTPCB(TPPTusrreq, "req so m state [", req, so, m, 389 tpcb?tpcb->tp_state:0); 390 ENDTRACE 391 392 if ((u_int)tpcb == 0 && req != PRU_ATTACH) { 393 IFTRACE(D_REQUEST) 394 tptraceTPCB(TPPTusrreq, "req failed NO TPCB[", 0, 0, 0, 0); 395 ENDTRACE 396 splx(s); 397 return ENOTCONN; 398 } 399 400 401 IFDEBUG(D_XPD) 402 extern struct mbuf *mfree; 403 struct mbuf *m = mfree, *n=MNULL; 404 405 if ( (u_int) tpcb != 0 ) { 406 n = tpcb->tp_Xrcv.sb_mb; 407 if(n) while(m) { 408 if(m == n) { 409 printf("enter usrreq %d Xrcv sb_mb 0x%x is on freelist!\n", 410 req, n); 411 } 412 m = m->m_next; 413 } 414 } 415 ENDDEBUG 416 417 switch (req) { 418 419 case PRU_ATTACH: 420 if (tpcb) { 421 error = EISCONN; 422 break; 423 } 424 if( error = tp_attach(so, so->so_proto->pr_domain->dom_family ) ) 425 break; 426 tpcb = sototpcb(so); 427 break; 428 429 case PRU_ABORT: /* called from close() */ 430 /* called for each incoming connect queued on the 431 * parent (accepting) socket 432 */ 433 if( tpcb->tp_state == TP_OPEN ) { 434 E.ATTR(T_DISC_req).e_reason = E_TP_NO_SESSION; 435 error = DoEvent(T_DISC_req); /* pretend it was a close() */ 436 break; 437 } /* else DROP THROUGH */ 438 439 case PRU_DETACH: /* called from close() */ 440 /* called only after disconnect was called */ 441 error = DoEvent(T_DETACH); 442 break; 443 444 case PRU_SHUTDOWN: 445 /* recv end may have been released; local credit might be zero */ 446 case PRU_DISCONNECT: 447 E.ATTR(T_DISC_req).e_reason = E_TP_NORMAL_DISC; 448 error = DoEvent(T_DISC_req); 449 break; 450 451 case PRU_BIND: 452 error = (tpcb->tp_nlproto->nlp_pcbbind)( so->so_pcb, nam ); 453 if (error == 0) { 454 tpcb->tp_lsuffixlen = sizeof(short); /* default */ 455 *(u_short *)(tpcb->tp_lsuffix) = (u_short) 456 (tpcb->tp_nlproto->nlp_getsufx)( so->so_pcb, TP_LOCAL ); 457 } 458 break; 459 460 case PRU_LISTEN: 461 if ( *SHORT_LSUFXP(tpcb) == (short)0 ) { 462 /* note: this suffix is independent of the extended suffix */ 463 if( error = (tpcb->tp_nlproto->nlp_pcbbind)(so->so_pcb, MNULL) ) 464 break; 465 } 466 if( tpcb->tp_lsuffixlen == 0) { 467 tpcb->tp_lsuffixlen = sizeof(short); /* default */ 468 *SHORT_LSUFXP(tpcb) = (short) 469 (tpcb->tp_nlproto->nlp_getsufx)( so->so_pcb, TP_LOCAL ); 470 } 471 IFDEBUG(D_TPISO) 472 if(tpcb->tp_state != TP_CLOSED) 473 printf("LISTEN ERROR: state 0x%x\n", tpcb->tp_state); 474 ENDDEBUG 475 error = DoEvent(T_LISTEN_req); 476 break; 477 478 case PRU_CONNECT2: 479 error = EOPNOTSUPP; /* for unix domain sockets */ 480 break; 481 482 case PRU_CONNECT: 483 IFTRACE(D_CONN) 484 tptraceTPCB(TPPTmisc, 485 "PRU_CONNECT: so *SHORT_LSUFXP(tpcb) 0x%x lsuflen 0x%x, class 0x%x", 486 tpcb->tp_sock, *SHORT_LSUFXP(tpcb), tpcb->tp_lsuffixlen, 487 tpcb->tp_class); 488 ENDTRACE 489 IFDEBUG(D_CONN) 490 printf("PRU_CONNECT: so *SHORT_LSUFXP(tpcb) 0x%x lsuflen 0x%x, class 0x%x", 491 tpcb->tp_sock, *SHORT_LSUFXP(tpcb), tpcb->tp_lsuffixlen, 492 tpcb->tp_class); 493 ENDDEBUG 494 if (*SHORT_LSUFXP(tpcb) == (short)0) { 495 /* no bind was done */ 496 /* note: this suffix is independent of the extended suffix */ 497 if( error = (tpcb->tp_nlproto->nlp_pcbbind)(so->so_pcb, MNULL) ) { 498 IFDEBUG(D_CONN) 499 printf("pcbbind returns error 0x%x\n", error ); 500 ENDDEBUG 501 break; 502 } 503 } 504 if (tpcb->tp_lsuffixlen == 0) { 505 /* didn't set an extended suffix */ 506 tpcb->tp_lsuffixlen = sizeof(short); 507 *SHORT_LSUFXP(tpcb) = (short) 508 (tpcb->tp_nlproto->nlp_getsufx)( so->so_pcb, TP_LOCAL ); 509 } 510 511 IFDEBUG(D_CONN) 512 printf("isop 0x%x isop->isop_socket offset 12 :\n", tpcb->tp_npcb); 513 dump_buf( tpcb->tp_npcb, 16); 514 ENDDEBUG 515 if( error = tp_route_to( nam, tpcb, /* channel */0) ) 516 break; 517 IFDEBUG(D_CONN) 518 printf( 519 "PRU_CONNECT after tpcb 0x%x so 0x%x npcb 0x%x flags 0x%x\n", 520 tpcb, so, tpcb->tp_npcb, tpcb->tp_flags); 521 printf("isop 0x%x isop->isop_socket offset 12 :\n", tpcb->tp_npcb); 522 dump_buf( tpcb->tp_npcb, 16); 523 ENDDEBUG 524 if( tpcb->tp_fsuffixlen == 0 ) { 525 /* didn't set peer extended suffix */ 526 tpcb->tp_fsuffixlen = sizeof(short); 527 *SHORT_FSUFXP(tpcb) = (short) 528 (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, TP_FOREIGN); 529 } 530 (void) (tpcb->tp_nlproto->nlp_mtu)(so, so->so_pcb, 531 &tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0); 532 if( tpcb->tp_state == TP_CLOSED) { 533 soisconnecting(so); 534 error = DoEvent(T_CONN_req); 535 } else { 536 (tpcb->tp_nlproto->nlp_pcbdisc)(so->so_pcb); 537 error = EISCONN; 538 } 539 IFPERF(tpcb) 540 u_int lsufx, fsufx; 541 lsufx = *(u_int *)(tpcb->tp_lsuffix); 542 fsufx = *(u_int *)(tpcb->tp_fsuffix); 543 544 tpmeas( tpcb->tp_lref, 545 TPtime_open | (tpcb->tp_xtd_format <<4 ), 546 &time, lsufx, fsufx, tpcb->tp_fref); 547 ENDPERF 548 break; 549 550 case PRU_ACCEPT: 551 /* all this garbage is to keep accept from returning 552 * before the 3-way handshake is done in class 4. 553 * it'll have to be modified for other classes 554 */ 555 IFDEBUG(D_REQUEST) 556 printf("PRU_ACCEPT so_error 0x%x\n", so->so_error); 557 ENDDEBUG 558 so->so_error = 0; 559 if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTED)== 0) { 560 error = EWOULDBLOCK; 561 break; 562 } 563 while ((so->so_state & SS_ISCONNECTED) == 0 && so->so_error == 0) { 564 sleep((caddr_t)&so->so_timeo, PZERO+1); 565 } 566 if (so->so_error) { 567 error = so->so_error; 568 } else { 569 struct sockaddr *sa = mtod(nam, struct sockaddr *); 570 571 nam->m_len = sizeof (struct sockaddr); 572 (tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, sa, TP_FOREIGN); 573 574 switch(sa->sa_family = sototpcb(so)->tp_domain) { 575 case AF_INET: 576 satosin(sa)->sin_port = 577 (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, TP_FOREIGN); 578 break; 579 case AF_ISO: 580 satosiso(sa)->siso_tsuffix = 581 (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, TP_FOREIGN); 582 /* doesn't cover the case where the suffix is extended - 583 * grotesque - the user *has* to do the getsockopt */ 584 break; 585 } 586 IFDEBUG(D_REQUEST) 587 printf("ACCEPT PEERADDDR:"); 588 dump_buf(sa, sizeof(struct sockaddr)); 589 ENDDEBUG 590 } 591 IFPERF(tpcb) 592 u_int lsufx, fsufx; 593 lsufx = *(u_int *)(tpcb->tp_lsuffix); 594 fsufx = *(u_int *)(tpcb->tp_fsuffix); 595 596 tpmeas( tpcb->tp_lref, TPtime_open, 597 &time, lsufx, fsufx, tpcb->tp_fref); 598 ENDPERF 599 break; 600 601 case PRU_RCVD: 602 IFTRACE(D_DATA) 603 tptraceTPCB(TPPTmisc, 604 "RCVD BF: lcredit sent_lcdt cc hiwat \n", 605 tpcb->tp_lcredit, tpcb->tp_sent_lcdt, 606 so->so_rcv.sb_cc, so->so_rcv.sb_hiwat); 607 LOCAL_CREDIT(tpcb); 608 tptraceTPCB(TPPTmisc, 609 "PRU_RCVD AF sbspace lcredit hiwat cc", 610 sbspace(&so->so_rcv), tpcb->tp_lcredit, 611 so->so_rcv.sb_cc, so->so_rcv.sb_hiwat); 612 ENDTRACE 613 error = DoEvent(T_USR_rcvd); 614 break; 615 616 case PRU_RCVOOB: 617 if ((so->so_state & SS_ISCONNECTED) == 0) { 618 error = ENOTCONN; 619 break; 620 } 621 if( ! tpcb->tp_xpd_service ) { 622 error = EOPNOTSUPP; 623 break; 624 } 625 /* kludge - nam is really flags here */ 626 error = tp_rcvoob(tpcb, so, m, outflags, (int)nam); 627 break; 628 629 case PRU_SENDOOB: 630 if ((so->so_state & SS_ISCONNECTED) == 0) { 631 error = ENOTCONN; 632 break; 633 } 634 if( ! tpcb->tp_xpd_service ) { 635 error = EOPNOTSUPP; 636 break; 637 } 638 error = tp_sendoob(tpcb, so, m, outflags); 639 break; 640 641 case PRU_SENDEOT: 642 eotsdu = 1; 643 /* fall through */ 644 case PRU_SEND: 645 /* 646 * The protocol machine copies mbuf chains, 647 * prepends headers, assigns seq numbers, and 648 * puts the packets on the device. 649 * When they are acked they are removed from the socket buf. 650 * 651 * sosend calls this up until sbspace goes negative. 652 * Sbspace may be made negative by appending this mbuf chain, 653 * possibly by a whole cluster. 654 */ 655 if ((so->so_state & SS_ISCONNECTED) == 0) { 656 error = ENOTCONN; 657 break; 658 } 659 { 660 register struct mbuf *n; 661 register int len=0; 662 register struct sockbuf *sb = &so->so_snd; 663 664 n = m; 665 while (n) { /* Could have eotsdu and no data.(presently MUST have 666 * an mbuf though, even if its length == 0) 667 */ 668 len += n->m_len; 669 if( n->m_next == MNULL && eotsdu ) { 670 CHANGE_MTYPE(n, TPMT_EOT); 671 } 672 n = n->m_next; 673 } 674 IFPERF(tpcb) 675 PStat(tpcb, Nb_from_sess) += len; 676 tpmeas(tpcb->tp_lref, TPtime_from_session, 0, 0, 677 PStat(tpcb, Nb_from_sess), len); 678 ENDPERF 679 IFDEBUG(D_SYSCALL) 680 printf( 681 "PRU_SEND: eot %d before sbappend 0x%x len 0x%x to sb @ 0x%x\n", 682 eotsdu, m,len, &sb->sb_mb); 683 dump_mbuf(sb->sb_mb, "so_snd.sb_mb"); 684 dump_mbuf(m, "m : to be added"); 685 ENDDEBUG 686 /* The last mbuf has type TPMT_EOT so it will never be compressed 687 * with TPMT_DATA mbufs, but if this was an EOTSDU request w/o 688 * any data, the only way to keep this mbuf from being thrown 689 * away is to link it through the m_act field 690 * We are ASSUMING that if there are any data at all with this 691 * request, the last mbuf will be non-empty!!! 692 */ 693 if( m->m_type == TPMT_EOT ) /* first mbuf in chain is EOT? */ 694 sbappendrecord(sb, m); /* to keep 2 TPMT_EOTs from being 695 compressed */ 696 else 697 sbappend(sb, m); 698 IFDEBUG(D_SYSCALL) 699 printf("PRU_SEND: eot %d after sbappend 0x%x len 0x%x\n", 700 eotsdu, m,len); 701 dump_mbuf(sb->sb_mb, "so_snd.sb_mb"); 702 ENDDEBUG 703 u.u_r.r_val1 += len; 704 error = DoEvent(T_DATA_req); 705 IFDEBUG(D_SYSCALL) 706 printf("PRU_SEND: after driver error 0x%x \n",error); 707 ENDDEBUG 708 } 709 break; 710 711 case PRU_SOCKADDR: { 712 struct sockaddr *sa = mtod(nam, struct sockaddr *); 713 714 nam->m_len = sizeof (struct sockaddr); 715 (tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, sa, TP_LOCAL); 716 switch ( sa->sa_family = sototpcb(so)->tp_domain ) { 717 case AF_INET: 718 satosin(sa)->sin_port = 719 (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, TP_LOCAL); 720 break; 721 case AF_ISO: 722 satosiso(sa)->siso_tsuffix = 723 (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, TP_LOCAL); 724 break; 725 } 726 } 727 break; 728 729 case PRU_PEERADDR: 730 if( (so->so_state & SS_ISCONNECTED) && 731 (so->so_state & SS_ISDISCONNECTING) == 0) { 732 struct sockaddr *sa = mtod(nam, struct sockaddr *); 733 734 nam->m_len = sizeof (struct sockaddr); 735 736 (tpcb->tp_nlproto->nlp_getnetaddr)(so->so_pcb, sa, TP_FOREIGN); 737 738 switch ( sa->sa_family = sototpcb(so)->tp_domain ) { 739 case AF_INET: 740 satosin(sa)->sin_port = 741 (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, TP_FOREIGN); 742 break; 743 case AF_ISO: 744 satosiso(sa)->siso_tsuffix = 745 (tpcb->tp_nlproto->nlp_getsufx)(so->so_pcb, TP_FOREIGN); 746 break; 747 } 748 IFDEBUG(D_REQUEST) 749 printf("PEERADDDR:"); 750 dump_buf(sa, sizeof(struct sockaddr)); 751 ENDDEBUG 752 } else 753 error = ENOTCONN; 754 break; 755 756 case PRU_CONTROL: 757 error = EOPNOTSUPP; 758 break; 759 760 case PRU_PROTOSEND: 761 case PRU_PROTORCV: 762 case PRU_SENSE: 763 case PRU_SLOWTIMO: 764 case PRU_FASTTIMO: 765 error = EOPNOTSUPP; 766 break; 767 768 default: 769 #ifdef ARGO_DEBUG 770 printf("tp_usrreq UNKNOWN PRU %d\n", req); 771 #endif ARGO_DEBUG 772 error = EOPNOTSUPP; 773 } 774 775 IFDEBUG(D_REQUEST) 776 printf("returning from tp_usrreq(so 0x%x) error 0x%x\n", so, error); 777 ENDDEBUG 778 IFTRACE(D_REQUEST) 779 tptraceTPCB(TPPTusrreq, "END req so m state [", req, so, m, 780 tpcb?0:tpcb->tp_state); 781 ENDTRACE 782 splx(s); 783 return error; 784 } 785