make kernel includes standard
[unix-history] / usr / src / sys / netiso / tp_subr2.c
CommitLineData
7bcd1bb8
KB
1/*-
2 * Copyright (c) 1991 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 *
5548a02f 7 * @(#)tp_subr2.c 7.21 (Berkeley) %G%
7bcd1bb8
KB
8 */
9
3202a7cd
KS
10/***********************************************************
11 Copyright IBM Corporation 1987
12
13 All Rights Reserved
14
15Permission to use, copy, modify, and distribute this software and its
16documentation for any purpose and without fee is hereby granted,
17provided that the above copyright notice appear in all copies and that
18both that copyright notice and this permission notice appear in
19supporting documentation, and that the name of IBM not be
20used in advertising or publicity pertaining to distribution of the
21software without specific, written prior permission.
22
23IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
29SOFTWARE.
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:
7bcd1bb8
KB
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.
3202a7cd
KS
48 */
49
3202a7cd
KS
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
5548a02f
KB
55#include <sys/param.h>
56#include <sys/systm.h>
57#include <sys/mbuf.h>
58#include <sys/socket.h>
59#include <sys/socketvar.h>
60#include <sys/domain.h>
61#include <sys/protosw.h>
62#include <sys/errno.h>
63#include <sys/time.h>
64#include <sys/kernel.h>
65
3202a7cd 66#undef MNULL
5548a02f
KB
67#include <netiso/argo_debug.h>
68#include <netiso/tp_param.h>
69#include <netiso/tp_ip.h>
70#include <netiso/iso.h>
71#include <netiso/iso_errno.h>
72#include <netiso/iso_pcb.h>
73#include <netiso/tp_timer.h>
74#include <netiso/tp_stat.h>
75#include <netiso/tp_tpdu.h>
76#include <netiso/tp_pcb.h>
77#include <netiso/tp_seq.h>
78#include <netiso/tp_trace.h>
79#include <netiso/tp_user.h>
80#include <netiso/cons.h>
3202a7cd 81
5548a02f
KB
82#include <net/if.h>
83#include <net/if_types.h>
194a383a
KS
84#ifdef TRUE
85#undef FALSE
86#undef TRUE
87#endif
5548a02f
KB
88#include <netccitt/x25.h>
89#include <netccitt/pk.h>
90#include <netccitt/pk_var.h>
194a383a 91
e900dd35
KS
92void tp_rsyset();
93
3202a7cd
KS
94/*
95 * NAME: tp_local_credit()
96 *
97 * CALLED FROM:
98 * tp_emit(), tp_usrreq()
99 *
100 * FUNCTION and ARGUMENTS:
101 * Computes the local credit and stashes it in tpcb->tp_lcredit.
102 * It's a macro in the production system rather than a procdure.
103 *
104 * RETURNS:
105 *
106 * SIDE EFFECTS:
107 *
108 * NOTES:
109 * This doesn't actually get called in a production system -
110 * the macro gets expanded instead in place of calls to this proc.
111 * But for debugging, we call this and that allows us to add
112 * debugging messages easily here.
113 */
114void
115tp_local_credit(tpcb)
116 struct tp_pcb *tpcb;
117{
118 LOCAL_CREDIT(tpcb);
119 IFDEBUG(D_CREDIT)
120 printf("ref 0x%x lcdt 0x%x l_tpdusize 0x%x decbit 0x%x\n",
378ea02c 121 tpcb->tp_lref,
3202a7cd
KS
122 tpcb->tp_lcredit,
123 tpcb->tp_l_tpdusize,
124 tpcb->tp_decbit,
125 tpcb->tp_cong_win
126 );
127 ENDDEBUG
128 IFTRACE(D_CREDIT)
129 tptraceTPCB(TPPTmisc,
130 "lcdt tpdusz \n",
131 tpcb->tp_lcredit, tpcb->tp_l_tpdusize, 0, 0);
132 ENDTRACE
133}
134
135/*
136 * NAME: tp_protocol_error()
137 *
138 * CALLED FROM:
139 * tp_driver(), when it doesn't know what to do with
140 * a combo of event, state, predicate
141 *
142 * FUNCTION and ARGUMENTS:
143 * print error mesg
144 *
145 * RETURN VALUE:
146 * EIO - always
147 *
148 * SIDE EFFECTS:
149 *
150 * NOTES:
151 */
152int
153tp_protocol_error(e,tpcb)
154 struct tp_event *e;
155 struct tp_pcb *tpcb;
156{
157 printf("TP PROTOCOL ERROR! tpcb 0x%x event 0x%x, state 0x%x\n",
158 tpcb, e->ev_number, tpcb->tp_state);
159 IFTRACE(D_DRIVER)
160 tptraceTPCB(TPPTmisc, "PROTOCOL ERROR tpcb event state",
161 tpcb, e->ev_number, tpcb->tp_state, 0 );
162 ENDTRACE
163 return EIO; /* for lack of anything better */
164}
165
166
167/* Not used at the moment */
168ProtoHook
169tp_drain()
170{
171 return 0;
172}
173
174
175/*
176 * NAME: tp_indicate()
177 *
178 * CALLED FROM:
179 * tp.trans when XPD arrive, when a connection is being disconnected by
180 * the arrival of a DR or ER, and when a connection times out.
181 *
182 * FUNCTION and ARGUMENTS:
183 * (ind) is the type of indication : T_DISCONNECT, T_XPD
184 * (error) is an E* value that will be put in the socket structure
185 * to be passed along to the user later.
186 * Gives a SIGURG to the user process or group indicated by the socket
187 * attached to the tpcb.
188 *
189 * RETURNS: Rien
190 *
191 * SIDE EFFECTS:
192 *
193 * NOTES:
194 */
195void
196tp_indicate(ind, tpcb, error)
197 int ind;
198 u_short error;
199 register struct tp_pcb *tpcb;
200{
201 register struct socket *so = tpcb->tp_sock;
202 IFTRACE(D_INDICATION)
9aed0596
KS
203 tptraceTPCB(TPPTindicate, ind, *(u_short *)(tpcb->tp_lsuffix),
204 *(u_short *)(tpcb->tp_fsuffix), error,so->so_pgid);
3202a7cd
KS
205 ENDTRACE
206 IFDEBUG(D_INDICATION)
a50e2bc0 207 char *ls, *fs;
3202a7cd
KS
208 ls = tpcb->tp_lsuffix,
209 fs = tpcb->tp_fsuffix,
210
211 printf(
a50e2bc0 212"indicate 0x%x lsuf 0x%02x%02x fsuf 0x%02x%02x err 0x%x noind 0x%x ref 0x%x\n",
3202a7cd
KS
213 ind,
214 *ls, *(ls+1), *fs, *(fs+1),
a50e2bc0 215 error, /*so->so_pgrp,*/
3202a7cd
KS
216 tpcb->tp_no_disc_indications,
217 tpcb->tp_lref);
218 ENDDEBUG
219
6726a5f3
KS
220 if (ind == ER_TPDU) {
221 register struct mbuf *m;
222 struct tp_disc_reason x;
223
224 if ((so->so_state & SS_CANTRCVMORE) == 0 &&
225 (m = m_get(M_DONTWAIT, MT_OOBDATA)) != 0) {
226
227 x.dr_hdr.cmsg_len = m->m_len = sizeof(x);
228 x.dr_hdr.cmsg_level = SOL_TRANSPORT;
229 x.dr_hdr.cmsg_type= TPOPT_DISC_REASON;
230 x.dr_reason = error;
231 *mtod(m, struct tp_disc_reason *) = x;
232 sbappendrecord(&tpcb->tp_Xrcv, m);
233 error = 0;
234 } else
235 error = ECONNRESET;
236 }
3202a7cd
KS
237 so->so_error = error;
238
239 if (ind == T_DISCONNECT) {
05b32603
KS
240 if (error == 0)
241 so->so_error = ENOTCONN;
3202a7cd
KS
242 if ( tpcb->tp_no_disc_indications )
243 return;
244 }
245 IFTRACE(D_INDICATION)
246 tptraceTPCB(TPPTmisc, "doing sohasoutofband(so)", so,0,0,0);
247 ENDTRACE
248 sohasoutofband(so);
249}
250
251/*
252 * NAME : tp_getoptions()
253 *
254 * CALLED FROM:
255 * tp.trans whenever we go into OPEN state
256 *
257 * FUNCTION and ARGUMENTS:
258 * sets the proper flags and values in the tpcb, to control
259 * the appropriate actions for the given class, options,
260 * sequence space, etc, etc.
261 *
262 * RETURNS: Nada
263 *
264 * SIDE EFFECTS:
265 *
266 * NOTES:
267 */
268void
269tp_getoptions(tpcb)
270struct tp_pcb *tpcb;
271{
272 tpcb->tp_seqmask =
273 tpcb->tp_xtd_format ? TP_XTD_FMT_MASK : TP_NML_FMT_MASK ;
274 tpcb->tp_seqbit =
275 tpcb->tp_xtd_format ? TP_XTD_FMT_BIT : TP_NML_FMT_BIT ;
276 tpcb->tp_seqhalf = tpcb->tp_seqbit >> 1;
277 tpcb->tp_dt_ticks =
3d28e0a4 278 max(tpcb->tp_dt_ticks, (tpcb->tp_peer_acktime + 2));
e900dd35 279 tp_rsyset(tpcb);
7893315b 280
3202a7cd
KS
281}
282
283/*
284 * NAME: tp_recycle_tsuffix()
285 *
286 * CALLED FROM:
287 * Called when a ref is frozen.
288 *
289 * FUNCTION and ARGUMENTS:
290 * allows the suffix to be reused.
291 *
292 * RETURNS: zilch
293 *
294 * SIDE EFFECTS:
295 *
296 * NOTES:
297 */
298void
299tp_recycle_tsuffix(tpcb)
300 struct tp_pcb *tpcb;
301{
a50e2bc0
KS
302 bzero((caddr_t)tpcb->tp_lsuffix, sizeof( tpcb->tp_lsuffix));
303 bzero((caddr_t)tpcb->tp_fsuffix, sizeof( tpcb->tp_fsuffix));
3202a7cd
KS
304 tpcb->tp_fsuffixlen = tpcb->tp_lsuffixlen = 0;
305
306 (tpcb->tp_nlproto->nlp_recycle_suffix)(tpcb->tp_npcb);
307}
308
309/*
310 * NAME: tp_quench()
311 *
312 * CALLED FROM:
313 * tp{af}_quench() when ICMP source quench or similar thing arrives.
314 *
315 * FUNCTION and ARGUMENTS:
316 * Drop the congestion window back to 1.
317 * Congestion window scheme:
318 * Initial value is 1. ("slow start" as Nagle, et. al. call it)
319 * For each good ack that arrives, the congestion window is increased
320 * by 1 (up to max size of logical infinity, which is to say,
321 * it doesn't wrap around).
322 * Source quench causes it to drop back to 1.
323 * tp_send() uses the smaller of (regular window, congestion window).
324 * One retransmission strategy option is to have any retransmission
325 * cause reset the congestion window back to 1.
326 *
327 * (cmd) is either PRC_QUENCH: source quench, or
328 * PRC_QUENCH2: dest. quench (dec bit)
329 *
330 * RETURNS:
331 *
332 * SIDE EFFECTS:
333 *
334 * NOTES:
335 */
336void
337tp_quench( tpcb, cmd )
338 struct tp_pcb *tpcb;
339 int cmd;
340{
341 IFDEBUG(D_QUENCH)
342 printf("tp_quench tpcb 0x%x ref 0x%x sufx 0x%x\n",
9aed0596 343 tpcb, tpcb->tp_lref, *(u_short *)(tpcb->tp_lsuffix));
3202a7cd
KS
344 printf("cong_win 0x%x decbit 0x%x \n",
345 tpcb->tp_cong_win, tpcb->tp_decbit);
346 ENDDEBUG
347 switch(cmd) {
348 case PRC_QUENCH:
bdf41b09 349 tpcb->tp_cong_win = tpcb->tp_l_tpdusize;
3202a7cd
KS
350 IncStat(ts_quench);
351 break;
352 case PRC_QUENCH2:
bdf41b09 353 tpcb->tp_cong_win = tpcb->tp_l_tpdusize; /* might as well quench source also */
3202a7cd
KS
354 tpcb->tp_decbit = TP_DECBIT_CLEAR_COUNT;
355 IncStat(ts_rcvdecbit);
356 break;
357 }
358}
359
360
361/*
362 * NAME: tp_netcmd()
363 *
364 * CALLED FROM:
365 *
366 * FUNCTION and ARGUMENTS:
367 *
368 * RETURNS:
369 *
370 * SIDE EFFECTS:
371 *
372 * NOTES:
373 */
374tp_netcmd( tpcb, cmd )
375 struct tp_pcb *tpcb;
376 int cmd;
377{
194a383a
KS
378#ifdef TPCONS
379 struct isopcb *isop;
380 struct pklcd *lcp;
381
382 if (tpcb->tp_netservice != ISO_CONS)
383 return;
384 isop = (struct isopcb *)tpcb->tp_npcb;
385 lcp = (struct pklcd *)isop->isop_chan;
3202a7cd
KS
386 switch (cmd) {
387
388 case CONN_CLOSE:
389 case CONN_REFUSE:
01acbfa1
KS
390 if (isop->isop_refcnt == 1) {
391 /* This is really superfluous, since it would happen
392 anyway in iso_pcbdetach, although it is a courtesy
393 to free up the x.25 channel before the refwait timer
394 expires. */
395 lcp->lcd_upper = 0;
396 lcp->lcd_upnext = 0;
194a383a 397 pk_disconnect(lcp);
01acbfa1
KS
398 isop->isop_chan = 0;
399 isop->isop_refcnt = 0;
400 }
3202a7cd
KS
401 break;
402
403 default:
404 printf("tp_netcmd(0x%x, 0x%x) NOT IMPLEMENTED\n", tpcb, cmd);
405 break;
406 }
194a383a 407#else TPCONS
3202a7cd 408 printf("tp_netcmd(): X25 NOT CONFIGURED!!\n");
194a383a 409#endif
3202a7cd
KS
410}
411/*
412 * CALLED FROM:
413 * tp_ctloutput() and tp_emit()
414 * FUNCTION and ARGUMENTS:
415 * Convert a class mask to the highest numeric value it represents.
416 */
417
418int
419tp_mask_to_num(x)
420 u_char x;
421{
422 register int j;
423
424 for(j = 4; j>=0 ;j--) {
425 if(x & (1<<j))
426 break;
427 }
428 ASSERT( (j == 4) || (j == 0) ); /* for now */
429 if( (j != 4) && (j != 0) ) {
430 printf("ASSERTION ERROR: tp_mask_to_num: x 0x%x j %d\n",
431 x, j);
432 }
433 IFTRACE(D_TPINPUT)
434 tptrace(TPPTmisc, "tp_mask_to_num(x) returns j", x, j, 0, 0);
435 ENDTRACE
436 IFDEBUG(D_TPINPUT)
437 printf("tp_mask_to_num(0x%x) returns 0x%x\n", x, j);
438 ENDDEBUG
439 return j;
440}
441
442static
443copyQOSparms(src, dst)
444 struct tp_conn_param *src, *dst;
445{
446 /* copy all but the bits stuff at the end */
447#define COPYSIZE (12 * sizeof(short))
448
a50e2bc0 449 bcopy((caddr_t)src, (caddr_t)dst, COPYSIZE);
3202a7cd
KS
450 dst->p_tpdusize = src->p_tpdusize;
451 dst->p_ack_strat = src->p_ack_strat;
452 dst->p_rx_strat = src->p_rx_strat;
453#undef COPYSIZE
454}
d696d41e
KS
455/*
456 * Determine a reasonable value for maxseg size.
457 * If the route is known, check route for mtu.
458 * We also initialize the congestion/slow start
459 * window to be a single segment if the destination isn't local.
460 * While looking at the routing entry, we also initialize other path-dependent
461 * parameters from pre-set or cached values in the routing entry.
462 */
463void
464tp_mss(tpcb, nhdr_size)
465 register struct tp_pcb *tpcb;
466 int nhdr_size;
467{
468 register struct rtentry *rt;
469 struct ifnet *ifp;
470 register int rtt, mss;
471 u_long bufsize;
d119092b 472 int i, ssthresh = 0, rt_mss;
d696d41e
KS
473 struct socket *so;
474
d119092b
KS
475 if (tpcb->tp_ptpdusize)
476 mss = tpcb->tp_ptpdusize << 7;
477 else
478 mss = 1 << tpcb->tp_tpdusize;
d696d41e
KS
479 so = tpcb->tp_sock;
480 if ((rt = *(tpcb->tp_routep)) == 0) {
481 bufsize = so->so_rcv.sb_hiwat;
482 goto punt_route;
483 }
484 ifp = rt->rt_ifp;
485
486#ifdef RTV_MTU /* if route characteristics exist ... */
487 /*
488 * While we're here, check if there's an initial rtt
489 * or rttvar. Convert from the route-table units
490 * to hz ticks for the smoothed timers and slow-timeout units
491 * for other inital variables.
492 */
493 if (tpcb->tp_rtt == 0 && (rtt = rt->rt_rmx.rmx_rtt)) {
494 tpcb->tp_rtt = rtt * hz / RTM_RTTUNIT;
495 if (rt->rt_rmx.rmx_rttvar)
496 tpcb->tp_rtv = rt->rt_rmx.rmx_rttvar
497 * hz / RTM_RTTUNIT;
498 else
499 tpcb->tp_rtv = tpcb->tp_rtt;
500 }
501 /*
502 * if there's an mtu associated with the route, use it
503 */
504 if (rt->rt_rmx.rmx_mtu)
d119092b 505 rt_mss = rt->rt_rmx.rmx_mtu - nhdr_size;
d696d41e
KS
506 else
507#endif /* RTV_MTU */
d119092b
KS
508 rt_mss = (ifp->if_mtu - nhdr_size);
509 if (tpcb->tp_ptpdusize == 0 || /* assume application doesn't care */
510 mss > rt_mss /* network won't support what was asked for */)
511 mss = rt_mss;
d696d41e
KS
512 /* can propose mtu which are multiples of 128 */
513 mss &= ~0x7f;
514 /*
515 * If there's a pipesize, change the socket buffer
516 * to that size.
517 */
518#ifdef RTV_SPIPE
519 if ((bufsize = rt->rt_rmx.rmx_sendpipe) > 0) {
520#endif
521 bufsize = min(bufsize, so->so_snd.sb_hiwat);
522 (void) sbreserve(&so->so_snd, bufsize);
523 }
524#ifdef RTV_SPIPE
525 if ((bufsize = rt->rt_rmx.rmx_recvpipe) > 0) {
526#endif
527 bufsize = min(bufsize, so->so_rcv.sb_hiwat);
528 (void) sbreserve(&so->so_rcv, bufsize);
529 } else
530 bufsize = so->so_rcv.sb_hiwat;
531#ifdef RTV_SSTHRESH
532 /*
533 * There's some sort of gateway or interface
534 * buffer limit on the path. Use this to set
535 * the slow start threshhold, but set the
536 * threshold to no less than 2*mss.
537 */
538 ssthresh = rt->rt_rmx.rmx_ssthresh;
539punt_route:
540 /*
541 * The current mss is initialized to the default value.
542 * If we compute a smaller value, reduce the current mss.
543 * If we compute a larger value, return it for use in sending
544 * a max seg size option.
545 * If we received an offer, don't exceed it.
546 * However, do not accept offers under 128 bytes.
547 */
548 if (tpcb->tp_l_tpdusize)
549 mss = min(mss, tpcb->tp_l_tpdusize);
550 /*
551 * We want a minimum recv window of 4 packets to
552 * signal packet loss by duplicate acks.
553 */
554 mss = min(mss, bufsize >> 2) & ~0x7f;
555 mss = max(mss, 128); /* sanity */
556 tpcb->tp_cong_win =
557 (rt == 0 || (rt->rt_flags & RTF_GATEWAY)) ? mss : bufsize;
558 tpcb->tp_l_tpdusize = mss;
e900dd35 559 tp_rsyset(tpcb);
d696d41e
KS
560 tpcb->tp_ssthresh = max(2 * mss, ssthresh);
561 /* Calculate log2 of mss */
562 for (i = TP_MIN_TPDUSIZE + 1; i <= TP_MAX_TPDUSIZE; i++)
563 if ((1 << i) > mss)
564 break;
565 i--;
566 tpcb->tp_tpdusize = i;
567#endif /* RTV_MTU */
568}
3202a7cd
KS
569
570/*
571 * CALLED FROM:
572 * tp_usrreq on PRU_CONNECT and tp_input on receipt of CR
573 *
574 * FUNCTION and ARGUMENTS:
d696d41e
KS
575 * -- An mbuf containing the peer's network address.
576 * -- Our control block, which will be modified
577 * -- In the case of cons, a control block for that layer.
3202a7cd 578 *
3202a7cd
KS
579 *
580 * RETURNS:
581 * errno value :
582 * EAFNOSUPPORT if can't find an nl_protosw for x.25 (really could panic)
583 * ECONNREFUSED if trying to run TP0 with non-type 37 address
584 * possibly other E* returned from cons_netcmd()
d696d41e
KS
585 *
586 * SIDE EFFECTS:
587 * Determines recommended tpdusize, buffering and intial delays
588 * based on information cached on the route.
3202a7cd
KS
589 */
590int
591tp_route_to( m, tpcb, channel)
592 struct mbuf *m;
593 register struct tp_pcb *tpcb;
194a383a 594 caddr_t channel;
3202a7cd
KS
595{
596 register struct sockaddr_iso *siso; /* NOTE: this may be a sockaddr_in */
597 extern struct tp_conn_param tp_conn_param[];
01acbfa1
KS
598 int error = 0, save_netservice = tpcb->tp_netservice;
599 register struct rtentry *rt = 0;
d696d41e 600 int nhdr_size, mtu, bufsize;
3202a7cd
KS
601
602 siso = mtod(m, struct sockaddr_iso *);
603 IFTRACE(D_CONN)
604 tptraceTPCB(TPPTmisc,
605 "route_to: so afi netservice class",
a50e2bc0 606 tpcb->tp_sock, siso->siso_addr.isoa_genaddr[0], tpcb->tp_netservice,
3202a7cd
KS
607 tpcb->tp_class);
608 ENDTRACE
609 IFDEBUG(D_CONN)
610 printf("tp_route_to( m x%x, channel 0x%x, tpcb 0x%x netserv 0x%x)\n",
611 m, channel, tpcb, tpcb->tp_netservice);
612 printf("m->mlen x%x, m->m_data:\n", m->m_len);
613 dump_buf(mtod(m, caddr_t), m->m_len);
614 ENDDEBUG
01acbfa1 615 if (channel) {
194a383a 616#ifdef TPCONS
01acbfa1 617 struct pklcd *lcp = (struct pklcd *)channel;
194a383a 618 struct isopcb *isop = (struct isopcb *)lcp->lcd_upnext,
f15f73d2 619 *isop_new = (struct isopcb *)tpcb->tp_npcb;
01acbfa1
KS
620 /* The next 2 lines believe that you haven't
621 set any network level options or done a pcbconnect
622 and XXXXXXX'edly apply to both inpcb's and isopcb's */
194a383a
KS
623 remque(isop_new);
624 free(isop_new, M_PCB);
f15f73d2 625 tpcb->tp_npcb = (caddr_t)isop;
01acbfa1
KS
626 tpcb->tp_netservice = ISO_CONS;
627 tpcb->tp_nlproto = nl_protosw + ISO_CONS;
d696d41e 628 if (isop->isop_refcnt++ == 0) {
194a383a 629 iso_putsufx(isop, tpcb->tp_lsuffix, tpcb->tp_lsuffixlen, TP_LOCAL);
d696d41e
KS
630 isop->isop_socket = tpcb->tp_sock;
631 } else
01acbfa1 632 /* there are already connections sharing this */;
194a383a 633#endif
01acbfa1
KS
634 } else {
635 switch (siso->siso_family) {
636 default:
637 error = EAFNOSUPPORT;
638 goto done;
639#ifdef ISO
640 case AF_ISO:
d696d41e
KS
641 {
642 struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb;
643 int flags = tpcb->tp_sock->so_options & SO_DONTROUTE;
01acbfa1 644 tpcb->tp_netservice = ISO_CLNS;
d696d41e
KS
645 if (clnp_route(&siso->siso_addr, &isop->isop_route,
646 flags, (void **)0, (void **)0) == 0) {
647 rt = isop->isop_route.ro_rt;
648 if (rt && rt->rt_flags & RTF_PROTO1)
01acbfa1
KS
649 tpcb->tp_netservice = ISO_CONS;
650 }
d696d41e 651 } break;
01acbfa1
KS
652#endif
653#ifdef INET
654 case AF_INET:
655 tpcb->tp_netservice = IN_CLNS;
01acbfa1 656#endif
d696d41e 657 }
01acbfa1
KS
658 if (tpcb->tp_nlproto->nlp_afamily != siso->siso_family) {
659 IFDEBUG(D_CONN)
660 printf("tp_route_to( CHANGING nlproto old 0x%x new 0x%x)\n",
661 save_netservice, tpcb->tp_netservice);
662 ENDDEBUG
663 if (error = tp_set_npcb(tpcb))
664 goto done;
665 }
666 IFDEBUG(D_CONN)
667 printf("tp_route_to calling nlp_pcbconn, netserv %d\n",
668 tpcb->tp_netservice);
669 ENDDEBUG
670 tpcb->tp_nlproto = nl_protosw + tpcb->tp_netservice;
f15f73d2 671 error = (tpcb->tp_nlproto->nlp_pcbconn)(tpcb->tp_npcb, m);
01acbfa1 672 }
d696d41e 673 if (error)
3202a7cd 674 goto done;
d696d41e
KS
675 nhdr_size = tpcb->tp_nlproto->nlp_mtu(tpcb); /* only gets common info */
676 tp_mss(tpcb, nhdr_size);
3202a7cd
KS
677done:
678 IFDEBUG(D_CONN)
679 printf("tp_route_to returns 0x%x\n", error);
680 ENDDEBUG
681 IFTRACE(D_CONN)
682 tptraceTPCB(TPPTmisc, "route_to: returns: error netserv class", error,
683 tpcb->tp_netservice, tpcb->tp_class, 0);
684 ENDTRACE
685 return error;
686}
687
74d56f78
KS
688
689/* class zero version */
690void
691tp0_stash( tpcb, e )
692 register struct tp_pcb *tpcb;
693 register struct tp_event *e;
694{
695#ifndef lint
696#define E e->ATTR(DT_TPDU)
697#else lint
698#define E e->ev_union.EV_DT_TPDU
699#endif lint
700
701 register struct sockbuf *sb = &tpcb->tp_sock->so_rcv;
702 register struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb;
703
704 IFPERF(tpcb)
705 PStat(tpcb, Nb_from_ll) += E.e_datalen;
706 tpmeas(tpcb->tp_lref, TPtime_from_ll, &e->e_time,
707 E.e_seq, PStat(tpcb, Nb_from_ll), E.e_datalen);
708 ENDPERF
709
710 IFDEBUG(D_STASH)
711 printf("stash EQ: seq 0x%x datalen 0x%x eot 0x%x",
712 E.e_seq, E.e_datalen, E.e_eot);
713 ENDDEBUG
714
715 IFTRACE(D_STASH)
716 tptraceTPCB(TPPTmisc, "stash EQ: seq len eot",
717 E.e_seq, E.e_datalen, E.e_eot, 0);
718 ENDTRACE
719
720 if ( E.e_eot ) {
721 register struct mbuf *n = E.e_data;
722 n->m_flags |= M_EOR;
723 n->m_act = MNULL; /* set on tp_input */
724 }
725 sbappend(sb, E.e_data);
726 IFDEBUG(D_STASH)
727 dump_mbuf(sb->sb_mb, "stash 0: so_rcv after appending");
728 ENDDEBUG
729 if (tpcb->tp_netservice != ISO_CONS)
730 printf("tp0_stash: tp running over something wierd\n");
731 else {
732 register struct pklcd *lcp = (struct pklcd *)isop->isop_chan;
733 pk_flowcontrol(lcp, sbspace(sb) <= 0, 1);
734 }
735}
736
737void
738tp0_openflow(tpcb)
739register struct tp_pcb *tpcb;
740{
741 register struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb;
742 if (tpcb->tp_netservice != ISO_CONS)
743 printf("tp0_openflow: tp running over something wierd\n");
744 else {
745 register struct pklcd *lcp = (struct pklcd *)isop->isop_chan;
746 if (lcp->lcd_rxrnr_condition)
747 pk_flowcontrol(lcp, 0, 0);
748 }
749}
750#ifndef TPCONS
751static
752pk_flowcontrol() {}
753#endif
754
3202a7cd
KS
755#ifdef TP_PERF_MEAS
756/*
757 * CALLED FROM:
758 * tp_ctloutput() when the user sets TPOPT_PERF_MEAS on
759 * and tp_newsocket() when a new connection is made from
760 * a listening socket with tp_perf_on == true.
761 * FUNCTION and ARGUMENTS:
762 * (tpcb) is the usual; this procedure gets a clear cluster mbuf for
763 * a tp_pmeas structure, and makes tpcb->tp_p_meas point to it.
764 * RETURN VALUE:
765 * ENOBUFS if it cannot get a cluster mbuf.
766 */
767
768int
769tp_setup_perf(tpcb)
770 register struct tp_pcb *tpcb;
771{
772 register struct mbuf *q;
773
a50e2bc0
KS
774 if( tpcb->tp_p_meas == 0 ) {
775 MGET(q, M_WAITOK, MT_PCB);
3202a7cd
KS
776 if (q == 0)
777 return ENOBUFS;
a50e2bc0
KS
778 MCLGET(q, M_WAITOK);
779 if ((q->m_flags & M_EXT) == 0) {
780 (void) m_free(q);
3202a7cd 781 return ENOBUFS;
3202a7cd 782 }
a50e2bc0
KS
783 q->m_len = sizeof (struct tp_pmeas);
784 tpcb->tp_p_mbuf = q;
785 tpcb->tp_p_meas = mtod(q, struct tp_pmeas *);
786 bzero( (caddr_t)tpcb->tp_p_meas, sizeof (struct tp_pmeas) );
787 IFDEBUG(D_PERF_MEAS)
788 printf(
789 "tpcb 0x%x so 0x%x ref 0x%x tp_p_meas 0x%x tp_perf_on 0x%x\n",
790 tpcb, tpcb->tp_sock, tpcb->tp_lref,
791 tpcb->tp_p_meas, tpcb->tp_perf_on);
792 ENDDEBUG
793 tpcb->tp_perf_on = 1;
3202a7cd
KS
794 }
795 return 0;
796}
797#endif TP_PERF_MEAS
798
799#ifdef ARGO_DEBUG
800dump_addr (addr)
801 register struct sockaddr *addr;
802{
803 switch( addr->sa_family ) {
804 case AF_INET:
a50e2bc0 805 dump_inaddr((struct sockaddr_in *)addr);
3202a7cd 806 break;
a50e2bc0 807#ifdef ISO
3202a7cd 808 case AF_ISO:
a50e2bc0 809 dump_isoaddr((struct sockaddr_iso *)addr);
3202a7cd 810 break;
a50e2bc0 811#endif ISO
3202a7cd
KS
812 default:
813 printf("BAD AF: 0x%x\n", addr->sa_family);
814 break;
815 }
816}
817
a50e2bc0
KS
818#define MAX_COLUMNS 8
819/*
820 * Dump the buffer to the screen in a readable format. Format is:
821 *
822 * hex/dec where hex is the hex format, dec is the decimal format.
823 * columns of hex/dec numbers will be printed, followed by the
824 * character representations (if printable).
825 */
826Dump_buf(buf, len)
827caddr_t buf;
828int len;
829{
830 int i,j;
67857e5a 831#define Buf ((u_char *)buf)
a50e2bc0
KS
832 printf("Dump buf 0x%x len 0x%x\n", buf, len);
833 for (i = 0; i < len; i += MAX_COLUMNS) {
834 printf("+%d:\t", i);
835 for (j = 0; j < MAX_COLUMNS; j++) {
836 if (i + j < len) {
67857e5a 837 printf("%x/%d\t", Buf[i+j], Buf[i+j]);
a50e2bc0
KS
838 } else {
839 printf(" ");
840 }
841 }
842
843 for (j = 0; j < MAX_COLUMNS; j++) {
844 if (i + j < len) {
67857e5a
KS
845 if (((Buf[i+j]) > 31) && ((Buf[i+j]) < 128))
846 printf("%c", Buf[i+j]);
a50e2bc0
KS
847 else
848 printf(".");
849 }
850 }
851 printf("\n");
852 }
853}
854
855
3202a7cd
KS
856#endif ARGO_DEBUG
857