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_subr2.c 7.14 (Berkeley) 09/26/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_subr2.c,v 5.5 88/11/18 17:28:55 nhall Exp $ 40 * $Source: /usr/argo/sys/netiso/RCS/tp_subr2.c,v $ 41 * 42 * Some auxiliary routines: 43 * tp_protocol_error: required by xebec- called when a combo of state, 44 * event, predicate isn't covered for by the transition file. 45 * tp_indicate: gives indications(signals) to the user process 46 * tp_getoptions: initializes variables that are affected by the options 47 * chosen. 48 */ 49 50 /* this def'n is to cause the expansion of this macro in the 51 * routine tp_local_credit : 52 */ 53 #define LOCAL_CREDIT_EXPAND 54 55 #include "param.h" 56 #include "systm.h" 57 #include "mbuf.h" 58 #include "socket.h" 59 #include "socketvar.h" 60 #include "domain.h" 61 #include "protosw.h" 62 #include "errno.h" 63 #include "types.h" 64 #include "time.h" 65 #include "kernel.h" 66 #undef MNULL 67 #include "argo_debug.h" 68 #include "tp_param.h" 69 #include "tp_ip.h" 70 #include "iso.h" 71 #include "iso_errno.h" 72 #include "iso_pcb.h" 73 #include "tp_timer.h" 74 #include "tp_stat.h" 75 #include "tp_tpdu.h" 76 #include "tp_pcb.h" 77 #include "tp_seq.h" 78 #include "tp_trace.h" 79 #include "tp_user.h" 80 #include "cons.h" 81 82 #include "../net/if.h" 83 #include "../net/if_types.h" 84 #ifdef TRUE 85 #undef FALSE 86 #undef TRUE 87 #endif 88 #include "../netccitt/x25.h" 89 #include "../netccitt/pk.h" 90 #include "../netccitt/pk_var.h" 91 92 /* 93 * NAME: tp_local_credit() 94 * 95 * CALLED FROM: 96 * tp_emit(), tp_usrreq() 97 * 98 * FUNCTION and ARGUMENTS: 99 * Computes the local credit and stashes it in tpcb->tp_lcredit. 100 * It's a macro in the production system rather than a procdure. 101 * 102 * RETURNS: 103 * 104 * SIDE EFFECTS: 105 * 106 * NOTES: 107 * This doesn't actually get called in a production system - 108 * the macro gets expanded instead in place of calls to this proc. 109 * But for debugging, we call this and that allows us to add 110 * debugging messages easily here. 111 */ 112 void 113 tp_local_credit(tpcb) 114 struct tp_pcb *tpcb; 115 { 116 LOCAL_CREDIT(tpcb); 117 IFDEBUG(D_CREDIT) 118 printf("ref 0x%x lcdt 0x%x l_tpdusize 0x%x decbit 0x%x\n", 119 tpcb->tp_refp - tp_ref, 120 tpcb->tp_lcredit, 121 tpcb->tp_l_tpdusize, 122 tpcb->tp_decbit, 123 tpcb->tp_cong_win 124 ); 125 ENDDEBUG 126 IFTRACE(D_CREDIT) 127 tptraceTPCB(TPPTmisc, 128 "lcdt tpdusz \n", 129 tpcb->tp_lcredit, tpcb->tp_l_tpdusize, 0, 0); 130 ENDTRACE 131 } 132 133 /* 134 * NAME: tp_protocol_error() 135 * 136 * CALLED FROM: 137 * tp_driver(), when it doesn't know what to do with 138 * a combo of event, state, predicate 139 * 140 * FUNCTION and ARGUMENTS: 141 * print error mesg 142 * 143 * RETURN VALUE: 144 * EIO - always 145 * 146 * SIDE EFFECTS: 147 * 148 * NOTES: 149 */ 150 int 151 tp_protocol_error(e,tpcb) 152 struct tp_event *e; 153 struct tp_pcb *tpcb; 154 { 155 printf("TP PROTOCOL ERROR! tpcb 0x%x event 0x%x, state 0x%x\n", 156 tpcb, e->ev_number, tpcb->tp_state); 157 IFTRACE(D_DRIVER) 158 tptraceTPCB(TPPTmisc, "PROTOCOL ERROR tpcb event state", 159 tpcb, e->ev_number, tpcb->tp_state, 0 ); 160 ENDTRACE 161 return EIO; /* for lack of anything better */ 162 } 163 164 165 /* Not used at the moment */ 166 ProtoHook 167 tp_drain() 168 { 169 return 0; 170 } 171 172 173 /* 174 * NAME: tp_indicate() 175 * 176 * CALLED FROM: 177 * tp.trans when XPD arrive, when a connection is being disconnected by 178 * the arrival of a DR or ER, and when a connection times out. 179 * 180 * FUNCTION and ARGUMENTS: 181 * (ind) is the type of indication : T_DISCONNECT, T_XPD 182 * (error) is an E* value that will be put in the socket structure 183 * to be passed along to the user later. 184 * Gives a SIGURG to the user process or group indicated by the socket 185 * attached to the tpcb. 186 * 187 * RETURNS: Rien 188 * 189 * SIDE EFFECTS: 190 * 191 * NOTES: 192 */ 193 void 194 tp_indicate(ind, tpcb, error) 195 int ind; 196 u_short error; 197 register struct tp_pcb *tpcb; 198 { 199 register struct socket *so = tpcb->tp_sock; 200 IFTRACE(D_INDICATION) 201 tptraceTPCB(TPPTindicate, ind, *(u_short *)(tpcb->tp_lsuffix), 202 *(u_short *)(tpcb->tp_fsuffix), error,so->so_pgid); 203 ENDTRACE 204 IFDEBUG(D_INDICATION) 205 char *ls, *fs; 206 ls = tpcb->tp_lsuffix, 207 fs = tpcb->tp_fsuffix, 208 209 printf( 210 "indicate 0x%x lsuf 0x%02x%02x fsuf 0x%02x%02x err 0x%x noind 0x%x ref 0x%x\n", 211 ind, 212 *ls, *(ls+1), *fs, *(fs+1), 213 error, /*so->so_pgrp,*/ 214 tpcb->tp_no_disc_indications, 215 tpcb->tp_lref); 216 ENDDEBUG 217 218 if (ind == ER_TPDU) { 219 register struct mbuf *m; 220 struct tp_disc_reason x; 221 222 if ((so->so_state & SS_CANTRCVMORE) == 0 && 223 (m = m_get(M_DONTWAIT, MT_OOBDATA)) != 0) { 224 225 x.dr_hdr.cmsg_len = m->m_len = sizeof(x); 226 x.dr_hdr.cmsg_level = SOL_TRANSPORT; 227 x.dr_hdr.cmsg_type= TPOPT_DISC_REASON; 228 x.dr_reason = error; 229 *mtod(m, struct tp_disc_reason *) = x; 230 sbappendrecord(&tpcb->tp_Xrcv, m); 231 error = 0; 232 } else 233 error = ECONNRESET; 234 } 235 so->so_error = error; 236 237 if (ind == T_DISCONNECT) { 238 so->so_error = ENOTCONN; 239 if ( tpcb->tp_no_disc_indications ) 240 return; 241 } 242 IFTRACE(D_INDICATION) 243 tptraceTPCB(TPPTmisc, "doing sohasoutofband(so)", so,0,0,0); 244 ENDTRACE 245 sohasoutofband(so); 246 } 247 248 /* 249 * NAME : tp_getoptions() 250 * 251 * CALLED FROM: 252 * tp.trans whenever we go into OPEN state 253 * 254 * FUNCTION and ARGUMENTS: 255 * sets the proper flags and values in the tpcb, to control 256 * the appropriate actions for the given class, options, 257 * sequence space, etc, etc. 258 * 259 * RETURNS: Nada 260 * 261 * SIDE EFFECTS: 262 * 263 * NOTES: 264 */ 265 void 266 tp_getoptions(tpcb) 267 struct tp_pcb *tpcb; 268 { 269 tpcb->tp_seqmask = 270 tpcb->tp_xtd_format ? TP_XTD_FMT_MASK : TP_NML_FMT_MASK ; 271 tpcb->tp_seqbit = 272 tpcb->tp_xtd_format ? TP_XTD_FMT_BIT : TP_NML_FMT_BIT ; 273 tpcb->tp_seqhalf = tpcb->tp_seqbit >> 1; 274 tpcb->tp_dt_ticks = 275 MAX(tpcb->tp_dt_ticks, (tpcb->tp_peer_acktime + 2)); 276 (void) tp_rsyset(tpcb); 277 278 } 279 280 /* 281 * NAME: tp_recycle_tsuffix() 282 * 283 * CALLED FROM: 284 * Called when a ref is frozen. 285 * 286 * FUNCTION and ARGUMENTS: 287 * allows the suffix to be reused. 288 * 289 * RETURNS: zilch 290 * 291 * SIDE EFFECTS: 292 * 293 * NOTES: 294 */ 295 void 296 tp_recycle_tsuffix(tpcb) 297 struct tp_pcb *tpcb; 298 { 299 bzero((caddr_t)tpcb->tp_lsuffix, sizeof( tpcb->tp_lsuffix)); 300 bzero((caddr_t)tpcb->tp_fsuffix, sizeof( tpcb->tp_fsuffix)); 301 tpcb->tp_fsuffixlen = tpcb->tp_lsuffixlen = 0; 302 303 (tpcb->tp_nlproto->nlp_recycle_suffix)(tpcb->tp_npcb); 304 } 305 306 /* 307 * NAME: tp_quench() 308 * 309 * CALLED FROM: 310 * tp{af}_quench() when ICMP source quench or similar thing arrives. 311 * 312 * FUNCTION and ARGUMENTS: 313 * Drop the congestion window back to 1. 314 * Congestion window scheme: 315 * Initial value is 1. ("slow start" as Nagle, et. al. call it) 316 * For each good ack that arrives, the congestion window is increased 317 * by 1 (up to max size of logical infinity, which is to say, 318 * it doesn't wrap around). 319 * Source quench causes it to drop back to 1. 320 * tp_send() uses the smaller of (regular window, congestion window). 321 * One retransmission strategy option is to have any retransmission 322 * cause reset the congestion window back to 1. 323 * 324 * (cmd) is either PRC_QUENCH: source quench, or 325 * PRC_QUENCH2: dest. quench (dec bit) 326 * 327 * RETURNS: 328 * 329 * SIDE EFFECTS: 330 * 331 * NOTES: 332 */ 333 void 334 tp_quench( tpcb, cmd ) 335 struct tp_pcb *tpcb; 336 int cmd; 337 { 338 IFDEBUG(D_QUENCH) 339 printf("tp_quench tpcb 0x%x ref 0x%x sufx 0x%x\n", 340 tpcb, tpcb->tp_lref, *(u_short *)(tpcb->tp_lsuffix)); 341 printf("cong_win 0x%x decbit 0x%x \n", 342 tpcb->tp_cong_win, tpcb->tp_decbit); 343 ENDDEBUG 344 switch(cmd) { 345 case PRC_QUENCH: 346 tpcb->tp_cong_win = tpcb->tp_l_tpdusize; 347 IncStat(ts_quench); 348 break; 349 case PRC_QUENCH2: 350 tpcb->tp_cong_win = tpcb->tp_l_tpdusize; /* might as well quench source also */ 351 tpcb->tp_decbit = TP_DECBIT_CLEAR_COUNT; 352 IncStat(ts_rcvdecbit); 353 break; 354 } 355 } 356 357 358 /* 359 * NAME: tp_netcmd() 360 * 361 * CALLED FROM: 362 * 363 * FUNCTION and ARGUMENTS: 364 * 365 * RETURNS: 366 * 367 * SIDE EFFECTS: 368 * 369 * NOTES: 370 */ 371 tp_netcmd( tpcb, cmd ) 372 struct tp_pcb *tpcb; 373 int cmd; 374 { 375 #ifdef TPCONS 376 struct isopcb *isop; 377 struct pklcd *lcp; 378 379 if (tpcb->tp_netservice != ISO_CONS) 380 return; 381 isop = (struct isopcb *)tpcb->tp_npcb; 382 lcp = (struct pklcd *)isop->isop_chan; 383 switch (cmd) { 384 385 case CONN_CLOSE: 386 case CONN_REFUSE: 387 if (isop->isop_refcnt == 1) { 388 /* This is really superfluous, since it would happen 389 anyway in iso_pcbdetach, although it is a courtesy 390 to free up the x.25 channel before the refwait timer 391 expires. */ 392 lcp->lcd_upper = 0; 393 lcp->lcd_upnext = 0; 394 pk_disconnect(lcp); 395 isop->isop_chan = 0; 396 isop->isop_refcnt = 0; 397 } 398 break; 399 400 default: 401 printf("tp_netcmd(0x%x, 0x%x) NOT IMPLEMENTED\n", tpcb, cmd); 402 break; 403 } 404 #else TPCONS 405 printf("tp_netcmd(): X25 NOT CONFIGURED!!\n"); 406 #endif 407 } 408 /* 409 * CALLED FROM: 410 * tp_ctloutput() and tp_emit() 411 * FUNCTION and ARGUMENTS: 412 * Convert a class mask to the highest numeric value it represents. 413 */ 414 415 int 416 tp_mask_to_num(x) 417 u_char x; 418 { 419 register int j; 420 421 for(j = 4; j>=0 ;j--) { 422 if(x & (1<<j)) 423 break; 424 } 425 ASSERT( (j == 4) || (j == 0) ); /* for now */ 426 if( (j != 4) && (j != 0) ) { 427 printf("ASSERTION ERROR: tp_mask_to_num: x 0x%x j %d\n", 428 x, j); 429 } 430 IFTRACE(D_TPINPUT) 431 tptrace(TPPTmisc, "tp_mask_to_num(x) returns j", x, j, 0, 0); 432 ENDTRACE 433 IFDEBUG(D_TPINPUT) 434 printf("tp_mask_to_num(0x%x) returns 0x%x\n", x, j); 435 ENDDEBUG 436 return j; 437 } 438 439 static 440 copyQOSparms(src, dst) 441 struct tp_conn_param *src, *dst; 442 { 443 /* copy all but the bits stuff at the end */ 444 #define COPYSIZE (12 * sizeof(short)) 445 446 bcopy((caddr_t)src, (caddr_t)dst, COPYSIZE); 447 dst->p_tpdusize = src->p_tpdusize; 448 dst->p_ack_strat = src->p_ack_strat; 449 dst->p_rx_strat = src->p_rx_strat; 450 #undef COPYSIZE 451 } 452 453 /* 454 * CALLED FROM: 455 * tp_usrreq on PRU_CONNECT and tp_input on receipt of CR 456 * 457 * FUNCTION and ARGUMENTS: 458 * route directly to x.25 if the address is type 37 - GROT. 459 * furthermore, let TP0 handle only type-37 addresses 460 * 461 * Since this assumes that its address argument is in a mbuf, the 462 * parameter was changed to reflect this assumtion. This also 463 * implies that an mbuf must be allocated when this is 464 * called from tp_input 465 * 466 * RETURNS: 467 * errno value : 468 * EAFNOSUPPORT if can't find an nl_protosw for x.25 (really could panic) 469 * ECONNREFUSED if trying to run TP0 with non-type 37 address 470 * possibly other E* returned from cons_netcmd() 471 * NOTE: 472 * Would like to eliminate as much of this as possible -- 473 * only one set of defaults (let the user set the parms according 474 * to parameters provided in the directory service). 475 * Left here for now 'cause we don't yet have a clean way to handle 476 * it on the passive end. 477 */ 478 int 479 tp_route_to( m, tpcb, channel) 480 struct mbuf *m; 481 register struct tp_pcb *tpcb; 482 caddr_t channel; 483 { 484 register struct sockaddr_iso *siso; /* NOTE: this may be a sockaddr_in */ 485 extern struct tp_conn_param tp_conn_param[]; 486 int error = 0, save_netservice = tpcb->tp_netservice; 487 register struct rtentry *rt = 0; 488 489 siso = mtod(m, struct sockaddr_iso *); 490 IFTRACE(D_CONN) 491 tptraceTPCB(TPPTmisc, 492 "route_to: so afi netservice class", 493 tpcb->tp_sock, siso->siso_addr.isoa_genaddr[0], tpcb->tp_netservice, 494 tpcb->tp_class); 495 ENDTRACE 496 IFDEBUG(D_CONN) 497 printf("tp_route_to( m x%x, channel 0x%x, tpcb 0x%x netserv 0x%x)\n", 498 m, channel, tpcb, tpcb->tp_netservice); 499 printf("m->mlen x%x, m->m_data:\n", m->m_len); 500 dump_buf(mtod(m, caddr_t), m->m_len); 501 ENDDEBUG 502 if (channel) { 503 #ifdef TPCONS 504 struct pklcd *lcp = (struct pklcd *)channel; 505 struct isopcb *isop = (struct isopcb *)lcp->lcd_upnext, 506 *isop_new = (struct isopcb *)tpcb->tp_npcb; 507 /* The next 2 lines believe that you haven't 508 set any network level options or done a pcbconnect 509 and XXXXXXX'edly apply to both inpcb's and isopcb's */ 510 remque(isop_new); 511 free(isop_new, M_PCB); 512 tpcb->tp_npcb = (caddr_t)isop; 513 tpcb->tp_netservice = ISO_CONS; 514 tpcb->tp_nlproto = nl_protosw + ISO_CONS; 515 isop->isop_socket = tpcb->tp_sock; 516 if (isop->isop_refcnt == 0) 517 iso_putsufx(isop, tpcb->tp_lsuffix, tpcb->tp_lsuffixlen, TP_LOCAL); 518 else 519 /* there are already connections sharing this */; 520 isop->isop_refcnt++; 521 #endif 522 } else { 523 switch (siso->siso_family) { 524 default: 525 error = EAFNOSUPPORT; 526 goto done; 527 #ifdef ISO 528 case AF_ISO: 529 tpcb->tp_netservice = ISO_CLNS; 530 if (rt = rtalloc1((struct sockaddr *)siso, 0)) { 531 rt->rt_refcnt--; 532 if (rt->rt_flags & RTF_PROTO1) 533 tpcb->tp_netservice = ISO_CONS; 534 } 535 break; 536 #endif 537 #ifdef INET 538 case AF_INET: 539 tpcb->tp_netservice = IN_CLNS; 540 } 541 #endif 542 if (tpcb->tp_nlproto->nlp_afamily != siso->siso_family) { 543 IFDEBUG(D_CONN) 544 printf("tp_route_to( CHANGING nlproto old 0x%x new 0x%x)\n", 545 save_netservice, tpcb->tp_netservice); 546 ENDDEBUG 547 if (error = tp_set_npcb(tpcb)) 548 goto done; 549 } 550 IFDEBUG(D_CONN) 551 printf("tp_route_to calling nlp_pcbconn, netserv %d\n", 552 tpcb->tp_netservice); 553 ENDDEBUG 554 tpcb->tp_nlproto = nl_protosw + tpcb->tp_netservice; 555 error = (tpcb->tp_nlproto->nlp_pcbconn)(tpcb->tp_npcb, m); 556 } 557 if( error ) 558 goto done; 559 560 { 561 switch(tpcb->tp_netservice) { 562 case ISO_COSNS: 563 case ISO_CLNS: 564 /* This is a kludge but seems necessary so the passive end 565 * can get long enough timers. sigh. 566 if( siso->siso_addr.osinet_idi[1] == (u_char)IDI_OSINET ) 567 */ 568 if (rt && rt->rt_ifp && rt->rt_ifp->if_type == IFT_X25) { 569 if( tpcb->tp_dont_change_params == 0) { 570 copyQOSparms( &tp_conn_param[ISO_COSNS], 571 &tpcb->_tp_param); 572 } 573 tpcb->tp_flags |= TPF_NLQOS_PDN; 574 } 575 /* drop through to IN_CLNS*/ 576 case IN_CLNS: 577 if (iso_localifa(siso)) 578 tpcb->tp_flags |= TPF_PEER_ON_SAMENET; 579 if((tpcb->tp_class & TP_CLASS_4) == 0) { 580 error = EPROTOTYPE; 581 break; 582 } 583 tpcb->tp_class = TP_CLASS_4; /* IGNORE dont_change_parms */ 584 break; 585 586 case ISO_CONS: 587 #ifdef TPCONS 588 tpcb->tp_flags |= TPF_NLQOS_PDN; 589 if( tpcb->tp_dont_change_params == 0 ) { 590 copyQOSparms( &tp_conn_param[ISO_CONS], 591 &tpcb->_tp_param); 592 } 593 /* 594 * for use over x.25 really need a small receive window, 595 * need to start slowly, need small max negotiable tpdu size, 596 * and need to use the congestion window to the max 597 * IGNORES tp_dont_change_params for these! 598 */ 599 if( tpcb->tp_sock->so_snd.sb_hiwat > 512 ) { 600 (void) soreserve(tpcb->tp_sock, 512, 512 );/* GAG */ 601 } 602 tpcb->tp_rx_strat = TPRX_USE_CW; 603 604 /* class 4 doesn't need to open a vc now - may use one already 605 * opened or may open one only when it sends a pkt. 606 */ 607 #else TPCONS 608 error = ECONNREFUSED; 609 #endif TPCONS 610 break; 611 default: 612 error = EPROTOTYPE; 613 } 614 615 } 616 if (error) { 617 tp_netcmd( tpcb, CONN_CLOSE); 618 goto done; 619 } 620 { /* start with the global rtt, rtv stats */ 621 register int i = 622 (int) tpcb->tp_flags & (TPF_PEER_ON_SAMENET | TPF_NLQOS_PDN); 623 624 tpcb->tp_rtt = tp_stat.ts_rtt[i]; 625 tpcb->tp_rtv = tp_stat.ts_rtv[i]; 626 } 627 done: 628 IFDEBUG(D_CONN) 629 printf("tp_route_to returns 0x%x\n", error); 630 ENDDEBUG 631 IFTRACE(D_CONN) 632 tptraceTPCB(TPPTmisc, "route_to: returns: error netserv class", error, 633 tpcb->tp_netservice, tpcb->tp_class, 0); 634 ENDTRACE 635 return error; 636 } 637 638 639 /* class zero version */ 640 void 641 tp0_stash( tpcb, e ) 642 register struct tp_pcb *tpcb; 643 register struct tp_event *e; 644 { 645 #ifndef lint 646 #define E e->ATTR(DT_TPDU) 647 #else lint 648 #define E e->ev_union.EV_DT_TPDU 649 #endif lint 650 651 register struct sockbuf *sb = &tpcb->tp_sock->so_rcv; 652 register struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb; 653 654 IFPERF(tpcb) 655 PStat(tpcb, Nb_from_ll) += E.e_datalen; 656 tpmeas(tpcb->tp_lref, TPtime_from_ll, &e->e_time, 657 E.e_seq, PStat(tpcb, Nb_from_ll), E.e_datalen); 658 ENDPERF 659 660 IFDEBUG(D_STASH) 661 printf("stash EQ: seq 0x%x datalen 0x%x eot 0x%x", 662 E.e_seq, E.e_datalen, E.e_eot); 663 ENDDEBUG 664 665 IFTRACE(D_STASH) 666 tptraceTPCB(TPPTmisc, "stash EQ: seq len eot", 667 E.e_seq, E.e_datalen, E.e_eot, 0); 668 ENDTRACE 669 670 if ( E.e_eot ) { 671 register struct mbuf *n = E.e_data; 672 n->m_flags |= M_EOR; 673 n->m_act = MNULL; /* set on tp_input */ 674 } 675 sbappend(sb, E.e_data); 676 IFDEBUG(D_STASH) 677 dump_mbuf(sb->sb_mb, "stash 0: so_rcv after appending"); 678 ENDDEBUG 679 if (tpcb->tp_netservice != ISO_CONS) 680 printf("tp0_stash: tp running over something wierd\n"); 681 else { 682 register struct pklcd *lcp = (struct pklcd *)isop->isop_chan; 683 pk_flowcontrol(lcp, sbspace(sb) <= 0, 1); 684 } 685 } 686 687 void 688 tp0_openflow(tpcb) 689 register struct tp_pcb *tpcb; 690 { 691 register struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb; 692 if (tpcb->tp_netservice != ISO_CONS) 693 printf("tp0_openflow: tp running over something wierd\n"); 694 else { 695 register struct pklcd *lcp = (struct pklcd *)isop->isop_chan; 696 if (lcp->lcd_rxrnr_condition) 697 pk_flowcontrol(lcp, 0, 0); 698 } 699 } 700 #ifndef TPCONS 701 static 702 pk_flowcontrol() {} 703 #endif 704 705 #ifdef TP_PERF_MEAS 706 /* 707 * CALLED FROM: 708 * tp_ctloutput() when the user sets TPOPT_PERF_MEAS on 709 * and tp_newsocket() when a new connection is made from 710 * a listening socket with tp_perf_on == true. 711 * FUNCTION and ARGUMENTS: 712 * (tpcb) is the usual; this procedure gets a clear cluster mbuf for 713 * a tp_pmeas structure, and makes tpcb->tp_p_meas point to it. 714 * RETURN VALUE: 715 * ENOBUFS if it cannot get a cluster mbuf. 716 */ 717 718 int 719 tp_setup_perf(tpcb) 720 register struct tp_pcb *tpcb; 721 { 722 register struct mbuf *q; 723 724 if( tpcb->tp_p_meas == 0 ) { 725 MGET(q, M_WAITOK, MT_PCB); 726 if (q == 0) 727 return ENOBUFS; 728 MCLGET(q, M_WAITOK); 729 if ((q->m_flags & M_EXT) == 0) { 730 (void) m_free(q); 731 return ENOBUFS; 732 } 733 q->m_len = sizeof (struct tp_pmeas); 734 tpcb->tp_p_mbuf = q; 735 tpcb->tp_p_meas = mtod(q, struct tp_pmeas *); 736 bzero( (caddr_t)tpcb->tp_p_meas, sizeof (struct tp_pmeas) ); 737 IFDEBUG(D_PERF_MEAS) 738 printf( 739 "tpcb 0x%x so 0x%x ref 0x%x tp_p_meas 0x%x tp_perf_on 0x%x\n", 740 tpcb, tpcb->tp_sock, tpcb->tp_lref, 741 tpcb->tp_p_meas, tpcb->tp_perf_on); 742 ENDDEBUG 743 tpcb->tp_perf_on = 1; 744 } 745 return 0; 746 } 747 #endif TP_PERF_MEAS 748 749 #ifdef ARGO_DEBUG 750 dump_addr (addr) 751 register struct sockaddr *addr; 752 { 753 switch( addr->sa_family ) { 754 case AF_INET: 755 dump_inaddr((struct sockaddr_in *)addr); 756 break; 757 #ifdef ISO 758 case AF_ISO: 759 dump_isoaddr((struct sockaddr_iso *)addr); 760 break; 761 #endif ISO 762 default: 763 printf("BAD AF: 0x%x\n", addr->sa_family); 764 break; 765 } 766 } 767 768 #define MAX_COLUMNS 8 769 /* 770 * Dump the buffer to the screen in a readable format. Format is: 771 * 772 * hex/dec where hex is the hex format, dec is the decimal format. 773 * columns of hex/dec numbers will be printed, followed by the 774 * character representations (if printable). 775 */ 776 Dump_buf(buf, len) 777 caddr_t buf; 778 int len; 779 { 780 int i,j; 781 #define Buf ((u_char *)buf) 782 printf("Dump buf 0x%x len 0x%x\n", buf, len); 783 for (i = 0; i < len; i += MAX_COLUMNS) { 784 printf("+%d:\t", i); 785 for (j = 0; j < MAX_COLUMNS; j++) { 786 if (i + j < len) { 787 printf("%x/%d\t", Buf[i+j], Buf[i+j]); 788 } else { 789 printf(" "); 790 } 791 } 792 793 for (j = 0; j < MAX_COLUMNS; j++) { 794 if (i + j < len) { 795 if (((Buf[i+j]) > 31) && ((Buf[i+j]) < 128)) 796 printf("%c", Buf[i+j]); 797 else 798 printf("."); 799 } 800 } 801 printf("\n"); 802 } 803 } 804 805 806 #endif ARGO_DEBUG 807 808