xref: /original-bsd/sys/netiso/tp_subr2.c (revision c8089215)
1 /***********************************************************
2 		Copyright IBM Corporation 1987
3 
4                       All Rights Reserved
5 
6 Permission to use, copy, modify, and distribute this software and its
7 documentation for any purpose and without fee is hereby granted,
8 provided that the above copyright notice appear in all copies and that
9 both that copyright notice and this permission notice appear in
10 supporting documentation, and that the name of IBM not be
11 used in advertising or publicity pertaining to distribution of the
12 software without specific, written prior permission.
13 
14 IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
15 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
16 IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
17 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
18 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
19 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
20 SOFTWARE.
21 
22 ******************************************************************/
23 
24 /*
25  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
26  */
27 /*
28  * ARGO TP
29  *
30  * $Header: tp_subr2.c,v 5.5 88/11/18 17:28:55 nhall Exp $
31  * $Source: /usr/argo/sys/netiso/RCS/tp_subr2.c,v $
32  *	@(#)tp_subr2.c	7.6 (Berkeley) 03/12/91
33  *
34  * Some auxiliary routines:
35  * 		tp_protocol_error: required by xebec- called when a combo of state,
36  *			event, predicate isn't covered for by the transition file.
37  *		tp_indicate: gives indications(signals) to the user process
38  *		tp_getoptions: initializes variables that are affected by the options
39  *          chosen.
40  */
41 
42 #ifndef lint
43 static char *rcsid = "$Header: tp_subr2.c,v 5.5 88/11/18 17:28:55 nhall Exp $";
44 #endif lint
45 
46 /* this def'n is to cause the expansion of this macro in the
47  * routine tp_local_credit :
48  */
49 #define LOCAL_CREDIT_EXPAND
50 
51 #include "param.h"
52 #include "mbuf.h"
53 #include "socket.h"
54 #include "socketvar.h"
55 #include "domain.h"
56 #include "protosw.h"
57 #include "errno.h"
58 #include "types.h"
59 #include "time.h"
60 #include "kernel.h"
61 #undef MNULL
62 #include "argo_debug.h"
63 #include "tp_param.h"
64 #include "tp_ip.h"
65 #include "iso.h"
66 #include "iso_errno.h"
67 #include "iso_pcb.h"
68 #include "tp_timer.h"
69 #include "tp_stat.h"
70 #include "tp_tpdu.h"
71 #include "tp_pcb.h"
72 #include "tp_seq.h"
73 #include "tp_trace.h"
74 #include "tp_user.h"
75 #include "cons.h"
76 
77 #include "../net/if.h"
78 #ifdef TRUE
79 #undef FALSE
80 #undef TRUE
81 #endif
82 #include "../netccitt/x25.h"
83 #include "../netccitt/pk.h"
84 #include "../netccitt/pk_var.h"
85 
86 /*
87  * NAME: 	tp_local_credit()
88  *
89  * CALLED FROM:
90  *  tp_emit(), tp_usrreq()
91  *
92  * FUNCTION and ARGUMENTS:
93  *	Computes the local credit and stashes it in tpcb->tp_lcredit.
94  *  It's a macro in the production system rather than a procdure.
95  *
96  * RETURNS:
97  *
98  * SIDE EFFECTS:
99  *
100  * NOTES:
101  *  This doesn't actually get called in a production system -
102  *  the macro gets expanded instead in place of calls to this proc.
103  *  But for debugging, we call this and that allows us to add
104  *  debugging messages easily here.
105  */
106 void
107 tp_local_credit(tpcb)
108 	struct tp_pcb *tpcb;
109 {
110 	LOCAL_CREDIT(tpcb);
111 	IFDEBUG(D_CREDIT)
112 		printf("ref 0x%x lcdt 0x%x l_tpdusize 0x%x decbit 0x%x\n",
113 			tpcb->tp_refp - tp_ref,
114 			tpcb->tp_lcredit,
115 			tpcb->tp_l_tpdusize,
116 			tpcb->tp_decbit,
117 			tpcb->tp_cong_win
118 			);
119 	ENDDEBUG
120 	IFTRACE(D_CREDIT)
121 		tptraceTPCB(TPPTmisc,
122 			"lcdt tpdusz \n",
123 			 tpcb->tp_lcredit, tpcb->tp_l_tpdusize, 0, 0);
124 	ENDTRACE
125 }
126 
127 /*
128  * NAME:  tp_protocol_error()
129  *
130  * CALLED FROM:
131  *  tp_driver(), when it doesn't know what to do with
132  * 	a combo of event, state, predicate
133  *
134  * FUNCTION and ARGUMENTS:
135  *  print error mesg
136  *
137  * RETURN VALUE:
138  *  EIO - always
139  *
140  * SIDE EFFECTS:
141  *
142  * NOTES:
143  */
144 int
145 tp_protocol_error(e,tpcb)
146 	struct tp_event	*e;
147 	struct tp_pcb	*tpcb;
148 {
149 	printf("TP PROTOCOL ERROR! tpcb 0x%x event 0x%x, state 0x%x\n",
150 		tpcb, e->ev_number, tpcb->tp_state);
151 	IFTRACE(D_DRIVER)
152 		tptraceTPCB(TPPTmisc, "PROTOCOL ERROR tpcb event state",
153 			tpcb, e->ev_number, tpcb->tp_state, 0 );
154 	ENDTRACE
155 	return EIO; /* for lack of anything better */
156 }
157 
158 
159 /* Not used at the moment */
160 ProtoHook
161 tp_drain()
162 {
163 	return 0;
164 }
165 
166 
167 /*
168  * NAME: tp_indicate()
169  *
170  * CALLED FROM:
171  * 	tp.trans when XPD arrive, when a connection is being disconnected by
172  *  the arrival of a DR or ER, and when a connection times out.
173  *
174  * FUNCTION and ARGUMENTS:
175  *  (ind) is the type of indication : T_DISCONNECT, T_XPD
176  *  (error) is an E* value that will be put in the socket structure
177  *  to be passed along to the user later.
178  * 	Gives a SIGURG to the user process or group indicated by the socket
179  * 	attached to the tpcb.
180  *
181  * RETURNS:  Rien
182  *
183  * SIDE EFFECTS:
184  *
185  * NOTES:
186  */
187 void
188 tp_indicate(ind, tpcb, error)
189 	int				ind;
190 	u_short			error;
191 	register struct tp_pcb	*tpcb;
192 {
193 	register struct socket *so = tpcb->tp_sock;
194 	IFTRACE(D_INDICATION)
195 		tptraceTPCB(TPPTindicate, ind, *(u_short *)(tpcb->tp_lsuffix),
196 			*(u_short *)(tpcb->tp_fsuffix), error,so->so_pgid);
197 	ENDTRACE
198 	IFDEBUG(D_INDICATION)
199 		char *ls, *fs;
200 		ls = tpcb->tp_lsuffix,
201 		fs = tpcb->tp_fsuffix,
202 
203 		printf(
204 "indicate 0x%x lsuf 0x%02x%02x fsuf 0x%02x%02x err 0x%x  noind 0x%x ref 0x%x\n",
205 		ind,
206 		*ls, *(ls+1), *fs, *(fs+1),
207 		error, /*so->so_pgrp,*/
208 		tpcb->tp_no_disc_indications,
209 		tpcb->tp_lref);
210 	ENDDEBUG
211 
212 	so->so_error = error;
213 
214 	if (ind == T_DISCONNECT)  {
215 		if ( tpcb->tp_no_disc_indications )
216 			return;
217 	}
218 	IFTRACE(D_INDICATION)
219 		tptraceTPCB(TPPTmisc, "doing sohasoutofband(so)", so,0,0,0);
220 	ENDTRACE
221 	sohasoutofband(so);
222 }
223 
224 /*
225  * NAME : tp_getoptions()
226  *
227  * CALLED FROM:
228  * 	tp.trans whenever we go into OPEN state
229  *
230  * FUNCTION and ARGUMENTS:
231  *  sets the proper flags and values in the tpcb, to control
232  *  the appropriate actions for the given class, options,
233  *  sequence space, etc, etc.
234  *
235  * RETURNS: Nada
236  *
237  * SIDE EFFECTS:
238  *
239  * NOTES:
240  */
241 void
242 tp_getoptions(tpcb)
243 struct tp_pcb *tpcb;
244 {
245 	tpcb->tp_seqmask =
246 		tpcb->tp_xtd_format ?	TP_XTD_FMT_MASK :	TP_NML_FMT_MASK ;
247 	tpcb->tp_seqbit =
248 		tpcb->tp_xtd_format ?	TP_XTD_FMT_BIT :	TP_NML_FMT_BIT ;
249 	tpcb->tp_seqhalf = tpcb->tp_seqbit >> 1;
250 	tpcb->tp_dt_ticks =
251 		MAX(tpcb->tp_dt_ticks, (tpcb->tp_peer_acktime + 2));
252 
253 }
254 
255 /*
256  * NAME:  tp_recycle_tsuffix()
257  *
258  * CALLED FROM:
259  *  Called when a ref is frozen.
260  *
261  * FUNCTION and ARGUMENTS:
262  *  allows the suffix to be reused.
263  *
264  * RETURNS: zilch
265  *
266  * SIDE EFFECTS:
267  *
268  * NOTES:
269  */
270 void
271 tp_recycle_tsuffix(tpcb)
272 	struct tp_pcb	*tpcb;
273 {
274 	bzero((caddr_t)tpcb->tp_lsuffix, sizeof( tpcb->tp_lsuffix));
275 	bzero((caddr_t)tpcb->tp_fsuffix, sizeof( tpcb->tp_fsuffix));
276 	tpcb->tp_fsuffixlen = tpcb->tp_lsuffixlen = 0;
277 
278 	(tpcb->tp_nlproto->nlp_recycle_suffix)(tpcb->tp_npcb);
279 }
280 
281 /*
282  * NAME: tp_quench()
283  *
284  * CALLED FROM:
285  *  tp{af}_quench() when ICMP source quench or similar thing arrives.
286  *
287  * FUNCTION and ARGUMENTS:
288  *  Drop the congestion window back to 1.
289  *  Congestion window scheme:
290  *  Initial value is 1.  ("slow start" as Nagle, et. al. call it)
291  *  For each good ack that arrives, the congestion window is increased
292  *  by 1 (up to max size of logical infinity, which is to say,
293  *	it doesn't wrap around).
294  *  Source quench causes it to drop back to 1.
295  *  tp_send() uses the smaller of (regular window, congestion window).
296  *  One retransmission strategy option is to have any retransmission
297  *	cause reset the congestion window back  to 1.
298  *
299  *	(cmd) is either PRC_QUENCH: source quench, or
300  *		PRC_QUENCH2: dest. quench (dec bit)
301  *
302  * RETURNS:
303  *
304  * SIDE EFFECTS:
305  *
306  * NOTES:
307  */
308 void
309 tp_quench( tpcb, cmd )
310 	struct tp_pcb *tpcb;
311 	int cmd;
312 {
313 	IFDEBUG(D_QUENCH)
314 		printf("tp_quench tpcb 0x%x ref 0x%x sufx 0x%x\n",
315 			tpcb, tpcb->tp_lref, *(u_short *)(tpcb->tp_lsuffix));
316 		printf("cong_win 0x%x decbit 0x%x \n",
317 			tpcb->tp_cong_win, tpcb->tp_decbit);
318 	ENDDEBUG
319 	switch(cmd) {
320 		case PRC_QUENCH:
321 			tpcb->tp_cong_win = 1;
322 			IncStat(ts_quench);
323 			break;
324 		case PRC_QUENCH2:
325 			tpcb->tp_cong_win = 1; /* might as well quench source also */
326 			tpcb->tp_decbit = TP_DECBIT_CLEAR_COUNT;
327 			IncStat(ts_rcvdecbit);
328 			break;
329 	}
330 }
331 
332 
333 /*
334  * NAME:	tp_netcmd()
335  *
336  * CALLED FROM:
337  *
338  * FUNCTION and ARGUMENTS:
339  *
340  * RETURNS:
341  *
342  * SIDE EFFECTS:
343  *
344  * NOTES:
345  */
346 tp_netcmd( tpcb, cmd )
347 	struct tp_pcb *tpcb;
348 	int cmd;
349 {
350 #ifdef TPCONS
351 	struct isopcb *isop;
352 	struct pklcd *lcp;
353 
354 	if (tpcb->tp_netservice != ISO_CONS)
355 		return;
356 	isop = (struct isopcb *)tpcb->tp_npcb;
357 	lcp = (struct pklcd *)isop->isop_chan;
358 	switch (cmd) {
359 
360 	case CONN_CLOSE:
361 	case CONN_REFUSE:
362 		if (isop->isop_refcnt == 1)
363 			pk_disconnect(lcp);
364 		isop->isop_chan = 0;
365 		isop->isop_refcnt = 0;
366 		break;
367 
368 	default:
369 		printf("tp_netcmd(0x%x, 0x%x) NOT IMPLEMENTED\n", tpcb, cmd);
370 		break;
371 	}
372 #else TPCONS
373 	printf("tp_netcmd(): X25 NOT CONFIGURED!!\n");
374 #endif
375 }
376 /*
377  * CALLED FROM:
378  *  tp_ctloutput() and tp_emit()
379  * FUNCTION and ARGUMENTS:
380  * 	Convert a class mask to the highest numeric value it represents.
381  */
382 
383 int
384 tp_mask_to_num(x)
385 	u_char x;
386 {
387 	register int j;
388 
389 	for(j = 4; j>=0 ;j--) {
390 		if(x & (1<<j))
391 			break;
392 	}
393 	ASSERT( (j == 4) || (j == 0) ); /* for now */
394 	if( (j != 4) && (j != 0) ) {
395 		printf("ASSERTION ERROR: tp_mask_to_num: x 0x%x j %d\n",
396 			x, j);
397 	}
398 	IFTRACE(D_TPINPUT)
399 		tptrace(TPPTmisc, "tp_mask_to_num(x) returns j", x, j, 0, 0);
400 	ENDTRACE
401 	IFDEBUG(D_TPINPUT)
402 		printf("tp_mask_to_num(0x%x) returns 0x%x\n", x, j);
403 	ENDDEBUG
404 	return j;
405 }
406 
407 static
408 copyQOSparms(src, dst)
409 	struct tp_conn_param *src, *dst;
410 {
411 	/* copy all but the bits stuff at the end */
412 #define COPYSIZE (12 * sizeof(short))
413 
414 	bcopy((caddr_t)src, (caddr_t)dst, COPYSIZE);
415 	dst->p_tpdusize = src->p_tpdusize;
416 	dst->p_ack_strat = src->p_ack_strat;
417 	dst->p_rx_strat = src->p_rx_strat;
418 #undef COPYSIZE
419 }
420 
421 /*
422  * CALLED FROM:
423  *  tp_usrreq on PRU_CONNECT and tp_input on receipt of CR
424  *
425  * FUNCTION and ARGUMENTS:
426  * 	route directly to x.25 if the address is type 37 - GROT.
427  *  furthermore, let TP0 handle only type-37 addresses
428  *
429  *	Since this assumes that its address argument is in a mbuf, the
430  *	parameter was changed to reflect this assumtion. This also
431  *	implies that an mbuf must be allocated when this is
432  *	called from tp_input
433  *
434  * RETURNS:
435  *	errno value	 :
436  *	EAFNOSUPPORT if can't find an nl_protosw for x.25 (really could panic)
437  *	ECONNREFUSED if trying to run TP0 with non-type 37 address
438  *  possibly other E* returned from cons_netcmd()
439  * NOTE:
440  *  Would like to eliminate as much of this as possible --
441  *  only one set of defaults (let the user set the parms according
442  *  to parameters provided in the directory service).
443  *  Left here for now 'cause we don't yet have a clean way to handle
444  *  it on the passive end.
445  */
446 int
447 tp_route_to( m, tpcb, channel)
448 	struct mbuf					*m;
449 	register struct tp_pcb		*tpcb;
450 	caddr_t 					channel;
451 {
452 	register struct sockaddr_iso *siso;	/* NOTE: this may be a sockaddr_in */
453 	extern struct tp_conn_param tp_conn_param[];
454 	struct pklcd *lcp = (struct pklcd *)channel;
455 	int error = 0;
456 
457 	siso = mtod(m, struct sockaddr_iso *);
458 	IFTRACE(D_CONN)
459 		tptraceTPCB(TPPTmisc,
460 		"route_to: so  afi netservice class",
461 		tpcb->tp_sock, siso->siso_addr.isoa_genaddr[0], tpcb->tp_netservice,
462 			tpcb->tp_class);
463 	ENDTRACE
464 	IFDEBUG(D_CONN)
465 		printf("tp_route_to( m x%x, channel 0x%x, tpcb 0x%x netserv 0x%x)\n",
466 			m, channel, tpcb, tpcb->tp_netservice);
467 		printf("m->mlen x%x, m->m_data:\n", m->m_len);
468 		dump_buf(mtod(m, caddr_t), m->m_len);
469 	ENDDEBUG
470 	if (siso->siso_family != tpcb->tp_domain) {
471 		error = EAFNOSUPPORT;
472 		goto done;
473 	}
474 	IFDEBUG(D_CONN)
475 		printf("tp_route_to  calling nlp_pcbconn, netserv %d\n",
476 			tpcb->tp_netservice);
477 	ENDDEBUG
478 #ifdef TPCONS
479 	if (lcp) {
480 		struct isopcb *isop = (struct isopcb *)lcp->lcd_upnext,
481 			*isop_new = (struct isopcb *)tpcb->tp_sock->so_pcb;
482 		remque(isop_new);
483 		free(isop_new, M_PCB);
484 		tpcb->tp_sock->so_pcb = (caddr_t)isop;
485 		if (isop->isop_refcnt == 0) {
486 			extern struct isopcb tp_isopcb;
487 			remque(isop);
488 			insque(isop, &tp_isopcb);
489 			isop->isop_head = &tp_isopcb;
490 			iso_putsufx(isop, tpcb->tp_lsuffix, tpcb->tp_lsuffixlen, TP_LOCAL);
491 		}
492 		/* else there are already connections sharing this */
493 		isop->isop_refcnt++;
494 	} else
495 #endif
496 		error = (tpcb->tp_nlproto->nlp_pcbconn)(tpcb->tp_sock->so_pcb, m);
497 	if( error )
498 		goto done;
499 
500 	{
501 		register int save_netservice = tpcb->tp_netservice;
502 
503 		switch(tpcb->tp_netservice) {
504 		case ISO_COSNS:
505 		case ISO_CLNS:
506 			/* This is a kludge but seems necessary so the passive end
507 			 * can get long enough timers. sigh.
508 			if( siso->siso_addr.osinet_idi[1] == (u_char)IDI_OSINET )
509 			 */
510 #define	IDI_OSINET	0x0004	/* bcd of "0004" */
511 			if( siso->siso_addr.isoa_genaddr[2] == (char)IDI_OSINET ) {
512 				if( tpcb->tp_dont_change_params == 0) {
513 					copyQOSparms( &tp_conn_param[ISO_COSNS],
514 							&tpcb->_tp_param);
515 				}
516 				tpcb->tp_flags |= TPF_NLQOS_PDN;
517 			}
518 			/* drop through to IN_CLNS*/
519 		case IN_CLNS:
520 			if (iso_localifa(siso))
521 				tpcb->tp_flags |= TPF_PEER_ON_SAMENET;
522 			if( (tpcb->tp_class & TP_CLASS_4)==0 ) {
523 				error = EPROTOTYPE;
524 				break;
525 			}
526 			tpcb->tp_class = TP_CLASS_4;  /* IGNORE dont_change_parms */
527 			break;
528 
529 		case ISO_CONS:
530 #ifdef TPCONS
531 			tpcb->tp_flags |= TPF_NLQOS_PDN;
532 			if( tpcb->tp_dont_change_params == 0 ) {
533 				copyQOSparms( &tp_conn_param[ISO_CONS],
534 							&tpcb->_tp_param);
535 			}
536 			/*
537 			 * for use over x.25 really need a small receive window,
538 			 * need to start slowly, need small max negotiable tpdu size,
539 			 * and need to use the congestion window to the max
540 			 * IGNORES tp_dont_change_params for these!
541 			 */
542 			if( tpcb->tp_sock->so_snd.sb_hiwat > 512 ) {
543 				(void) soreserve(tpcb->tp_sock, 512, 512 );/* GAG */
544 			}
545 			tpcb->tp_rx_strat =  TPRX_USE_CW;
546 
547 			if( (tpcb->tp_nlproto != &nl_protosw[ISO_CONS]) ) {
548 				IFDEBUG(D_CONN)
549 					printf(
550 					"tp_route_to( CHANGING nlproto old 0x%x new 0x%x)\n",
551 							tpcb->tp_nlproto , &nl_protosw[ISO_CONS]);
552 				ENDDEBUG
553 				tpcb->tp_nlproto = &nl_protosw[ISO_CONS];
554 			}
555 			/* class 4 doesn't need to open a vc now - may use one already
556 			 * opened or may open one only when it sends a pkt.
557 			 */
558 #else TPCONS
559 			error = ECONNREFUSED;
560 #endif TPCONS
561 			break;
562 		default:
563 			error = EPROTOTYPE;
564 		}
565 
566 		ASSERT( save_netservice == tpcb->tp_netservice);
567 	}
568 	if (error) {
569 		tp_netcmd( tpcb, CONN_CLOSE);
570 		goto done;
571 	}
572 	{	/* start with the global rtt, rtv stats */
573 		register int i =
574 		   (int) tpcb->tp_flags & (TPF_PEER_ON_SAMENET | TPF_NLQOS_PDN);
575 
576 		tpcb->tp_rtt = tp_stat.ts_rtt[i];
577 		tpcb->tp_rtv = tp_stat.ts_rtv[i];
578 	}
579 done:
580 	IFDEBUG(D_CONN)
581 		printf("tp_route_to  returns 0x%x\n", error);
582 	ENDDEBUG
583 	IFTRACE(D_CONN)
584 		tptraceTPCB(TPPTmisc, "route_to: returns: error netserv class", error,
585 			tpcb->tp_netservice, tpcb->tp_class, 0);
586 	ENDTRACE
587 	return error;
588 }
589 
590 
591 /* class zero version */
592 void
593 tp0_stash( tpcb, e )
594 	register struct tp_pcb		*tpcb;
595 	register struct tp_event	*e;
596 {
597 #ifndef lint
598 #define E e->ATTR(DT_TPDU)
599 #else lint
600 #define E e->ev_union.EV_DT_TPDU
601 #endif lint
602 
603 	register struct sockbuf *sb = &tpcb->tp_sock->so_rcv;
604 	register struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb;
605 
606 	IFPERF(tpcb)
607 		PStat(tpcb, Nb_from_ll) += E.e_datalen;
608 		tpmeas(tpcb->tp_lref, TPtime_from_ll, &e->e_time,
609 				E.e_seq, PStat(tpcb, Nb_from_ll), E.e_datalen);
610 	ENDPERF
611 
612 	IFDEBUG(D_STASH)
613 		printf("stash EQ: seq 0x%x datalen 0x%x eot 0x%x",
614 		E.e_seq, E.e_datalen, E.e_eot);
615 	ENDDEBUG
616 
617 	IFTRACE(D_STASH)
618 		tptraceTPCB(TPPTmisc, "stash EQ: seq len eot",
619 		E.e_seq, E.e_datalen, E.e_eot, 0);
620 	ENDTRACE
621 
622 	if ( E.e_eot ) {
623 		register struct mbuf *n = E.e_data;
624 		n->m_flags |= M_EOR;
625 		n->m_act = MNULL; /* set on tp_input */
626 	}
627 	sbappend(sb, E.e_data);
628 	IFDEBUG(D_STASH)
629 		dump_mbuf(sb->sb_mb, "stash 0: so_rcv after appending");
630 	ENDDEBUG
631 	if (tpcb->tp_netservice != ISO_CONS)
632 		printf("tp0_stash: tp running over something wierd\n");
633 	else {
634 		register struct pklcd *lcp = (struct pklcd *)isop->isop_chan;
635 		pk_flowcontrol(lcp, sbspace(sb) <= 0, 1);
636 	}
637 }
638 
639 void
640 tp0_openflow(tpcb)
641 register struct tp_pcb *tpcb;
642 {
643 	register struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb;
644 	if (tpcb->tp_netservice != ISO_CONS)
645 		printf("tp0_openflow: tp running over something wierd\n");
646 	else {
647 		register struct pklcd *lcp = (struct pklcd *)isop->isop_chan;
648 		if (lcp->lcd_rxrnr_condition)
649 			pk_flowcontrol(lcp, 0, 0);
650 	}
651 }
652 #ifndef TPCONS
653 static
654 pk_flowcontrol() {}
655 #endif
656 
657 #ifdef TP_PERF_MEAS
658 /*
659  * CALLED FROM:
660  *  tp_ctloutput() when the user sets TPOPT_PERF_MEAS on
661  *  and tp_newsocket() when a new connection is made from
662  *  a listening socket with tp_perf_on == true.
663  * FUNCTION and ARGUMENTS:
664  *  (tpcb) is the usual; this procedure gets a clear cluster mbuf for
665  *  a tp_pmeas structure, and makes tpcb->tp_p_meas point to it.
666  * RETURN VALUE:
667  *  ENOBUFS if it cannot get a cluster mbuf.
668  */
669 
670 int
671 tp_setup_perf(tpcb)
672 	register struct tp_pcb *tpcb;
673 {
674 	register struct mbuf *q;
675 
676 	if( tpcb->tp_p_meas == 0 ) {
677 		MGET(q, M_WAITOK, MT_PCB);
678 		if (q == 0)
679 			return ENOBUFS;
680 		MCLGET(q, M_WAITOK);
681 		if ((q->m_flags & M_EXT) == 0) {
682 			(void) m_free(q);
683 			return ENOBUFS;
684 		}
685 		q->m_len = sizeof (struct tp_pmeas);
686 		tpcb->tp_p_mbuf = q;
687 		tpcb->tp_p_meas = mtod(q, struct tp_pmeas *);
688 		bzero( (caddr_t)tpcb->tp_p_meas, sizeof (struct tp_pmeas) );
689 		IFDEBUG(D_PERF_MEAS)
690 			printf(
691 			"tpcb 0x%x so 0x%x ref 0x%x tp_p_meas 0x%x tp_perf_on 0x%x\n",
692 				tpcb, tpcb->tp_sock, tpcb->tp_lref,
693 				tpcb->tp_p_meas, tpcb->tp_perf_on);
694 		ENDDEBUG
695 		tpcb->tp_perf_on = 1;
696 	}
697 	return 0;
698 }
699 #endif TP_PERF_MEAS
700 
701 #ifdef ARGO_DEBUG
702 dump_addr (addr)
703 	register struct sockaddr *addr;
704 {
705 	switch( addr->sa_family ) {
706 		case AF_INET:
707 			dump_inaddr((struct sockaddr_in *)addr);
708 			break;
709 #ifdef ISO
710 		case AF_ISO:
711 			dump_isoaddr((struct sockaddr_iso *)addr);
712 			break;
713 #endif ISO
714 		default:
715 			printf("BAD AF: 0x%x\n", addr->sa_family);
716 			break;
717 	}
718 }
719 
720 #define	MAX_COLUMNS	8
721 /*
722  *	Dump the buffer to the screen in a readable format. Format is:
723  *
724  *		hex/dec  where hex is the hex format, dec is the decimal format.
725  *		columns of hex/dec numbers will be printed, followed by the
726  *		character representations (if printable).
727  */
728 Dump_buf(buf, len)
729 caddr_t	buf;
730 int		len;
731 {
732 	int		i,j;
733 
734 	printf("Dump buf 0x%x len 0x%x\n", buf, len);
735 	for (i = 0; i < len; i += MAX_COLUMNS) {
736 		printf("+%d:\t", i);
737 		for (j = 0; j < MAX_COLUMNS; j++) {
738 			if (i + j < len) {
739 				printf("%x/%d\t", buf[i+j]&0xff, buf[i+j]);
740 			} else {
741 				printf("	");
742 			}
743 		}
744 
745 		for (j = 0; j < MAX_COLUMNS; j++) {
746 			if (i + j < len) {
747 				if (((buf[i+j]) > 31) && ((buf[i+j]) < 128))
748 					printf("%c", buf[i+j]&0xff);
749 				else
750 					printf(".");
751 			}
752 		}
753 		printf("\n");
754 	}
755 }
756 
757 
758 #endif ARGO_DEBUG
759 
760