136403Ssklower /*********************************************************** 236403Ssklower Copyright IBM Corporation 1987 336403Ssklower 436403Ssklower All Rights Reserved 536403Ssklower 636403Ssklower Permission to use, copy, modify, and distribute this software and its 736403Ssklower documentation for any purpose and without fee is hereby granted, 836403Ssklower provided that the above copyright notice appear in all copies and that 936403Ssklower both that copyright notice and this permission notice appear in 1036403Ssklower supporting documentation, and that the name of IBM not be 1136403Ssklower used in advertising or publicity pertaining to distribution of the 1236403Ssklower software without specific, written prior permission. 1336403Ssklower 1436403Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 1536403Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 1636403Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 1736403Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 1836403Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 1936403Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 2036403Ssklower SOFTWARE. 2136403Ssklower 2236403Ssklower ******************************************************************/ 2336403Ssklower 2436403Ssklower /* 2536403Ssklower * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison 2636403Ssklower */ 2736403Ssklower /* 2836403Ssklower * ARGO TP 2937469Ssklower * $Header: /var/src/sys/netiso/RCS/tp_iso.c,v 5.1 89/02/09 16:20:51 hagens Exp $ 3037469Ssklower * $Source: /var/src/sys/netiso/RCS/tp_iso.c,v $ 31*44422Ssklower * @(#)tp_iso.c 7.8 (Berkeley) 06/28/90 3236403Ssklower * 3336403Ssklower * Here is where you find the iso-dependent code. We've tried 3436403Ssklower * keep all net-level and (primarily) address-family-dependent stuff 3536403Ssklower * out of the tp source, and everthing here is reached indirectly 3636403Ssklower * through a switch table (struct nl_protosw *) tpcb->tp_nlproto 3736403Ssklower * (see tp_pcb.c). 3836403Ssklower * The routines here are: 3936403Ssklower * iso_getsufx: gets transport suffix out of an isopcb structure. 4036403Ssklower * iso_putsufx: put transport suffix into an isopcb structure. 4136403Ssklower * iso_putnetaddr: put a whole net addr into an isopcb. 4236403Ssklower * iso_getnetaddr: get a whole net addr from an isopcb. 43*44422Ssklower * iso_cmpnetaddr: compare a whole net addr from an isopcb. 4436403Ssklower * iso_recycle_suffix: clear suffix for reuse in isopcb 4536403Ssklower * tpclnp_ctlinput: handle ER CNLPdu : icmp-like stuff 4636403Ssklower * tpclnp_mtu: figure out what size tpdu to use 4736403Ssklower * tpclnp_input: take a pkt from clnp, strip off its clnp header, 4836403Ssklower * give to tp 4936403Ssklower * tpclnp_output_dg: package a pkt for clnp given 2 addresses & some data 5036403Ssklower * tpclnp_output: package a pkt for clnp given an isopcb & some data 5136403Ssklower */ 5236403Ssklower 5336403Ssklower #ifndef lint 5437469Ssklower static char *rcsid = "$Header: /var/src/sys/netiso/RCS/tp_iso.c,v 5.1 89/02/09 16:20:51 hagens Exp $"; 5536403Ssklower #endif lint 5636403Ssklower 5736403Ssklower #ifdef ISO 5836403Ssklower 5937469Ssklower #include "param.h" 6037469Ssklower #include "socket.h" 6137469Ssklower #include "socketvar.h" 6237469Ssklower #include "domain.h" 6337469Ssklower #include "malloc.h" 6437469Ssklower #include "mbuf.h" 6537469Ssklower #include "errno.h" 6637469Ssklower #include "time.h" 6737469Ssklower #include "protosw.h" 6837469Ssklower 6936403Ssklower #include "../net/if.h" 7036403Ssklower #include "../net/route.h" 7136403Ssklower 7237469Ssklower #include "argo_debug.h" 7337469Ssklower #include "tp_param.h" 7437469Ssklower #include "tp_stat.h" 7537469Ssklower #include "tp_pcb.h" 7637469Ssklower #include "tp_trace.h" 7737469Ssklower #include "tp_stat.h" 7837469Ssklower #include "tp_tpdu.h" 7937469Ssklower #include "tp_clnp.h" 8039926Ssklower #include "cltp_var.h" 8136403Ssklower 8236403Ssklower /* 8336403Ssklower * CALLED FROM: 8436403Ssklower * pr_usrreq() on PRU_BIND, PRU_CONNECT, PRU_ACCEPT, and PRU_PEERADDR 8537469Ssklower * FUNCTION, ARGUMENTS: 8636403Ssklower * The argument (which) takes the value TP_LOCAL or TP_FOREIGN. 8736403Ssklower */ 8836403Ssklower 8937469Ssklower iso_getsufx(isop, lenp, data_out, which) 9036403Ssklower struct isopcb *isop; 9137469Ssklower u_short *lenp; 9237469Ssklower caddr_t data_out; 9336403Ssklower int which; 9436403Ssklower { 9537469Ssklower register struct sockaddr_iso *addr = 0; 9637469Ssklower 9736403Ssklower switch (which) { 9836403Ssklower case TP_LOCAL: 9937469Ssklower addr = isop->isop_laddr; 10037469Ssklower break; 10136403Ssklower 10236403Ssklower case TP_FOREIGN: 10337469Ssklower addr = isop->isop_faddr; 10436403Ssklower } 10537469Ssklower if (addr) 10638841Ssklower bcopy(TSEL(addr), data_out, (*lenp = addr->siso_tlen)); 10736403Ssklower } 10836403Ssklower 10936403Ssklower /* CALLED FROM: 11036403Ssklower * tp_newsocket(); i.e., when a connection is being established by an 11136403Ssklower * incoming CR_TPDU. 11236403Ssklower * 11336403Ssklower * FUNCTION, ARGUMENTS: 11436403Ssklower * Put a transport suffix (found in name) into an isopcb structure (isop). 11536403Ssklower * The argument (which) takes the value TP_LOCAL or TP_FOREIGN. 11636403Ssklower */ 11736403Ssklower void 11837469Ssklower iso_putsufx(isop, sufxloc, sufxlen, which) 11936403Ssklower struct isopcb *isop; 12037469Ssklower caddr_t sufxloc; 12137469Ssklower int sufxlen, which; 12236403Ssklower { 12337469Ssklower struct sockaddr_iso **dst, *backup; 12437469Ssklower register struct sockaddr_iso *addr; 12537469Ssklower struct mbuf *m; 12637469Ssklower int len; 12737469Ssklower 12836403Ssklower switch (which) { 12937469Ssklower default: 13037469Ssklower return; 13137469Ssklower 13236403Ssklower case TP_LOCAL: 13337469Ssklower dst = &isop->isop_laddr; 13437469Ssklower backup = &isop->isop_sladdr; 13536403Ssklower break; 13637469Ssklower 13736403Ssklower case TP_FOREIGN: 13837469Ssklower dst = &isop->isop_faddr; 13937469Ssklower backup = &isop->isop_sfaddr; 14036403Ssklower } 14137469Ssklower if ((addr = *dst) == 0) { 14237469Ssklower addr = *dst = backup; 14337469Ssklower addr->siso_nlen = 0; 14438841Ssklower addr->siso_slen = 0; 14538841Ssklower addr->siso_plen = 0; 14637469Ssklower printf("iso_putsufx on un-initialized isopcb\n"); 14737469Ssklower } 14837469Ssklower len = sufxlen + addr->siso_nlen + 14938841Ssklower (sizeof(*addr) - sizeof(addr->siso_data)); 15037469Ssklower if (addr == backup) { 15138841Ssklower if (len > sizeof(*addr)) { 15237469Ssklower m = m_getclr(M_DONTWAIT, MT_SONAME); 15337469Ssklower if (m == 0) 15437469Ssklower return; 15537469Ssklower addr = *dst = mtod(m, struct sockaddr_iso *); 15637469Ssklower *addr = *backup; 15737469Ssklower m->m_len = len; 15837469Ssklower } 15938841Ssklower } 16037469Ssklower bcopy(sufxloc, TSEL(addr), sufxlen); 16138841Ssklower addr->siso_tlen = sufxlen; 16237469Ssklower addr->siso_len = len; 16336403Ssklower } 16436403Ssklower 16536403Ssklower /* 16636403Ssklower * CALLED FROM: 16736403Ssklower * tp.trans whenever we go into REFWAIT state. 16836403Ssklower * FUNCTION and ARGUMENT: 16936403Ssklower * Called when a ref is frozen, to allow the suffix to be reused. 17036403Ssklower * (isop) is the net level pcb. This really shouldn't have to be 17136403Ssklower * done in a NET level pcb but... for the internet world that just 17236403Ssklower * the way it is done in BSD... 17336403Ssklower * The alternative is to have the port unusable until the reference 17436403Ssklower * timer goes off. 17536403Ssklower */ 17636403Ssklower void 17736403Ssklower iso_recycle_tsuffix(isop) 17836403Ssklower struct isopcb *isop; 17936403Ssklower { 18038841Ssklower isop->isop_laddr->siso_tlen = isop->isop_faddr->siso_tlen = 0; 18136403Ssklower } 18236403Ssklower 18336403Ssklower /* 18436403Ssklower * CALLED FROM: 18536403Ssklower * tp_newsocket(); i.e., when a connection is being established by an 18636403Ssklower * incoming CR_TPDU. 18736403Ssklower * 18836403Ssklower * FUNCTION and ARGUMENTS: 18936403Ssklower * Copy a whole net addr from a struct sockaddr (name). 19036403Ssklower * into an isopcb (isop). 19136403Ssklower * The argument (which) takes values TP_LOCAL or TP_FOREIGN 19236403Ssklower */ 19336403Ssklower void 19436403Ssklower iso_putnetaddr(isop, name, which) 19536403Ssklower register struct isopcb *isop; 19636403Ssklower struct sockaddr_iso *name; 19736403Ssklower int which; 19836403Ssklower { 19937469Ssklower struct sockaddr_iso **sisop, *backup; 20037469Ssklower register struct sockaddr_iso *siso; 20137469Ssklower 20236403Ssklower switch (which) { 203*44422Ssklower default: 204*44422Ssklower printf("iso_putnetaddr: should panic\n"); 205*44422Ssklower return; 20636403Ssklower case TP_LOCAL: 20737469Ssklower sisop = &isop->isop_laddr; 20837469Ssklower backup = &isop->isop_sladdr; 20936403Ssklower break; 21036403Ssklower case TP_FOREIGN: 21137469Ssklower sisop = &isop->isop_faddr; 21237469Ssklower backup = &isop->isop_sfaddr; 21336403Ssklower } 21437469Ssklower siso = ((*sisop == 0) ? (*sisop = backup) : *sisop); 21537469Ssklower IFDEBUG(D_TPISO) 21637469Ssklower printf("ISO_PUTNETADDR\n"); 21737469Ssklower dump_isoaddr(isop->isop_faddr); 21837469Ssklower ENDDEBUG 21937469Ssklower siso->siso_addr = name->siso_addr; 22036403Ssklower } 22136403Ssklower 22236403Ssklower /* 22336403Ssklower * CALLED FROM: 224*44422Ssklower * tp_input() when a connection is being established by an 225*44422Ssklower * incoming CR_TPDU, and considered for interception. 226*44422Ssklower * 227*44422Ssklower * FUNCTION and ARGUMENTS: 228*44422Ssklower * compare a whole net addr from a struct sockaddr (name), 229*44422Ssklower * with that implicitly stored in an isopcb (isop). 230*44422Ssklower * The argument (which) takes values TP_LOCAL or TP_FOREIGN. 231*44422Ssklower */ 232*44422Ssklower iso_cmpnetaddr(isop, name, which) 233*44422Ssklower register struct isopcb *isop; 234*44422Ssklower register struct sockaddr_iso *name; 235*44422Ssklower int which; 236*44422Ssklower { 237*44422Ssklower struct sockaddr_iso **sisop, *backup; 238*44422Ssklower register struct sockaddr_iso *siso; 239*44422Ssklower 240*44422Ssklower switch (which) { 241*44422Ssklower default: 242*44422Ssklower printf("iso_cmpnetaddr: should panic\n"); 243*44422Ssklower return 0; 244*44422Ssklower case TP_LOCAL: 245*44422Ssklower sisop = &isop->isop_laddr; 246*44422Ssklower backup = &isop->isop_sladdr; 247*44422Ssklower break; 248*44422Ssklower case TP_FOREIGN: 249*44422Ssklower sisop = &isop->isop_faddr; 250*44422Ssklower backup = &isop->isop_sfaddr; 251*44422Ssklower } 252*44422Ssklower siso = ((*sisop == 0) ? (*sisop = backup) : *sisop); 253*44422Ssklower IFDEBUG(D_TPISO) 254*44422Ssklower printf("ISO_CMPNETADDR\n"); 255*44422Ssklower dump_isoaddr(siso); 256*44422Ssklower ENDDEBUG 257*44422Ssklower if (name->siso_tlen && bcmp(TSEL(name), TSEL(siso), name->siso_tlen)) 258*44422Ssklower return (0); 259*44422Ssklower return (bcmp((caddr_t)name->siso_data, 260*44422Ssklower (caddr_t)siso->siso_data, name->siso_nlen) == 0); 261*44422Ssklower } 262*44422Ssklower 263*44422Ssklower /* 264*44422Ssklower * CALLED FROM: 26536403Ssklower * pr_usrreq() PRU_SOCKADDR, PRU_ACCEPT, PRU_PEERADDR 26636403Ssklower * FUNCTION and ARGUMENTS: 26736403Ssklower * Copy a whole net addr from an isopcb (isop) into 26836403Ssklower * a struct sockaddr (name). 26936403Ssklower * The argument (which) takes values TP_LOCAL or TP_FOREIGN. 27036403Ssklower */ 27136403Ssklower 27236403Ssklower void 27336403Ssklower iso_getnetaddr( isop, name, which) 27436403Ssklower struct isopcb *isop; 27537469Ssklower struct mbuf *name; 27636403Ssklower int which; 27736403Ssklower { 27837469Ssklower struct sockaddr_iso *siso = 27937469Ssklower (which == TP_LOCAL ? isop->isop_laddr : isop->isop_faddr); 28037469Ssklower if (siso) 28137469Ssklower bcopy((caddr_t)siso, mtod(name, caddr_t), 28237469Ssklower (unsigned)(name->m_len = siso->siso_len)); 28337469Ssklower else 28437469Ssklower name->m_len = 0; 28536403Ssklower } 28636403Ssklower 28736403Ssklower /* 28836403Ssklower * CALLED FROM: 28936403Ssklower * tp_input() on incoming CR, CC, and pr_usrreq() for PRU_CONNECT 29036403Ssklower * FUNCTION, ARGUMENTS, SIDE EFFECTS and RETURN VALUE: 29136403Ssklower * Determine the proper maximum transmission unit, i.e., MTU, to use, given 29236403Ssklower * a) the header size for the network protocol and the max transmission 29336403Ssklower * unit on the subnet interface, determined from the information in (isop), 29436403Ssklower * b) the max size negotiated so far (negot) 29536403Ssklower * c) the window size used by the tp connection (found in so), 29636403Ssklower * 29736403Ssklower * The result is put in the integer *size in its integer form and in 29836403Ssklower * *negot in its logarithmic form. 29936403Ssklower * 30036403Ssklower * The rules are: 30136403Ssklower * a) can only negotiate down from the value found in *negot. 30236403Ssklower * b) the MTU must be < the windowsize, 30336403Ssklower * c) If src and dest are on the same net, 30436403Ssklower * we will negotiate the closest size larger than MTU but really USE 30536403Ssklower * the actual device mtu - ll hdr sizes. 30636403Ssklower * otherwise we negotiate the closest size smaller than MTU - ll hdr sizes. 30736403Ssklower */ 30836403Ssklower 30936403Ssklower void 31036403Ssklower tpclnp_mtu(so, isop, size, negot ) 31136403Ssklower struct socket *so; 31236403Ssklower struct isopcb *isop; 31336403Ssklower int *size; 31436403Ssklower u_char *negot; 31536403Ssklower { 31639230Ssklower struct ifnet *ifp = 0; 31739230Ssklower struct iso_ifaddr *ia = 0; 31836403Ssklower register int i; 31936403Ssklower int windowsize = so->so_rcv.sb_hiwat; 32036403Ssklower int clnp_size; 32136403Ssklower int sizeismtu = 0; 32239230Ssklower register struct rtentry *rt = isop->isop_route.ro_rt; 32336403Ssklower 32436403Ssklower IFDEBUG(D_CONN) 32536403Ssklower printf("tpclnp_mtu(0x%x,0x%x,0x%x,0x%x)\n", so, isop, size, negot); 32636403Ssklower ENDDEBUG 32736403Ssklower IFTRACE(D_CONN) 32836403Ssklower tptrace(TPPTmisc, "ENTER GET MTU: size negot \n",*size, *negot, 0, 0); 32936403Ssklower ENDTRACE 33036403Ssklower 33136403Ssklower *size = 1 << *negot; 33236403Ssklower 33336403Ssklower if( *size > windowsize ) { 33436403Ssklower *size = windowsize; 33536403Ssklower } 33636403Ssklower 33739230Ssklower if (rt == 0 || (rt->rt_flags & RTF_UP == 0) || 33839230Ssklower (ia = (struct iso_ifaddr *)rt->rt_ifa) == 0 || 33939230Ssklower (ifp = ia->ia_ifp) == 0) { 34039230Ssklower IFDEBUG(D_CONN) 34139230Ssklower printf("tpclnp_mtu routing abort rt=0x%x ia=0x%x ifp=0x%x\n", 34239230Ssklower rt, ia, ifp) 34339230Ssklower ENDDEBUG 34436403Ssklower return; 34539230Ssklower } 34636403Ssklower 34736403Ssklower /* TODO - make this indirect off the socket structure to the 34836403Ssklower * network layer to get headersize 34936403Ssklower */ 35037469Ssklower if (isop->isop_laddr) 35137469Ssklower clnp_size = clnp_hdrsize(isop->isop_laddr->siso_addr.isoa_len); 35237469Ssklower else 35337469Ssklower clnp_size = 20; 35436403Ssklower 35536403Ssklower if(*size > ifp->if_mtu - clnp_size) { 35636403Ssklower *size = ifp->if_mtu - clnp_size; 35736403Ssklower sizeismtu = 1; 35836403Ssklower } 35937469Ssklower /* have to transform size to the log2 of size */ 36037469Ssklower for(i=TP_MIN_TPDUSIZE; (i<TP_MAX_TPDUSIZE && ((1<<i) <= *size)) ; i++) 36137469Ssklower ; 36237469Ssklower i--; 36337469Ssklower 36436403Ssklower IFTRACE(D_CONN) 36536403Ssklower tptrace(TPPTmisc, "GET MTU MID: tpcb size negot i \n", 36636403Ssklower *size, *negot, i, 0); 36736403Ssklower ENDTRACE 36836403Ssklower 36939926Ssklower *size = 1<<i; 37036403Ssklower *negot = i; 37136403Ssklower 37236403Ssklower IFDEBUG(D_CONN) 37336403Ssklower printf("GET MTU RETURNS: ifp %s size 0x%x negot 0x%x\n", 37436403Ssklower ifp->if_name, *size, *negot); 37536403Ssklower ENDDEBUG 37636403Ssklower IFTRACE(D_CONN) 37736403Ssklower tptrace(TPPTmisc, "EXIT GET MTU: tpcb size negot \n", 37836403Ssklower *size, *negot, 0, 0); 37936403Ssklower ENDTRACE 38036403Ssklower } 38136403Ssklower 38236403Ssklower 38336403Ssklower /* 38436403Ssklower * CALLED FROM: 38536403Ssklower * tp_emit() 38636403Ssklower * FUNCTION and ARGUMENTS: 38736403Ssklower * Take a packet(m0) from tp and package it so that clnp will accept it. 38836403Ssklower * This means prepending space for the clnp header and filling in a few 38936403Ssklower * of the fields. 39036403Ssklower * inp is the isopcb structure; datalen is the length of the data in the 39136403Ssklower * mbuf string m0. 39236403Ssklower * RETURN VALUE: 39336403Ssklower * whatever (E*) is returned form the net layer output routine. 39436403Ssklower */ 39536403Ssklower 39636403Ssklower int 39736403Ssklower tpclnp_output(isop, m0, datalen, nochksum) 39836403Ssklower struct isopcb *isop; 39936403Ssklower struct mbuf *m0; 40036403Ssklower int datalen; 40136403Ssklower int nochksum; 40236403Ssklower { 40337469Ssklower register struct mbuf *m = m0; 40436403Ssklower IncStat(ts_tpdu_sent); 40536403Ssklower 40636403Ssklower IFDEBUG(D_TPISO) 40736403Ssklower struct tpdu *hdr = mtod(m0, struct tpdu *); 40836403Ssklower 40936403Ssklower printf( 41036403Ssklower "abt to call clnp_output: datalen 0x%x, hdr.li 0x%x, hdr.dutype 0x%x nocsum x%x dst addr:\n", 41136403Ssklower datalen, 41236403Ssklower (int)hdr->tpdu_li, (int)hdr->tpdu_type, nochksum); 41337469Ssklower dump_isoaddr(isop->isop_faddr); 41436403Ssklower printf("\nsrc addr:\n"); 41537469Ssklower dump_isoaddr(isop->isop_laddr); 41636403Ssklower dump_mbuf(m0, "at tpclnp_output"); 41736403Ssklower ENDDEBUG 41836403Ssklower 41936403Ssklower return 42038841Ssklower clnp_output(m0, isop, datalen, /* flags */nochksum ? CLNP_NO_CKSUM : 0); 42136403Ssklower } 42236403Ssklower 42336403Ssklower /* 42436403Ssklower * CALLED FROM: 42536403Ssklower * tp_error_emit() 42636403Ssklower * FUNCTION and ARGUMENTS: 42736403Ssklower * This is a copy of tpclnp_output that takes the addresses 42836403Ssklower * instead of a pcb. It's used by the tp_error_emit, when we 42936403Ssklower * don't have an iso_pcb with which to call the normal output rtn. 43036403Ssklower * RETURN VALUE: 43136403Ssklower * ENOBUFS or 43236403Ssklower * whatever (E*) is returned form the net layer output routine. 43336403Ssklower */ 43436403Ssklower 43536403Ssklower int 43636403Ssklower tpclnp_output_dg(laddr, faddr, m0, datalen, ro, nochksum) 43736403Ssklower struct iso_addr *laddr, *faddr; 43836403Ssklower struct mbuf *m0; 43936403Ssklower int datalen; 44036403Ssklower struct route *ro; 44136403Ssklower int nochksum; 44236403Ssklower { 44336403Ssklower struct isopcb tmppcb; 44436403Ssklower int err; 44536403Ssklower int flags; 44637469Ssklower register struct mbuf *m = m0; 44736403Ssklower 44836403Ssklower IFDEBUG(D_TPISO) 44936403Ssklower printf("tpclnp_output_dg datalen 0x%x m0 0x%x\n", datalen, m0); 45036403Ssklower ENDDEBUG 45136403Ssklower 45236403Ssklower /* 45336403Ssklower * Fill in minimal portion of isopcb so that clnp can send the 45436403Ssklower * packet. 45536403Ssklower */ 45636403Ssklower bzero((caddr_t)&tmppcb, sizeof(tmppcb)); 45737469Ssklower tmppcb.isop_laddr = &tmppcb.isop_sladdr; 45837469Ssklower tmppcb.isop_laddr->siso_addr = *laddr; 45937469Ssklower tmppcb.isop_faddr = &tmppcb.isop_sfaddr; 46037469Ssklower tmppcb.isop_faddr->siso_addr = *faddr; 46136403Ssklower 46236403Ssklower IFDEBUG(D_TPISO) 46336403Ssklower printf("tpclnp_output_dg faddr: \n"); 46437469Ssklower dump_isoaddr(&tmppcb.isop_sfaddr); 46536403Ssklower printf("\ntpclnp_output_dg laddr: \n"); 46637469Ssklower dump_isoaddr(&tmppcb.isop_sladdr); 46736403Ssklower printf("\n"); 46836403Ssklower ENDDEBUG 46936403Ssklower 47036403Ssklower /* 47136403Ssklower * Do not use packet cache since this is a one shot error packet 47236403Ssklower */ 47336403Ssklower flags = (CLNP_NOCACHE|(nochksum?CLNP_NO_CKSUM:0)); 47436403Ssklower 47536403Ssklower IncStat(ts_tpdu_sent); 47636403Ssklower 47738841Ssklower err = clnp_output(m0, &tmppcb, datalen, flags); 47836403Ssklower 47936403Ssklower /* 48036403Ssklower * Free route allocated by clnp (if the route was indeed allocated) 48136403Ssklower */ 48236403Ssklower if (tmppcb.isop_route.ro_rt) 48336403Ssklower RTFREE(tmppcb.isop_route.ro_rt); 48436403Ssklower 48536403Ssklower return(err); 48636403Ssklower } 48736403Ssklower /* 48836403Ssklower * CALLED FROM: 48936403Ssklower * clnp's input routine, indirectly through the protosw. 49036403Ssklower * FUNCTION and ARGUMENTS: 49136403Ssklower * Take a packet (m) from clnp, strip off the clnp header and give it to tp 49236403Ssklower * No return value. 49336403Ssklower */ 49436403Ssklower ProtoHook 49539927Ssklower tpclnp_input(m, src, dst, clnp_len, ce_bit) 49639926Ssklower register struct mbuf *m; 49739926Ssklower struct sockaddr_iso *src, *dst; 49839927Ssklower int clnp_len, ce_bit; 49936403Ssklower { 50036403Ssklower int s = splnet(); 50137469Ssklower struct mbuf *tp_inputprep(); 50239926Ssklower int tp_input(), cltp_input(), (*input)() = tp_input; 50336403Ssklower 50436403Ssklower IncStat(ts_pkt_rcvd); 50536403Ssklower 50636403Ssklower IFDEBUG(D_TPINPUT) 50736403Ssklower printf("tpclnp_input: m 0x%x clnp_len 0x%x\n", m, clnp_len); 50836403Ssklower dump_mbuf(m, "at tpclnp_input"); 50936403Ssklower ENDDEBUG 51036403Ssklower /* 51136403Ssklower * CLNP gives us an mbuf chain WITH the clnp header pulled up, 51236403Ssklower * and the length of the clnp header. 51336403Ssklower * First, strip off the Clnp header. leave the mbuf there for the 51436403Ssklower * pullup that follows. 51536403Ssklower */ 51636403Ssklower 51736403Ssklower m->m_len -= clnp_len; 51837469Ssklower m->m_data += clnp_len; 51936403Ssklower 52037469Ssklower m = tp_inputprep(m); 52139926Ssklower if (m == 0) 52239926Ssklower return 0; 52339926Ssklower if (mtod(m, u_char *)[1] == UD_TPDU_type) 52439926Ssklower input = cltp_input; 52536403Ssklower 52636403Ssklower IFDEBUG(D_TPINPUT) 52736403Ssklower dump_mbuf(m, "after tpclnp_input both pullups"); 52836403Ssklower ENDDEBUG 52936403Ssklower 53036403Ssklower IFDEBUG(D_TPISO) 53139926Ssklower printf("calling %sinput : src 0x%x, dst 0x%x, src addr:\n", 53239926Ssklower (input == tp_input ? "tp_" : "clts_"), src, dst); 53339926Ssklower dump_isoaddr(src); 53436403Ssklower printf(" dst addr:\n"); 53539926Ssklower dump_isoaddr(dst); 53636403Ssklower ENDDEBUG 53736403Ssklower 53839926Ssklower (void) (*input)(m, (struct sockaddr *)src, (struct sockaddr *)dst, 53939927Ssklower 0, tpclnp_output_dg, ce_bit); 54036403Ssklower 54136403Ssklower IFDEBUG(D_QUENCH) 54236403Ssklower { 54336403Ssklower if(time.tv_usec & 0x4 && time.tv_usec & 0x40) { 54436403Ssklower printf("tpclnp_input: FAKING %s\n", 54536403Ssklower tp_stat.ts_pkt_rcvd & 0x1?"QUENCH":"QUENCH2"); 54636403Ssklower if(tp_stat.ts_pkt_rcvd & 0x1) { 54736403Ssklower tpclnp_ctlinput(PRC_QUENCH, &src); 54836403Ssklower } else { 54936403Ssklower tpclnp_ctlinput(PRC_QUENCH2, &src); 55036403Ssklower } 55136403Ssklower } 55236403Ssklower } 55336403Ssklower ENDDEBUG 55436403Ssklower 55536403Ssklower splx(s); 55636403Ssklower return 0; 55736403Ssklower } 55836403Ssklower 55936403Ssklower ProtoHook 56036403Ssklower iso_rtchange() 56136403Ssklower { 56236403Ssklower return 0; 56336403Ssklower } 56436403Ssklower 56536403Ssklower /* 56636403Ssklower * CALLED FROM: 56736403Ssklower * tpclnp_ctlinput() 56836403Ssklower * FUNCTION and ARGUMENTS: 56936403Ssklower * find the tpcb pointer and pass it to tp_quench 57036403Ssklower */ 57136403Ssklower void 57236403Ssklower tpiso_decbit(isop) 57336403Ssklower struct isopcb *isop; 57436403Ssklower { 57537469Ssklower tp_quench((struct tp_pcb *)isop->isop_socket->so_tpcb, PRC_QUENCH2); 57636403Ssklower } 57736403Ssklower /* 57836403Ssklower * CALLED FROM: 57936403Ssklower * tpclnp_ctlinput() 58036403Ssklower * FUNCTION and ARGUMENTS: 58136403Ssklower * find the tpcb pointer and pass it to tp_quench 58236403Ssklower */ 58336403Ssklower void 58436403Ssklower tpiso_quench(isop) 58536403Ssklower struct isopcb *isop; 58636403Ssklower { 58737469Ssklower tp_quench((struct tp_pcb *)isop->isop_socket->so_tpcb, PRC_QUENCH); 58836403Ssklower } 58936403Ssklower 59036403Ssklower /* 59136403Ssklower * CALLED FROM: 59236403Ssklower * The network layer through the protosw table. 59336403Ssklower * FUNCTION and ARGUMENTS: 59436403Ssklower * When clnp an ICMP-like msg this gets called. 59536403Ssklower * It either returns an error status to the user or 59636403Ssklower * it causes all connections on this address to be aborted 59736403Ssklower * by calling the appropriate xx_notify() routine. 59836403Ssklower * (cmd) is the type of ICMP error. 59936403Ssklower * (siso) is the address of the guy who sent the ER CLNPDU 60036403Ssklower */ 60136403Ssklower ProtoHook 60236403Ssklower tpclnp_ctlinput(cmd, siso) 60336403Ssklower int cmd; 60436403Ssklower struct sockaddr_iso *siso; 60536403Ssklower { 60636403Ssklower extern u_char inetctlerrmap[]; 60736403Ssklower extern ProtoHook tpiso_abort(); 60836403Ssklower extern ProtoHook iso_rtchange(); 60936403Ssklower extern ProtoHook tpiso_reset(); 61037469Ssklower void iso_pcbnotify(); 61136403Ssklower 61236403Ssklower IFDEBUG(D_TPINPUT) 61339926Ssklower printf("tpclnp_ctlinput1: cmd 0x%x addr: \n", cmd); 61439926Ssklower dump_isoaddr(siso); 61536403Ssklower ENDDEBUG 61636403Ssklower 61736403Ssklower if (cmd < 0 || cmd > PRC_NCMDS) 61836403Ssklower return 0; 61939926Ssklower if (siso->siso_family != AF_ISO) 62039926Ssklower return 0; 62136403Ssklower switch (cmd) { 62236403Ssklower 62336403Ssklower case PRC_QUENCH2: 62439926Ssklower iso_pcbnotify(&tp_isopcb, siso, 0, (int (*)())tpiso_decbit); 62536403Ssklower break; 62636403Ssklower 62736403Ssklower case PRC_QUENCH: 62839926Ssklower iso_pcbnotify(&tp_isopcb, siso, 0, (int (*)())tpiso_quench); 62936403Ssklower break; 63036403Ssklower 63136403Ssklower case PRC_TIMXCEED_REASS: 63236403Ssklower case PRC_ROUTEDEAD: 63339926Ssklower iso_pcbnotify(&tp_isopcb, siso, 0, tpiso_reset); 63436403Ssklower break; 63536403Ssklower 63636403Ssklower case PRC_HOSTUNREACH: 63736403Ssklower case PRC_UNREACH_NET: 63836403Ssklower case PRC_IFDOWN: 63936403Ssklower case PRC_HOSTDEAD: 64039926Ssklower iso_pcbnotify(&tp_isopcb, siso, 64136403Ssklower (int)inetctlerrmap[cmd], iso_rtchange); 64236403Ssklower break; 64336403Ssklower 64436403Ssklower default: 64536403Ssklower /* 64636403Ssklower case PRC_MSGSIZE: 64736403Ssklower case PRC_UNREACH_HOST: 64836403Ssklower case PRC_UNREACH_PROTOCOL: 64936403Ssklower case PRC_UNREACH_PORT: 65036403Ssklower case PRC_UNREACH_NEEDFRAG: 65136403Ssklower case PRC_UNREACH_SRCFAIL: 65236403Ssklower case PRC_REDIRECT_NET: 65336403Ssklower case PRC_REDIRECT_HOST: 65436403Ssklower case PRC_REDIRECT_TOSNET: 65536403Ssklower case PRC_REDIRECT_TOSHOST: 65636403Ssklower case PRC_TIMXCEED_INTRANS: 65736403Ssklower case PRC_PARAMPROB: 65836403Ssklower */ 65939926Ssklower iso_pcbnotify(&tp_isopcb, siso, (int)inetctlerrmap[cmd], tpiso_abort); 66036403Ssklower break; 66136403Ssklower } 66236403Ssklower return 0; 66336403Ssklower } 66439926Ssklower /* 66539926Ssklower * XXX - Variant which is called by clnp_er.c with an isoaddr rather 66639926Ssklower * than a sockaddr_iso. 66739926Ssklower */ 66836403Ssklower 66939926Ssklower static struct sockaddr_iso siso = {sizeof(siso), AF_ISO}; 67039926Ssklower tpclnp_ctlinput1(cmd, isoa) 67139926Ssklower int cmd; 67239926Ssklower struct iso_addr *isoa; 67339926Ssklower { 67439926Ssklower bzero((caddr_t)&siso.siso_addr, sizeof(siso.siso_addr)); 67539926Ssklower bcopy((caddr_t)isoa, (caddr_t)&siso.siso_addr, isoa->isoa_len); 67639926Ssklower tpclnp_ctlinput(cmd, &siso); 67739926Ssklower } 67839926Ssklower 67936403Ssklower /* 68036403Ssklower * These next 2 routines are 68136403Ssklower * CALLED FROM: 68236403Ssklower * xxx_notify() from tp_ctlinput() when 68336403Ssklower * net level gets some ICMP-equiv. type event. 68436403Ssklower * FUNCTION and ARGUMENTS: 68536403Ssklower * Cause the connection to be aborted with some sort of error 68636403Ssklower * reason indicating that the network layer caused the abort. 68736403Ssklower * Fakes an ER TPDU so we can go through the driver. 68836403Ssklower * abort always aborts the TP connection. 68936403Ssklower * reset may or may not, depending on the TP class that's in use. 69036403Ssklower */ 69136403Ssklower ProtoHook 69236403Ssklower tpiso_abort(isop) 69336403Ssklower struct isopcb *isop; 69436403Ssklower { 69536403Ssklower struct tp_event e; 69636403Ssklower 69736403Ssklower IFDEBUG(D_CONN) 69836403Ssklower printf("tpiso_abort 0x%x\n", isop); 69936403Ssklower ENDDEBUG 70036403Ssklower e.ev_number = ER_TPDU; 70136403Ssklower e.ATTR(ER_TPDU).e_reason = ECONNABORTED; 70236403Ssklower return tp_driver((struct tp_pcb *)isop->isop_socket->so_tpcb, &e); 70336403Ssklower } 70436403Ssklower 70536403Ssklower ProtoHook 70636403Ssklower tpiso_reset(isop) 70736403Ssklower struct isopcb *isop; 70836403Ssklower { 70936403Ssklower struct tp_event e; 71036403Ssklower 71136403Ssklower e.ev_number = T_NETRESET; 71236403Ssklower return tp_driver((struct tp_pcb *)isop->isop_socket->so_tpcb, &e); 71336403Ssklower 71436403Ssklower } 71536403Ssklower 71636403Ssklower #endif ISO 717