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