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.19 (Berkeley) 05/27/92 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 void tp_rsyset(); 93 94 /* 95 * NAME: tp_local_credit() 96 * 97 * CALLED FROM: 98 * tp_emit(), tp_usrreq() 99 * 100 * FUNCTION and ARGUMENTS: 101 * Computes the local credit and stashes it in tpcb->tp_lcredit. 102 * It's a macro in the production system rather than a procdure. 103 * 104 * RETURNS: 105 * 106 * SIDE EFFECTS: 107 * 108 * NOTES: 109 * This doesn't actually get called in a production system - 110 * the macro gets expanded instead in place of calls to this proc. 111 * But for debugging, we call this and that allows us to add 112 * debugging messages easily here. 113 */ 114 void 115 tp_local_credit(tpcb) 116 struct tp_pcb *tpcb; 117 { 118 LOCAL_CREDIT(tpcb); 119 IFDEBUG(D_CREDIT) 120 printf("ref 0x%x lcdt 0x%x l_tpdusize 0x%x decbit 0x%x\n", 121 tpcb->tp_lref, 122 tpcb->tp_lcredit, 123 tpcb->tp_l_tpdusize, 124 tpcb->tp_decbit, 125 tpcb->tp_cong_win 126 ); 127 ENDDEBUG 128 IFTRACE(D_CREDIT) 129 tptraceTPCB(TPPTmisc, 130 "lcdt tpdusz \n", 131 tpcb->tp_lcredit, tpcb->tp_l_tpdusize, 0, 0); 132 ENDTRACE 133 } 134 135 /* 136 * NAME: tp_protocol_error() 137 * 138 * CALLED FROM: 139 * tp_driver(), when it doesn't know what to do with 140 * a combo of event, state, predicate 141 * 142 * FUNCTION and ARGUMENTS: 143 * print error mesg 144 * 145 * RETURN VALUE: 146 * EIO - always 147 * 148 * SIDE EFFECTS: 149 * 150 * NOTES: 151 */ 152 int 153 tp_protocol_error(e,tpcb) 154 struct tp_event *e; 155 struct tp_pcb *tpcb; 156 { 157 printf("TP PROTOCOL ERROR! tpcb 0x%x event 0x%x, state 0x%x\n", 158 tpcb, e->ev_number, tpcb->tp_state); 159 IFTRACE(D_DRIVER) 160 tptraceTPCB(TPPTmisc, "PROTOCOL ERROR tpcb event state", 161 tpcb, e->ev_number, tpcb->tp_state, 0 ); 162 ENDTRACE 163 return EIO; /* for lack of anything better */ 164 } 165 166 167 /* Not used at the moment */ 168 ProtoHook 169 tp_drain() 170 { 171 return 0; 172 } 173 174 175 /* 176 * NAME: tp_indicate() 177 * 178 * CALLED FROM: 179 * tp.trans when XPD arrive, when a connection is being disconnected by 180 * the arrival of a DR or ER, and when a connection times out. 181 * 182 * FUNCTION and ARGUMENTS: 183 * (ind) is the type of indication : T_DISCONNECT, T_XPD 184 * (error) is an E* value that will be put in the socket structure 185 * to be passed along to the user later. 186 * Gives a SIGURG to the user process or group indicated by the socket 187 * attached to the tpcb. 188 * 189 * RETURNS: Rien 190 * 191 * SIDE EFFECTS: 192 * 193 * NOTES: 194 */ 195 void 196 tp_indicate(ind, tpcb, error) 197 int ind; 198 u_short error; 199 register struct tp_pcb *tpcb; 200 { 201 register struct socket *so = tpcb->tp_sock; 202 IFTRACE(D_INDICATION) 203 tptraceTPCB(TPPTindicate, ind, *(u_short *)(tpcb->tp_lsuffix), 204 *(u_short *)(tpcb->tp_fsuffix), error,so->so_pgid); 205 ENDTRACE 206 IFDEBUG(D_INDICATION) 207 char *ls, *fs; 208 ls = tpcb->tp_lsuffix, 209 fs = tpcb->tp_fsuffix, 210 211 printf( 212 "indicate 0x%x lsuf 0x%02x%02x fsuf 0x%02x%02x err 0x%x noind 0x%x ref 0x%x\n", 213 ind, 214 *ls, *(ls+1), *fs, *(fs+1), 215 error, /*so->so_pgrp,*/ 216 tpcb->tp_no_disc_indications, 217 tpcb->tp_lref); 218 ENDDEBUG 219 220 if (ind == ER_TPDU) { 221 register struct mbuf *m; 222 struct tp_disc_reason x; 223 224 if ((so->so_state & SS_CANTRCVMORE) == 0 && 225 (m = m_get(M_DONTWAIT, MT_OOBDATA)) != 0) { 226 227 x.dr_hdr.cmsg_len = m->m_len = sizeof(x); 228 x.dr_hdr.cmsg_level = SOL_TRANSPORT; 229 x.dr_hdr.cmsg_type= TPOPT_DISC_REASON; 230 x.dr_reason = error; 231 *mtod(m, struct tp_disc_reason *) = x; 232 sbappendrecord(&tpcb->tp_Xrcv, m); 233 error = 0; 234 } else 235 error = ECONNRESET; 236 } 237 so->so_error = error; 238 239 if (ind == T_DISCONNECT) { 240 if (error == 0) 241 so->so_error = ENOTCONN; 242 if ( tpcb->tp_no_disc_indications ) 243 return; 244 } 245 IFTRACE(D_INDICATION) 246 tptraceTPCB(TPPTmisc, "doing sohasoutofband(so)", so,0,0,0); 247 ENDTRACE 248 sohasoutofband(so); 249 } 250 251 /* 252 * NAME : tp_getoptions() 253 * 254 * CALLED FROM: 255 * tp.trans whenever we go into OPEN state 256 * 257 * FUNCTION and ARGUMENTS: 258 * sets the proper flags and values in the tpcb, to control 259 * the appropriate actions for the given class, options, 260 * sequence space, etc, etc. 261 * 262 * RETURNS: Nada 263 * 264 * SIDE EFFECTS: 265 * 266 * NOTES: 267 */ 268 void 269 tp_getoptions(tpcb) 270 struct tp_pcb *tpcb; 271 { 272 tpcb->tp_seqmask = 273 tpcb->tp_xtd_format ? TP_XTD_FMT_MASK : TP_NML_FMT_MASK ; 274 tpcb->tp_seqbit = 275 tpcb->tp_xtd_format ? TP_XTD_FMT_BIT : TP_NML_FMT_BIT ; 276 tpcb->tp_seqhalf = tpcb->tp_seqbit >> 1; 277 tpcb->tp_dt_ticks = 278 MAX(tpcb->tp_dt_ticks, (tpcb->tp_peer_acktime + 2)); 279 tp_rsyset(tpcb); 280 281 } 282 283 /* 284 * NAME: tp_recycle_tsuffix() 285 * 286 * CALLED FROM: 287 * Called when a ref is frozen. 288 * 289 * FUNCTION and ARGUMENTS: 290 * allows the suffix to be reused. 291 * 292 * RETURNS: zilch 293 * 294 * SIDE EFFECTS: 295 * 296 * NOTES: 297 */ 298 void 299 tp_recycle_tsuffix(tpcb) 300 struct tp_pcb *tpcb; 301 { 302 bzero((caddr_t)tpcb->tp_lsuffix, sizeof( tpcb->tp_lsuffix)); 303 bzero((caddr_t)tpcb->tp_fsuffix, sizeof( tpcb->tp_fsuffix)); 304 tpcb->tp_fsuffixlen = tpcb->tp_lsuffixlen = 0; 305 306 (tpcb->tp_nlproto->nlp_recycle_suffix)(tpcb->tp_npcb); 307 } 308 309 /* 310 * NAME: tp_quench() 311 * 312 * CALLED FROM: 313 * tp{af}_quench() when ICMP source quench or similar thing arrives. 314 * 315 * FUNCTION and ARGUMENTS: 316 * Drop the congestion window back to 1. 317 * Congestion window scheme: 318 * Initial value is 1. ("slow start" as Nagle, et. al. call it) 319 * For each good ack that arrives, the congestion window is increased 320 * by 1 (up to max size of logical infinity, which is to say, 321 * it doesn't wrap around). 322 * Source quench causes it to drop back to 1. 323 * tp_send() uses the smaller of (regular window, congestion window). 324 * One retransmission strategy option is to have any retransmission 325 * cause reset the congestion window back to 1. 326 * 327 * (cmd) is either PRC_QUENCH: source quench, or 328 * PRC_QUENCH2: dest. quench (dec bit) 329 * 330 * RETURNS: 331 * 332 * SIDE EFFECTS: 333 * 334 * NOTES: 335 */ 336 void 337 tp_quench( tpcb, cmd ) 338 struct tp_pcb *tpcb; 339 int cmd; 340 { 341 IFDEBUG(D_QUENCH) 342 printf("tp_quench tpcb 0x%x ref 0x%x sufx 0x%x\n", 343 tpcb, tpcb->tp_lref, *(u_short *)(tpcb->tp_lsuffix)); 344 printf("cong_win 0x%x decbit 0x%x \n", 345 tpcb->tp_cong_win, tpcb->tp_decbit); 346 ENDDEBUG 347 switch(cmd) { 348 case PRC_QUENCH: 349 tpcb->tp_cong_win = tpcb->tp_l_tpdusize; 350 IncStat(ts_quench); 351 break; 352 case PRC_QUENCH2: 353 tpcb->tp_cong_win = tpcb->tp_l_tpdusize; /* might as well quench source also */ 354 tpcb->tp_decbit = TP_DECBIT_CLEAR_COUNT; 355 IncStat(ts_rcvdecbit); 356 break; 357 } 358 } 359 360 361 /* 362 * NAME: tp_netcmd() 363 * 364 * CALLED FROM: 365 * 366 * FUNCTION and ARGUMENTS: 367 * 368 * RETURNS: 369 * 370 * SIDE EFFECTS: 371 * 372 * NOTES: 373 */ 374 tp_netcmd( tpcb, cmd ) 375 struct tp_pcb *tpcb; 376 int cmd; 377 { 378 #ifdef TPCONS 379 struct isopcb *isop; 380 struct pklcd *lcp; 381 382 if (tpcb->tp_netservice != ISO_CONS) 383 return; 384 isop = (struct isopcb *)tpcb->tp_npcb; 385 lcp = (struct pklcd *)isop->isop_chan; 386 switch (cmd) { 387 388 case CONN_CLOSE: 389 case CONN_REFUSE: 390 if (isop->isop_refcnt == 1) { 391 /* This is really superfluous, since it would happen 392 anyway in iso_pcbdetach, although it is a courtesy 393 to free up the x.25 channel before the refwait timer 394 expires. */ 395 lcp->lcd_upper = 0; 396 lcp->lcd_upnext = 0; 397 pk_disconnect(lcp); 398 isop->isop_chan = 0; 399 isop->isop_refcnt = 0; 400 } 401 break; 402 403 default: 404 printf("tp_netcmd(0x%x, 0x%x) NOT IMPLEMENTED\n", tpcb, cmd); 405 break; 406 } 407 #else TPCONS 408 printf("tp_netcmd(): X25 NOT CONFIGURED!!\n"); 409 #endif 410 } 411 /* 412 * CALLED FROM: 413 * tp_ctloutput() and tp_emit() 414 * FUNCTION and ARGUMENTS: 415 * Convert a class mask to the highest numeric value it represents. 416 */ 417 418 int 419 tp_mask_to_num(x) 420 u_char x; 421 { 422 register int j; 423 424 for(j = 4; j>=0 ;j--) { 425 if(x & (1<<j)) 426 break; 427 } 428 ASSERT( (j == 4) || (j == 0) ); /* for now */ 429 if( (j != 4) && (j != 0) ) { 430 printf("ASSERTION ERROR: tp_mask_to_num: x 0x%x j %d\n", 431 x, j); 432 } 433 IFTRACE(D_TPINPUT) 434 tptrace(TPPTmisc, "tp_mask_to_num(x) returns j", x, j, 0, 0); 435 ENDTRACE 436 IFDEBUG(D_TPINPUT) 437 printf("tp_mask_to_num(0x%x) returns 0x%x\n", x, j); 438 ENDDEBUG 439 return j; 440 } 441 442 static 443 copyQOSparms(src, dst) 444 struct tp_conn_param *src, *dst; 445 { 446 /* copy all but the bits stuff at the end */ 447 #define COPYSIZE (12 * sizeof(short)) 448 449 bcopy((caddr_t)src, (caddr_t)dst, COPYSIZE); 450 dst->p_tpdusize = src->p_tpdusize; 451 dst->p_ack_strat = src->p_ack_strat; 452 dst->p_rx_strat = src->p_rx_strat; 453 #undef COPYSIZE 454 } 455 /* 456 * Determine a reasonable value for maxseg size. 457 * If the route is known, check route for mtu. 458 * We also initialize the congestion/slow start 459 * window to be a single segment if the destination isn't local. 460 * While looking at the routing entry, we also initialize other path-dependent 461 * parameters from pre-set or cached values in the routing entry. 462 */ 463 void 464 tp_mss(tpcb, nhdr_size) 465 register struct tp_pcb *tpcb; 466 int nhdr_size; 467 { 468 register struct rtentry *rt; 469 struct ifnet *ifp; 470 register int rtt, mss; 471 u_long bufsize; 472 int i, ssthresh = 0, rt_mss; 473 struct socket *so; 474 475 if (tpcb->tp_ptpdusize) 476 mss = tpcb->tp_ptpdusize << 7; 477 else 478 mss = 1 << tpcb->tp_tpdusize; 479 so = tpcb->tp_sock; 480 if ((rt = *(tpcb->tp_routep)) == 0) { 481 bufsize = so->so_rcv.sb_hiwat; 482 goto punt_route; 483 } 484 ifp = rt->rt_ifp; 485 486 #ifdef RTV_MTU /* if route characteristics exist ... */ 487 /* 488 * While we're here, check if there's an initial rtt 489 * or rttvar. Convert from the route-table units 490 * to hz ticks for the smoothed timers and slow-timeout units 491 * for other inital variables. 492 */ 493 if (tpcb->tp_rtt == 0 && (rtt = rt->rt_rmx.rmx_rtt)) { 494 tpcb->tp_rtt = rtt * hz / RTM_RTTUNIT; 495 if (rt->rt_rmx.rmx_rttvar) 496 tpcb->tp_rtv = rt->rt_rmx.rmx_rttvar 497 * hz / RTM_RTTUNIT; 498 else 499 tpcb->tp_rtv = tpcb->tp_rtt; 500 } 501 /* 502 * if there's an mtu associated with the route, use it 503 */ 504 if (rt->rt_rmx.rmx_mtu) 505 rt_mss = rt->rt_rmx.rmx_mtu - nhdr_size; 506 else 507 #endif /* RTV_MTU */ 508 rt_mss = (ifp->if_mtu - nhdr_size); 509 if (tpcb->tp_ptpdusize == 0 || /* assume application doesn't care */ 510 mss > rt_mss /* network won't support what was asked for */) 511 mss = rt_mss; 512 /* can propose mtu which are multiples of 128 */ 513 mss &= ~0x7f; 514 /* 515 * If there's a pipesize, change the socket buffer 516 * to that size. 517 */ 518 #ifdef RTV_SPIPE 519 if ((bufsize = rt->rt_rmx.rmx_sendpipe) > 0) { 520 #endif 521 bufsize = min(bufsize, so->so_snd.sb_hiwat); 522 (void) sbreserve(&so->so_snd, bufsize); 523 } 524 #ifdef RTV_SPIPE 525 if ((bufsize = rt->rt_rmx.rmx_recvpipe) > 0) { 526 #endif 527 bufsize = min(bufsize, so->so_rcv.sb_hiwat); 528 (void) sbreserve(&so->so_rcv, bufsize); 529 } else 530 bufsize = so->so_rcv.sb_hiwat; 531 #ifdef RTV_SSTHRESH 532 /* 533 * There's some sort of gateway or interface 534 * buffer limit on the path. Use this to set 535 * the slow start threshhold, but set the 536 * threshold to no less than 2*mss. 537 */ 538 ssthresh = rt->rt_rmx.rmx_ssthresh; 539 punt_route: 540 /* 541 * The current mss is initialized to the default value. 542 * If we compute a smaller value, reduce the current mss. 543 * If we compute a larger value, return it for use in sending 544 * a max seg size option. 545 * If we received an offer, don't exceed it. 546 * However, do not accept offers under 128 bytes. 547 */ 548 if (tpcb->tp_l_tpdusize) 549 mss = min(mss, tpcb->tp_l_tpdusize); 550 /* 551 * We want a minimum recv window of 4 packets to 552 * signal packet loss by duplicate acks. 553 */ 554 mss = min(mss, bufsize >> 2) & ~0x7f; 555 mss = max(mss, 128); /* sanity */ 556 tpcb->tp_cong_win = 557 (rt == 0 || (rt->rt_flags & RTF_GATEWAY)) ? mss : bufsize; 558 tpcb->tp_l_tpdusize = mss; 559 tp_rsyset(tpcb); 560 tpcb->tp_ssthresh = max(2 * mss, ssthresh); 561 /* Calculate log2 of mss */ 562 for (i = TP_MIN_TPDUSIZE + 1; i <= TP_MAX_TPDUSIZE; i++) 563 if ((1 << i) > mss) 564 break; 565 i--; 566 tpcb->tp_tpdusize = i; 567 #endif /* RTV_MTU */ 568 } 569 570 /* 571 * CALLED FROM: 572 * tp_usrreq on PRU_CONNECT and tp_input on receipt of CR 573 * 574 * FUNCTION and ARGUMENTS: 575 * -- An mbuf containing the peer's network address. 576 * -- Our control block, which will be modified 577 * -- In the case of cons, a control block for that layer. 578 * 579 * 580 * RETURNS: 581 * errno value : 582 * EAFNOSUPPORT if can't find an nl_protosw for x.25 (really could panic) 583 * ECONNREFUSED if trying to run TP0 with non-type 37 address 584 * possibly other E* returned from cons_netcmd() 585 * 586 * SIDE EFFECTS: 587 * Determines recommended tpdusize, buffering and intial delays 588 * based on information cached on the route. 589 */ 590 int 591 tp_route_to( m, tpcb, channel) 592 struct mbuf *m; 593 register struct tp_pcb *tpcb; 594 caddr_t channel; 595 { 596 register struct sockaddr_iso *siso; /* NOTE: this may be a sockaddr_in */ 597 extern struct tp_conn_param tp_conn_param[]; 598 int error = 0, save_netservice = tpcb->tp_netservice; 599 register struct rtentry *rt = 0; 600 int nhdr_size, mtu, bufsize; 601 602 siso = mtod(m, struct sockaddr_iso *); 603 IFTRACE(D_CONN) 604 tptraceTPCB(TPPTmisc, 605 "route_to: so afi netservice class", 606 tpcb->tp_sock, siso->siso_addr.isoa_genaddr[0], tpcb->tp_netservice, 607 tpcb->tp_class); 608 ENDTRACE 609 IFDEBUG(D_CONN) 610 printf("tp_route_to( m x%x, channel 0x%x, tpcb 0x%x netserv 0x%x)\n", 611 m, channel, tpcb, tpcb->tp_netservice); 612 printf("m->mlen x%x, m->m_data:\n", m->m_len); 613 dump_buf(mtod(m, caddr_t), m->m_len); 614 ENDDEBUG 615 if (channel) { 616 #ifdef TPCONS 617 struct pklcd *lcp = (struct pklcd *)channel; 618 struct isopcb *isop = (struct isopcb *)lcp->lcd_upnext, 619 *isop_new = (struct isopcb *)tpcb->tp_npcb; 620 /* The next 2 lines believe that you haven't 621 set any network level options or done a pcbconnect 622 and XXXXXXX'edly apply to both inpcb's and isopcb's */ 623 remque(isop_new); 624 free(isop_new, M_PCB); 625 tpcb->tp_npcb = (caddr_t)isop; 626 tpcb->tp_netservice = ISO_CONS; 627 tpcb->tp_nlproto = nl_protosw + ISO_CONS; 628 if (isop->isop_refcnt++ == 0) { 629 iso_putsufx(isop, tpcb->tp_lsuffix, tpcb->tp_lsuffixlen, TP_LOCAL); 630 isop->isop_socket = tpcb->tp_sock; 631 } else 632 /* there are already connections sharing this */; 633 #endif 634 } else { 635 switch (siso->siso_family) { 636 default: 637 error = EAFNOSUPPORT; 638 goto done; 639 #ifdef ISO 640 case AF_ISO: 641 { 642 struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb; 643 int flags = tpcb->tp_sock->so_options & SO_DONTROUTE; 644 tpcb->tp_netservice = ISO_CLNS; 645 if (clnp_route(&siso->siso_addr, &isop->isop_route, 646 flags, (void **)0, (void **)0) == 0) { 647 rt = isop->isop_route.ro_rt; 648 if (rt && rt->rt_flags & RTF_PROTO1) 649 tpcb->tp_netservice = ISO_CONS; 650 } 651 } break; 652 #endif 653 #ifdef INET 654 case AF_INET: 655 tpcb->tp_netservice = IN_CLNS; 656 #endif 657 } 658 if (tpcb->tp_nlproto->nlp_afamily != siso->siso_family) { 659 IFDEBUG(D_CONN) 660 printf("tp_route_to( CHANGING nlproto old 0x%x new 0x%x)\n", 661 save_netservice, tpcb->tp_netservice); 662 ENDDEBUG 663 if (error = tp_set_npcb(tpcb)) 664 goto done; 665 } 666 IFDEBUG(D_CONN) 667 printf("tp_route_to calling nlp_pcbconn, netserv %d\n", 668 tpcb->tp_netservice); 669 ENDDEBUG 670 tpcb->tp_nlproto = nl_protosw + tpcb->tp_netservice; 671 error = (tpcb->tp_nlproto->nlp_pcbconn)(tpcb->tp_npcb, m); 672 } 673 if (error) 674 goto done; 675 nhdr_size = tpcb->tp_nlproto->nlp_mtu(tpcb); /* only gets common info */ 676 tp_mss(tpcb, nhdr_size); 677 done: 678 IFDEBUG(D_CONN) 679 printf("tp_route_to returns 0x%x\n", error); 680 ENDDEBUG 681 IFTRACE(D_CONN) 682 tptraceTPCB(TPPTmisc, "route_to: returns: error netserv class", error, 683 tpcb->tp_netservice, tpcb->tp_class, 0); 684 ENDTRACE 685 return error; 686 } 687 688 689 /* class zero version */ 690 void 691 tp0_stash( tpcb, e ) 692 register struct tp_pcb *tpcb; 693 register struct tp_event *e; 694 { 695 #ifndef lint 696 #define E e->ATTR(DT_TPDU) 697 #else lint 698 #define E e->ev_union.EV_DT_TPDU 699 #endif lint 700 701 register struct sockbuf *sb = &tpcb->tp_sock->so_rcv; 702 register struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb; 703 704 IFPERF(tpcb) 705 PStat(tpcb, Nb_from_ll) += E.e_datalen; 706 tpmeas(tpcb->tp_lref, TPtime_from_ll, &e->e_time, 707 E.e_seq, PStat(tpcb, Nb_from_ll), E.e_datalen); 708 ENDPERF 709 710 IFDEBUG(D_STASH) 711 printf("stash EQ: seq 0x%x datalen 0x%x eot 0x%x", 712 E.e_seq, E.e_datalen, E.e_eot); 713 ENDDEBUG 714 715 IFTRACE(D_STASH) 716 tptraceTPCB(TPPTmisc, "stash EQ: seq len eot", 717 E.e_seq, E.e_datalen, E.e_eot, 0); 718 ENDTRACE 719 720 if ( E.e_eot ) { 721 register struct mbuf *n = E.e_data; 722 n->m_flags |= M_EOR; 723 n->m_act = MNULL; /* set on tp_input */ 724 } 725 sbappend(sb, E.e_data); 726 IFDEBUG(D_STASH) 727 dump_mbuf(sb->sb_mb, "stash 0: so_rcv after appending"); 728 ENDDEBUG 729 if (tpcb->tp_netservice != ISO_CONS) 730 printf("tp0_stash: tp running over something wierd\n"); 731 else { 732 register struct pklcd *lcp = (struct pklcd *)isop->isop_chan; 733 pk_flowcontrol(lcp, sbspace(sb) <= 0, 1); 734 } 735 } 736 737 void 738 tp0_openflow(tpcb) 739 register struct tp_pcb *tpcb; 740 { 741 register struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb; 742 if (tpcb->tp_netservice != ISO_CONS) 743 printf("tp0_openflow: tp running over something wierd\n"); 744 else { 745 register struct pklcd *lcp = (struct pklcd *)isop->isop_chan; 746 if (lcp->lcd_rxrnr_condition) 747 pk_flowcontrol(lcp, 0, 0); 748 } 749 } 750 #ifndef TPCONS 751 static 752 pk_flowcontrol() {} 753 #endif 754 755 #ifdef TP_PERF_MEAS 756 /* 757 * CALLED FROM: 758 * tp_ctloutput() when the user sets TPOPT_PERF_MEAS on 759 * and tp_newsocket() when a new connection is made from 760 * a listening socket with tp_perf_on == true. 761 * FUNCTION and ARGUMENTS: 762 * (tpcb) is the usual; this procedure gets a clear cluster mbuf for 763 * a tp_pmeas structure, and makes tpcb->tp_p_meas point to it. 764 * RETURN VALUE: 765 * ENOBUFS if it cannot get a cluster mbuf. 766 */ 767 768 int 769 tp_setup_perf(tpcb) 770 register struct tp_pcb *tpcb; 771 { 772 register struct mbuf *q; 773 774 if( tpcb->tp_p_meas == 0 ) { 775 MGET(q, M_WAITOK, MT_PCB); 776 if (q == 0) 777 return ENOBUFS; 778 MCLGET(q, M_WAITOK); 779 if ((q->m_flags & M_EXT) == 0) { 780 (void) m_free(q); 781 return ENOBUFS; 782 } 783 q->m_len = sizeof (struct tp_pmeas); 784 tpcb->tp_p_mbuf = q; 785 tpcb->tp_p_meas = mtod(q, struct tp_pmeas *); 786 bzero( (caddr_t)tpcb->tp_p_meas, sizeof (struct tp_pmeas) ); 787 IFDEBUG(D_PERF_MEAS) 788 printf( 789 "tpcb 0x%x so 0x%x ref 0x%x tp_p_meas 0x%x tp_perf_on 0x%x\n", 790 tpcb, tpcb->tp_sock, tpcb->tp_lref, 791 tpcb->tp_p_meas, tpcb->tp_perf_on); 792 ENDDEBUG 793 tpcb->tp_perf_on = 1; 794 } 795 return 0; 796 } 797 #endif TP_PERF_MEAS 798 799 #ifdef ARGO_DEBUG 800 dump_addr (addr) 801 register struct sockaddr *addr; 802 { 803 switch( addr->sa_family ) { 804 case AF_INET: 805 dump_inaddr((struct sockaddr_in *)addr); 806 break; 807 #ifdef ISO 808 case AF_ISO: 809 dump_isoaddr((struct sockaddr_iso *)addr); 810 break; 811 #endif ISO 812 default: 813 printf("BAD AF: 0x%x\n", addr->sa_family); 814 break; 815 } 816 } 817 818 #define MAX_COLUMNS 8 819 /* 820 * Dump the buffer to the screen in a readable format. Format is: 821 * 822 * hex/dec where hex is the hex format, dec is the decimal format. 823 * columns of hex/dec numbers will be printed, followed by the 824 * character representations (if printable). 825 */ 826 Dump_buf(buf, len) 827 caddr_t buf; 828 int len; 829 { 830 int i,j; 831 #define Buf ((u_char *)buf) 832 printf("Dump buf 0x%x len 0x%x\n", buf, len); 833 for (i = 0; i < len; i += MAX_COLUMNS) { 834 printf("+%d:\t", i); 835 for (j = 0; j < MAX_COLUMNS; j++) { 836 if (i + j < len) { 837 printf("%x/%d\t", Buf[i+j], Buf[i+j]); 838 } else { 839 printf(" "); 840 } 841 } 842 843 for (j = 0; j < MAX_COLUMNS; j++) { 844 if (i + j < len) { 845 if (((Buf[i+j]) > 31) && ((Buf[i+j]) < 128)) 846 printf("%c", Buf[i+j]); 847 else 848 printf("."); 849 } 850 } 851 printf("\n"); 852 } 853 } 854 855 856 #endif ARGO_DEBUG 857 858