149268Sbostic /*-
263222Sbostic * Copyright (c) 1991, 1993
363222Sbostic * The Regents of the University of California. All rights reserved.
449268Sbostic *
549268Sbostic * %sccs.include.redist.c%
649268Sbostic *
7*67779Ssklower * @(#)tp_iso.c 8.2 (Berkeley) 09/22/94
849268Sbostic */
949268Sbostic
1036403Ssklower /***********************************************************
1136403Ssklower Copyright IBM Corporation 1987
1236403Ssklower
1336403Ssklower All Rights Reserved
1436403Ssklower
1536403Ssklower Permission to use, copy, modify, and distribute this software and its
1636403Ssklower documentation for any purpose and without fee is hereby granted,
1736403Ssklower provided that the above copyright notice appear in all copies and that
1836403Ssklower both that copyright notice and this permission notice appear in
1936403Ssklower supporting documentation, and that the name of IBM not be
2036403Ssklower used in advertising or publicity pertaining to distribution of the
2136403Ssklower software without specific, written prior permission.
2236403Ssklower
2336403Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
2436403Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
2536403Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
2636403Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
2736403Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
2836403Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2936403Ssklower SOFTWARE.
3036403Ssklower
3136403Ssklower ******************************************************************/
3236403Ssklower
3336403Ssklower /*
3436403Ssklower * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
3536403Ssklower */
3636403Ssklower /*
3736403Ssklower * ARGO TP
3837469Ssklower * $Header: /var/src/sys/netiso/RCS/tp_iso.c,v 5.1 89/02/09 16:20:51 hagens Exp $
3937469Ssklower * $Source: /var/src/sys/netiso/RCS/tp_iso.c,v $
4036403Ssklower *
4136403Ssklower * Here is where you find the iso-dependent code. We've tried
4236403Ssklower * keep all net-level and (primarily) address-family-dependent stuff
4336403Ssklower * out of the tp source, and everthing here is reached indirectly
4436403Ssklower * through a switch table (struct nl_protosw *) tpcb->tp_nlproto
4536403Ssklower * (see tp_pcb.c).
4636403Ssklower * The routines here are:
4736403Ssklower * iso_getsufx: gets transport suffix out of an isopcb structure.
4836403Ssklower * iso_putsufx: put transport suffix into an isopcb structure.
4936403Ssklower * iso_putnetaddr: put a whole net addr into an isopcb.
5036403Ssklower * iso_getnetaddr: get a whole net addr from an isopcb.
5144422Ssklower * iso_cmpnetaddr: compare a whole net addr from an isopcb.
5236403Ssklower * iso_recycle_suffix: clear suffix for reuse in isopcb
5336403Ssklower * tpclnp_ctlinput: handle ER CNLPdu : icmp-like stuff
5436403Ssklower * tpclnp_mtu: figure out what size tpdu to use
5536403Ssklower * tpclnp_input: take a pkt from clnp, strip off its clnp header,
5636403Ssklower * give to tp
5736403Ssklower * tpclnp_output_dg: package a pkt for clnp given 2 addresses & some data
5836403Ssklower * tpclnp_output: package a pkt for clnp given an isopcb & some data
5936403Ssklower */
6036403Ssklower
6136403Ssklower #ifdef ISO
6236403Ssklower
6356533Sbostic #include <sys/param.h>
6456533Sbostic #include <sys/socket.h>
6556533Sbostic #include <sys/socketvar.h>
6656533Sbostic #include <sys/domain.h>
6756533Sbostic #include <sys/malloc.h>
6856533Sbostic #include <sys/mbuf.h>
6956533Sbostic #include <sys/errno.h>
7056533Sbostic #include <sys/time.h>
7156533Sbostic #include <sys/protosw.h>
72*67779Ssklower #include <sys/kernel.h>
7337469Ssklower
7456533Sbostic #include <net/if.h>
7556533Sbostic #include <net/route.h>
7636403Ssklower
7756533Sbostic #include <netiso/argo_debug.h>
7856533Sbostic #include <netiso/tp_param.h>
7956533Sbostic #include <netiso/tp_stat.h>
8056533Sbostic #include <netiso/tp_pcb.h>
8156533Sbostic #include <netiso/tp_trace.h>
8256533Sbostic #include <netiso/tp_stat.h>
8356533Sbostic #include <netiso/tp_tpdu.h>
8456533Sbostic #include <netiso/tp_clnp.h>
8556533Sbostic #include <netiso/cltp_var.h>
8636403Ssklower
8736403Ssklower /*
8836403Ssklower * CALLED FROM:
8936403Ssklower * pr_usrreq() on PRU_BIND, PRU_CONNECT, PRU_ACCEPT, and PRU_PEERADDR
9037469Ssklower * FUNCTION, ARGUMENTS:
9136403Ssklower * The argument (which) takes the value TP_LOCAL or TP_FOREIGN.
9236403Ssklower */
9336403Ssklower
9437469Ssklower iso_getsufx(isop, lenp, data_out, which)
9536403Ssklower struct isopcb *isop;
9637469Ssklower u_short *lenp;
9737469Ssklower caddr_t data_out;
9836403Ssklower int which;
9936403Ssklower {
10037469Ssklower register struct sockaddr_iso *addr = 0;
10137469Ssklower
10236403Ssklower switch (which) {
10336403Ssklower case TP_LOCAL:
10437469Ssklower addr = isop->isop_laddr;
10537469Ssklower break;
10636403Ssklower
10736403Ssklower case TP_FOREIGN:
10837469Ssklower addr = isop->isop_faddr;
10936403Ssklower }
11037469Ssklower if (addr)
11138841Ssklower bcopy(TSEL(addr), data_out, (*lenp = addr->siso_tlen));
11236403Ssklower }
11336403Ssklower
11436403Ssklower /* CALLED FROM:
11536403Ssklower * tp_newsocket(); i.e., when a connection is being established by an
11636403Ssklower * incoming CR_TPDU.
11736403Ssklower *
11836403Ssklower * FUNCTION, ARGUMENTS:
11936403Ssklower * Put a transport suffix (found in name) into an isopcb structure (isop).
12036403Ssklower * The argument (which) takes the value TP_LOCAL or TP_FOREIGN.
12136403Ssklower */
12236403Ssklower void
iso_putsufx(isop,sufxloc,sufxlen,which)12337469Ssklower iso_putsufx(isop, sufxloc, sufxlen, which)
12436403Ssklower struct isopcb *isop;
12537469Ssklower caddr_t sufxloc;
12637469Ssklower int sufxlen, which;
12736403Ssklower {
12837469Ssklower struct sockaddr_iso **dst, *backup;
12937469Ssklower register struct sockaddr_iso *addr;
13037469Ssklower struct mbuf *m;
13137469Ssklower int len;
13237469Ssklower
13336403Ssklower switch (which) {
13437469Ssklower default:
13537469Ssklower return;
13637469Ssklower
13736403Ssklower case TP_LOCAL:
13837469Ssklower dst = &isop->isop_laddr;
13937469Ssklower backup = &isop->isop_sladdr;
14036403Ssklower break;
14137469Ssklower
14236403Ssklower case TP_FOREIGN:
14337469Ssklower dst = &isop->isop_faddr;
14437469Ssklower backup = &isop->isop_sfaddr;
14536403Ssklower }
14637469Ssklower if ((addr = *dst) == 0) {
14737469Ssklower addr = *dst = backup;
14837469Ssklower addr->siso_nlen = 0;
14938841Ssklower addr->siso_slen = 0;
15038841Ssklower addr->siso_plen = 0;
15137469Ssklower printf("iso_putsufx on un-initialized isopcb\n");
15237469Ssklower }
15337469Ssklower len = sufxlen + addr->siso_nlen +
15438841Ssklower (sizeof(*addr) - sizeof(addr->siso_data));
15537469Ssklower if (addr == backup) {
15638841Ssklower if (len > sizeof(*addr)) {
15737469Ssklower m = m_getclr(M_DONTWAIT, MT_SONAME);
15837469Ssklower if (m == 0)
15937469Ssklower return;
16037469Ssklower addr = *dst = mtod(m, struct sockaddr_iso *);
16137469Ssklower *addr = *backup;
16237469Ssklower m->m_len = len;
16337469Ssklower }
16438841Ssklower }
16537469Ssklower bcopy(sufxloc, TSEL(addr), sufxlen);
16638841Ssklower addr->siso_tlen = sufxlen;
16737469Ssklower addr->siso_len = len;
16836403Ssklower }
16936403Ssklower
17036403Ssklower /*
17136403Ssklower * CALLED FROM:
17236403Ssklower * tp.trans whenever we go into REFWAIT state.
17336403Ssklower * FUNCTION and ARGUMENT:
17436403Ssklower * Called when a ref is frozen, to allow the suffix to be reused.
17536403Ssklower * (isop) is the net level pcb. This really shouldn't have to be
17636403Ssklower * done in a NET level pcb but... for the internet world that just
17736403Ssklower * the way it is done in BSD...
17836403Ssklower * The alternative is to have the port unusable until the reference
17936403Ssklower * timer goes off.
18036403Ssklower */
18136403Ssklower void
iso_recycle_tsuffix(isop)18236403Ssklower iso_recycle_tsuffix(isop)
18336403Ssklower struct isopcb *isop;
18436403Ssklower {
18538841Ssklower isop->isop_laddr->siso_tlen = isop->isop_faddr->siso_tlen = 0;
18636403Ssklower }
18736403Ssklower
18836403Ssklower /*
18936403Ssklower * CALLED FROM:
19036403Ssklower * tp_newsocket(); i.e., when a connection is being established by an
19136403Ssklower * incoming CR_TPDU.
19236403Ssklower *
19336403Ssklower * FUNCTION and ARGUMENTS:
19436403Ssklower * Copy a whole net addr from a struct sockaddr (name).
19536403Ssklower * into an isopcb (isop).
19636403Ssklower * The argument (which) takes values TP_LOCAL or TP_FOREIGN
19736403Ssklower */
19836403Ssklower void
iso_putnetaddr(isop,name,which)19936403Ssklower iso_putnetaddr(isop, name, which)
20036403Ssklower register struct isopcb *isop;
20136403Ssklower struct sockaddr_iso *name;
20236403Ssklower int which;
20336403Ssklower {
20437469Ssklower struct sockaddr_iso **sisop, *backup;
20537469Ssklower register struct sockaddr_iso *siso;
20637469Ssklower
20736403Ssklower switch (which) {
20844422Ssklower default:
20944422Ssklower printf("iso_putnetaddr: should panic\n");
21044422Ssklower return;
21136403Ssklower case TP_LOCAL:
21237469Ssklower sisop = &isop->isop_laddr;
21337469Ssklower backup = &isop->isop_sladdr;
21436403Ssklower break;
21536403Ssklower case TP_FOREIGN:
21637469Ssklower sisop = &isop->isop_faddr;
21737469Ssklower backup = &isop->isop_sfaddr;
21836403Ssklower }
21937469Ssklower siso = ((*sisop == 0) ? (*sisop = backup) : *sisop);
22037469Ssklower IFDEBUG(D_TPISO)
22137469Ssklower printf("ISO_PUTNETADDR\n");
22237469Ssklower dump_isoaddr(isop->isop_faddr);
22337469Ssklower ENDDEBUG
22437469Ssklower siso->siso_addr = name->siso_addr;
22536403Ssklower }
22636403Ssklower
22736403Ssklower /*
22836403Ssklower * CALLED FROM:
22944422Ssklower * tp_input() when a connection is being established by an
23044422Ssklower * incoming CR_TPDU, and considered for interception.
23144422Ssklower *
23244422Ssklower * FUNCTION and ARGUMENTS:
23344422Ssklower * compare a whole net addr from a struct sockaddr (name),
23444422Ssklower * with that implicitly stored in an isopcb (isop).
23544422Ssklower * The argument (which) takes values TP_LOCAL or TP_FOREIGN.
23644422Ssklower */
iso_cmpnetaddr(isop,name,which)23744422Ssklower iso_cmpnetaddr(isop, name, which)
23844422Ssklower register struct isopcb *isop;
23944422Ssklower register struct sockaddr_iso *name;
24044422Ssklower int which;
24144422Ssklower {
24244422Ssklower struct sockaddr_iso **sisop, *backup;
24344422Ssklower register struct sockaddr_iso *siso;
24444422Ssklower
24544422Ssklower switch (which) {
24644422Ssklower default:
24744422Ssklower printf("iso_cmpnetaddr: should panic\n");
24844422Ssklower return 0;
24944422Ssklower case TP_LOCAL:
25044422Ssklower sisop = &isop->isop_laddr;
25144422Ssklower backup = &isop->isop_sladdr;
25244422Ssklower break;
25344422Ssklower case TP_FOREIGN:
25444422Ssklower sisop = &isop->isop_faddr;
25544422Ssklower backup = &isop->isop_sfaddr;
25644422Ssklower }
25744422Ssklower siso = ((*sisop == 0) ? (*sisop = backup) : *sisop);
25844422Ssklower IFDEBUG(D_TPISO)
25944422Ssklower printf("ISO_CMPNETADDR\n");
26044422Ssklower dump_isoaddr(siso);
26144422Ssklower ENDDEBUG
26244422Ssklower if (name->siso_tlen && bcmp(TSEL(name), TSEL(siso), name->siso_tlen))
26344422Ssklower return (0);
26444422Ssklower return (bcmp((caddr_t)name->siso_data,
26544422Ssklower (caddr_t)siso->siso_data, name->siso_nlen) == 0);
26644422Ssklower }
26744422Ssklower
26844422Ssklower /*
26944422Ssklower * CALLED FROM:
27036403Ssklower * pr_usrreq() PRU_SOCKADDR, PRU_ACCEPT, PRU_PEERADDR
27136403Ssklower * FUNCTION and ARGUMENTS:
27236403Ssklower * Copy a whole net addr from an isopcb (isop) into
27336403Ssklower * a struct sockaddr (name).
27436403Ssklower * The argument (which) takes values TP_LOCAL or TP_FOREIGN.
27536403Ssklower */
27636403Ssklower
27736403Ssklower void
iso_getnetaddr(isop,name,which)27836403Ssklower iso_getnetaddr( isop, name, which)
27936403Ssklower struct isopcb *isop;
28037469Ssklower struct mbuf *name;
28136403Ssklower int which;
28236403Ssklower {
28337469Ssklower struct sockaddr_iso *siso =
28437469Ssklower (which == TP_LOCAL ? isop->isop_laddr : isop->isop_faddr);
28537469Ssklower if (siso)
28637469Ssklower bcopy((caddr_t)siso, mtod(name, caddr_t),
28737469Ssklower (unsigned)(name->m_len = siso->siso_len));
28837469Ssklower else
28937469Ssklower name->m_len = 0;
29036403Ssklower }
29136403Ssklower /*
29251246Ssklower * NAME: tpclnp_mtu()
29351246Ssklower *
29436403Ssklower * CALLED FROM:
29551246Ssklower * tp_route_to() on incoming CR, CC, and pr_usrreq() for PRU_CONNECT
29636403Ssklower *
29751246Ssklower * FUNCTION, ARGUMENTS, and RETURN VALUE:
29851246Ssklower *
29951246Ssklower * Perform subnetwork dependent part of determining MTU information.
30051246Ssklower * It appears that setting a double pointer to the rtentry associated with
30151246Ssklower * the destination, and returning the header size for the network protocol
30251246Ssklower * suffices.
30336403Ssklower *
30451246Ssklower * SIDE EFFECTS:
30551246Ssklower * Sets tp_routep pointer in pcb.
30651246Ssklower *
30751246Ssklower * NOTES:
30836403Ssklower */
tpclnp_mtu(tpcb)30951246Ssklower tpclnp_mtu(tpcb)
31051246Ssklower register struct tp_pcb *tpcb;
31136403Ssklower {
31251246Ssklower struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb;
31336403Ssklower
31436403Ssklower IFDEBUG(D_CONN)
31551246Ssklower printf("tpclnp_mtu(tpcb)\n", tpcb);
31636403Ssklower ENDDEBUG
31751246Ssklower tpcb->tp_routep = &(isop->isop_route.ro_rt);
31851246Ssklower if (tpcb->tp_netservice == ISO_CONS)
31951246Ssklower return 0;
32051246Ssklower else
32151246Ssklower return (sizeof(struct clnp_fixed) + sizeof(struct clnp_segment) +
32251246Ssklower 2 * sizeof(struct iso_addr));
32336403Ssklower
32436403Ssklower }
32536403Ssklower
32636403Ssklower /*
32736403Ssklower * CALLED FROM:
32836403Ssklower * tp_emit()
32936403Ssklower * FUNCTION and ARGUMENTS:
33036403Ssklower * Take a packet(m0) from tp and package it so that clnp will accept it.
33136403Ssklower * This means prepending space for the clnp header and filling in a few
33236403Ssklower * of the fields.
33351246Ssklower * isop is the isopcb structure; datalen is the length of the data in the
33436403Ssklower * mbuf string m0.
33536403Ssklower * RETURN VALUE:
33636403Ssklower * whatever (E*) is returned form the net layer output routine.
33736403Ssklower */
33836403Ssklower
33936403Ssklower int
tpclnp_output(isop,m0,datalen,nochksum)34036403Ssklower tpclnp_output(isop, m0, datalen, nochksum)
34136403Ssklower struct isopcb *isop;
34236403Ssklower struct mbuf *m0;
34336403Ssklower int datalen;
34436403Ssklower int nochksum;
34536403Ssklower {
34637469Ssklower register struct mbuf *m = m0;
34736403Ssklower IncStat(ts_tpdu_sent);
34836403Ssklower
34936403Ssklower IFDEBUG(D_TPISO)
35036403Ssklower struct tpdu *hdr = mtod(m0, struct tpdu *);
35136403Ssklower
35236403Ssklower printf(
35336403Ssklower "abt to call clnp_output: datalen 0x%x, hdr.li 0x%x, hdr.dutype 0x%x nocsum x%x dst addr:\n",
35436403Ssklower datalen,
35536403Ssklower (int)hdr->tpdu_li, (int)hdr->tpdu_type, nochksum);
35637469Ssklower dump_isoaddr(isop->isop_faddr);
35736403Ssklower printf("\nsrc addr:\n");
35837469Ssklower dump_isoaddr(isop->isop_laddr);
35936403Ssklower dump_mbuf(m0, "at tpclnp_output");
36036403Ssklower ENDDEBUG
36136403Ssklower
36236403Ssklower return
36338841Ssklower clnp_output(m0, isop, datalen, /* flags */nochksum ? CLNP_NO_CKSUM : 0);
36436403Ssklower }
36536403Ssklower
36636403Ssklower /*
36736403Ssklower * CALLED FROM:
36836403Ssklower * tp_error_emit()
36936403Ssklower * FUNCTION and ARGUMENTS:
37036403Ssklower * This is a copy of tpclnp_output that takes the addresses
37136403Ssklower * instead of a pcb. It's used by the tp_error_emit, when we
37236403Ssklower * don't have an iso_pcb with which to call the normal output rtn.
37336403Ssklower * RETURN VALUE:
37436403Ssklower * ENOBUFS or
37536403Ssklower * whatever (E*) is returned form the net layer output routine.
37636403Ssklower */
37736403Ssklower
37836403Ssklower int
tpclnp_output_dg(laddr,faddr,m0,datalen,ro,nochksum)37936403Ssklower tpclnp_output_dg(laddr, faddr, m0, datalen, ro, nochksum)
38036403Ssklower struct iso_addr *laddr, *faddr;
38136403Ssklower struct mbuf *m0;
38236403Ssklower int datalen;
38336403Ssklower struct route *ro;
38436403Ssklower int nochksum;
38536403Ssklower {
38636403Ssklower struct isopcb tmppcb;
38736403Ssklower int err;
38836403Ssklower int flags;
38937469Ssklower register struct mbuf *m = m0;
39036403Ssklower
39136403Ssklower IFDEBUG(D_TPISO)
39236403Ssklower printf("tpclnp_output_dg datalen 0x%x m0 0x%x\n", datalen, m0);
39336403Ssklower ENDDEBUG
39436403Ssklower
39536403Ssklower /*
39636403Ssklower * Fill in minimal portion of isopcb so that clnp can send the
39736403Ssklower * packet.
39836403Ssklower */
39936403Ssklower bzero((caddr_t)&tmppcb, sizeof(tmppcb));
40037469Ssklower tmppcb.isop_laddr = &tmppcb.isop_sladdr;
40137469Ssklower tmppcb.isop_laddr->siso_addr = *laddr;
40237469Ssklower tmppcb.isop_faddr = &tmppcb.isop_sfaddr;
40337469Ssklower tmppcb.isop_faddr->siso_addr = *faddr;
40436403Ssklower
40536403Ssklower IFDEBUG(D_TPISO)
40636403Ssklower printf("tpclnp_output_dg faddr: \n");
40737469Ssklower dump_isoaddr(&tmppcb.isop_sfaddr);
40836403Ssklower printf("\ntpclnp_output_dg laddr: \n");
40937469Ssklower dump_isoaddr(&tmppcb.isop_sladdr);
41036403Ssklower printf("\n");
41136403Ssklower ENDDEBUG
41236403Ssklower
41336403Ssklower /*
41436403Ssklower * Do not use packet cache since this is a one shot error packet
41536403Ssklower */
41636403Ssklower flags = (CLNP_NOCACHE|(nochksum?CLNP_NO_CKSUM:0));
41736403Ssklower
41836403Ssklower IncStat(ts_tpdu_sent);
41936403Ssklower
42038841Ssklower err = clnp_output(m0, &tmppcb, datalen, flags);
42136403Ssklower
42236403Ssklower /*
42336403Ssklower * Free route allocated by clnp (if the route was indeed allocated)
42436403Ssklower */
42536403Ssklower if (tmppcb.isop_route.ro_rt)
42636403Ssklower RTFREE(tmppcb.isop_route.ro_rt);
42736403Ssklower
42836403Ssklower return(err);
42936403Ssklower }
43036403Ssklower /*
43136403Ssklower * CALLED FROM:
43236403Ssklower * clnp's input routine, indirectly through the protosw.
43336403Ssklower * FUNCTION and ARGUMENTS:
43436403Ssklower * Take a packet (m) from clnp, strip off the clnp header and give it to tp
43536403Ssklower * No return value.
43636403Ssklower */
43736403Ssklower ProtoHook
tpclnp_input(m,src,dst,clnp_len,ce_bit)43839927Ssklower tpclnp_input(m, src, dst, clnp_len, ce_bit)
43939926Ssklower register struct mbuf *m;
44039926Ssklower struct sockaddr_iso *src, *dst;
44139927Ssklower int clnp_len, ce_bit;
44236403Ssklower {
44337469Ssklower struct mbuf *tp_inputprep();
44439926Ssklower int tp_input(), cltp_input(), (*input)() = tp_input;
44536403Ssklower
44636403Ssklower IncStat(ts_pkt_rcvd);
44736403Ssklower
44836403Ssklower IFDEBUG(D_TPINPUT)
44936403Ssklower printf("tpclnp_input: m 0x%x clnp_len 0x%x\n", m, clnp_len);
45036403Ssklower dump_mbuf(m, "at tpclnp_input");
45136403Ssklower ENDDEBUG
45236403Ssklower /*
45336403Ssklower * CLNP gives us an mbuf chain WITH the clnp header pulled up,
45436403Ssklower * and the length of the clnp header.
45536403Ssklower * First, strip off the Clnp header. leave the mbuf there for the
45636403Ssklower * pullup that follows.
45736403Ssklower */
45836403Ssklower m->m_len -= clnp_len;
45937469Ssklower m->m_data += clnp_len;
46056911Ssklower m->m_pkthdr.len -= clnp_len;
46156911Ssklower /* XXXX: should probably be in clnp_input */
46256911Ssklower switch (dst->siso_data[dst->siso_nlen - 1]) {
46356911Ssklower #ifdef TUBA
46456911Ssklower case ISOPROTO_TCP:
46556911Ssklower return (tuba_tcpinput(m, src, dst));
46656911Ssklower #endif
46756911Ssklower case 0:
46856911Ssklower if (m->m_len == 0 && (m = m_pullup(m, 1)) == 0)
46956911Ssklower return 0;
47056911Ssklower if (*(mtod(m, u_char *)) == ISO10747_IDRP)
47156911Ssklower return (idrp_input(m, src, dst));
47256911Ssklower }
47337469Ssklower m = tp_inputprep(m);
47439926Ssklower if (m == 0)
47539926Ssklower return 0;
47639926Ssklower if (mtod(m, u_char *)[1] == UD_TPDU_type)
47739926Ssklower input = cltp_input;
47836403Ssklower
47936403Ssklower IFDEBUG(D_TPINPUT)
48036403Ssklower dump_mbuf(m, "after tpclnp_input both pullups");
48136403Ssklower ENDDEBUG
48236403Ssklower
48336403Ssklower IFDEBUG(D_TPISO)
48439926Ssklower printf("calling %sinput : src 0x%x, dst 0x%x, src addr:\n",
48539926Ssklower (input == tp_input ? "tp_" : "clts_"), src, dst);
48639926Ssklower dump_isoaddr(src);
48736403Ssklower printf(" dst addr:\n");
48839926Ssklower dump_isoaddr(dst);
48936403Ssklower ENDDEBUG
49036403Ssklower
49139926Ssklower (void) (*input)(m, (struct sockaddr *)src, (struct sockaddr *)dst,
49239927Ssklower 0, tpclnp_output_dg, ce_bit);
49336403Ssklower
49436403Ssklower IFDEBUG(D_QUENCH)
49536403Ssklower {
49636403Ssklower if(time.tv_usec & 0x4 && time.tv_usec & 0x40) {
49736403Ssklower printf("tpclnp_input: FAKING %s\n",
49836403Ssklower tp_stat.ts_pkt_rcvd & 0x1?"QUENCH":"QUENCH2");
49936403Ssklower if(tp_stat.ts_pkt_rcvd & 0x1) {
50036403Ssklower tpclnp_ctlinput(PRC_QUENCH, &src);
50136403Ssklower } else {
50236403Ssklower tpclnp_ctlinput(PRC_QUENCH2, &src);
50336403Ssklower }
50436403Ssklower }
50536403Ssklower }
50636403Ssklower ENDDEBUG
50736403Ssklower
50836403Ssklower return 0;
50936403Ssklower }
51036403Ssklower
51136403Ssklower ProtoHook
iso_rtchange()51236403Ssklower iso_rtchange()
51336403Ssklower {
51436403Ssklower return 0;
51536403Ssklower }
51636403Ssklower
51736403Ssklower /*
51836403Ssklower * CALLED FROM:
51936403Ssklower * tpclnp_ctlinput()
52036403Ssklower * FUNCTION and ARGUMENTS:
52136403Ssklower * find the tpcb pointer and pass it to tp_quench
52236403Ssklower */
52336403Ssklower void
tpiso_decbit(isop)52436403Ssklower tpiso_decbit(isop)
52536403Ssklower struct isopcb *isop;
52636403Ssklower {
52750435Ssklower tp_quench((struct tp_pcb *)isop->isop_socket->so_pcb, PRC_QUENCH2);
52836403Ssklower }
52936403Ssklower /*
53036403Ssklower * CALLED FROM:
53136403Ssklower * tpclnp_ctlinput()
53236403Ssklower * FUNCTION and ARGUMENTS:
53336403Ssklower * find the tpcb pointer and pass it to tp_quench
53436403Ssklower */
53536403Ssklower void
tpiso_quench(isop)53636403Ssklower tpiso_quench(isop)
53736403Ssklower struct isopcb *isop;
53836403Ssklower {
53950435Ssklower tp_quench((struct tp_pcb *)isop->isop_socket->so_pcb, PRC_QUENCH);
54036403Ssklower }
54136403Ssklower
54236403Ssklower /*
54336403Ssklower * CALLED FROM:
54436403Ssklower * The network layer through the protosw table.
54536403Ssklower * FUNCTION and ARGUMENTS:
54636403Ssklower * When clnp an ICMP-like msg this gets called.
54736403Ssklower * It either returns an error status to the user or
54836403Ssklower * it causes all connections on this address to be aborted
54936403Ssklower * by calling the appropriate xx_notify() routine.
55036403Ssklower * (cmd) is the type of ICMP error.
55136403Ssklower * (siso) is the address of the guy who sent the ER CLNPDU
55236403Ssklower */
55336403Ssklower ProtoHook
tpclnp_ctlinput(cmd,siso)55436403Ssklower tpclnp_ctlinput(cmd, siso)
55536403Ssklower int cmd;
55636403Ssklower struct sockaddr_iso *siso;
55736403Ssklower {
55836403Ssklower extern u_char inetctlerrmap[];
55936403Ssklower extern ProtoHook tpiso_abort();
56036403Ssklower extern ProtoHook iso_rtchange();
56136403Ssklower extern ProtoHook tpiso_reset();
56237469Ssklower void iso_pcbnotify();
56336403Ssklower
56436403Ssklower IFDEBUG(D_TPINPUT)
56539926Ssklower printf("tpclnp_ctlinput1: cmd 0x%x addr: \n", cmd);
56639926Ssklower dump_isoaddr(siso);
56736403Ssklower ENDDEBUG
56836403Ssklower
56936403Ssklower if (cmd < 0 || cmd > PRC_NCMDS)
57036403Ssklower return 0;
57139926Ssklower if (siso->siso_family != AF_ISO)
57239926Ssklower return 0;
57336403Ssklower switch (cmd) {
57436403Ssklower
57536403Ssklower case PRC_QUENCH2:
57639926Ssklower iso_pcbnotify(&tp_isopcb, siso, 0, (int (*)())tpiso_decbit);
57736403Ssklower break;
57836403Ssklower
57936403Ssklower case PRC_QUENCH:
58039926Ssklower iso_pcbnotify(&tp_isopcb, siso, 0, (int (*)())tpiso_quench);
58136403Ssklower break;
58236403Ssklower
58336403Ssklower case PRC_TIMXCEED_REASS:
58436403Ssklower case PRC_ROUTEDEAD:
58539926Ssklower iso_pcbnotify(&tp_isopcb, siso, 0, tpiso_reset);
58636403Ssklower break;
58736403Ssklower
58836403Ssklower case PRC_HOSTUNREACH:
58936403Ssklower case PRC_UNREACH_NET:
59036403Ssklower case PRC_IFDOWN:
59136403Ssklower case PRC_HOSTDEAD:
59239926Ssklower iso_pcbnotify(&tp_isopcb, siso,
59336403Ssklower (int)inetctlerrmap[cmd], iso_rtchange);
59436403Ssklower break;
59536403Ssklower
59636403Ssklower default:
59736403Ssklower /*
59836403Ssklower case PRC_MSGSIZE:
59936403Ssklower case PRC_UNREACH_HOST:
60036403Ssklower case PRC_UNREACH_PROTOCOL:
60136403Ssklower case PRC_UNREACH_PORT:
60236403Ssklower case PRC_UNREACH_NEEDFRAG:
60336403Ssklower case PRC_UNREACH_SRCFAIL:
60436403Ssklower case PRC_REDIRECT_NET:
60536403Ssklower case PRC_REDIRECT_HOST:
60636403Ssklower case PRC_REDIRECT_TOSNET:
60736403Ssklower case PRC_REDIRECT_TOSHOST:
60836403Ssklower case PRC_TIMXCEED_INTRANS:
60936403Ssklower case PRC_PARAMPROB:
61036403Ssklower */
61139926Ssklower iso_pcbnotify(&tp_isopcb, siso, (int)inetctlerrmap[cmd], tpiso_abort);
61236403Ssklower break;
61336403Ssklower }
61436403Ssklower return 0;
61536403Ssklower }
61639926Ssklower /*
61739926Ssklower * XXX - Variant which is called by clnp_er.c with an isoaddr rather
61839926Ssklower * than a sockaddr_iso.
61939926Ssklower */
62036403Ssklower
62139926Ssklower static struct sockaddr_iso siso = {sizeof(siso), AF_ISO};
tpclnp_ctlinput1(cmd,isoa)62239926Ssklower tpclnp_ctlinput1(cmd, isoa)
62339926Ssklower int cmd;
62439926Ssklower struct iso_addr *isoa;
62539926Ssklower {
62639926Ssklower bzero((caddr_t)&siso.siso_addr, sizeof(siso.siso_addr));
62739926Ssklower bcopy((caddr_t)isoa, (caddr_t)&siso.siso_addr, isoa->isoa_len);
62839926Ssklower tpclnp_ctlinput(cmd, &siso);
62939926Ssklower }
63039926Ssklower
63136403Ssklower /*
63236403Ssklower * These next 2 routines are
63336403Ssklower * CALLED FROM:
63436403Ssklower * xxx_notify() from tp_ctlinput() when
63536403Ssklower * net level gets some ICMP-equiv. type event.
63636403Ssklower * FUNCTION and ARGUMENTS:
63736403Ssklower * Cause the connection to be aborted with some sort of error
63836403Ssklower * reason indicating that the network layer caused the abort.
63936403Ssklower * Fakes an ER TPDU so we can go through the driver.
64036403Ssklower * abort always aborts the TP connection.
64136403Ssklower * reset may or may not, depending on the TP class that's in use.
64236403Ssklower */
64336403Ssklower ProtoHook
tpiso_abort(isop)64436403Ssklower tpiso_abort(isop)
64536403Ssklower struct isopcb *isop;
64636403Ssklower {
64736403Ssklower struct tp_event e;
64836403Ssklower
64936403Ssklower IFDEBUG(D_CONN)
65036403Ssklower printf("tpiso_abort 0x%x\n", isop);
65136403Ssklower ENDDEBUG
65236403Ssklower e.ev_number = ER_TPDU;
65336403Ssklower e.ATTR(ER_TPDU).e_reason = ECONNABORTED;
65450435Ssklower return tp_driver((struct tp_pcb *)isop->isop_socket->so_pcb, &e);
65536403Ssklower }
65636403Ssklower
65736403Ssklower ProtoHook
tpiso_reset(isop)65836403Ssklower tpiso_reset(isop)
65936403Ssklower struct isopcb *isop;
66036403Ssklower {
66136403Ssklower struct tp_event e;
66236403Ssklower
66336403Ssklower e.ev_number = T_NETRESET;
66450435Ssklower return tp_driver((struct tp_pcb *)isop->isop_socket->so_pcb, &e);
66536403Ssklower
66636403Ssklower }
66736403Ssklower
66860359Sbostic #endif /* ISO */
669