+/*-
+ * 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
*
* $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.5 (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 <sys/param.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/domain.h>
+#include <sys/protosw.h>
+#include <sys/errno.h>
+#include <sys/time.h>
+#include <sys/kernel.h>
+
#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 <netiso/argo_debug.h>
+#include <netiso/tp_param.h>
+#include <netiso/tp_ip.h>
+#include <netiso/iso.h>
+#include <netiso/iso_errno.h>
+#include <netiso/iso_pcb.h>
+#include <netiso/tp_timer.h>
+#include <netiso/tp_stat.h>
+#include <netiso/tp_tpdu.h>
+#include <netiso/tp_pcb.h>
+#include <netiso/tp_seq.h>
+#include <netiso/tp_trace.h>
+#include <netiso/tp_user.h>
+#include <netiso/cons.h>
+
+#include <net/if.h>
+#include <net/if_types.h>
#ifdef TRUE
#undef FALSE
#undef TRUE
#endif
-#include "../netccitt/x25.h"
-#include "../netccitt/pk.h"
-#include "../netccitt/pk_var.h"
+#include <netccitt/x25.h>
+#include <netccitt/pk.h>
+#include <netccitt/pk_var.h>
+
+void tp_rsyset();
/*
* NAME: tp_local_credit()
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,
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;
}
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);
+
}
/*
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;
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
}
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)
{
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)
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);
return error;
}
+
+/* class zero version */
+void
+tp0_stash( tpcb, e )
+ register struct tp_pcb *tpcb;
+ register struct tp_event *e;
+{
+#ifndef lint
+#define E e->ATTR(DT_TPDU)
+#else /* lint */
+#define E e->ev_union.EV_DT_TPDU
+#endif /* lint */
+
+ register struct sockbuf *sb = &tpcb->tp_sock->so_rcv;
+ register struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb;
+
+ IFPERF(tpcb)
+ PStat(tpcb, Nb_from_ll) += E.e_datalen;
+ tpmeas(tpcb->tp_lref, TPtime_from_ll, &e->e_time,
+ E.e_seq, PStat(tpcb, Nb_from_ll), E.e_datalen);
+ ENDPERF
+
+ IFDEBUG(D_STASH)
+ printf("stash EQ: seq 0x%x datalen 0x%x eot 0x%x",
+ E.e_seq, E.e_datalen, E.e_eot);
+ ENDDEBUG
+
+ IFTRACE(D_STASH)
+ tptraceTPCB(TPPTmisc, "stash EQ: seq len eot",
+ E.e_seq, E.e_datalen, E.e_eot, 0);
+ ENDTRACE
+
+ if ( E.e_eot ) {
+ register struct mbuf *n = E.e_data;
+ n->m_flags |= M_EOR;
+ n->m_act = MNULL; /* set on tp_input */
+ }
+ sbappend(sb, E.e_data);
+ IFDEBUG(D_STASH)
+ dump_mbuf(sb->sb_mb, "stash 0: so_rcv after appending");
+ ENDDEBUG
+ if (tpcb->tp_netservice != ISO_CONS)
+ printf("tp0_stash: tp running over something wierd\n");
+ else {
+ register struct pklcd *lcp = (struct pklcd *)isop->isop_chan;
+ pk_flowcontrol(lcp, sbspace(sb) <= 0, 1);
+ }
+}
+
+void
+tp0_openflow(tpcb)
+register struct tp_pcb *tpcb;
+{
+ register struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb;
+ if (tpcb->tp_netservice != ISO_CONS)
+ printf("tp0_openflow: tp running over something wierd\n");
+ else {
+ register struct pklcd *lcp = (struct pklcd *)isop->isop_chan;
+ if (lcp->lcd_rxrnr_condition)
+ pk_flowcontrol(lcp, 0, 0);
+ }
+}
+#ifndef TPCONS
+static
+pk_flowcontrol() {}
+#endif
+
#ifdef TP_PERF_MEAS
/*
* CALLED FROM:
}
return 0;
}
-#endif TP_PERF_MEAS
+#endif /* TP_PERF_MEAS */
#ifdef ARGO_DEBUG
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;
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(" ");
}
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(".");
}
printf("\n");
}
}
-
-
-#endif ARGO_DEBUG
-
+#endif /* ARGO_DEBUG */