add _SSIZE_T_
[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 *
d696d41e 7 * @(#)tp_subr2.c 7.17 (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
55#include "param.h"
b7f6af29 56#include "systm.h"
3202a7cd
KS
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
a50e2bc0
KS
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"
3202a7cd 81
194a383a 82#include "../net/if.h"
01acbfa1 83#include "../net/if_types.h"
194a383a
KS
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
3202a7cd
KS
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 */
112void
113tp_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",
378ea02c 119 tpcb->tp_lref,
3202a7cd
KS
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 */
150int
151tp_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 */
166ProtoHook
167tp_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 */
193void
194tp_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)
9aed0596
KS
201 tptraceTPCB(TPPTindicate, ind, *(u_short *)(tpcb->tp_lsuffix),
202 *(u_short *)(tpcb->tp_fsuffix), error,so->so_pgid);
3202a7cd
KS
203 ENDTRACE
204 IFDEBUG(D_INDICATION)
a50e2bc0 205 char *ls, *fs;
3202a7cd
KS
206 ls = tpcb->tp_lsuffix,
207 fs = tpcb->tp_fsuffix,
208
209 printf(
a50e2bc0 210"indicate 0x%x lsuf 0x%02x%02x fsuf 0x%02x%02x err 0x%x noind 0x%x ref 0x%x\n",
3202a7cd
KS
211 ind,
212 *ls, *(ls+1), *fs, *(fs+1),
a50e2bc0 213 error, /*so->so_pgrp,*/
3202a7cd
KS
214 tpcb->tp_no_disc_indications,
215 tpcb->tp_lref);
216 ENDDEBUG
217
6726a5f3
KS
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 }
3202a7cd
KS
235 so->so_error = error;
236
237 if (ind == T_DISCONNECT) {
05b32603
KS
238 if (error == 0)
239 so->so_error = ENOTCONN;
3202a7cd
KS
240 if ( tpcb->tp_no_disc_indications )
241 return;
242 }
243 IFTRACE(D_INDICATION)
244 tptraceTPCB(TPPTmisc, "doing sohasoutofband(so)", so,0,0,0);
245 ENDTRACE
246 sohasoutofband(so);
247}
248
249/*
250 * NAME : tp_getoptions()
251 *
252 * CALLED FROM:
253 * tp.trans whenever we go into OPEN state
254 *
255 * FUNCTION and ARGUMENTS:
256 * sets the proper flags and values in the tpcb, to control
257 * the appropriate actions for the given class, options,
258 * sequence space, etc, etc.
259 *
260 * RETURNS: Nada
261 *
262 * SIDE EFFECTS:
263 *
264 * NOTES:
265 */
266void
267tp_getoptions(tpcb)
268struct tp_pcb *tpcb;
269{
270 tpcb->tp_seqmask =
271 tpcb->tp_xtd_format ? TP_XTD_FMT_MASK : TP_NML_FMT_MASK ;
272 tpcb->tp_seqbit =
273 tpcb->tp_xtd_format ? TP_XTD_FMT_BIT : TP_NML_FMT_BIT ;
274 tpcb->tp_seqhalf = tpcb->tp_seqbit >> 1;
275 tpcb->tp_dt_ticks =
276 MAX(tpcb->tp_dt_ticks, (tpcb->tp_peer_acktime + 2));
7893315b
KS
277 (void) tp_rsyset(tpcb);
278
3202a7cd
KS
279}
280
281/*
282 * NAME: tp_recycle_tsuffix()
283 *
284 * CALLED FROM:
285 * Called when a ref is frozen.
286 *
287 * FUNCTION and ARGUMENTS:
288 * allows the suffix to be reused.
289 *
290 * RETURNS: zilch
291 *
292 * SIDE EFFECTS:
293 *
294 * NOTES:
295 */
296void
297tp_recycle_tsuffix(tpcb)
298 struct tp_pcb *tpcb;
299{
a50e2bc0
KS
300 bzero((caddr_t)tpcb->tp_lsuffix, sizeof( tpcb->tp_lsuffix));
301 bzero((caddr_t)tpcb->tp_fsuffix, sizeof( tpcb->tp_fsuffix));
3202a7cd
KS
302 tpcb->tp_fsuffixlen = tpcb->tp_lsuffixlen = 0;
303
304 (tpcb->tp_nlproto->nlp_recycle_suffix)(tpcb->tp_npcb);
305}
306
307/*
308 * NAME: tp_quench()
309 *
310 * CALLED FROM:
311 * tp{af}_quench() when ICMP source quench or similar thing arrives.
312 *
313 * FUNCTION and ARGUMENTS:
314 * Drop the congestion window back to 1.
315 * Congestion window scheme:
316 * Initial value is 1. ("slow start" as Nagle, et. al. call it)
317 * For each good ack that arrives, the congestion window is increased
318 * by 1 (up to max size of logical infinity, which is to say,
319 * it doesn't wrap around).
320 * Source quench causes it to drop back to 1.
321 * tp_send() uses the smaller of (regular window, congestion window).
322 * One retransmission strategy option is to have any retransmission
323 * cause reset the congestion window back to 1.
324 *
325 * (cmd) is either PRC_QUENCH: source quench, or
326 * PRC_QUENCH2: dest. quench (dec bit)
327 *
328 * RETURNS:
329 *
330 * SIDE EFFECTS:
331 *
332 * NOTES:
333 */
334void
335tp_quench( tpcb, cmd )
336 struct tp_pcb *tpcb;
337 int cmd;
338{
339 IFDEBUG(D_QUENCH)
340 printf("tp_quench tpcb 0x%x ref 0x%x sufx 0x%x\n",
9aed0596 341 tpcb, tpcb->tp_lref, *(u_short *)(tpcb->tp_lsuffix));
3202a7cd
KS
342 printf("cong_win 0x%x decbit 0x%x \n",
343 tpcb->tp_cong_win, tpcb->tp_decbit);
344 ENDDEBUG
345 switch(cmd) {
346 case PRC_QUENCH:
bdf41b09 347 tpcb->tp_cong_win = tpcb->tp_l_tpdusize;
3202a7cd
KS
348 IncStat(ts_quench);
349 break;
350 case PRC_QUENCH2:
bdf41b09 351 tpcb->tp_cong_win = tpcb->tp_l_tpdusize; /* might as well quench source also */
3202a7cd
KS
352 tpcb->tp_decbit = TP_DECBIT_CLEAR_COUNT;
353 IncStat(ts_rcvdecbit);
354 break;
355 }
356}
357
358
359/*
360 * NAME: tp_netcmd()
361 *
362 * CALLED FROM:
363 *
364 * FUNCTION and ARGUMENTS:
365 *
366 * RETURNS:
367 *
368 * SIDE EFFECTS:
369 *
370 * NOTES:
371 */
372tp_netcmd( tpcb, cmd )
373 struct tp_pcb *tpcb;
374 int cmd;
375{
194a383a
KS
376#ifdef TPCONS
377 struct isopcb *isop;
378 struct pklcd *lcp;
379
380 if (tpcb->tp_netservice != ISO_CONS)
381 return;
382 isop = (struct isopcb *)tpcb->tp_npcb;
383 lcp = (struct pklcd *)isop->isop_chan;
3202a7cd
KS
384 switch (cmd) {
385
386 case CONN_CLOSE:
387 case CONN_REFUSE:
01acbfa1
KS
388 if (isop->isop_refcnt == 1) {
389 /* This is really superfluous, since it would happen
390 anyway in iso_pcbdetach, although it is a courtesy
391 to free up the x.25 channel before the refwait timer
392 expires. */
393 lcp->lcd_upper = 0;
394 lcp->lcd_upnext = 0;
194a383a 395 pk_disconnect(lcp);
01acbfa1
KS
396 isop->isop_chan = 0;
397 isop->isop_refcnt = 0;
398 }
3202a7cd
KS
399 break;
400
401 default:
402 printf("tp_netcmd(0x%x, 0x%x) NOT IMPLEMENTED\n", tpcb, cmd);
403 break;
404 }
194a383a 405#else TPCONS
3202a7cd 406 printf("tp_netcmd(): X25 NOT CONFIGURED!!\n");
194a383a 407#endif
3202a7cd
KS
408}
409/*
410 * CALLED FROM:
411 * tp_ctloutput() and tp_emit()
412 * FUNCTION and ARGUMENTS:
413 * Convert a class mask to the highest numeric value it represents.
414 */
415
416int
417tp_mask_to_num(x)
418 u_char x;
419{
420 register int j;
421
422 for(j = 4; j>=0 ;j--) {
423 if(x & (1<<j))
424 break;
425 }
426 ASSERT( (j == 4) || (j == 0) ); /* for now */
427 if( (j != 4) && (j != 0) ) {
428 printf("ASSERTION ERROR: tp_mask_to_num: x 0x%x j %d\n",
429 x, j);
430 }
431 IFTRACE(D_TPINPUT)
432 tptrace(TPPTmisc, "tp_mask_to_num(x) returns j", x, j, 0, 0);
433 ENDTRACE
434 IFDEBUG(D_TPINPUT)
435 printf("tp_mask_to_num(0x%x) returns 0x%x\n", x, j);
436 ENDDEBUG
437 return j;
438}
439
440static
441copyQOSparms(src, dst)
442 struct tp_conn_param *src, *dst;
443{
444 /* copy all but the bits stuff at the end */
445#define COPYSIZE (12 * sizeof(short))
446
a50e2bc0 447 bcopy((caddr_t)src, (caddr_t)dst, COPYSIZE);
3202a7cd
KS
448 dst->p_tpdusize = src->p_tpdusize;
449 dst->p_ack_strat = src->p_ack_strat;
450 dst->p_rx_strat = src->p_rx_strat;
451#undef COPYSIZE
452}
d696d41e
KS
453/*
454 * Determine a reasonable value for maxseg size.
455 * If the route is known, check route for mtu.
456 * We also initialize the congestion/slow start
457 * window to be a single segment if the destination isn't local.
458 * While looking at the routing entry, we also initialize other path-dependent
459 * parameters from pre-set or cached values in the routing entry.
460 */
461void
462tp_mss(tpcb, nhdr_size)
463 register struct tp_pcb *tpcb;
464 int nhdr_size;
465{
466 register struct rtentry *rt;
467 struct ifnet *ifp;
468 register int rtt, mss;
469 u_long bufsize;
470 int i, ssthresh = 0;
471 struct socket *so;
472
473 mss = 1 << tpcb->tp_tpdusize;
474 so = tpcb->tp_sock;
475 if ((rt = *(tpcb->tp_routep)) == 0) {
476 bufsize = so->so_rcv.sb_hiwat;
477 goto punt_route;
478 }
479 ifp = rt->rt_ifp;
480
481#ifdef RTV_MTU /* if route characteristics exist ... */
482 /*
483 * While we're here, check if there's an initial rtt
484 * or rttvar. Convert from the route-table units
485 * to hz ticks for the smoothed timers and slow-timeout units
486 * for other inital variables.
487 */
488 if (tpcb->tp_rtt == 0 && (rtt = rt->rt_rmx.rmx_rtt)) {
489 tpcb->tp_rtt = rtt * hz / RTM_RTTUNIT;
490 if (rt->rt_rmx.rmx_rttvar)
491 tpcb->tp_rtv = rt->rt_rmx.rmx_rttvar
492 * hz / RTM_RTTUNIT;
493 else
494 tpcb->tp_rtv = tpcb->tp_rtt;
495 }
496 /*
497 * if there's an mtu associated with the route, use it
498 */
499 if (rt->rt_rmx.rmx_mtu)
500 mss = rt->rt_rmx.rmx_mtu - nhdr_size;
501 else
502#endif /* RTV_MTU */
503 mss = (ifp->if_mtu - nhdr_size);
504 /* can propose mtu which are multiples of 128 */
505 mss &= ~0x7f;
506 /*
507 * If there's a pipesize, change the socket buffer
508 * to that size.
509 */
510#ifdef RTV_SPIPE
511 if ((bufsize = rt->rt_rmx.rmx_sendpipe) > 0) {
512#endif
513 bufsize = min(bufsize, so->so_snd.sb_hiwat);
514 (void) sbreserve(&so->so_snd, bufsize);
515 }
516#ifdef RTV_SPIPE
517 if ((bufsize = rt->rt_rmx.rmx_recvpipe) > 0) {
518#endif
519 bufsize = min(bufsize, so->so_rcv.sb_hiwat);
520 (void) sbreserve(&so->so_rcv, bufsize);
521 } else
522 bufsize = so->so_rcv.sb_hiwat;
523#ifdef RTV_SSTHRESH
524 /*
525 * There's some sort of gateway or interface
526 * buffer limit on the path. Use this to set
527 * the slow start threshhold, but set the
528 * threshold to no less than 2*mss.
529 */
530 ssthresh = rt->rt_rmx.rmx_ssthresh;
531punt_route:
532 /*
533 * The current mss is initialized to the default value.
534 * If we compute a smaller value, reduce the current mss.
535 * If we compute a larger value, return it for use in sending
536 * a max seg size option.
537 * If we received an offer, don't exceed it.
538 * However, do not accept offers under 128 bytes.
539 */
540 if (tpcb->tp_l_tpdusize)
541 mss = min(mss, tpcb->tp_l_tpdusize);
542 /*
543 * We want a minimum recv window of 4 packets to
544 * signal packet loss by duplicate acks.
545 */
546 mss = min(mss, bufsize >> 2) & ~0x7f;
547 mss = max(mss, 128); /* sanity */
548 tpcb->tp_cong_win =
549 (rt == 0 || (rt->rt_flags & RTF_GATEWAY)) ? mss : bufsize;
550 tpcb->tp_l_tpdusize = mss;
551 tpcb->tp_ssthresh = max(2 * mss, ssthresh);
552 /* Calculate log2 of mss */
553 for (i = TP_MIN_TPDUSIZE + 1; i <= TP_MAX_TPDUSIZE; i++)
554 if ((1 << i) > mss)
555 break;
556 i--;
557 tpcb->tp_tpdusize = i;
558#endif /* RTV_MTU */
559}
3202a7cd
KS
560
561/*
562 * CALLED FROM:
563 * tp_usrreq on PRU_CONNECT and tp_input on receipt of CR
564 *
565 * FUNCTION and ARGUMENTS:
d696d41e
KS
566 * -- An mbuf containing the peer's network address.
567 * -- Our control block, which will be modified
568 * -- In the case of cons, a control block for that layer.
3202a7cd 569 *
3202a7cd
KS
570 *
571 * RETURNS:
572 * errno value :
573 * EAFNOSUPPORT if can't find an nl_protosw for x.25 (really could panic)
574 * ECONNREFUSED if trying to run TP0 with non-type 37 address
575 * possibly other E* returned from cons_netcmd()
d696d41e
KS
576 *
577 * SIDE EFFECTS:
578 * Determines recommended tpdusize, buffering and intial delays
579 * based on information cached on the route.
3202a7cd
KS
580 */
581int
582tp_route_to( m, tpcb, channel)
583 struct mbuf *m;
584 register struct tp_pcb *tpcb;
194a383a 585 caddr_t channel;
3202a7cd
KS
586{
587 register struct sockaddr_iso *siso; /* NOTE: this may be a sockaddr_in */
588 extern struct tp_conn_param tp_conn_param[];
01acbfa1
KS
589 int error = 0, save_netservice = tpcb->tp_netservice;
590 register struct rtentry *rt = 0;
d696d41e 591 int nhdr_size, mtu, bufsize;
3202a7cd
KS
592
593 siso = mtod(m, struct sockaddr_iso *);
594 IFTRACE(D_CONN)
595 tptraceTPCB(TPPTmisc,
596 "route_to: so afi netservice class",
a50e2bc0 597 tpcb->tp_sock, siso->siso_addr.isoa_genaddr[0], tpcb->tp_netservice,
3202a7cd
KS
598 tpcb->tp_class);
599 ENDTRACE
600 IFDEBUG(D_CONN)
601 printf("tp_route_to( m x%x, channel 0x%x, tpcb 0x%x netserv 0x%x)\n",
602 m, channel, tpcb, tpcb->tp_netservice);
603 printf("m->mlen x%x, m->m_data:\n", m->m_len);
604 dump_buf(mtod(m, caddr_t), m->m_len);
605 ENDDEBUG
01acbfa1 606 if (channel) {
194a383a 607#ifdef TPCONS
01acbfa1 608 struct pklcd *lcp = (struct pklcd *)channel;
194a383a 609 struct isopcb *isop = (struct isopcb *)lcp->lcd_upnext,
f15f73d2 610 *isop_new = (struct isopcb *)tpcb->tp_npcb;
01acbfa1
KS
611 /* The next 2 lines believe that you haven't
612 set any network level options or done a pcbconnect
613 and XXXXXXX'edly apply to both inpcb's and isopcb's */
194a383a
KS
614 remque(isop_new);
615 free(isop_new, M_PCB);
f15f73d2 616 tpcb->tp_npcb = (caddr_t)isop;
01acbfa1
KS
617 tpcb->tp_netservice = ISO_CONS;
618 tpcb->tp_nlproto = nl_protosw + ISO_CONS;
d696d41e 619 if (isop->isop_refcnt++ == 0) {
194a383a 620 iso_putsufx(isop, tpcb->tp_lsuffix, tpcb->tp_lsuffixlen, TP_LOCAL);
d696d41e
KS
621 isop->isop_socket = tpcb->tp_sock;
622 } else
01acbfa1 623 /* there are already connections sharing this */;
194a383a 624#endif
01acbfa1
KS
625 } else {
626 switch (siso->siso_family) {
627 default:
628 error = EAFNOSUPPORT;
629 goto done;
630#ifdef ISO
631 case AF_ISO:
d696d41e
KS
632 {
633 struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb;
634 int flags = tpcb->tp_sock->so_options & SO_DONTROUTE;
01acbfa1 635 tpcb->tp_netservice = ISO_CLNS;
d696d41e
KS
636 if (clnp_route(&siso->siso_addr, &isop->isop_route,
637 flags, (void **)0, (void **)0) == 0) {
638 rt = isop->isop_route.ro_rt;
639 if (rt && rt->rt_flags & RTF_PROTO1)
01acbfa1
KS
640 tpcb->tp_netservice = ISO_CONS;
641 }
d696d41e 642 } break;
01acbfa1
KS
643#endif
644#ifdef INET
645 case AF_INET:
646 tpcb->tp_netservice = IN_CLNS;
01acbfa1 647#endif
d696d41e 648 }
01acbfa1
KS
649 if (tpcb->tp_nlproto->nlp_afamily != siso->siso_family) {
650 IFDEBUG(D_CONN)
651 printf("tp_route_to( CHANGING nlproto old 0x%x new 0x%x)\n",
652 save_netservice, tpcb->tp_netservice);
653 ENDDEBUG
654 if (error = tp_set_npcb(tpcb))
655 goto done;
656 }
657 IFDEBUG(D_CONN)
658 printf("tp_route_to calling nlp_pcbconn, netserv %d\n",
659 tpcb->tp_netservice);
660 ENDDEBUG
661 tpcb->tp_nlproto = nl_protosw + tpcb->tp_netservice;
f15f73d2 662 error = (tpcb->tp_nlproto->nlp_pcbconn)(tpcb->tp_npcb, m);
01acbfa1 663 }
d696d41e 664 if (error)
3202a7cd 665 goto done;
d696d41e
KS
666 nhdr_size = tpcb->tp_nlproto->nlp_mtu(tpcb); /* only gets common info */
667 tp_mss(tpcb, nhdr_size);
3202a7cd
KS
668done:
669 IFDEBUG(D_CONN)
670 printf("tp_route_to returns 0x%x\n", error);
671 ENDDEBUG
672 IFTRACE(D_CONN)
673 tptraceTPCB(TPPTmisc, "route_to: returns: error netserv class", error,
674 tpcb->tp_netservice, tpcb->tp_class, 0);
675 ENDTRACE
676 return error;
677}
678
74d56f78
KS
679
680/* class zero version */
681void
682tp0_stash( tpcb, e )
683 register struct tp_pcb *tpcb;
684 register struct tp_event *e;
685{
686#ifndef lint
687#define E e->ATTR(DT_TPDU)
688#else lint
689#define E e->ev_union.EV_DT_TPDU
690#endif lint
691
692 register struct sockbuf *sb = &tpcb->tp_sock->so_rcv;
693 register struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb;
694
695 IFPERF(tpcb)
696 PStat(tpcb, Nb_from_ll) += E.e_datalen;
697 tpmeas(tpcb->tp_lref, TPtime_from_ll, &e->e_time,
698 E.e_seq, PStat(tpcb, Nb_from_ll), E.e_datalen);
699 ENDPERF
700
701 IFDEBUG(D_STASH)
702 printf("stash EQ: seq 0x%x datalen 0x%x eot 0x%x",
703 E.e_seq, E.e_datalen, E.e_eot);
704 ENDDEBUG
705
706 IFTRACE(D_STASH)
707 tptraceTPCB(TPPTmisc, "stash EQ: seq len eot",
708 E.e_seq, E.e_datalen, E.e_eot, 0);
709 ENDTRACE
710
711 if ( E.e_eot ) {
712 register struct mbuf *n = E.e_data;
713 n->m_flags |= M_EOR;
714 n->m_act = MNULL; /* set on tp_input */
715 }
716 sbappend(sb, E.e_data);
717 IFDEBUG(D_STASH)
718 dump_mbuf(sb->sb_mb, "stash 0: so_rcv after appending");
719 ENDDEBUG
720 if (tpcb->tp_netservice != ISO_CONS)
721 printf("tp0_stash: tp running over something wierd\n");
722 else {
723 register struct pklcd *lcp = (struct pklcd *)isop->isop_chan;
724 pk_flowcontrol(lcp, sbspace(sb) <= 0, 1);
725 }
726}
727
728void
729tp0_openflow(tpcb)
730register struct tp_pcb *tpcb;
731{
732 register struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb;
733 if (tpcb->tp_netservice != ISO_CONS)
734 printf("tp0_openflow: tp running over something wierd\n");
735 else {
736 register struct pklcd *lcp = (struct pklcd *)isop->isop_chan;
737 if (lcp->lcd_rxrnr_condition)
738 pk_flowcontrol(lcp, 0, 0);
739 }
740}
741#ifndef TPCONS
742static
743pk_flowcontrol() {}
744#endif
745
3202a7cd
KS
746#ifdef TP_PERF_MEAS
747/*
748 * CALLED FROM:
749 * tp_ctloutput() when the user sets TPOPT_PERF_MEAS on
750 * and tp_newsocket() when a new connection is made from
751 * a listening socket with tp_perf_on == true.
752 * FUNCTION and ARGUMENTS:
753 * (tpcb) is the usual; this procedure gets a clear cluster mbuf for
754 * a tp_pmeas structure, and makes tpcb->tp_p_meas point to it.
755 * RETURN VALUE:
756 * ENOBUFS if it cannot get a cluster mbuf.
757 */
758
759int
760tp_setup_perf(tpcb)
761 register struct tp_pcb *tpcb;
762{
763 register struct mbuf *q;
764
a50e2bc0
KS
765 if( tpcb->tp_p_meas == 0 ) {
766 MGET(q, M_WAITOK, MT_PCB);
3202a7cd
KS
767 if (q == 0)
768 return ENOBUFS;
a50e2bc0
KS
769 MCLGET(q, M_WAITOK);
770 if ((q->m_flags & M_EXT) == 0) {
771 (void) m_free(q);
3202a7cd 772 return ENOBUFS;
3202a7cd 773 }
a50e2bc0
KS
774 q->m_len = sizeof (struct tp_pmeas);
775 tpcb->tp_p_mbuf = q;
776 tpcb->tp_p_meas = mtod(q, struct tp_pmeas *);
777 bzero( (caddr_t)tpcb->tp_p_meas, sizeof (struct tp_pmeas) );
778 IFDEBUG(D_PERF_MEAS)
779 printf(
780 "tpcb 0x%x so 0x%x ref 0x%x tp_p_meas 0x%x tp_perf_on 0x%x\n",
781 tpcb, tpcb->tp_sock, tpcb->tp_lref,
782 tpcb->tp_p_meas, tpcb->tp_perf_on);
783 ENDDEBUG
784 tpcb->tp_perf_on = 1;
3202a7cd
KS
785 }
786 return 0;
787}
788#endif TP_PERF_MEAS
789
790#ifdef ARGO_DEBUG
791dump_addr (addr)
792 register struct sockaddr *addr;
793{
794 switch( addr->sa_family ) {
795 case AF_INET:
a50e2bc0 796 dump_inaddr((struct sockaddr_in *)addr);
3202a7cd 797 break;
a50e2bc0 798#ifdef ISO
3202a7cd 799 case AF_ISO:
a50e2bc0 800 dump_isoaddr((struct sockaddr_iso *)addr);
3202a7cd 801 break;
a50e2bc0 802#endif ISO
3202a7cd
KS
803 default:
804 printf("BAD AF: 0x%x\n", addr->sa_family);
805 break;
806 }
807}
808
a50e2bc0
KS
809#define MAX_COLUMNS 8
810/*
811 * Dump the buffer to the screen in a readable format. Format is:
812 *
813 * hex/dec where hex is the hex format, dec is the decimal format.
814 * columns of hex/dec numbers will be printed, followed by the
815 * character representations (if printable).
816 */
817Dump_buf(buf, len)
818caddr_t buf;
819int len;
820{
821 int i,j;
67857e5a 822#define Buf ((u_char *)buf)
a50e2bc0
KS
823 printf("Dump buf 0x%x len 0x%x\n", buf, len);
824 for (i = 0; i < len; i += MAX_COLUMNS) {
825 printf("+%d:\t", i);
826 for (j = 0; j < MAX_COLUMNS; j++) {
827 if (i + j < len) {
67857e5a 828 printf("%x/%d\t", Buf[i+j], Buf[i+j]);
a50e2bc0
KS
829 } else {
830 printf(" ");
831 }
832 }
833
834 for (j = 0; j < MAX_COLUMNS; j++) {
835 if (i + j < len) {
67857e5a
KS
836 if (((Buf[i+j]) > 31) && ((Buf[i+j]) < 128))
837 printf("%c", Buf[i+j]);
a50e2bc0
KS
838 else
839 printf(".");
840 }
841 }
842 printf("\n");
843 }
844}
845
846
3202a7cd
KS
847#endif ARGO_DEBUG
848