1*49268Sbostic /*- 2*49268Sbostic * Copyright (c) 1991 The Regents of the University of California. 3*49268Sbostic * All rights reserved. 4*49268Sbostic * 5*49268Sbostic * %sccs.include.redist.c% 6*49268Sbostic * 7*49268Sbostic * @(#)tp_subr2.c 7.8 (Berkeley) 05/06/91 8*49268Sbostic */ 9*49268Sbostic 1036414Ssklower /*********************************************************** 1136414Ssklower Copyright IBM Corporation 1987 1236414Ssklower 1336414Ssklower All Rights Reserved 1436414Ssklower 1536414Ssklower Permission to use, copy, modify, and distribute this software and its 1636414Ssklower documentation for any purpose and without fee is hereby granted, 1736414Ssklower provided that the above copyright notice appear in all copies and that 1836414Ssklower both that copyright notice and this permission notice appear in 1936414Ssklower supporting documentation, and that the name of IBM not be 2036414Ssklower used in advertising or publicity pertaining to distribution of the 2136414Ssklower software without specific, written prior permission. 2236414Ssklower 2336414Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 2436414Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 2536414Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 2636414Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 2736414Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 2836414Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 2936414Ssklower SOFTWARE. 3036414Ssklower 3136414Ssklower ******************************************************************/ 3236414Ssklower 3336414Ssklower /* 3436414Ssklower * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison 3536414Ssklower */ 3636414Ssklower /* 3736414Ssklower * ARGO TP 3836414Ssklower * 3936414Ssklower * $Header: tp_subr2.c,v 5.5 88/11/18 17:28:55 nhall Exp $ 4036414Ssklower * $Source: /usr/argo/sys/netiso/RCS/tp_subr2.c,v $ 4136414Ssklower * 4236414Ssklower * Some auxiliary routines: 43*49268Sbostic * tp_protocol_error: required by xebec- called when a combo of state, 44*49268Sbostic * event, predicate isn't covered for by the transition file. 45*49268Sbostic * tp_indicate: gives indications(signals) to the user process 46*49268Sbostic * tp_getoptions: initializes variables that are affected by the options 47*49268Sbostic * chosen. 4836414Ssklower */ 4936414Ssklower 5036414Ssklower /* this def'n is to cause the expansion of this macro in the 5136414Ssklower * routine tp_local_credit : 5236414Ssklower */ 5336414Ssklower #define LOCAL_CREDIT_EXPAND 5436414Ssklower 5536414Ssklower #include "param.h" 5636414Ssklower #include "mbuf.h" 5736414Ssklower #include "socket.h" 5836414Ssklower #include "socketvar.h" 5936414Ssklower #include "domain.h" 6036414Ssklower #include "protosw.h" 6136414Ssklower #include "errno.h" 6236414Ssklower #include "types.h" 6336414Ssklower #include "time.h" 6436414Ssklower #include "kernel.h" 6536414Ssklower #undef MNULL 6637469Ssklower #include "argo_debug.h" 6737469Ssklower #include "tp_param.h" 6837469Ssklower #include "tp_ip.h" 6937469Ssklower #include "iso.h" 7037469Ssklower #include "iso_errno.h" 7137469Ssklower #include "iso_pcb.h" 7237469Ssklower #include "tp_timer.h" 7337469Ssklower #include "tp_stat.h" 7437469Ssklower #include "tp_tpdu.h" 7537469Ssklower #include "tp_pcb.h" 7637469Ssklower #include "tp_seq.h" 7737469Ssklower #include "tp_trace.h" 7837469Ssklower #include "tp_user.h" 7937469Ssklower #include "cons.h" 8036414Ssklower 8145900Ssklower #include "../net/if.h" 8245900Ssklower #ifdef TRUE 8345900Ssklower #undef FALSE 8445900Ssklower #undef TRUE 8545900Ssklower #endif 8645900Ssklower #include "../netccitt/x25.h" 8745900Ssklower #include "../netccitt/pk.h" 8845900Ssklower #include "../netccitt/pk_var.h" 8945900Ssklower 9036414Ssklower /* 9136414Ssklower * NAME: tp_local_credit() 9236414Ssklower * 9336414Ssklower * CALLED FROM: 9436414Ssklower * tp_emit(), tp_usrreq() 9536414Ssklower * 9636414Ssklower * FUNCTION and ARGUMENTS: 9736414Ssklower * Computes the local credit and stashes it in tpcb->tp_lcredit. 9836414Ssklower * It's a macro in the production system rather than a procdure. 9936414Ssklower * 10036414Ssklower * RETURNS: 10136414Ssklower * 10236414Ssklower * SIDE EFFECTS: 10336414Ssklower * 10436414Ssklower * NOTES: 10536414Ssklower * This doesn't actually get called in a production system - 10636414Ssklower * the macro gets expanded instead in place of calls to this proc. 10736414Ssklower * But for debugging, we call this and that allows us to add 10836414Ssklower * debugging messages easily here. 10936414Ssklower */ 11036414Ssklower void 11136414Ssklower tp_local_credit(tpcb) 11236414Ssklower struct tp_pcb *tpcb; 11336414Ssklower { 11436414Ssklower LOCAL_CREDIT(tpcb); 11536414Ssklower IFDEBUG(D_CREDIT) 11636414Ssklower printf("ref 0x%x lcdt 0x%x l_tpdusize 0x%x decbit 0x%x\n", 11736414Ssklower tpcb->tp_refp - tp_ref, 11836414Ssklower tpcb->tp_lcredit, 11936414Ssklower tpcb->tp_l_tpdusize, 12036414Ssklower tpcb->tp_decbit, 12136414Ssklower tpcb->tp_cong_win 12236414Ssklower ); 12336414Ssklower ENDDEBUG 12436414Ssklower IFTRACE(D_CREDIT) 12536414Ssklower tptraceTPCB(TPPTmisc, 12636414Ssklower "lcdt tpdusz \n", 12736414Ssklower tpcb->tp_lcredit, tpcb->tp_l_tpdusize, 0, 0); 12836414Ssklower ENDTRACE 12936414Ssklower } 13036414Ssklower 13136414Ssklower /* 13236414Ssklower * NAME: tp_protocol_error() 13336414Ssklower * 13436414Ssklower * CALLED FROM: 13536414Ssklower * tp_driver(), when it doesn't know what to do with 13636414Ssklower * a combo of event, state, predicate 13736414Ssklower * 13836414Ssklower * FUNCTION and ARGUMENTS: 13936414Ssklower * print error mesg 14036414Ssklower * 14136414Ssklower * RETURN VALUE: 14236414Ssklower * EIO - always 14336414Ssklower * 14436414Ssklower * SIDE EFFECTS: 14536414Ssklower * 14636414Ssklower * NOTES: 14736414Ssklower */ 14836414Ssklower int 14936414Ssklower tp_protocol_error(e,tpcb) 15036414Ssklower struct tp_event *e; 15136414Ssklower struct tp_pcb *tpcb; 15236414Ssklower { 15336414Ssklower printf("TP PROTOCOL ERROR! tpcb 0x%x event 0x%x, state 0x%x\n", 15436414Ssklower tpcb, e->ev_number, tpcb->tp_state); 15536414Ssklower IFTRACE(D_DRIVER) 15636414Ssklower tptraceTPCB(TPPTmisc, "PROTOCOL ERROR tpcb event state", 15736414Ssklower tpcb, e->ev_number, tpcb->tp_state, 0 ); 15836414Ssklower ENDTRACE 15936414Ssklower return EIO; /* for lack of anything better */ 16036414Ssklower } 16136414Ssklower 16236414Ssklower 16336414Ssklower /* Not used at the moment */ 16436414Ssklower ProtoHook 16536414Ssklower tp_drain() 16636414Ssklower { 16736414Ssklower return 0; 16836414Ssklower } 16936414Ssklower 17036414Ssklower 17136414Ssklower /* 17236414Ssklower * NAME: tp_indicate() 17336414Ssklower * 17436414Ssklower * CALLED FROM: 17536414Ssklower * tp.trans when XPD arrive, when a connection is being disconnected by 17636414Ssklower * the arrival of a DR or ER, and when a connection times out. 17736414Ssklower * 17836414Ssklower * FUNCTION and ARGUMENTS: 17936414Ssklower * (ind) is the type of indication : T_DISCONNECT, T_XPD 18036414Ssklower * (error) is an E* value that will be put in the socket structure 18136414Ssklower * to be passed along to the user later. 18236414Ssklower * Gives a SIGURG to the user process or group indicated by the socket 18336414Ssklower * attached to the tpcb. 18436414Ssklower * 18536414Ssklower * RETURNS: Rien 18636414Ssklower * 18736414Ssklower * SIDE EFFECTS: 18836414Ssklower * 18936414Ssklower * NOTES: 19036414Ssklower */ 19136414Ssklower void 19236414Ssklower tp_indicate(ind, tpcb, error) 19336414Ssklower int ind; 19436414Ssklower u_short error; 19536414Ssklower register struct tp_pcb *tpcb; 19636414Ssklower { 19736414Ssklower register struct socket *so = tpcb->tp_sock; 19836414Ssklower IFTRACE(D_INDICATION) 19939197Ssklower tptraceTPCB(TPPTindicate, ind, *(u_short *)(tpcb->tp_lsuffix), 20039197Ssklower *(u_short *)(tpcb->tp_fsuffix), error,so->so_pgid); 20136414Ssklower ENDTRACE 20236414Ssklower IFDEBUG(D_INDICATION) 20337469Ssklower char *ls, *fs; 20436414Ssklower ls = tpcb->tp_lsuffix, 20536414Ssklower fs = tpcb->tp_fsuffix, 20636414Ssklower 20736414Ssklower printf( 20837469Ssklower "indicate 0x%x lsuf 0x%02x%02x fsuf 0x%02x%02x err 0x%x noind 0x%x ref 0x%x\n", 20936414Ssklower ind, 21036414Ssklower *ls, *(ls+1), *fs, *(fs+1), 21137469Ssklower error, /*so->so_pgrp,*/ 21236414Ssklower tpcb->tp_no_disc_indications, 21336414Ssklower tpcb->tp_lref); 21436414Ssklower ENDDEBUG 21536414Ssklower 21648744Ssklower if (ind == ER_TPDU) { 21748744Ssklower register struct mbuf *m; 21848744Ssklower struct tp_disc_reason x; 21948744Ssklower 22048744Ssklower if ((so->so_state & SS_CANTRCVMORE) == 0 && 22148744Ssklower (m = m_get(M_DONTWAIT, MT_OOBDATA)) != 0) { 22248744Ssklower 22348744Ssklower x.dr_hdr.cmsg_len = m->m_len = sizeof(x); 22448744Ssklower x.dr_hdr.cmsg_level = SOL_TRANSPORT; 22548744Ssklower x.dr_hdr.cmsg_type= TPOPT_DISC_REASON; 22648744Ssklower x.dr_reason = error; 22748744Ssklower *mtod(m, struct tp_disc_reason *) = x; 22848744Ssklower sbappendrecord(&tpcb->tp_Xrcv, m); 22948744Ssklower error = 0; 23048744Ssklower } else 23148744Ssklower error = ECONNRESET; 23248744Ssklower } 23336414Ssklower so->so_error = error; 23436414Ssklower 23536414Ssklower if (ind == T_DISCONNECT) { 23648744Ssklower so->so_error = ENOTCONN; 23736414Ssklower if ( tpcb->tp_no_disc_indications ) 23836414Ssklower return; 23936414Ssklower } 24036414Ssklower IFTRACE(D_INDICATION) 24136414Ssklower tptraceTPCB(TPPTmisc, "doing sohasoutofband(so)", so,0,0,0); 24236414Ssklower ENDTRACE 24336414Ssklower sohasoutofband(so); 24436414Ssklower } 24536414Ssklower 24636414Ssklower /* 24736414Ssklower * NAME : tp_getoptions() 24836414Ssklower * 24936414Ssklower * CALLED FROM: 25036414Ssklower * tp.trans whenever we go into OPEN state 25136414Ssklower * 25236414Ssklower * FUNCTION and ARGUMENTS: 25336414Ssklower * sets the proper flags and values in the tpcb, to control 25436414Ssklower * the appropriate actions for the given class, options, 25536414Ssklower * sequence space, etc, etc. 25636414Ssklower * 25736414Ssklower * RETURNS: Nada 25836414Ssklower * 25936414Ssklower * SIDE EFFECTS: 26036414Ssklower * 26136414Ssklower * NOTES: 26236414Ssklower */ 26336414Ssklower void 26436414Ssklower tp_getoptions(tpcb) 26536414Ssklower struct tp_pcb *tpcb; 26636414Ssklower { 26736414Ssklower tpcb->tp_seqmask = 26836414Ssklower tpcb->tp_xtd_format ? TP_XTD_FMT_MASK : TP_NML_FMT_MASK ; 26936414Ssklower tpcb->tp_seqbit = 27036414Ssklower tpcb->tp_xtd_format ? TP_XTD_FMT_BIT : TP_NML_FMT_BIT ; 27136414Ssklower tpcb->tp_seqhalf = tpcb->tp_seqbit >> 1; 27236414Ssklower tpcb->tp_dt_ticks = 27336414Ssklower MAX(tpcb->tp_dt_ticks, (tpcb->tp_peer_acktime + 2)); 27436414Ssklower 27536414Ssklower } 27636414Ssklower 27736414Ssklower /* 27836414Ssklower * NAME: tp_recycle_tsuffix() 27936414Ssklower * 28036414Ssklower * CALLED FROM: 28136414Ssklower * Called when a ref is frozen. 28236414Ssklower * 28336414Ssklower * FUNCTION and ARGUMENTS: 28436414Ssklower * allows the suffix to be reused. 28536414Ssklower * 28636414Ssklower * RETURNS: zilch 28736414Ssklower * 28836414Ssklower * SIDE EFFECTS: 28936414Ssklower * 29036414Ssklower * NOTES: 29136414Ssklower */ 29236414Ssklower void 29336414Ssklower tp_recycle_tsuffix(tpcb) 29436414Ssklower struct tp_pcb *tpcb; 29536414Ssklower { 29637469Ssklower bzero((caddr_t)tpcb->tp_lsuffix, sizeof( tpcb->tp_lsuffix)); 29737469Ssklower bzero((caddr_t)tpcb->tp_fsuffix, sizeof( tpcb->tp_fsuffix)); 29836414Ssklower tpcb->tp_fsuffixlen = tpcb->tp_lsuffixlen = 0; 29936414Ssklower 30036414Ssklower (tpcb->tp_nlproto->nlp_recycle_suffix)(tpcb->tp_npcb); 30136414Ssklower } 30236414Ssklower 30336414Ssklower /* 30436414Ssklower * NAME: tp_quench() 30536414Ssklower * 30636414Ssklower * CALLED FROM: 30736414Ssklower * tp{af}_quench() when ICMP source quench or similar thing arrives. 30836414Ssklower * 30936414Ssklower * FUNCTION and ARGUMENTS: 31036414Ssklower * Drop the congestion window back to 1. 31136414Ssklower * Congestion window scheme: 31236414Ssklower * Initial value is 1. ("slow start" as Nagle, et. al. call it) 31336414Ssklower * For each good ack that arrives, the congestion window is increased 31436414Ssklower * by 1 (up to max size of logical infinity, which is to say, 31536414Ssklower * it doesn't wrap around). 31636414Ssklower * Source quench causes it to drop back to 1. 31736414Ssklower * tp_send() uses the smaller of (regular window, congestion window). 31836414Ssklower * One retransmission strategy option is to have any retransmission 31936414Ssklower * cause reset the congestion window back to 1. 32036414Ssklower * 32136414Ssklower * (cmd) is either PRC_QUENCH: source quench, or 32236414Ssklower * PRC_QUENCH2: dest. quench (dec bit) 32336414Ssklower * 32436414Ssklower * RETURNS: 32536414Ssklower * 32636414Ssklower * SIDE EFFECTS: 32736414Ssklower * 32836414Ssklower * NOTES: 32936414Ssklower */ 33036414Ssklower void 33136414Ssklower tp_quench( tpcb, cmd ) 33236414Ssklower struct tp_pcb *tpcb; 33336414Ssklower int cmd; 33436414Ssklower { 33536414Ssklower IFDEBUG(D_QUENCH) 33636414Ssklower printf("tp_quench tpcb 0x%x ref 0x%x sufx 0x%x\n", 33739197Ssklower tpcb, tpcb->tp_lref, *(u_short *)(tpcb->tp_lsuffix)); 33836414Ssklower printf("cong_win 0x%x decbit 0x%x \n", 33936414Ssklower tpcb->tp_cong_win, tpcb->tp_decbit); 34036414Ssklower ENDDEBUG 34136414Ssklower switch(cmd) { 34236414Ssklower case PRC_QUENCH: 34336414Ssklower tpcb->tp_cong_win = 1; 34436414Ssklower IncStat(ts_quench); 34536414Ssklower break; 34636414Ssklower case PRC_QUENCH2: 34736414Ssklower tpcb->tp_cong_win = 1; /* might as well quench source also */ 34836414Ssklower tpcb->tp_decbit = TP_DECBIT_CLEAR_COUNT; 34936414Ssklower IncStat(ts_rcvdecbit); 35036414Ssklower break; 35136414Ssklower } 35236414Ssklower } 35336414Ssklower 35436414Ssklower 35536414Ssklower /* 35636414Ssklower * NAME: tp_netcmd() 35736414Ssklower * 35836414Ssklower * CALLED FROM: 35936414Ssklower * 36036414Ssklower * FUNCTION and ARGUMENTS: 36136414Ssklower * 36236414Ssklower * RETURNS: 36336414Ssklower * 36436414Ssklower * SIDE EFFECTS: 36536414Ssklower * 36636414Ssklower * NOTES: 36736414Ssklower */ 36836414Ssklower tp_netcmd( tpcb, cmd ) 36936414Ssklower struct tp_pcb *tpcb; 37036414Ssklower int cmd; 37136414Ssklower { 37245900Ssklower #ifdef TPCONS 37345900Ssklower struct isopcb *isop; 37445900Ssklower struct pklcd *lcp; 37545900Ssklower 37645900Ssklower if (tpcb->tp_netservice != ISO_CONS) 37745900Ssklower return; 37845900Ssklower isop = (struct isopcb *)tpcb->tp_npcb; 37945900Ssklower lcp = (struct pklcd *)isop->isop_chan; 38036414Ssklower switch (cmd) { 38136414Ssklower 38236414Ssklower case CONN_CLOSE: 38336414Ssklower case CONN_REFUSE: 38445900Ssklower if (isop->isop_refcnt == 1) 38545900Ssklower pk_disconnect(lcp); 38645900Ssklower isop->isop_chan = 0; 38745900Ssklower isop->isop_refcnt = 0; 38836414Ssklower break; 38936414Ssklower 39036414Ssklower default: 39136414Ssklower printf("tp_netcmd(0x%x, 0x%x) NOT IMPLEMENTED\n", tpcb, cmd); 39236414Ssklower break; 39336414Ssklower } 39445900Ssklower #else TPCONS 39536414Ssklower printf("tp_netcmd(): X25 NOT CONFIGURED!!\n"); 39645900Ssklower #endif 39736414Ssklower } 39836414Ssklower /* 39936414Ssklower * CALLED FROM: 40036414Ssklower * tp_ctloutput() and tp_emit() 40136414Ssklower * FUNCTION and ARGUMENTS: 40236414Ssklower * Convert a class mask to the highest numeric value it represents. 40336414Ssklower */ 40436414Ssklower 40536414Ssklower int 40636414Ssklower tp_mask_to_num(x) 40736414Ssklower u_char x; 40836414Ssklower { 40936414Ssklower register int j; 41036414Ssklower 41136414Ssklower for(j = 4; j>=0 ;j--) { 41236414Ssklower if(x & (1<<j)) 41336414Ssklower break; 41436414Ssklower } 41536414Ssklower ASSERT( (j == 4) || (j == 0) ); /* for now */ 41636414Ssklower if( (j != 4) && (j != 0) ) { 41736414Ssklower printf("ASSERTION ERROR: tp_mask_to_num: x 0x%x j %d\n", 41836414Ssklower x, j); 41936414Ssklower } 42036414Ssklower IFTRACE(D_TPINPUT) 42136414Ssklower tptrace(TPPTmisc, "tp_mask_to_num(x) returns j", x, j, 0, 0); 42236414Ssklower ENDTRACE 42336414Ssklower IFDEBUG(D_TPINPUT) 42436414Ssklower printf("tp_mask_to_num(0x%x) returns 0x%x\n", x, j); 42536414Ssklower ENDDEBUG 42636414Ssklower return j; 42736414Ssklower } 42836414Ssklower 42936414Ssklower static 43036414Ssklower copyQOSparms(src, dst) 43136414Ssklower struct tp_conn_param *src, *dst; 43236414Ssklower { 43336414Ssklower /* copy all but the bits stuff at the end */ 43436414Ssklower #define COPYSIZE (12 * sizeof(short)) 43536414Ssklower 43637469Ssklower bcopy((caddr_t)src, (caddr_t)dst, COPYSIZE); 43736414Ssklower dst->p_tpdusize = src->p_tpdusize; 43836414Ssklower dst->p_ack_strat = src->p_ack_strat; 43936414Ssklower dst->p_rx_strat = src->p_rx_strat; 44036414Ssklower #undef COPYSIZE 44136414Ssklower } 44236414Ssklower 44336414Ssklower /* 44436414Ssklower * CALLED FROM: 44536414Ssklower * tp_usrreq on PRU_CONNECT and tp_input on receipt of CR 44636414Ssklower * 44736414Ssklower * FUNCTION and ARGUMENTS: 44836414Ssklower * route directly to x.25 if the address is type 37 - GROT. 44936414Ssklower * furthermore, let TP0 handle only type-37 addresses 45036414Ssklower * 45136414Ssklower * Since this assumes that its address argument is in a mbuf, the 45236414Ssklower * parameter was changed to reflect this assumtion. This also 45336414Ssklower * implies that an mbuf must be allocated when this is 45436414Ssklower * called from tp_input 45536414Ssklower * 45636414Ssklower * RETURNS: 45736414Ssklower * errno value : 45836414Ssklower * EAFNOSUPPORT if can't find an nl_protosw for x.25 (really could panic) 45936414Ssklower * ECONNREFUSED if trying to run TP0 with non-type 37 address 46036414Ssklower * possibly other E* returned from cons_netcmd() 46136414Ssklower * NOTE: 46236414Ssklower * Would like to eliminate as much of this as possible -- 46336414Ssklower * only one set of defaults (let the user set the parms according 46436414Ssklower * to parameters provided in the directory service). 46536414Ssklower * Left here for now 'cause we don't yet have a clean way to handle 46636414Ssklower * it on the passive end. 46736414Ssklower */ 46836414Ssklower int 46936414Ssklower tp_route_to( m, tpcb, channel) 47036414Ssklower struct mbuf *m; 47136414Ssklower register struct tp_pcb *tpcb; 47245900Ssklower caddr_t channel; 47336414Ssklower { 47436414Ssklower register struct sockaddr_iso *siso; /* NOTE: this may be a sockaddr_in */ 47536414Ssklower extern struct tp_conn_param tp_conn_param[]; 47645900Ssklower struct pklcd *lcp = (struct pklcd *)channel; 47736414Ssklower int error = 0; 47836414Ssklower 47936414Ssklower siso = mtod(m, struct sockaddr_iso *); 48036414Ssklower IFTRACE(D_CONN) 48136414Ssklower tptraceTPCB(TPPTmisc, 48236414Ssklower "route_to: so afi netservice class", 48337469Ssklower tpcb->tp_sock, siso->siso_addr.isoa_genaddr[0], tpcb->tp_netservice, 48436414Ssklower tpcb->tp_class); 48536414Ssklower ENDTRACE 48636414Ssklower IFDEBUG(D_CONN) 48736414Ssklower printf("tp_route_to( m x%x, channel 0x%x, tpcb 0x%x netserv 0x%x)\n", 48836414Ssklower m, channel, tpcb, tpcb->tp_netservice); 48936414Ssklower printf("m->mlen x%x, m->m_data:\n", m->m_len); 49036414Ssklower dump_buf(mtod(m, caddr_t), m->m_len); 49136414Ssklower ENDDEBUG 49245900Ssklower if (siso->siso_family != tpcb->tp_domain) { 49336414Ssklower error = EAFNOSUPPORT; 49436414Ssklower goto done; 49536414Ssklower } 49637469Ssklower IFDEBUG(D_CONN) 49737469Ssklower printf("tp_route_to calling nlp_pcbconn, netserv %d\n", 49837469Ssklower tpcb->tp_netservice); 49937469Ssklower ENDDEBUG 50045900Ssklower #ifdef TPCONS 50145900Ssklower if (lcp) { 50245900Ssklower struct isopcb *isop = (struct isopcb *)lcp->lcd_upnext, 50345900Ssklower *isop_new = (struct isopcb *)tpcb->tp_sock->so_pcb; 50445900Ssklower remque(isop_new); 50545900Ssklower free(isop_new, M_PCB); 50645900Ssklower tpcb->tp_sock->so_pcb = (caddr_t)isop; 50745900Ssklower if (isop->isop_refcnt == 0) { 50845900Ssklower extern struct isopcb tp_isopcb; 50945900Ssklower remque(isop); 51045900Ssklower insque(isop, &tp_isopcb); 51145900Ssklower isop->isop_head = &tp_isopcb; 51245900Ssklower iso_putsufx(isop, tpcb->tp_lsuffix, tpcb->tp_lsuffixlen, TP_LOCAL); 51345900Ssklower } 51445900Ssklower /* else there are already connections sharing this */ 51545900Ssklower isop->isop_refcnt++; 51645900Ssklower } else 51745900Ssklower #endif 51845900Ssklower error = (tpcb->tp_nlproto->nlp_pcbconn)(tpcb->tp_sock->so_pcb, m); 51937469Ssklower if( error ) 52037469Ssklower goto done; 52137469Ssklower 52236414Ssklower { 52336414Ssklower register int save_netservice = tpcb->tp_netservice; 52436414Ssklower 52536414Ssklower switch(tpcb->tp_netservice) { 52636414Ssklower case ISO_COSNS: 52736414Ssklower case ISO_CLNS: 52836414Ssklower /* This is a kludge but seems necessary so the passive end 52936414Ssklower * can get long enough timers. sigh. 53037469Ssklower if( siso->siso_addr.osinet_idi[1] == (u_char)IDI_OSINET ) 53136414Ssklower */ 53238841Ssklower #define IDI_OSINET 0x0004 /* bcd of "0004" */ 53337469Ssklower if( siso->siso_addr.isoa_genaddr[2] == (char)IDI_OSINET ) { 53436414Ssklower if( tpcb->tp_dont_change_params == 0) { 53536414Ssklower copyQOSparms( &tp_conn_param[ISO_COSNS], 53636414Ssklower &tpcb->_tp_param); 53736414Ssklower } 53836414Ssklower tpcb->tp_flags |= TPF_NLQOS_PDN; 53936414Ssklower } 54036414Ssklower /* drop through to IN_CLNS*/ 54136414Ssklower case IN_CLNS: 54237469Ssklower if (iso_localifa(siso)) 54337469Ssklower tpcb->tp_flags |= TPF_PEER_ON_SAMENET; 54436414Ssklower if( (tpcb->tp_class & TP_CLASS_4)==0 ) { 54536414Ssklower error = EPROTOTYPE; 54636414Ssklower break; 54736414Ssklower } 54836414Ssklower tpcb->tp_class = TP_CLASS_4; /* IGNORE dont_change_parms */ 54936414Ssklower break; 55036414Ssklower 55136414Ssklower case ISO_CONS: 55245900Ssklower #ifdef TPCONS 55336414Ssklower tpcb->tp_flags |= TPF_NLQOS_PDN; 55436414Ssklower if( tpcb->tp_dont_change_params == 0 ) { 55536414Ssklower copyQOSparms( &tp_conn_param[ISO_CONS], 55636414Ssklower &tpcb->_tp_param); 55736414Ssklower } 55836414Ssklower /* 55936414Ssklower * for use over x.25 really need a small receive window, 56036414Ssklower * need to start slowly, need small max negotiable tpdu size, 56136414Ssklower * and need to use the congestion window to the max 56236414Ssklower * IGNORES tp_dont_change_params for these! 56336414Ssklower */ 56436414Ssklower if( tpcb->tp_sock->so_snd.sb_hiwat > 512 ) { 56536414Ssklower (void) soreserve(tpcb->tp_sock, 512, 512 );/* GAG */ 56636414Ssklower } 56736414Ssklower tpcb->tp_rx_strat = TPRX_USE_CW; 56836414Ssklower 56936414Ssklower if( (tpcb->tp_nlproto != &nl_protosw[ISO_CONS]) ) { 57036414Ssklower IFDEBUG(D_CONN) 57136414Ssklower printf( 57236414Ssklower "tp_route_to( CHANGING nlproto old 0x%x new 0x%x)\n", 57336414Ssklower tpcb->tp_nlproto , &nl_protosw[ISO_CONS]); 57436414Ssklower ENDDEBUG 57536414Ssklower tpcb->tp_nlproto = &nl_protosw[ISO_CONS]; 57636414Ssklower } 57736414Ssklower /* class 4 doesn't need to open a vc now - may use one already 57836414Ssklower * opened or may open one only when it sends a pkt. 57936414Ssklower */ 58045900Ssklower #else TPCONS 58136414Ssklower error = ECONNREFUSED; 58245900Ssklower #endif TPCONS 58336414Ssklower break; 58436414Ssklower default: 58536414Ssklower error = EPROTOTYPE; 58636414Ssklower } 58736414Ssklower 58836414Ssklower ASSERT( save_netservice == tpcb->tp_netservice); 58936414Ssklower } 59045900Ssklower if (error) { 59136414Ssklower tp_netcmd( tpcb, CONN_CLOSE); 59236414Ssklower goto done; 59336414Ssklower } 59436414Ssklower { /* start with the global rtt, rtv stats */ 59536414Ssklower register int i = 59636414Ssklower (int) tpcb->tp_flags & (TPF_PEER_ON_SAMENET | TPF_NLQOS_PDN); 59736414Ssklower 59836414Ssklower tpcb->tp_rtt = tp_stat.ts_rtt[i]; 59936414Ssklower tpcb->tp_rtv = tp_stat.ts_rtv[i]; 60036414Ssklower } 60136414Ssklower done: 60236414Ssklower IFDEBUG(D_CONN) 60336414Ssklower printf("tp_route_to returns 0x%x\n", error); 60436414Ssklower ENDDEBUG 60536414Ssklower IFTRACE(D_CONN) 60636414Ssklower tptraceTPCB(TPPTmisc, "route_to: returns: error netserv class", error, 60736414Ssklower tpcb->tp_netservice, tpcb->tp_class, 0); 60836414Ssklower ENDTRACE 60936414Ssklower return error; 61036414Ssklower } 61136414Ssklower 61247280Ssklower 61347280Ssklower /* class zero version */ 61447280Ssklower void 61547280Ssklower tp0_stash( tpcb, e ) 61647280Ssklower register struct tp_pcb *tpcb; 61747280Ssklower register struct tp_event *e; 61847280Ssklower { 61947280Ssklower #ifndef lint 62047280Ssklower #define E e->ATTR(DT_TPDU) 62147280Ssklower #else lint 62247280Ssklower #define E e->ev_union.EV_DT_TPDU 62347280Ssklower #endif lint 62447280Ssklower 62547280Ssklower register struct sockbuf *sb = &tpcb->tp_sock->so_rcv; 62647280Ssklower register struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb; 62747280Ssklower 62847280Ssklower IFPERF(tpcb) 62947280Ssklower PStat(tpcb, Nb_from_ll) += E.e_datalen; 63047280Ssklower tpmeas(tpcb->tp_lref, TPtime_from_ll, &e->e_time, 63147280Ssklower E.e_seq, PStat(tpcb, Nb_from_ll), E.e_datalen); 63247280Ssklower ENDPERF 63347280Ssklower 63447280Ssklower IFDEBUG(D_STASH) 63547280Ssklower printf("stash EQ: seq 0x%x datalen 0x%x eot 0x%x", 63647280Ssklower E.e_seq, E.e_datalen, E.e_eot); 63747280Ssklower ENDDEBUG 63847280Ssklower 63947280Ssklower IFTRACE(D_STASH) 64047280Ssklower tptraceTPCB(TPPTmisc, "stash EQ: seq len eot", 64147280Ssklower E.e_seq, E.e_datalen, E.e_eot, 0); 64247280Ssklower ENDTRACE 64347280Ssklower 64447280Ssklower if ( E.e_eot ) { 64547280Ssklower register struct mbuf *n = E.e_data; 64647280Ssklower n->m_flags |= M_EOR; 64747280Ssklower n->m_act = MNULL; /* set on tp_input */ 64847280Ssklower } 64947280Ssklower sbappend(sb, E.e_data); 65047280Ssklower IFDEBUG(D_STASH) 65147280Ssklower dump_mbuf(sb->sb_mb, "stash 0: so_rcv after appending"); 65247280Ssklower ENDDEBUG 65347280Ssklower if (tpcb->tp_netservice != ISO_CONS) 65447280Ssklower printf("tp0_stash: tp running over something wierd\n"); 65547280Ssklower else { 65647280Ssklower register struct pklcd *lcp = (struct pklcd *)isop->isop_chan; 65747280Ssklower pk_flowcontrol(lcp, sbspace(sb) <= 0, 1); 65847280Ssklower } 65947280Ssklower } 66047280Ssklower 66147280Ssklower void 66247280Ssklower tp0_openflow(tpcb) 66347280Ssklower register struct tp_pcb *tpcb; 66447280Ssklower { 66547280Ssklower register struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb; 66647280Ssklower if (tpcb->tp_netservice != ISO_CONS) 66747280Ssklower printf("tp0_openflow: tp running over something wierd\n"); 66847280Ssklower else { 66947280Ssklower register struct pklcd *lcp = (struct pklcd *)isop->isop_chan; 67047280Ssklower if (lcp->lcd_rxrnr_condition) 67147280Ssklower pk_flowcontrol(lcp, 0, 0); 67247280Ssklower } 67347280Ssklower } 67447280Ssklower #ifndef TPCONS 67547280Ssklower static 67647280Ssklower pk_flowcontrol() {} 67747280Ssklower #endif 67847280Ssklower 67936414Ssklower #ifdef TP_PERF_MEAS 68036414Ssklower /* 68136414Ssklower * CALLED FROM: 68236414Ssklower * tp_ctloutput() when the user sets TPOPT_PERF_MEAS on 68336414Ssklower * and tp_newsocket() when a new connection is made from 68436414Ssklower * a listening socket with tp_perf_on == true. 68536414Ssklower * FUNCTION and ARGUMENTS: 68636414Ssklower * (tpcb) is the usual; this procedure gets a clear cluster mbuf for 68736414Ssklower * a tp_pmeas structure, and makes tpcb->tp_p_meas point to it. 68836414Ssklower * RETURN VALUE: 68936414Ssklower * ENOBUFS if it cannot get a cluster mbuf. 69036414Ssklower */ 69136414Ssklower 69236414Ssklower int 69336414Ssklower tp_setup_perf(tpcb) 69436414Ssklower register struct tp_pcb *tpcb; 69536414Ssklower { 69636414Ssklower register struct mbuf *q; 69736414Ssklower 69837469Ssklower if( tpcb->tp_p_meas == 0 ) { 69937469Ssklower MGET(q, M_WAITOK, MT_PCB); 70036414Ssklower if (q == 0) 70136414Ssklower return ENOBUFS; 70237469Ssklower MCLGET(q, M_WAITOK); 70337469Ssklower if ((q->m_flags & M_EXT) == 0) { 70437469Ssklower (void) m_free(q); 70536414Ssklower return ENOBUFS; 70636414Ssklower } 70737469Ssklower q->m_len = sizeof (struct tp_pmeas); 70837469Ssklower tpcb->tp_p_mbuf = q; 70937469Ssklower tpcb->tp_p_meas = mtod(q, struct tp_pmeas *); 71037469Ssklower bzero( (caddr_t)tpcb->tp_p_meas, sizeof (struct tp_pmeas) ); 71137469Ssklower IFDEBUG(D_PERF_MEAS) 71237469Ssklower printf( 71337469Ssklower "tpcb 0x%x so 0x%x ref 0x%x tp_p_meas 0x%x tp_perf_on 0x%x\n", 71437469Ssklower tpcb, tpcb->tp_sock, tpcb->tp_lref, 71537469Ssklower tpcb->tp_p_meas, tpcb->tp_perf_on); 71637469Ssklower ENDDEBUG 71737469Ssklower tpcb->tp_perf_on = 1; 71836414Ssklower } 71936414Ssklower return 0; 72036414Ssklower } 72136414Ssklower #endif TP_PERF_MEAS 72236414Ssklower 72336414Ssklower #ifdef ARGO_DEBUG 72436414Ssklower dump_addr (addr) 72536414Ssklower register struct sockaddr *addr; 72636414Ssklower { 72736414Ssklower switch( addr->sa_family ) { 72836414Ssklower case AF_INET: 72937469Ssklower dump_inaddr((struct sockaddr_in *)addr); 73036414Ssklower break; 73137469Ssklower #ifdef ISO 73236414Ssklower case AF_ISO: 73337469Ssklower dump_isoaddr((struct sockaddr_iso *)addr); 73436414Ssklower break; 73537469Ssklower #endif ISO 73636414Ssklower default: 73736414Ssklower printf("BAD AF: 0x%x\n", addr->sa_family); 73836414Ssklower break; 73936414Ssklower } 74036414Ssklower } 74136414Ssklower 74237469Ssklower #define MAX_COLUMNS 8 74337469Ssklower /* 74437469Ssklower * Dump the buffer to the screen in a readable format. Format is: 74537469Ssklower * 74637469Ssklower * hex/dec where hex is the hex format, dec is the decimal format. 74737469Ssklower * columns of hex/dec numbers will be printed, followed by the 74837469Ssklower * character representations (if printable). 74937469Ssklower */ 75037469Ssklower Dump_buf(buf, len) 75137469Ssklower caddr_t buf; 75237469Ssklower int len; 75337469Ssklower { 75437469Ssklower int i,j; 75537469Ssklower 75637469Ssklower printf("Dump buf 0x%x len 0x%x\n", buf, len); 75737469Ssklower for (i = 0; i < len; i += MAX_COLUMNS) { 75837469Ssklower printf("+%d:\t", i); 75937469Ssklower for (j = 0; j < MAX_COLUMNS; j++) { 76037469Ssklower if (i + j < len) { 76137469Ssklower printf("%x/%d\t", buf[i+j]&0xff, buf[i+j]); 76237469Ssklower } else { 76337469Ssklower printf(" "); 76437469Ssklower } 76537469Ssklower } 76637469Ssklower 76737469Ssklower for (j = 0; j < MAX_COLUMNS; j++) { 76837469Ssklower if (i + j < len) { 76937469Ssklower if (((buf[i+j]) > 31) && ((buf[i+j]) < 128)) 77037469Ssklower printf("%c", buf[i+j]&0xff); 77137469Ssklower else 77237469Ssklower printf("."); 77337469Ssklower } 77437469Ssklower } 77537469Ssklower printf("\n"); 77637469Ssklower } 77737469Ssklower } 77837469Ssklower 77937469Ssklower 78036414Ssklower #endif ARGO_DEBUG 78136414Ssklower 782