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