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.16 (Berkeley) 09/30/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_lref, 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 if (error == 0) 239 so->so_error = ENOTCONN; 240 if ( tpcb->tp_no_disc_indications ) 241 return; 242 } 243 IFTRACE(D_INDICATION) 244 tptraceTPCB(TPPTmisc, "doing sohasoutofband(so)", so,0,0,0); 245 ENDTRACE 246 sohasoutofband(so); 247 } 248 249 /* 250 * NAME : tp_getoptions() 251 * 252 * CALLED FROM: 253 * tp.trans whenever we go into OPEN state 254 * 255 * FUNCTION and ARGUMENTS: 256 * sets the proper flags and values in the tpcb, to control 257 * the appropriate actions for the given class, options, 258 * sequence space, etc, etc. 259 * 260 * RETURNS: Nada 261 * 262 * SIDE EFFECTS: 263 * 264 * NOTES: 265 */ 266 void 267 tp_getoptions(tpcb) 268 struct tp_pcb *tpcb; 269 { 270 tpcb->tp_seqmask = 271 tpcb->tp_xtd_format ? TP_XTD_FMT_MASK : TP_NML_FMT_MASK ; 272 tpcb->tp_seqbit = 273 tpcb->tp_xtd_format ? TP_XTD_FMT_BIT : TP_NML_FMT_BIT ; 274 tpcb->tp_seqhalf = tpcb->tp_seqbit >> 1; 275 tpcb->tp_dt_ticks = 276 MAX(tpcb->tp_dt_ticks, (tpcb->tp_peer_acktime + 2)); 277 (void) tp_rsyset(tpcb); 278 279 } 280 281 /* 282 * NAME: tp_recycle_tsuffix() 283 * 284 * CALLED FROM: 285 * Called when a ref is frozen. 286 * 287 * FUNCTION and ARGUMENTS: 288 * allows the suffix to be reused. 289 * 290 * RETURNS: zilch 291 * 292 * SIDE EFFECTS: 293 * 294 * NOTES: 295 */ 296 void 297 tp_recycle_tsuffix(tpcb) 298 struct tp_pcb *tpcb; 299 { 300 bzero((caddr_t)tpcb->tp_lsuffix, sizeof( tpcb->tp_lsuffix)); 301 bzero((caddr_t)tpcb->tp_fsuffix, sizeof( tpcb->tp_fsuffix)); 302 tpcb->tp_fsuffixlen = tpcb->tp_lsuffixlen = 0; 303 304 (tpcb->tp_nlproto->nlp_recycle_suffix)(tpcb->tp_npcb); 305 } 306 307 /* 308 * NAME: tp_quench() 309 * 310 * CALLED FROM: 311 * tp{af}_quench() when ICMP source quench or similar thing arrives. 312 * 313 * FUNCTION and ARGUMENTS: 314 * Drop the congestion window back to 1. 315 * Congestion window scheme: 316 * Initial value is 1. ("slow start" as Nagle, et. al. call it) 317 * For each good ack that arrives, the congestion window is increased 318 * by 1 (up to max size of logical infinity, which is to say, 319 * it doesn't wrap around). 320 * Source quench causes it to drop back to 1. 321 * tp_send() uses the smaller of (regular window, congestion window). 322 * One retransmission strategy option is to have any retransmission 323 * cause reset the congestion window back to 1. 324 * 325 * (cmd) is either PRC_QUENCH: source quench, or 326 * PRC_QUENCH2: dest. quench (dec bit) 327 * 328 * RETURNS: 329 * 330 * SIDE EFFECTS: 331 * 332 * NOTES: 333 */ 334 void 335 tp_quench( tpcb, cmd ) 336 struct tp_pcb *tpcb; 337 int cmd; 338 { 339 IFDEBUG(D_QUENCH) 340 printf("tp_quench tpcb 0x%x ref 0x%x sufx 0x%x\n", 341 tpcb, tpcb->tp_lref, *(u_short *)(tpcb->tp_lsuffix)); 342 printf("cong_win 0x%x decbit 0x%x \n", 343 tpcb->tp_cong_win, tpcb->tp_decbit); 344 ENDDEBUG 345 switch(cmd) { 346 case PRC_QUENCH: 347 tpcb->tp_cong_win = tpcb->tp_l_tpdusize; 348 IncStat(ts_quench); 349 break; 350 case PRC_QUENCH2: 351 tpcb->tp_cong_win = tpcb->tp_l_tpdusize; /* might as well quench source also */ 352 tpcb->tp_decbit = TP_DECBIT_CLEAR_COUNT; 353 IncStat(ts_rcvdecbit); 354 break; 355 } 356 } 357 358 359 /* 360 * NAME: tp_netcmd() 361 * 362 * CALLED FROM: 363 * 364 * FUNCTION and ARGUMENTS: 365 * 366 * RETURNS: 367 * 368 * SIDE EFFECTS: 369 * 370 * NOTES: 371 */ 372 tp_netcmd( tpcb, cmd ) 373 struct tp_pcb *tpcb; 374 int cmd; 375 { 376 #ifdef TPCONS 377 struct isopcb *isop; 378 struct pklcd *lcp; 379 380 if (tpcb->tp_netservice != ISO_CONS) 381 return; 382 isop = (struct isopcb *)tpcb->tp_npcb; 383 lcp = (struct pklcd *)isop->isop_chan; 384 switch (cmd) { 385 386 case CONN_CLOSE: 387 case CONN_REFUSE: 388 if (isop->isop_refcnt == 1) { 389 /* This is really superfluous, since it would happen 390 anyway in iso_pcbdetach, although it is a courtesy 391 to free up the x.25 channel before the refwait timer 392 expires. */ 393 lcp->lcd_upper = 0; 394 lcp->lcd_upnext = 0; 395 pk_disconnect(lcp); 396 isop->isop_chan = 0; 397 isop->isop_refcnt = 0; 398 } 399 break; 400 401 default: 402 printf("tp_netcmd(0x%x, 0x%x) NOT IMPLEMENTED\n", tpcb, cmd); 403 break; 404 } 405 #else TPCONS 406 printf("tp_netcmd(): X25 NOT CONFIGURED!!\n"); 407 #endif 408 } 409 /* 410 * CALLED FROM: 411 * tp_ctloutput() and tp_emit() 412 * FUNCTION and ARGUMENTS: 413 * Convert a class mask to the highest numeric value it represents. 414 */ 415 416 int 417 tp_mask_to_num(x) 418 u_char x; 419 { 420 register int j; 421 422 for(j = 4; j>=0 ;j--) { 423 if(x & (1<<j)) 424 break; 425 } 426 ASSERT( (j == 4) || (j == 0) ); /* for now */ 427 if( (j != 4) && (j != 0) ) { 428 printf("ASSERTION ERROR: tp_mask_to_num: x 0x%x j %d\n", 429 x, j); 430 } 431 IFTRACE(D_TPINPUT) 432 tptrace(TPPTmisc, "tp_mask_to_num(x) returns j", x, j, 0, 0); 433 ENDTRACE 434 IFDEBUG(D_TPINPUT) 435 printf("tp_mask_to_num(0x%x) returns 0x%x\n", x, j); 436 ENDDEBUG 437 return j; 438 } 439 440 static 441 copyQOSparms(src, dst) 442 struct tp_conn_param *src, *dst; 443 { 444 /* copy all but the bits stuff at the end */ 445 #define COPYSIZE (12 * sizeof(short)) 446 447 bcopy((caddr_t)src, (caddr_t)dst, COPYSIZE); 448 dst->p_tpdusize = src->p_tpdusize; 449 dst->p_ack_strat = src->p_ack_strat; 450 dst->p_rx_strat = src->p_rx_strat; 451 #undef COPYSIZE 452 } 453 454 /* 455 * CALLED FROM: 456 * tp_usrreq on PRU_CONNECT and tp_input on receipt of CR 457 * 458 * FUNCTION and ARGUMENTS: 459 * route directly to x.25 if the address is type 37 - GROT. 460 * furthermore, let TP0 handle only type-37 addresses 461 * 462 * Since this assumes that its address argument is in a mbuf, the 463 * parameter was changed to reflect this assumtion. This also 464 * implies that an mbuf must be allocated when this is 465 * called from tp_input 466 * 467 * RETURNS: 468 * errno value : 469 * EAFNOSUPPORT if can't find an nl_protosw for x.25 (really could panic) 470 * ECONNREFUSED if trying to run TP0 with non-type 37 address 471 * possibly other E* returned from cons_netcmd() 472 * NOTE: 473 * Would like to eliminate as much of this as possible -- 474 * only one set of defaults (let the user set the parms according 475 * to parameters provided in the directory service). 476 * Left here for now 'cause we don't yet have a clean way to handle 477 * it on the passive end. 478 */ 479 int 480 tp_route_to( m, tpcb, channel) 481 struct mbuf *m; 482 register struct tp_pcb *tpcb; 483 caddr_t channel; 484 { 485 register struct sockaddr_iso *siso; /* NOTE: this may be a sockaddr_in */ 486 extern struct tp_conn_param tp_conn_param[]; 487 int error = 0, save_netservice = tpcb->tp_netservice; 488 register struct rtentry *rt = 0; 489 490 siso = mtod(m, struct sockaddr_iso *); 491 IFTRACE(D_CONN) 492 tptraceTPCB(TPPTmisc, 493 "route_to: so afi netservice class", 494 tpcb->tp_sock, siso->siso_addr.isoa_genaddr[0], tpcb->tp_netservice, 495 tpcb->tp_class); 496 ENDTRACE 497 IFDEBUG(D_CONN) 498 printf("tp_route_to( m x%x, channel 0x%x, tpcb 0x%x netserv 0x%x)\n", 499 m, channel, tpcb, tpcb->tp_netservice); 500 printf("m->mlen x%x, m->m_data:\n", m->m_len); 501 dump_buf(mtod(m, caddr_t), m->m_len); 502 ENDDEBUG 503 if (channel) { 504 #ifdef TPCONS 505 struct pklcd *lcp = (struct pklcd *)channel; 506 struct isopcb *isop = (struct isopcb *)lcp->lcd_upnext, 507 *isop_new = (struct isopcb *)tpcb->tp_npcb; 508 /* The next 2 lines believe that you haven't 509 set any network level options or done a pcbconnect 510 and XXXXXXX'edly apply to both inpcb's and isopcb's */ 511 remque(isop_new); 512 free(isop_new, M_PCB); 513 tpcb->tp_npcb = (caddr_t)isop; 514 tpcb->tp_netservice = ISO_CONS; 515 tpcb->tp_nlproto = nl_protosw + ISO_CONS; 516 isop->isop_socket = tpcb->tp_sock; 517 if (isop->isop_refcnt == 0) 518 iso_putsufx(isop, tpcb->tp_lsuffix, tpcb->tp_lsuffixlen, TP_LOCAL); 519 else 520 /* there are already connections sharing this */; 521 isop->isop_refcnt++; 522 #endif 523 } else { 524 switch (siso->siso_family) { 525 default: 526 error = EAFNOSUPPORT; 527 goto done; 528 #ifdef ISO 529 case AF_ISO: 530 tpcb->tp_netservice = ISO_CLNS; 531 if (rt = rtalloc1((struct sockaddr *)siso, 0)) { 532 rt->rt_refcnt--; 533 if (rt->rt_flags & RTF_PROTO1) 534 tpcb->tp_netservice = ISO_CONS; 535 } 536 break; 537 #endif 538 #ifdef INET 539 case AF_INET: 540 tpcb->tp_netservice = IN_CLNS; 541 } 542 #endif 543 if (tpcb->tp_nlproto->nlp_afamily != siso->siso_family) { 544 IFDEBUG(D_CONN) 545 printf("tp_route_to( CHANGING nlproto old 0x%x new 0x%x)\n", 546 save_netservice, tpcb->tp_netservice); 547 ENDDEBUG 548 if (error = tp_set_npcb(tpcb)) 549 goto done; 550 } 551 IFDEBUG(D_CONN) 552 printf("tp_route_to calling nlp_pcbconn, netserv %d\n", 553 tpcb->tp_netservice); 554 ENDDEBUG 555 tpcb->tp_nlproto = nl_protosw + tpcb->tp_netservice; 556 error = (tpcb->tp_nlproto->nlp_pcbconn)(tpcb->tp_npcb, m); 557 } 558 if( error ) 559 goto done; 560 561 { 562 switch(tpcb->tp_netservice) { 563 case ISO_COSNS: 564 case ISO_CLNS: 565 /* This is a kludge but seems necessary so the passive end 566 * can get long enough timers. sigh. 567 if( siso->siso_addr.osinet_idi[1] == (u_char)IDI_OSINET ) 568 */ 569 if (rt && rt->rt_ifp && rt->rt_ifp->if_type == IFT_X25) { 570 if( tpcb->tp_dont_change_params == 0) { 571 copyQOSparms( &tp_conn_param[ISO_COSNS], 572 &tpcb->_tp_param); 573 } 574 tpcb->tp_flags |= TPF_NLQOS_PDN; 575 } 576 /* drop through to IN_CLNS*/ 577 case IN_CLNS: 578 if (iso_localifa(siso)) 579 tpcb->tp_flags |= TPF_PEER_ON_SAMENET; 580 if((tpcb->tp_class & TP_CLASS_4) == 0) { 581 error = EPROTOTYPE; 582 break; 583 } 584 tpcb->tp_class = TP_CLASS_4; /* IGNORE dont_change_parms */ 585 break; 586 587 case ISO_CONS: 588 #ifdef TPCONS 589 tpcb->tp_flags |= TPF_NLQOS_PDN; 590 if( tpcb->tp_dont_change_params == 0 ) { 591 copyQOSparms( &tp_conn_param[ISO_CONS], 592 &tpcb->_tp_param); 593 } 594 /* 595 * for use over x.25 really need a small receive window, 596 * need to start slowly, need small max negotiable tpdu size, 597 * and need to use the congestion window to the max 598 * IGNORES tp_dont_change_params for these! 599 */ 600 if( tpcb->tp_sock->so_snd.sb_hiwat > 512 ) { 601 (void) soreserve(tpcb->tp_sock, 512, 512 );/* GAG */ 602 } 603 tpcb->tp_rx_strat = TPRX_USE_CW; 604 605 /* class 4 doesn't need to open a vc now - may use one already 606 * opened or may open one only when it sends a pkt. 607 */ 608 #else TPCONS 609 error = ECONNREFUSED; 610 #endif TPCONS 611 break; 612 default: 613 error = EPROTOTYPE; 614 } 615 616 } 617 if (error) { 618 tp_netcmd( tpcb, CONN_CLOSE); 619 goto done; 620 } 621 { /* start with the global rtt, rtv stats */ 622 register int i = 623 (int) tpcb->tp_flags & (TPF_PEER_ON_SAMENET | TPF_NLQOS_PDN); 624 625 tpcb->tp_rtt = tp_stat.ts_rtt[i]; 626 tpcb->tp_rtv = tp_stat.ts_rtv[i]; 627 } 628 done: 629 IFDEBUG(D_CONN) 630 printf("tp_route_to returns 0x%x\n", error); 631 ENDDEBUG 632 IFTRACE(D_CONN) 633 tptraceTPCB(TPPTmisc, "route_to: returns: error netserv class", error, 634 tpcb->tp_netservice, tpcb->tp_class, 0); 635 ENDTRACE 636 return error; 637 } 638 639 640 /* class zero version */ 641 void 642 tp0_stash( tpcb, e ) 643 register struct tp_pcb *tpcb; 644 register struct tp_event *e; 645 { 646 #ifndef lint 647 #define E e->ATTR(DT_TPDU) 648 #else lint 649 #define E e->ev_union.EV_DT_TPDU 650 #endif lint 651 652 register struct sockbuf *sb = &tpcb->tp_sock->so_rcv; 653 register struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb; 654 655 IFPERF(tpcb) 656 PStat(tpcb, Nb_from_ll) += E.e_datalen; 657 tpmeas(tpcb->tp_lref, TPtime_from_ll, &e->e_time, 658 E.e_seq, PStat(tpcb, Nb_from_ll), E.e_datalen); 659 ENDPERF 660 661 IFDEBUG(D_STASH) 662 printf("stash EQ: seq 0x%x datalen 0x%x eot 0x%x", 663 E.e_seq, E.e_datalen, E.e_eot); 664 ENDDEBUG 665 666 IFTRACE(D_STASH) 667 tptraceTPCB(TPPTmisc, "stash EQ: seq len eot", 668 E.e_seq, E.e_datalen, E.e_eot, 0); 669 ENDTRACE 670 671 if ( E.e_eot ) { 672 register struct mbuf *n = E.e_data; 673 n->m_flags |= M_EOR; 674 n->m_act = MNULL; /* set on tp_input */ 675 } 676 sbappend(sb, E.e_data); 677 IFDEBUG(D_STASH) 678 dump_mbuf(sb->sb_mb, "stash 0: so_rcv after appending"); 679 ENDDEBUG 680 if (tpcb->tp_netservice != ISO_CONS) 681 printf("tp0_stash: tp running over something wierd\n"); 682 else { 683 register struct pklcd *lcp = (struct pklcd *)isop->isop_chan; 684 pk_flowcontrol(lcp, sbspace(sb) <= 0, 1); 685 } 686 } 687 688 void 689 tp0_openflow(tpcb) 690 register struct tp_pcb *tpcb; 691 { 692 register struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb; 693 if (tpcb->tp_netservice != ISO_CONS) 694 printf("tp0_openflow: tp running over something wierd\n"); 695 else { 696 register struct pklcd *lcp = (struct pklcd *)isop->isop_chan; 697 if (lcp->lcd_rxrnr_condition) 698 pk_flowcontrol(lcp, 0, 0); 699 } 700 } 701 #ifndef TPCONS 702 static 703 pk_flowcontrol() {} 704 #endif 705 706 #ifdef TP_PERF_MEAS 707 /* 708 * CALLED FROM: 709 * tp_ctloutput() when the user sets TPOPT_PERF_MEAS on 710 * and tp_newsocket() when a new connection is made from 711 * a listening socket with tp_perf_on == true. 712 * FUNCTION and ARGUMENTS: 713 * (tpcb) is the usual; this procedure gets a clear cluster mbuf for 714 * a tp_pmeas structure, and makes tpcb->tp_p_meas point to it. 715 * RETURN VALUE: 716 * ENOBUFS if it cannot get a cluster mbuf. 717 */ 718 719 int 720 tp_setup_perf(tpcb) 721 register struct tp_pcb *tpcb; 722 { 723 register struct mbuf *q; 724 725 if( tpcb->tp_p_meas == 0 ) { 726 MGET(q, M_WAITOK, MT_PCB); 727 if (q == 0) 728 return ENOBUFS; 729 MCLGET(q, M_WAITOK); 730 if ((q->m_flags & M_EXT) == 0) { 731 (void) m_free(q); 732 return ENOBUFS; 733 } 734 q->m_len = sizeof (struct tp_pmeas); 735 tpcb->tp_p_mbuf = q; 736 tpcb->tp_p_meas = mtod(q, struct tp_pmeas *); 737 bzero( (caddr_t)tpcb->tp_p_meas, sizeof (struct tp_pmeas) ); 738 IFDEBUG(D_PERF_MEAS) 739 printf( 740 "tpcb 0x%x so 0x%x ref 0x%x tp_p_meas 0x%x tp_perf_on 0x%x\n", 741 tpcb, tpcb->tp_sock, tpcb->tp_lref, 742 tpcb->tp_p_meas, tpcb->tp_perf_on); 743 ENDDEBUG 744 tpcb->tp_perf_on = 1; 745 } 746 return 0; 747 } 748 #endif TP_PERF_MEAS 749 750 #ifdef ARGO_DEBUG 751 dump_addr (addr) 752 register struct sockaddr *addr; 753 { 754 switch( addr->sa_family ) { 755 case AF_INET: 756 dump_inaddr((struct sockaddr_in *)addr); 757 break; 758 #ifdef ISO 759 case AF_ISO: 760 dump_isoaddr((struct sockaddr_iso *)addr); 761 break; 762 #endif ISO 763 default: 764 printf("BAD AF: 0x%x\n", addr->sa_family); 765 break; 766 } 767 } 768 769 #define MAX_COLUMNS 8 770 /* 771 * Dump the buffer to the screen in a readable format. Format is: 772 * 773 * hex/dec where hex is the hex format, dec is the decimal format. 774 * columns of hex/dec numbers will be printed, followed by the 775 * character representations (if printable). 776 */ 777 Dump_buf(buf, len) 778 caddr_t buf; 779 int len; 780 { 781 int i,j; 782 #define Buf ((u_char *)buf) 783 printf("Dump buf 0x%x len 0x%x\n", buf, len); 784 for (i = 0; i < len; i += MAX_COLUMNS) { 785 printf("+%d:\t", i); 786 for (j = 0; j < MAX_COLUMNS; j++) { 787 if (i + j < len) { 788 printf("%x/%d\t", Buf[i+j], Buf[i+j]); 789 } else { 790 printf(" "); 791 } 792 } 793 794 for (j = 0; j < MAX_COLUMNS; j++) { 795 if (i + j < len) { 796 if (((Buf[i+j]) > 31) && ((Buf[i+j]) < 128)) 797 printf("%c", Buf[i+j]); 798 else 799 printf("."); 800 } 801 } 802 printf("\n"); 803 } 804 } 805 806 807 #endif ARGO_DEBUG 808 809