xref: /original-bsd/sys/netiso/tp_subr2.c (revision b9df2d9d)
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