X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/74d56f78ea18c1e3f06b5cc086daba128d4965c2..4d8170e59e43abc00690852d097c26731af5297c:/usr/src/sys/netiso/tp_subr2.c diff --git a/usr/src/sys/netiso/tp_subr2.c b/usr/src/sys/netiso/tp_subr2.c index 1c2a988b8f..7c52947538 100644 --- a/usr/src/sys/netiso/tp_subr2.c +++ b/usr/src/sys/netiso/tp_subr2.c @@ -1,3 +1,12 @@ +/*- + * Copyright (c) 1991 The Regents of the University of California. + * All rights reserved. + * + * %sccs.include.redist.c% + * + * @(#)tp_subr2.c 7.22 (Berkeley) %G% + */ + /*********************************************************** Copyright IBM Corporation 1987 @@ -29,59 +38,58 @@ SOFTWARE. * * $Header: tp_subr2.c,v 5.5 88/11/18 17:28:55 nhall Exp $ * $Source: /usr/argo/sys/netiso/RCS/tp_subr2.c,v $ - * @(#)tp_subr2.c 7.6 (Berkeley) %G% * * Some auxiliary routines: - * tp_protocol_error: required by xebec- called when a combo of state, - * event, predicate isn't covered for by the transition file. - * tp_indicate: gives indications(signals) to the user process - * tp_getoptions: initializes variables that are affected by the options - * chosen. + * tp_protocol_error: required by xebec- called when a combo of state, + * event, predicate isn't covered for by the transition file. + * tp_indicate: gives indications(signals) to the user process + * tp_getoptions: initializes variables that are affected by the options + * chosen. */ -#ifndef lint -static char *rcsid = "$Header: tp_subr2.c,v 5.5 88/11/18 17:28:55 nhall Exp $"; -#endif lint - /* this def'n is to cause the expansion of this macro in the * routine tp_local_credit : */ #define LOCAL_CREDIT_EXPAND -#include "param.h" -#include "mbuf.h" -#include "socket.h" -#include "socketvar.h" -#include "domain.h" -#include "protosw.h" -#include "errno.h" -#include "types.h" -#include "time.h" -#include "kernel.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + #undef MNULL -#include "argo_debug.h" -#include "tp_param.h" -#include "tp_ip.h" -#include "iso.h" -#include "iso_errno.h" -#include "iso_pcb.h" -#include "tp_timer.h" -#include "tp_stat.h" -#include "tp_tpdu.h" -#include "tp_pcb.h" -#include "tp_seq.h" -#include "tp_trace.h" -#include "tp_user.h" -#include "cons.h" - -#include "../net/if.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include #ifdef TRUE #undef FALSE #undef TRUE #endif -#include "../netccitt/x25.h" -#include "../netccitt/pk.h" -#include "../netccitt/pk_var.h" +#include +#include +#include + +void tp_rsyset(); /* * NAME: tp_local_credit() @@ -110,7 +118,7 @@ tp_local_credit(tpcb) LOCAL_CREDIT(tpcb); IFDEBUG(D_CREDIT) printf("ref 0x%x lcdt 0x%x l_tpdusize 0x%x decbit 0x%x\n", - tpcb->tp_refp - tp_ref, + tpcb->tp_lref, tpcb->tp_lcredit, tpcb->tp_l_tpdusize, tpcb->tp_decbit, @@ -209,9 +217,28 @@ tp_indicate(ind, tpcb, error) tpcb->tp_lref); ENDDEBUG + if (ind == ER_TPDU) { + register struct mbuf *m; + struct tp_disc_reason x; + + if ((so->so_state & SS_CANTRCVMORE) == 0 && + (m = m_get(M_DONTWAIT, MT_OOBDATA)) != 0) { + + x.dr_hdr.cmsg_len = m->m_len = sizeof(x); + x.dr_hdr.cmsg_level = SOL_TRANSPORT; + x.dr_hdr.cmsg_type= TPOPT_DISC_REASON; + x.dr_reason = error; + *mtod(m, struct tp_disc_reason *) = x; + sbappendrecord(&tpcb->tp_Xrcv, m); + error = 0; + } else + error = ECONNRESET; + } so->so_error = error; if (ind == T_DISCONNECT) { + if (error == 0) + so->so_error = ENOTCONN; if ( tpcb->tp_no_disc_indications ) return; } @@ -248,8 +275,9 @@ struct tp_pcb *tpcb; tpcb->tp_xtd_format ? TP_XTD_FMT_BIT : TP_NML_FMT_BIT ; tpcb->tp_seqhalf = tpcb->tp_seqbit >> 1; tpcb->tp_dt_ticks = - MAX(tpcb->tp_dt_ticks, (tpcb->tp_peer_acktime + 2)); - + max(tpcb->tp_dt_ticks, (tpcb->tp_peer_acktime + 2)); + tp_rsyset(tpcb); + } /* @@ -318,11 +346,11 @@ tp_quench( tpcb, cmd ) ENDDEBUG switch(cmd) { case PRC_QUENCH: - tpcb->tp_cong_win = 1; + tpcb->tp_cong_win = tpcb->tp_l_tpdusize; IncStat(ts_quench); break; case PRC_QUENCH2: - tpcb->tp_cong_win = 1; /* might as well quench source also */ + tpcb->tp_cong_win = tpcb->tp_l_tpdusize; /* might as well quench source also */ tpcb->tp_decbit = TP_DECBIT_CLEAR_COUNT; IncStat(ts_rcvdecbit); break; @@ -359,17 +387,24 @@ tp_netcmd( tpcb, cmd ) case CONN_CLOSE: case CONN_REFUSE: - if (isop->isop_refcnt == 1) + if (isop->isop_refcnt == 1) { + /* This is really superfluous, since it would happen + anyway in iso_pcbdetach, although it is a courtesy + to free up the x.25 channel before the refwait timer + expires. */ + lcp->lcd_upper = 0; + lcp->lcd_upnext = 0; pk_disconnect(lcp); - isop->isop_chan = 0; - isop->isop_refcnt = 0; + isop->isop_chan = 0; + isop->isop_refcnt = 0; + } break; default: printf("tp_netcmd(0x%x, 0x%x) NOT IMPLEMENTED\n", tpcb, cmd); break; } -#else TPCONS +#else /* TPCONS */ printf("tp_netcmd(): X25 NOT CONFIGURED!!\n"); #endif } @@ -417,31 +452,140 @@ copyQOSparms(src, dst) dst->p_rx_strat = src->p_rx_strat; #undef COPYSIZE } +/* + * Determine a reasonable value for maxseg size. + * If the route is known, check route for mtu. + * We also initialize the congestion/slow start + * window to be a single segment if the destination isn't local. + * While looking at the routing entry, we also initialize other path-dependent + * parameters from pre-set or cached values in the routing entry. + */ +void +tp_mss(tpcb, nhdr_size) + register struct tp_pcb *tpcb; + int nhdr_size; +{ + register struct rtentry *rt; + struct ifnet *ifp; + register int rtt, mss; + u_long bufsize; + int i, ssthresh = 0, rt_mss; + struct socket *so; + + if (tpcb->tp_ptpdusize) + mss = tpcb->tp_ptpdusize << 7; + else + mss = 1 << tpcb->tp_tpdusize; + so = tpcb->tp_sock; + if ((rt = *(tpcb->tp_routep)) == 0) { + bufsize = so->so_rcv.sb_hiwat; + goto punt_route; + } + ifp = rt->rt_ifp; + +#ifdef RTV_MTU /* if route characteristics exist ... */ + /* + * While we're here, check if there's an initial rtt + * or rttvar. Convert from the route-table units + * to hz ticks for the smoothed timers and slow-timeout units + * for other inital variables. + */ + if (tpcb->tp_rtt == 0 && (rtt = rt->rt_rmx.rmx_rtt)) { + tpcb->tp_rtt = rtt * hz / RTM_RTTUNIT; + if (rt->rt_rmx.rmx_rttvar) + tpcb->tp_rtv = rt->rt_rmx.rmx_rttvar + * hz / RTM_RTTUNIT; + else + tpcb->tp_rtv = tpcb->tp_rtt; + } + /* + * if there's an mtu associated with the route, use it + */ + if (rt->rt_rmx.rmx_mtu) + rt_mss = rt->rt_rmx.rmx_mtu - nhdr_size; + else +#endif /* RTV_MTU */ + rt_mss = (ifp->if_mtu - nhdr_size); + if (tpcb->tp_ptpdusize == 0 || /* assume application doesn't care */ + mss > rt_mss /* network won't support what was asked for */) + mss = rt_mss; + /* can propose mtu which are multiples of 128 */ + mss &= ~0x7f; + /* + * If there's a pipesize, change the socket buffer + * to that size. + */ +#ifdef RTV_SPIPE + if ((bufsize = rt->rt_rmx.rmx_sendpipe) > 0) { +#endif + bufsize = min(bufsize, so->so_snd.sb_hiwat); + (void) sbreserve(&so->so_snd, bufsize); + } +#ifdef RTV_SPIPE + if ((bufsize = rt->rt_rmx.rmx_recvpipe) > 0) { +#endif + bufsize = min(bufsize, so->so_rcv.sb_hiwat); + (void) sbreserve(&so->so_rcv, bufsize); + } else + bufsize = so->so_rcv.sb_hiwat; +#ifdef RTV_SSTHRESH + /* + * There's some sort of gateway or interface + * buffer limit on the path. Use this to set + * the slow start threshhold, but set the + * threshold to no less than 2*mss. + */ + ssthresh = rt->rt_rmx.rmx_ssthresh; +punt_route: + /* + * The current mss is initialized to the default value. + * If we compute a smaller value, reduce the current mss. + * If we compute a larger value, return it for use in sending + * a max seg size option. + * If we received an offer, don't exceed it. + * However, do not accept offers under 128 bytes. + */ + if (tpcb->tp_l_tpdusize) + mss = min(mss, tpcb->tp_l_tpdusize); + /* + * We want a minimum recv window of 4 packets to + * signal packet loss by duplicate acks. + */ + mss = min(mss, bufsize >> 2) & ~0x7f; + mss = max(mss, 128); /* sanity */ + tpcb->tp_cong_win = + (rt == 0 || (rt->rt_flags & RTF_GATEWAY)) ? mss : bufsize; + tpcb->tp_l_tpdusize = mss; + tp_rsyset(tpcb); + tpcb->tp_ssthresh = max(2 * mss, ssthresh); + /* Calculate log2 of mss */ + for (i = TP_MIN_TPDUSIZE + 1; i <= TP_MAX_TPDUSIZE; i++) + if ((1 << i) > mss) + break; + i--; + tpcb->tp_tpdusize = i; +#endif /* RTV_MTU */ +} /* * CALLED FROM: * tp_usrreq on PRU_CONNECT and tp_input on receipt of CR * * FUNCTION and ARGUMENTS: - * route directly to x.25 if the address is type 37 - GROT. - * furthermore, let TP0 handle only type-37 addresses + * -- An mbuf containing the peer's network address. + * -- Our control block, which will be modified + * -- In the case of cons, a control block for that layer. * - * Since this assumes that its address argument is in a mbuf, the - * parameter was changed to reflect this assumtion. This also - * implies that an mbuf must be allocated when this is - * called from tp_input * * RETURNS: * errno value : * EAFNOSUPPORT if can't find an nl_protosw for x.25 (really could panic) * ECONNREFUSED if trying to run TP0 with non-type 37 address * possibly other E* returned from cons_netcmd() - * NOTE: - * Would like to eliminate as much of this as possible -- - * only one set of defaults (let the user set the parms according - * to parameters provided in the directory service). - * Left here for now 'cause we don't yet have a clean way to handle - * it on the passive end. + * + * SIDE EFFECTS: + * Determines recommended tpdusize, buffering and intial delays + * based on information cached on the route. */ int tp_route_to( m, tpcb, channel) @@ -451,8 +595,9 @@ tp_route_to( m, tpcb, channel) { register struct sockaddr_iso *siso; /* NOTE: this may be a sockaddr_in */ extern struct tp_conn_param tp_conn_param[]; - struct pklcd *lcp = (struct pklcd *)channel; - int error = 0; + int error = 0, save_netservice = tpcb->tp_netservice; + register struct rtentry *rt = 0; + int nhdr_size, mtu, bufsize; siso = mtod(m, struct sockaddr_iso *); IFTRACE(D_CONN) @@ -467,115 +612,68 @@ tp_route_to( m, tpcb, channel) printf("m->mlen x%x, m->m_data:\n", m->m_len); dump_buf(mtod(m, caddr_t), m->m_len); ENDDEBUG - if (siso->siso_family != tpcb->tp_domain) { - error = EAFNOSUPPORT; - goto done; - } - IFDEBUG(D_CONN) - printf("tp_route_to calling nlp_pcbconn, netserv %d\n", - tpcb->tp_netservice); - ENDDEBUG + if (channel) { #ifdef TPCONS - if (lcp) { + struct pklcd *lcp = (struct pklcd *)channel; struct isopcb *isop = (struct isopcb *)lcp->lcd_upnext, - *isop_new = (struct isopcb *)tpcb->tp_sock->so_pcb; + *isop_new = (struct isopcb *)tpcb->tp_npcb; + /* The next 2 lines believe that you haven't + set any network level options or done a pcbconnect + and XXXXXXX'edly apply to both inpcb's and isopcb's */ remque(isop_new); free(isop_new, M_PCB); - tpcb->tp_sock->so_pcb = (caddr_t)isop; - if (isop->isop_refcnt == 0) { - extern struct isopcb tp_isopcb; - remque(isop); - insque(isop, &tp_isopcb); - isop->isop_head = &tp_isopcb; + tpcb->tp_npcb = (caddr_t)isop; + tpcb->tp_netservice = ISO_CONS; + tpcb->tp_nlproto = nl_protosw + ISO_CONS; + if (isop->isop_refcnt++ == 0) { iso_putsufx(isop, tpcb->tp_lsuffix, tpcb->tp_lsuffixlen, TP_LOCAL); - } - /* else there are already connections sharing this */ - isop->isop_refcnt++; - } else + isop->isop_socket = tpcb->tp_sock; + } else + /* there are already connections sharing this */; #endif - error = (tpcb->tp_nlproto->nlp_pcbconn)(tpcb->tp_sock->so_pcb, m); - if( error ) - goto done; - - { - register int save_netservice = tpcb->tp_netservice; - - switch(tpcb->tp_netservice) { - case ISO_COSNS: - case ISO_CLNS: - /* This is a kludge but seems necessary so the passive end - * can get long enough timers. sigh. - if( siso->siso_addr.osinet_idi[1] == (u_char)IDI_OSINET ) - */ -#define IDI_OSINET 0x0004 /* bcd of "0004" */ - if( siso->siso_addr.isoa_genaddr[2] == (char)IDI_OSINET ) { - if( tpcb->tp_dont_change_params == 0) { - copyQOSparms( &tp_conn_param[ISO_COSNS], - &tpcb->_tp_param); - } - tpcb->tp_flags |= TPF_NLQOS_PDN; - } - /* drop through to IN_CLNS*/ - case IN_CLNS: - if (iso_localifa(siso)) - tpcb->tp_flags |= TPF_PEER_ON_SAMENET; - if( (tpcb->tp_class & TP_CLASS_4)==0 ) { - error = EPROTOTYPE; - break; - } - tpcb->tp_class = TP_CLASS_4; /* IGNORE dont_change_parms */ - break; - - case ISO_CONS: -#ifdef TPCONS - tpcb->tp_flags |= TPF_NLQOS_PDN; - if( tpcb->tp_dont_change_params == 0 ) { - copyQOSparms( &tp_conn_param[ISO_CONS], - &tpcb->_tp_param); - } - /* - * for use over x.25 really need a small receive window, - * need to start slowly, need small max negotiable tpdu size, - * and need to use the congestion window to the max - * IGNORES tp_dont_change_params for these! - */ - if( tpcb->tp_sock->so_snd.sb_hiwat > 512 ) { - (void) soreserve(tpcb->tp_sock, 512, 512 );/* GAG */ - } - tpcb->tp_rx_strat = TPRX_USE_CW; - - if( (tpcb->tp_nlproto != &nl_protosw[ISO_CONS]) ) { - IFDEBUG(D_CONN) - printf( - "tp_route_to( CHANGING nlproto old 0x%x new 0x%x)\n", - tpcb->tp_nlproto , &nl_protosw[ISO_CONS]); - ENDDEBUG - tpcb->tp_nlproto = &nl_protosw[ISO_CONS]; - } - /* class 4 doesn't need to open a vc now - may use one already - * opened or may open one only when it sends a pkt. - */ -#else TPCONS - error = ECONNREFUSED; -#endif TPCONS - break; + } else { + switch (siso->siso_family) { default: - error = EPROTOTYPE; + error = EAFNOSUPPORT; + goto done; +#ifdef ISO + case AF_ISO: + { + struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb; + int flags = tpcb->tp_sock->so_options & SO_DONTROUTE; + tpcb->tp_netservice = ISO_CLNS; + if (clnp_route(&siso->siso_addr, &isop->isop_route, + flags, (void **)0, (void **)0) == 0) { + rt = isop->isop_route.ro_rt; + if (rt && rt->rt_flags & RTF_PROTO1) + tpcb->tp_netservice = ISO_CONS; + } + } break; +#endif +#ifdef INET + case AF_INET: + tpcb->tp_netservice = IN_CLNS; +#endif } - - ASSERT( save_netservice == tpcb->tp_netservice); + if (tpcb->tp_nlproto->nlp_afamily != siso->siso_family) { + IFDEBUG(D_CONN) + printf("tp_route_to( CHANGING nlproto old 0x%x new 0x%x)\n", + save_netservice, tpcb->tp_netservice); + ENDDEBUG + if (error = tp_set_npcb(tpcb)) + goto done; + } + IFDEBUG(D_CONN) + printf("tp_route_to calling nlp_pcbconn, netserv %d\n", + tpcb->tp_netservice); + ENDDEBUG + tpcb->tp_nlproto = nl_protosw + tpcb->tp_netservice; + error = (tpcb->tp_nlproto->nlp_pcbconn)(tpcb->tp_npcb, m); } - if (error) { - tp_netcmd( tpcb, CONN_CLOSE); + if (error) goto done; - } - { /* start with the global rtt, rtv stats */ - register int i = - (int) tpcb->tp_flags & (TPF_PEER_ON_SAMENET | TPF_NLQOS_PDN); - - tpcb->tp_rtt = tp_stat.ts_rtt[i]; - tpcb->tp_rtv = tp_stat.ts_rtv[i]; - } + nhdr_size = tpcb->tp_nlproto->nlp_mtu(tpcb); /* only gets common info */ + tp_mss(tpcb, nhdr_size); done: IFDEBUG(D_CONN) printf("tp_route_to returns 0x%x\n", error); @@ -596,9 +694,9 @@ tp0_stash( tpcb, e ) { #ifndef lint #define E e->ATTR(DT_TPDU) -#else lint +#else /* lint */ #define E e->ev_union.EV_DT_TPDU -#endif lint +#endif /* lint */ register struct sockbuf *sb = &tpcb->tp_sock->so_rcv; register struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb; @@ -696,7 +794,7 @@ tp_setup_perf(tpcb) } return 0; } -#endif TP_PERF_MEAS +#endif /* TP_PERF_MEAS */ #ifdef ARGO_DEBUG dump_addr (addr) @@ -710,7 +808,7 @@ dump_addr (addr) case AF_ISO: dump_isoaddr((struct sockaddr_iso *)addr); break; -#endif ISO +#endif /* ISO */ default: printf("BAD AF: 0x%x\n", addr->sa_family); break; @@ -730,13 +828,13 @@ caddr_t buf; int len; { int i,j; - +#define Buf ((u_char *)buf) printf("Dump buf 0x%x len 0x%x\n", buf, len); for (i = 0; i < len; i += MAX_COLUMNS) { printf("+%d:\t", i); for (j = 0; j < MAX_COLUMNS; j++) { if (i + j < len) { - printf("%x/%d\t", buf[i+j]&0xff, buf[i+j]); + printf("%x/%d\t", Buf[i+j], Buf[i+j]); } else { printf(" "); } @@ -744,8 +842,8 @@ int len; for (j = 0; j < MAX_COLUMNS; j++) { if (i + j < len) { - if (((buf[i+j]) > 31) && ((buf[i+j]) < 128)) - printf("%c", buf[i+j]&0xff); + if (((Buf[i+j]) > 31) && ((Buf[i+j]) < 128)) + printf("%c", Buf[i+j]); else printf("."); } @@ -753,7 +851,4 @@ int len; printf("\n"); } } - - -#endif ARGO_DEBUG - +#endif /* ARGO_DEBUG */