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