xref: /original-bsd/sys/netiso/tp_subr2.c (revision e9409ad8)
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.14 (Berkeley) 09/26/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_refp - tp_ref,
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 		so->so_error = ENOTCONN;
239 		if ( tpcb->tp_no_disc_indications )
240 			return;
241 	}
242 	IFTRACE(D_INDICATION)
243 		tptraceTPCB(TPPTmisc, "doing sohasoutofband(so)", so,0,0,0);
244 	ENDTRACE
245 	sohasoutofband(so);
246 }
247 
248 /*
249  * NAME : tp_getoptions()
250  *
251  * CALLED FROM:
252  * 	tp.trans whenever we go into OPEN state
253  *
254  * FUNCTION and ARGUMENTS:
255  *  sets the proper flags and values in the tpcb, to control
256  *  the appropriate actions for the given class, options,
257  *  sequence space, etc, etc.
258  *
259  * RETURNS: Nada
260  *
261  * SIDE EFFECTS:
262  *
263  * NOTES:
264  */
265 void
266 tp_getoptions(tpcb)
267 struct tp_pcb *tpcb;
268 {
269 	tpcb->tp_seqmask =
270 		tpcb->tp_xtd_format ?	TP_XTD_FMT_MASK :	TP_NML_FMT_MASK ;
271 	tpcb->tp_seqbit =
272 		tpcb->tp_xtd_format ?	TP_XTD_FMT_BIT :	TP_NML_FMT_BIT ;
273 	tpcb->tp_seqhalf = tpcb->tp_seqbit >> 1;
274 	tpcb->tp_dt_ticks =
275 		MAX(tpcb->tp_dt_ticks, (tpcb->tp_peer_acktime + 2));
276 	(void) tp_rsyset(tpcb);
277 
278 }
279 
280 /*
281  * NAME:  tp_recycle_tsuffix()
282  *
283  * CALLED FROM:
284  *  Called when a ref is frozen.
285  *
286  * FUNCTION and ARGUMENTS:
287  *  allows the suffix to be reused.
288  *
289  * RETURNS: zilch
290  *
291  * SIDE EFFECTS:
292  *
293  * NOTES:
294  */
295 void
296 tp_recycle_tsuffix(tpcb)
297 	struct tp_pcb	*tpcb;
298 {
299 	bzero((caddr_t)tpcb->tp_lsuffix, sizeof( tpcb->tp_lsuffix));
300 	bzero((caddr_t)tpcb->tp_fsuffix, sizeof( tpcb->tp_fsuffix));
301 	tpcb->tp_fsuffixlen = tpcb->tp_lsuffixlen = 0;
302 
303 	(tpcb->tp_nlproto->nlp_recycle_suffix)(tpcb->tp_npcb);
304 }
305 
306 /*
307  * NAME: tp_quench()
308  *
309  * CALLED FROM:
310  *  tp{af}_quench() when ICMP source quench or similar thing arrives.
311  *
312  * FUNCTION and ARGUMENTS:
313  *  Drop the congestion window back to 1.
314  *  Congestion window scheme:
315  *  Initial value is 1.  ("slow start" as Nagle, et. al. call it)
316  *  For each good ack that arrives, the congestion window is increased
317  *  by 1 (up to max size of logical infinity, which is to say,
318  *	it doesn't wrap around).
319  *  Source quench causes it to drop back to 1.
320  *  tp_send() uses the smaller of (regular window, congestion window).
321  *  One retransmission strategy option is to have any retransmission
322  *	cause reset the congestion window back  to 1.
323  *
324  *	(cmd) is either PRC_QUENCH: source quench, or
325  *		PRC_QUENCH2: dest. quench (dec bit)
326  *
327  * RETURNS:
328  *
329  * SIDE EFFECTS:
330  *
331  * NOTES:
332  */
333 void
334 tp_quench( tpcb, cmd )
335 	struct tp_pcb *tpcb;
336 	int cmd;
337 {
338 	IFDEBUG(D_QUENCH)
339 		printf("tp_quench tpcb 0x%x ref 0x%x sufx 0x%x\n",
340 			tpcb, tpcb->tp_lref, *(u_short *)(tpcb->tp_lsuffix));
341 		printf("cong_win 0x%x decbit 0x%x \n",
342 			tpcb->tp_cong_win, tpcb->tp_decbit);
343 	ENDDEBUG
344 	switch(cmd) {
345 		case PRC_QUENCH:
346 			tpcb->tp_cong_win = tpcb->tp_l_tpdusize;
347 			IncStat(ts_quench);
348 			break;
349 		case PRC_QUENCH2:
350 			tpcb->tp_cong_win = tpcb->tp_l_tpdusize; /* might as well quench source also */
351 			tpcb->tp_decbit = TP_DECBIT_CLEAR_COUNT;
352 			IncStat(ts_rcvdecbit);
353 			break;
354 	}
355 }
356 
357 
358 /*
359  * NAME:	tp_netcmd()
360  *
361  * CALLED FROM:
362  *
363  * FUNCTION and ARGUMENTS:
364  *
365  * RETURNS:
366  *
367  * SIDE EFFECTS:
368  *
369  * NOTES:
370  */
371 tp_netcmd( tpcb, cmd )
372 	struct tp_pcb *tpcb;
373 	int cmd;
374 {
375 #ifdef TPCONS
376 	struct isopcb *isop;
377 	struct pklcd *lcp;
378 
379 	if (tpcb->tp_netservice != ISO_CONS)
380 		return;
381 	isop = (struct isopcb *)tpcb->tp_npcb;
382 	lcp = (struct pklcd *)isop->isop_chan;
383 	switch (cmd) {
384 
385 	case CONN_CLOSE:
386 	case CONN_REFUSE:
387 		if (isop->isop_refcnt == 1) {
388 			/* This is really superfluous, since it would happen
389 			   anyway in iso_pcbdetach, although it is a courtesy
390 			   to free up the x.25 channel before the refwait timer
391 			   expires. */
392 			lcp->lcd_upper = 0;
393 			lcp->lcd_upnext = 0;
394 			pk_disconnect(lcp);
395 			isop->isop_chan = 0;
396 			isop->isop_refcnt = 0;
397 		}
398 		break;
399 
400 	default:
401 		printf("tp_netcmd(0x%x, 0x%x) NOT IMPLEMENTED\n", tpcb, cmd);
402 		break;
403 	}
404 #else TPCONS
405 	printf("tp_netcmd(): X25 NOT CONFIGURED!!\n");
406 #endif
407 }
408 /*
409  * CALLED FROM:
410  *  tp_ctloutput() and tp_emit()
411  * FUNCTION and ARGUMENTS:
412  * 	Convert a class mask to the highest numeric value it represents.
413  */
414 
415 int
416 tp_mask_to_num(x)
417 	u_char x;
418 {
419 	register int j;
420 
421 	for(j = 4; j>=0 ;j--) {
422 		if(x & (1<<j))
423 			break;
424 	}
425 	ASSERT( (j == 4) || (j == 0) ); /* for now */
426 	if( (j != 4) && (j != 0) ) {
427 		printf("ASSERTION ERROR: tp_mask_to_num: x 0x%x j %d\n",
428 			x, j);
429 	}
430 	IFTRACE(D_TPINPUT)
431 		tptrace(TPPTmisc, "tp_mask_to_num(x) returns j", x, j, 0, 0);
432 	ENDTRACE
433 	IFDEBUG(D_TPINPUT)
434 		printf("tp_mask_to_num(0x%x) returns 0x%x\n", x, j);
435 	ENDDEBUG
436 	return j;
437 }
438 
439 static
440 copyQOSparms(src, dst)
441 	struct tp_conn_param *src, *dst;
442 {
443 	/* copy all but the bits stuff at the end */
444 #define COPYSIZE (12 * sizeof(short))
445 
446 	bcopy((caddr_t)src, (caddr_t)dst, COPYSIZE);
447 	dst->p_tpdusize = src->p_tpdusize;
448 	dst->p_ack_strat = src->p_ack_strat;
449 	dst->p_rx_strat = src->p_rx_strat;
450 #undef COPYSIZE
451 }
452 
453 /*
454  * CALLED FROM:
455  *  tp_usrreq on PRU_CONNECT and tp_input on receipt of CR
456  *
457  * FUNCTION and ARGUMENTS:
458  * 	route directly to x.25 if the address is type 37 - GROT.
459  *  furthermore, let TP0 handle only type-37 addresses
460  *
461  *	Since this assumes that its address argument is in a mbuf, the
462  *	parameter was changed to reflect this assumtion. This also
463  *	implies that an mbuf must be allocated when this is
464  *	called from tp_input
465  *
466  * RETURNS:
467  *	errno value	 :
468  *	EAFNOSUPPORT if can't find an nl_protosw for x.25 (really could panic)
469  *	ECONNREFUSED if trying to run TP0 with non-type 37 address
470  *  possibly other E* returned from cons_netcmd()
471  * NOTE:
472  *  Would like to eliminate as much of this as possible --
473  *  only one set of defaults (let the user set the parms according
474  *  to parameters provided in the directory service).
475  *  Left here for now 'cause we don't yet have a clean way to handle
476  *  it on the passive end.
477  */
478 int
479 tp_route_to( m, tpcb, channel)
480 	struct mbuf					*m;
481 	register struct tp_pcb		*tpcb;
482 	caddr_t 					channel;
483 {
484 	register struct sockaddr_iso *siso;	/* NOTE: this may be a sockaddr_in */
485 	extern struct tp_conn_param tp_conn_param[];
486 	int error = 0, save_netservice = tpcb->tp_netservice;
487 	register struct rtentry *rt = 0;
488 
489 	siso = mtod(m, struct sockaddr_iso *);
490 	IFTRACE(D_CONN)
491 		tptraceTPCB(TPPTmisc,
492 		"route_to: so  afi netservice class",
493 		tpcb->tp_sock, siso->siso_addr.isoa_genaddr[0], tpcb->tp_netservice,
494 			tpcb->tp_class);
495 	ENDTRACE
496 	IFDEBUG(D_CONN)
497 		printf("tp_route_to( m x%x, channel 0x%x, tpcb 0x%x netserv 0x%x)\n",
498 			m, channel, tpcb, tpcb->tp_netservice);
499 		printf("m->mlen x%x, m->m_data:\n", m->m_len);
500 		dump_buf(mtod(m, caddr_t), m->m_len);
501 	ENDDEBUG
502 	if (channel) {
503 #ifdef TPCONS
504 		struct pklcd *lcp = (struct pklcd *)channel;
505 		struct isopcb *isop = (struct isopcb *)lcp->lcd_upnext,
506 			*isop_new = (struct isopcb *)tpcb->tp_npcb;
507 		/* The next 2 lines believe that you haven't
508 		   set any network level options or done a pcbconnect
509 		   and XXXXXXX'edly apply to both inpcb's and isopcb's */
510 		remque(isop_new);
511 		free(isop_new, M_PCB);
512 		tpcb->tp_npcb = (caddr_t)isop;
513 		tpcb->tp_netservice = ISO_CONS;
514 		tpcb->tp_nlproto = nl_protosw + ISO_CONS;
515 		isop->isop_socket = tpcb->tp_sock;
516 		if (isop->isop_refcnt == 0)
517 			iso_putsufx(isop, tpcb->tp_lsuffix, tpcb->tp_lsuffixlen, TP_LOCAL);
518 		else
519 			/* there are already connections sharing this */;
520 		isop->isop_refcnt++;
521 #endif
522 	} else {
523 		switch (siso->siso_family) {
524 		default:
525 			error = EAFNOSUPPORT;
526 			goto done;
527 #ifdef ISO
528 		case AF_ISO:
529 			tpcb->tp_netservice = ISO_CLNS;
530 			if (rt = rtalloc1((struct sockaddr *)siso, 0)) {
531 				rt->rt_refcnt--;
532 				if (rt->rt_flags & RTF_PROTO1)
533 					tpcb->tp_netservice = ISO_CONS;
534 			}
535 			break;
536 #endif
537 #ifdef INET
538 		case AF_INET:
539 			tpcb->tp_netservice = IN_CLNS;
540 		}
541 #endif
542 		if (tpcb->tp_nlproto->nlp_afamily != siso->siso_family) {
543 			IFDEBUG(D_CONN)
544 				printf("tp_route_to( CHANGING nlproto old 0x%x new 0x%x)\n",
545 						save_netservice, tpcb->tp_netservice);
546 			ENDDEBUG
547 			if (error = tp_set_npcb(tpcb))
548 				goto done;
549 		}
550 		IFDEBUG(D_CONN)
551 			printf("tp_route_to  calling nlp_pcbconn, netserv %d\n",
552 				tpcb->tp_netservice);
553 		ENDDEBUG
554 		tpcb->tp_nlproto = nl_protosw + tpcb->tp_netservice;
555 		error = (tpcb->tp_nlproto->nlp_pcbconn)(tpcb->tp_npcb, m);
556 	}
557 	if( error )
558 		goto done;
559 
560 	{
561 		switch(tpcb->tp_netservice) {
562 		case ISO_COSNS:
563 		case ISO_CLNS:
564 			/* This is a kludge but seems necessary so the passive end
565 			 * can get long enough timers. sigh.
566 			if( siso->siso_addr.osinet_idi[1] == (u_char)IDI_OSINET )
567 			 */
568 			if (rt && rt->rt_ifp && rt->rt_ifp->if_type == IFT_X25) {
569 				if( tpcb->tp_dont_change_params == 0) {
570 					copyQOSparms( &tp_conn_param[ISO_COSNS],
571 							&tpcb->_tp_param);
572 				}
573 				tpcb->tp_flags |= TPF_NLQOS_PDN;
574 			}
575 			/* drop through to IN_CLNS*/
576 		case IN_CLNS:
577 			if (iso_localifa(siso))
578 				tpcb->tp_flags |= TPF_PEER_ON_SAMENET;
579 			if((tpcb->tp_class & TP_CLASS_4) == 0) {
580 				error = EPROTOTYPE;
581 				break;
582 			}
583 			tpcb->tp_class = TP_CLASS_4;  /* IGNORE dont_change_parms */
584 			break;
585 
586 		case ISO_CONS:
587 #ifdef TPCONS
588 			tpcb->tp_flags |= TPF_NLQOS_PDN;
589 			if( tpcb->tp_dont_change_params == 0 ) {
590 				copyQOSparms( &tp_conn_param[ISO_CONS],
591 							&tpcb->_tp_param);
592 			}
593 			/*
594 			 * for use over x.25 really need a small receive window,
595 			 * need to start slowly, need small max negotiable tpdu size,
596 			 * and need to use the congestion window to the max
597 			 * IGNORES tp_dont_change_params for these!
598 			 */
599 			if( tpcb->tp_sock->so_snd.sb_hiwat > 512 ) {
600 				(void) soreserve(tpcb->tp_sock, 512, 512 );/* GAG */
601 			}
602 			tpcb->tp_rx_strat =  TPRX_USE_CW;
603 
604 			/* class 4 doesn't need to open a vc now - may use one already
605 			 * opened or may open one only when it sends a pkt.
606 			 */
607 #else TPCONS
608 			error = ECONNREFUSED;
609 #endif TPCONS
610 			break;
611 		default:
612 			error = EPROTOTYPE;
613 		}
614 
615 	}
616 	if (error) {
617 		tp_netcmd( tpcb, CONN_CLOSE);
618 		goto done;
619 	}
620 	{	/* start with the global rtt, rtv stats */
621 		register int i =
622 		   (int) tpcb->tp_flags & (TPF_PEER_ON_SAMENET | TPF_NLQOS_PDN);
623 
624 		tpcb->tp_rtt = tp_stat.ts_rtt[i];
625 		tpcb->tp_rtv = tp_stat.ts_rtv[i];
626 	}
627 done:
628 	IFDEBUG(D_CONN)
629 		printf("tp_route_to  returns 0x%x\n", error);
630 	ENDDEBUG
631 	IFTRACE(D_CONN)
632 		tptraceTPCB(TPPTmisc, "route_to: returns: error netserv class", error,
633 			tpcb->tp_netservice, tpcb->tp_class, 0);
634 	ENDTRACE
635 	return error;
636 }
637 
638 
639 /* class zero version */
640 void
641 tp0_stash( tpcb, e )
642 	register struct tp_pcb		*tpcb;
643 	register struct tp_event	*e;
644 {
645 #ifndef lint
646 #define E e->ATTR(DT_TPDU)
647 #else lint
648 #define E e->ev_union.EV_DT_TPDU
649 #endif lint
650 
651 	register struct sockbuf *sb = &tpcb->tp_sock->so_rcv;
652 	register struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb;
653 
654 	IFPERF(tpcb)
655 		PStat(tpcb, Nb_from_ll) += E.e_datalen;
656 		tpmeas(tpcb->tp_lref, TPtime_from_ll, &e->e_time,
657 				E.e_seq, PStat(tpcb, Nb_from_ll), E.e_datalen);
658 	ENDPERF
659 
660 	IFDEBUG(D_STASH)
661 		printf("stash EQ: seq 0x%x datalen 0x%x eot 0x%x",
662 		E.e_seq, E.e_datalen, E.e_eot);
663 	ENDDEBUG
664 
665 	IFTRACE(D_STASH)
666 		tptraceTPCB(TPPTmisc, "stash EQ: seq len eot",
667 		E.e_seq, E.e_datalen, E.e_eot, 0);
668 	ENDTRACE
669 
670 	if ( E.e_eot ) {
671 		register struct mbuf *n = E.e_data;
672 		n->m_flags |= M_EOR;
673 		n->m_act = MNULL; /* set on tp_input */
674 	}
675 	sbappend(sb, E.e_data);
676 	IFDEBUG(D_STASH)
677 		dump_mbuf(sb->sb_mb, "stash 0: so_rcv after appending");
678 	ENDDEBUG
679 	if (tpcb->tp_netservice != ISO_CONS)
680 		printf("tp0_stash: tp running over something wierd\n");
681 	else {
682 		register struct pklcd *lcp = (struct pklcd *)isop->isop_chan;
683 		pk_flowcontrol(lcp, sbspace(sb) <= 0, 1);
684 	}
685 }
686 
687 void
688 tp0_openflow(tpcb)
689 register struct tp_pcb *tpcb;
690 {
691 	register struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb;
692 	if (tpcb->tp_netservice != ISO_CONS)
693 		printf("tp0_openflow: tp running over something wierd\n");
694 	else {
695 		register struct pklcd *lcp = (struct pklcd *)isop->isop_chan;
696 		if (lcp->lcd_rxrnr_condition)
697 			pk_flowcontrol(lcp, 0, 0);
698 	}
699 }
700 #ifndef TPCONS
701 static
702 pk_flowcontrol() {}
703 #endif
704 
705 #ifdef TP_PERF_MEAS
706 /*
707  * CALLED FROM:
708  *  tp_ctloutput() when the user sets TPOPT_PERF_MEAS on
709  *  and tp_newsocket() when a new connection is made from
710  *  a listening socket with tp_perf_on == true.
711  * FUNCTION and ARGUMENTS:
712  *  (tpcb) is the usual; this procedure gets a clear cluster mbuf for
713  *  a tp_pmeas structure, and makes tpcb->tp_p_meas point to it.
714  * RETURN VALUE:
715  *  ENOBUFS if it cannot get a cluster mbuf.
716  */
717 
718 int
719 tp_setup_perf(tpcb)
720 	register struct tp_pcb *tpcb;
721 {
722 	register struct mbuf *q;
723 
724 	if( tpcb->tp_p_meas == 0 ) {
725 		MGET(q, M_WAITOK, MT_PCB);
726 		if (q == 0)
727 			return ENOBUFS;
728 		MCLGET(q, M_WAITOK);
729 		if ((q->m_flags & M_EXT) == 0) {
730 			(void) m_free(q);
731 			return ENOBUFS;
732 		}
733 		q->m_len = sizeof (struct tp_pmeas);
734 		tpcb->tp_p_mbuf = q;
735 		tpcb->tp_p_meas = mtod(q, struct tp_pmeas *);
736 		bzero( (caddr_t)tpcb->tp_p_meas, sizeof (struct tp_pmeas) );
737 		IFDEBUG(D_PERF_MEAS)
738 			printf(
739 			"tpcb 0x%x so 0x%x ref 0x%x tp_p_meas 0x%x tp_perf_on 0x%x\n",
740 				tpcb, tpcb->tp_sock, tpcb->tp_lref,
741 				tpcb->tp_p_meas, tpcb->tp_perf_on);
742 		ENDDEBUG
743 		tpcb->tp_perf_on = 1;
744 	}
745 	return 0;
746 }
747 #endif TP_PERF_MEAS
748 
749 #ifdef ARGO_DEBUG
750 dump_addr (addr)
751 	register struct sockaddr *addr;
752 {
753 	switch( addr->sa_family ) {
754 		case AF_INET:
755 			dump_inaddr((struct sockaddr_in *)addr);
756 			break;
757 #ifdef ISO
758 		case AF_ISO:
759 			dump_isoaddr((struct sockaddr_iso *)addr);
760 			break;
761 #endif ISO
762 		default:
763 			printf("BAD AF: 0x%x\n", addr->sa_family);
764 			break;
765 	}
766 }
767 
768 #define	MAX_COLUMNS	8
769 /*
770  *	Dump the buffer to the screen in a readable format. Format is:
771  *
772  *		hex/dec  where hex is the hex format, dec is the decimal format.
773  *		columns of hex/dec numbers will be printed, followed by the
774  *		character representations (if printable).
775  */
776 Dump_buf(buf, len)
777 caddr_t	buf;
778 int		len;
779 {
780 	int		i,j;
781 #define Buf ((u_char *)buf)
782 	printf("Dump buf 0x%x len 0x%x\n", buf, len);
783 	for (i = 0; i < len; i += MAX_COLUMNS) {
784 		printf("+%d:\t", i);
785 		for (j = 0; j < MAX_COLUMNS; j++) {
786 			if (i + j < len) {
787 				printf("%x/%d\t", Buf[i+j], Buf[i+j]);
788 			} else {
789 				printf("	");
790 			}
791 		}
792 
793 		for (j = 0; j < MAX_COLUMNS; j++) {
794 			if (i + j < len) {
795 				if (((Buf[i+j]) > 31) && ((Buf[i+j]) < 128))
796 					printf("%c", Buf[i+j]);
797 				else
798 					printf(".");
799 			}
800 		}
801 		printf("\n");
802 	}
803 }
804 
805 
806 #endif ARGO_DEBUG
807 
808