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