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