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