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.18 (Berkeley) 12/17/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 * Determine a reasonable value for maxseg size. 455 * If the route is known, check route for mtu. 456 * We also initialize the congestion/slow start 457 * window to be a single segment if the destination isn't local. 458 * While looking at the routing entry, we also initialize other path-dependent 459 * parameters from pre-set or cached values in the routing entry. 460 */ 461 void 462 tp_mss(tpcb, nhdr_size) 463 register struct tp_pcb *tpcb; 464 int nhdr_size; 465 { 466 register struct rtentry *rt; 467 struct ifnet *ifp; 468 register int rtt, mss; 469 u_long bufsize; 470 int i, ssthresh = 0, rt_mss; 471 struct socket *so; 472 473 if (tpcb->tp_ptpdusize) 474 mss = tpcb->tp_ptpdusize << 7; 475 else 476 mss = 1 << tpcb->tp_tpdusize; 477 so = tpcb->tp_sock; 478 if ((rt = *(tpcb->tp_routep)) == 0) { 479 bufsize = so->so_rcv.sb_hiwat; 480 goto punt_route; 481 } 482 ifp = rt->rt_ifp; 483 484 #ifdef RTV_MTU /* if route characteristics exist ... */ 485 /* 486 * While we're here, check if there's an initial rtt 487 * or rttvar. Convert from the route-table units 488 * to hz ticks for the smoothed timers and slow-timeout units 489 * for other inital variables. 490 */ 491 if (tpcb->tp_rtt == 0 && (rtt = rt->rt_rmx.rmx_rtt)) { 492 tpcb->tp_rtt = rtt * hz / RTM_RTTUNIT; 493 if (rt->rt_rmx.rmx_rttvar) 494 tpcb->tp_rtv = rt->rt_rmx.rmx_rttvar 495 * hz / RTM_RTTUNIT; 496 else 497 tpcb->tp_rtv = tpcb->tp_rtt; 498 } 499 /* 500 * if there's an mtu associated with the route, use it 501 */ 502 if (rt->rt_rmx.rmx_mtu) 503 rt_mss = rt->rt_rmx.rmx_mtu - nhdr_size; 504 else 505 #endif /* RTV_MTU */ 506 rt_mss = (ifp->if_mtu - nhdr_size); 507 if (tpcb->tp_ptpdusize == 0 || /* assume application doesn't care */ 508 mss > rt_mss /* network won't support what was asked for */) 509 mss = rt_mss; 510 /* can propose mtu which are multiples of 128 */ 511 mss &= ~0x7f; 512 /* 513 * If there's a pipesize, change the socket buffer 514 * to that size. 515 */ 516 #ifdef RTV_SPIPE 517 if ((bufsize = rt->rt_rmx.rmx_sendpipe) > 0) { 518 #endif 519 bufsize = min(bufsize, so->so_snd.sb_hiwat); 520 (void) sbreserve(&so->so_snd, bufsize); 521 } 522 #ifdef RTV_SPIPE 523 if ((bufsize = rt->rt_rmx.rmx_recvpipe) > 0) { 524 #endif 525 bufsize = min(bufsize, so->so_rcv.sb_hiwat); 526 (void) sbreserve(&so->so_rcv, bufsize); 527 } else 528 bufsize = so->so_rcv.sb_hiwat; 529 #ifdef RTV_SSTHRESH 530 /* 531 * There's some sort of gateway or interface 532 * buffer limit on the path. Use this to set 533 * the slow start threshhold, but set the 534 * threshold to no less than 2*mss. 535 */ 536 ssthresh = rt->rt_rmx.rmx_ssthresh; 537 punt_route: 538 /* 539 * The current mss is initialized to the default value. 540 * If we compute a smaller value, reduce the current mss. 541 * If we compute a larger value, return it for use in sending 542 * a max seg size option. 543 * If we received an offer, don't exceed it. 544 * However, do not accept offers under 128 bytes. 545 */ 546 if (tpcb->tp_l_tpdusize) 547 mss = min(mss, tpcb->tp_l_tpdusize); 548 /* 549 * We want a minimum recv window of 4 packets to 550 * signal packet loss by duplicate acks. 551 */ 552 mss = min(mss, bufsize >> 2) & ~0x7f; 553 mss = max(mss, 128); /* sanity */ 554 tpcb->tp_cong_win = 555 (rt == 0 || (rt->rt_flags & RTF_GATEWAY)) ? mss : bufsize; 556 tpcb->tp_l_tpdusize = mss; 557 tpcb->tp_ssthresh = max(2 * mss, ssthresh); 558 /* Calculate log2 of mss */ 559 for (i = TP_MIN_TPDUSIZE + 1; i <= TP_MAX_TPDUSIZE; i++) 560 if ((1 << i) > mss) 561 break; 562 i--; 563 tpcb->tp_tpdusize = i; 564 #endif /* RTV_MTU */ 565 } 566 567 /* 568 * CALLED FROM: 569 * tp_usrreq on PRU_CONNECT and tp_input on receipt of CR 570 * 571 * FUNCTION and ARGUMENTS: 572 * -- An mbuf containing the peer's network address. 573 * -- Our control block, which will be modified 574 * -- In the case of cons, a control block for that layer. 575 * 576 * 577 * RETURNS: 578 * errno value : 579 * EAFNOSUPPORT if can't find an nl_protosw for x.25 (really could panic) 580 * ECONNREFUSED if trying to run TP0 with non-type 37 address 581 * possibly other E* returned from cons_netcmd() 582 * 583 * SIDE EFFECTS: 584 * Determines recommended tpdusize, buffering and intial delays 585 * based on information cached on the route. 586 */ 587 int 588 tp_route_to( m, tpcb, channel) 589 struct mbuf *m; 590 register struct tp_pcb *tpcb; 591 caddr_t channel; 592 { 593 register struct sockaddr_iso *siso; /* NOTE: this may be a sockaddr_in */ 594 extern struct tp_conn_param tp_conn_param[]; 595 int error = 0, save_netservice = tpcb->tp_netservice; 596 register struct rtentry *rt = 0; 597 int nhdr_size, mtu, bufsize; 598 599 siso = mtod(m, struct sockaddr_iso *); 600 IFTRACE(D_CONN) 601 tptraceTPCB(TPPTmisc, 602 "route_to: so afi netservice class", 603 tpcb->tp_sock, siso->siso_addr.isoa_genaddr[0], tpcb->tp_netservice, 604 tpcb->tp_class); 605 ENDTRACE 606 IFDEBUG(D_CONN) 607 printf("tp_route_to( m x%x, channel 0x%x, tpcb 0x%x netserv 0x%x)\n", 608 m, channel, tpcb, tpcb->tp_netservice); 609 printf("m->mlen x%x, m->m_data:\n", m->m_len); 610 dump_buf(mtod(m, caddr_t), m->m_len); 611 ENDDEBUG 612 if (channel) { 613 #ifdef TPCONS 614 struct pklcd *lcp = (struct pklcd *)channel; 615 struct isopcb *isop = (struct isopcb *)lcp->lcd_upnext, 616 *isop_new = (struct isopcb *)tpcb->tp_npcb; 617 /* The next 2 lines believe that you haven't 618 set any network level options or done a pcbconnect 619 and XXXXXXX'edly apply to both inpcb's and isopcb's */ 620 remque(isop_new); 621 free(isop_new, M_PCB); 622 tpcb->tp_npcb = (caddr_t)isop; 623 tpcb->tp_netservice = ISO_CONS; 624 tpcb->tp_nlproto = nl_protosw + ISO_CONS; 625 if (isop->isop_refcnt++ == 0) { 626 iso_putsufx(isop, tpcb->tp_lsuffix, tpcb->tp_lsuffixlen, TP_LOCAL); 627 isop->isop_socket = tpcb->tp_sock; 628 } else 629 /* there are already connections sharing this */; 630 #endif 631 } else { 632 switch (siso->siso_family) { 633 default: 634 error = EAFNOSUPPORT; 635 goto done; 636 #ifdef ISO 637 case AF_ISO: 638 { 639 struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb; 640 int flags = tpcb->tp_sock->so_options & SO_DONTROUTE; 641 tpcb->tp_netservice = ISO_CLNS; 642 if (clnp_route(&siso->siso_addr, &isop->isop_route, 643 flags, (void **)0, (void **)0) == 0) { 644 rt = isop->isop_route.ro_rt; 645 if (rt && rt->rt_flags & RTF_PROTO1) 646 tpcb->tp_netservice = ISO_CONS; 647 } 648 } break; 649 #endif 650 #ifdef INET 651 case AF_INET: 652 tpcb->tp_netservice = IN_CLNS; 653 #endif 654 } 655 if (tpcb->tp_nlproto->nlp_afamily != siso->siso_family) { 656 IFDEBUG(D_CONN) 657 printf("tp_route_to( CHANGING nlproto old 0x%x new 0x%x)\n", 658 save_netservice, tpcb->tp_netservice); 659 ENDDEBUG 660 if (error = tp_set_npcb(tpcb)) 661 goto done; 662 } 663 IFDEBUG(D_CONN) 664 printf("tp_route_to calling nlp_pcbconn, netserv %d\n", 665 tpcb->tp_netservice); 666 ENDDEBUG 667 tpcb->tp_nlproto = nl_protosw + tpcb->tp_netservice; 668 error = (tpcb->tp_nlproto->nlp_pcbconn)(tpcb->tp_npcb, m); 669 } 670 if (error) 671 goto done; 672 nhdr_size = tpcb->tp_nlproto->nlp_mtu(tpcb); /* only gets common info */ 673 tp_mss(tpcb, nhdr_size); 674 done: 675 IFDEBUG(D_CONN) 676 printf("tp_route_to returns 0x%x\n", error); 677 ENDDEBUG 678 IFTRACE(D_CONN) 679 tptraceTPCB(TPPTmisc, "route_to: returns: error netserv class", error, 680 tpcb->tp_netservice, tpcb->tp_class, 0); 681 ENDTRACE 682 return error; 683 } 684 685 686 /* class zero version */ 687 void 688 tp0_stash( tpcb, e ) 689 register struct tp_pcb *tpcb; 690 register struct tp_event *e; 691 { 692 #ifndef lint 693 #define E e->ATTR(DT_TPDU) 694 #else lint 695 #define E e->ev_union.EV_DT_TPDU 696 #endif lint 697 698 register struct sockbuf *sb = &tpcb->tp_sock->so_rcv; 699 register struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb; 700 701 IFPERF(tpcb) 702 PStat(tpcb, Nb_from_ll) += E.e_datalen; 703 tpmeas(tpcb->tp_lref, TPtime_from_ll, &e->e_time, 704 E.e_seq, PStat(tpcb, Nb_from_ll), E.e_datalen); 705 ENDPERF 706 707 IFDEBUG(D_STASH) 708 printf("stash EQ: seq 0x%x datalen 0x%x eot 0x%x", 709 E.e_seq, E.e_datalen, E.e_eot); 710 ENDDEBUG 711 712 IFTRACE(D_STASH) 713 tptraceTPCB(TPPTmisc, "stash EQ: seq len eot", 714 E.e_seq, E.e_datalen, E.e_eot, 0); 715 ENDTRACE 716 717 if ( E.e_eot ) { 718 register struct mbuf *n = E.e_data; 719 n->m_flags |= M_EOR; 720 n->m_act = MNULL; /* set on tp_input */ 721 } 722 sbappend(sb, E.e_data); 723 IFDEBUG(D_STASH) 724 dump_mbuf(sb->sb_mb, "stash 0: so_rcv after appending"); 725 ENDDEBUG 726 if (tpcb->tp_netservice != ISO_CONS) 727 printf("tp0_stash: tp running over something wierd\n"); 728 else { 729 register struct pklcd *lcp = (struct pklcd *)isop->isop_chan; 730 pk_flowcontrol(lcp, sbspace(sb) <= 0, 1); 731 } 732 } 733 734 void 735 tp0_openflow(tpcb) 736 register struct tp_pcb *tpcb; 737 { 738 register struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb; 739 if (tpcb->tp_netservice != ISO_CONS) 740 printf("tp0_openflow: tp running over something wierd\n"); 741 else { 742 register struct pklcd *lcp = (struct pklcd *)isop->isop_chan; 743 if (lcp->lcd_rxrnr_condition) 744 pk_flowcontrol(lcp, 0, 0); 745 } 746 } 747 #ifndef TPCONS 748 static 749 pk_flowcontrol() {} 750 #endif 751 752 #ifdef TP_PERF_MEAS 753 /* 754 * CALLED FROM: 755 * tp_ctloutput() when the user sets TPOPT_PERF_MEAS on 756 * and tp_newsocket() when a new connection is made from 757 * a listening socket with tp_perf_on == true. 758 * FUNCTION and ARGUMENTS: 759 * (tpcb) is the usual; this procedure gets a clear cluster mbuf for 760 * a tp_pmeas structure, and makes tpcb->tp_p_meas point to it. 761 * RETURN VALUE: 762 * ENOBUFS if it cannot get a cluster mbuf. 763 */ 764 765 int 766 tp_setup_perf(tpcb) 767 register struct tp_pcb *tpcb; 768 { 769 register struct mbuf *q; 770 771 if( tpcb->tp_p_meas == 0 ) { 772 MGET(q, M_WAITOK, MT_PCB); 773 if (q == 0) 774 return ENOBUFS; 775 MCLGET(q, M_WAITOK); 776 if ((q->m_flags & M_EXT) == 0) { 777 (void) m_free(q); 778 return ENOBUFS; 779 } 780 q->m_len = sizeof (struct tp_pmeas); 781 tpcb->tp_p_mbuf = q; 782 tpcb->tp_p_meas = mtod(q, struct tp_pmeas *); 783 bzero( (caddr_t)tpcb->tp_p_meas, sizeof (struct tp_pmeas) ); 784 IFDEBUG(D_PERF_MEAS) 785 printf( 786 "tpcb 0x%x so 0x%x ref 0x%x tp_p_meas 0x%x tp_perf_on 0x%x\n", 787 tpcb, tpcb->tp_sock, tpcb->tp_lref, 788 tpcb->tp_p_meas, tpcb->tp_perf_on); 789 ENDDEBUG 790 tpcb->tp_perf_on = 1; 791 } 792 return 0; 793 } 794 #endif TP_PERF_MEAS 795 796 #ifdef ARGO_DEBUG 797 dump_addr (addr) 798 register struct sockaddr *addr; 799 { 800 switch( addr->sa_family ) { 801 case AF_INET: 802 dump_inaddr((struct sockaddr_in *)addr); 803 break; 804 #ifdef ISO 805 case AF_ISO: 806 dump_isoaddr((struct sockaddr_iso *)addr); 807 break; 808 #endif ISO 809 default: 810 printf("BAD AF: 0x%x\n", addr->sa_family); 811 break; 812 } 813 } 814 815 #define MAX_COLUMNS 8 816 /* 817 * Dump the buffer to the screen in a readable format. Format is: 818 * 819 * hex/dec where hex is the hex format, dec is the decimal format. 820 * columns of hex/dec numbers will be printed, followed by the 821 * character representations (if printable). 822 */ 823 Dump_buf(buf, len) 824 caddr_t buf; 825 int len; 826 { 827 int i,j; 828 #define Buf ((u_char *)buf) 829 printf("Dump buf 0x%x len 0x%x\n", buf, len); 830 for (i = 0; i < len; i += MAX_COLUMNS) { 831 printf("+%d:\t", i); 832 for (j = 0; j < MAX_COLUMNS; j++) { 833 if (i + j < len) { 834 printf("%x/%d\t", Buf[i+j], Buf[i+j]); 835 } else { 836 printf(" "); 837 } 838 } 839 840 for (j = 0; j < MAX_COLUMNS; j++) { 841 if (i + j < len) { 842 if (((Buf[i+j]) > 31) && ((Buf[i+j]) < 128)) 843 printf("%c", Buf[i+j]); 844 else 845 printf("."); 846 } 847 } 848 printf("\n"); 849 } 850 } 851 852 853 #endif ARGO_DEBUG 854 855