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