1*49268Sbostic /*- 2*49268Sbostic * Copyright (c) 1991 The Regents of the University of California. 3*49268Sbostic * All rights reserved. 4*49268Sbostic * 5*49268Sbostic * %sccs.include.redist.c% 6*49268Sbostic * 7*49268Sbostic * @(#)tp_iso.c 7.11 (Berkeley) 05/06/91 8*49268Sbostic */ 9*49268Sbostic 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 6337469Ssklower #include "param.h" 6437469Ssklower #include "socket.h" 6537469Ssklower #include "socketvar.h" 6637469Ssklower #include "domain.h" 6737469Ssklower #include "malloc.h" 6837469Ssklower #include "mbuf.h" 6937469Ssklower #include "errno.h" 7037469Ssklower #include "time.h" 7137469Ssklower #include "protosw.h" 7237469Ssklower 7336403Ssklower #include "../net/if.h" 7436403Ssklower #include "../net/route.h" 7536403Ssklower 7637469Ssklower #include "argo_debug.h" 7737469Ssklower #include "tp_param.h" 7837469Ssklower #include "tp_stat.h" 7937469Ssklower #include "tp_pcb.h" 8037469Ssklower #include "tp_trace.h" 8137469Ssklower #include "tp_stat.h" 8237469Ssklower #include "tp_tpdu.h" 8337469Ssklower #include "tp_clnp.h" 8439926Ssklower #include "cltp_var.h" 8536403Ssklower 8636403Ssklower /* 8736403Ssklower * CALLED FROM: 8836403Ssklower * pr_usrreq() on PRU_BIND, PRU_CONNECT, PRU_ACCEPT, and PRU_PEERADDR 8937469Ssklower * FUNCTION, ARGUMENTS: 9036403Ssklower * The argument (which) takes the value TP_LOCAL or TP_FOREIGN. 9136403Ssklower */ 9236403Ssklower 9337469Ssklower iso_getsufx(isop, lenp, data_out, which) 9436403Ssklower struct isopcb *isop; 9537469Ssklower u_short *lenp; 9637469Ssklower caddr_t data_out; 9736403Ssklower int which; 9836403Ssklower { 9937469Ssklower register struct sockaddr_iso *addr = 0; 10037469Ssklower 10136403Ssklower switch (which) { 10236403Ssklower case TP_LOCAL: 10337469Ssklower addr = isop->isop_laddr; 10437469Ssklower break; 10536403Ssklower 10636403Ssklower case TP_FOREIGN: 10737469Ssklower addr = isop->isop_faddr; 10836403Ssklower } 10937469Ssklower if (addr) 11038841Ssklower bcopy(TSEL(addr), data_out, (*lenp = addr->siso_tlen)); 11136403Ssklower } 11236403Ssklower 11336403Ssklower /* CALLED FROM: 11436403Ssklower * tp_newsocket(); i.e., when a connection is being established by an 11536403Ssklower * incoming CR_TPDU. 11636403Ssklower * 11736403Ssklower * FUNCTION, ARGUMENTS: 11836403Ssklower * Put a transport suffix (found in name) into an isopcb structure (isop). 11936403Ssklower * The argument (which) takes the value TP_LOCAL or TP_FOREIGN. 12036403Ssklower */ 12136403Ssklower void 12237469Ssklower iso_putsufx(isop, sufxloc, sufxlen, which) 12336403Ssklower struct isopcb *isop; 12437469Ssklower caddr_t sufxloc; 12537469Ssklower int sufxlen, which; 12636403Ssklower { 12737469Ssklower struct sockaddr_iso **dst, *backup; 12837469Ssklower register struct sockaddr_iso *addr; 12937469Ssklower struct mbuf *m; 13037469Ssklower int len; 13137469Ssklower 13236403Ssklower switch (which) { 13337469Ssklower default: 13437469Ssklower return; 13537469Ssklower 13636403Ssklower case TP_LOCAL: 13737469Ssklower dst = &isop->isop_laddr; 13837469Ssklower backup = &isop->isop_sladdr; 13936403Ssklower break; 14037469Ssklower 14136403Ssklower case TP_FOREIGN: 14237469Ssklower dst = &isop->isop_faddr; 14337469Ssklower backup = &isop->isop_sfaddr; 14436403Ssklower } 14537469Ssklower if ((addr = *dst) == 0) { 14637469Ssklower addr = *dst = backup; 14737469Ssklower addr->siso_nlen = 0; 14838841Ssklower addr->siso_slen = 0; 14938841Ssklower addr->siso_plen = 0; 15037469Ssklower printf("iso_putsufx on un-initialized isopcb\n"); 15137469Ssklower } 15237469Ssklower len = sufxlen + addr->siso_nlen + 15338841Ssklower (sizeof(*addr) - sizeof(addr->siso_data)); 15437469Ssklower if (addr == backup) { 15538841Ssklower if (len > sizeof(*addr)) { 15637469Ssklower m = m_getclr(M_DONTWAIT, MT_SONAME); 15737469Ssklower if (m == 0) 15837469Ssklower return; 15937469Ssklower addr = *dst = mtod(m, struct sockaddr_iso *); 16037469Ssklower *addr = *backup; 16137469Ssklower m->m_len = len; 16237469Ssklower } 16338841Ssklower } 16437469Ssklower bcopy(sufxloc, TSEL(addr), sufxlen); 16538841Ssklower addr->siso_tlen = sufxlen; 16637469Ssklower addr->siso_len = len; 16736403Ssklower } 16836403Ssklower 16936403Ssklower /* 17036403Ssklower * CALLED FROM: 17136403Ssklower * tp.trans whenever we go into REFWAIT state. 17236403Ssklower * FUNCTION and ARGUMENT: 17336403Ssklower * Called when a ref is frozen, to allow the suffix to be reused. 17436403Ssklower * (isop) is the net level pcb. This really shouldn't have to be 17536403Ssklower * done in a NET level pcb but... for the internet world that just 17636403Ssklower * the way it is done in BSD... 17736403Ssklower * The alternative is to have the port unusable until the reference 17836403Ssklower * timer goes off. 17936403Ssklower */ 18036403Ssklower void 18136403Ssklower iso_recycle_tsuffix(isop) 18236403Ssklower struct isopcb *isop; 18336403Ssklower { 18438841Ssklower isop->isop_laddr->siso_tlen = isop->isop_faddr->siso_tlen = 0; 18536403Ssklower } 18636403Ssklower 18736403Ssklower /* 18836403Ssklower * CALLED FROM: 18936403Ssklower * tp_newsocket(); i.e., when a connection is being established by an 19036403Ssklower * incoming CR_TPDU. 19136403Ssklower * 19236403Ssklower * FUNCTION and ARGUMENTS: 19336403Ssklower * Copy a whole net addr from a struct sockaddr (name). 19436403Ssklower * into an isopcb (isop). 19536403Ssklower * The argument (which) takes values TP_LOCAL or TP_FOREIGN 19636403Ssklower */ 19736403Ssklower void 19836403Ssklower iso_putnetaddr(isop, name, which) 19936403Ssklower register struct isopcb *isop; 20036403Ssklower struct sockaddr_iso *name; 20136403Ssklower int which; 20236403Ssklower { 20337469Ssklower struct sockaddr_iso **sisop, *backup; 20437469Ssklower register struct sockaddr_iso *siso; 20537469Ssklower 20636403Ssklower switch (which) { 20744422Ssklower default: 20844422Ssklower printf("iso_putnetaddr: should panic\n"); 20944422Ssklower return; 21036403Ssklower case TP_LOCAL: 21137469Ssklower sisop = &isop->isop_laddr; 21237469Ssklower backup = &isop->isop_sladdr; 21336403Ssklower break; 21436403Ssklower case TP_FOREIGN: 21537469Ssklower sisop = &isop->isop_faddr; 21637469Ssklower backup = &isop->isop_sfaddr; 21736403Ssklower } 21837469Ssklower siso = ((*sisop == 0) ? (*sisop = backup) : *sisop); 21937469Ssklower IFDEBUG(D_TPISO) 22037469Ssklower printf("ISO_PUTNETADDR\n"); 22137469Ssklower dump_isoaddr(isop->isop_faddr); 22237469Ssklower ENDDEBUG 22337469Ssklower siso->siso_addr = name->siso_addr; 22436403Ssklower } 22536403Ssklower 22636403Ssklower /* 22736403Ssklower * CALLED FROM: 22844422Ssklower * tp_input() when a connection is being established by an 22944422Ssklower * incoming CR_TPDU, and considered for interception. 23044422Ssklower * 23144422Ssklower * FUNCTION and ARGUMENTS: 23244422Ssklower * compare a whole net addr from a struct sockaddr (name), 23344422Ssklower * with that implicitly stored in an isopcb (isop). 23444422Ssklower * The argument (which) takes values TP_LOCAL or TP_FOREIGN. 23544422Ssklower */ 23644422Ssklower iso_cmpnetaddr(isop, name, which) 23744422Ssklower register struct isopcb *isop; 23844422Ssklower register struct sockaddr_iso *name; 23944422Ssklower int which; 24044422Ssklower { 24144422Ssklower struct sockaddr_iso **sisop, *backup; 24244422Ssklower register struct sockaddr_iso *siso; 24344422Ssklower 24444422Ssklower switch (which) { 24544422Ssklower default: 24644422Ssklower printf("iso_cmpnetaddr: should panic\n"); 24744422Ssklower return 0; 24844422Ssklower case TP_LOCAL: 24944422Ssklower sisop = &isop->isop_laddr; 25044422Ssklower backup = &isop->isop_sladdr; 25144422Ssklower break; 25244422Ssklower case TP_FOREIGN: 25344422Ssklower sisop = &isop->isop_faddr; 25444422Ssklower backup = &isop->isop_sfaddr; 25544422Ssklower } 25644422Ssklower siso = ((*sisop == 0) ? (*sisop = backup) : *sisop); 25744422Ssklower IFDEBUG(D_TPISO) 25844422Ssklower printf("ISO_CMPNETADDR\n"); 25944422Ssklower dump_isoaddr(siso); 26044422Ssklower ENDDEBUG 26144422Ssklower if (name->siso_tlen && bcmp(TSEL(name), TSEL(siso), name->siso_tlen)) 26244422Ssklower return (0); 26344422Ssklower return (bcmp((caddr_t)name->siso_data, 26444422Ssklower (caddr_t)siso->siso_data, name->siso_nlen) == 0); 26544422Ssklower } 26644422Ssklower 26744422Ssklower /* 26844422Ssklower * CALLED FROM: 26936403Ssklower * pr_usrreq() PRU_SOCKADDR, PRU_ACCEPT, PRU_PEERADDR 27036403Ssklower * FUNCTION and ARGUMENTS: 27136403Ssklower * Copy a whole net addr from an isopcb (isop) into 27236403Ssklower * a struct sockaddr (name). 27336403Ssklower * The argument (which) takes values TP_LOCAL or TP_FOREIGN. 27436403Ssklower */ 27536403Ssklower 27636403Ssklower void 27736403Ssklower iso_getnetaddr( isop, name, which) 27836403Ssklower struct isopcb *isop; 27937469Ssklower struct mbuf *name; 28036403Ssklower int which; 28136403Ssklower { 28237469Ssklower struct sockaddr_iso *siso = 28337469Ssklower (which == TP_LOCAL ? isop->isop_laddr : isop->isop_faddr); 28437469Ssklower if (siso) 28537469Ssklower bcopy((caddr_t)siso, mtod(name, caddr_t), 28637469Ssklower (unsigned)(name->m_len = siso->siso_len)); 28737469Ssklower else 28837469Ssklower name->m_len = 0; 28936403Ssklower } 29036403Ssklower 29136403Ssklower /* 29236403Ssklower * CALLED FROM: 29336403Ssklower * tp_input() on incoming CR, CC, and pr_usrreq() for PRU_CONNECT 29436403Ssklower * FUNCTION, ARGUMENTS, SIDE EFFECTS and RETURN VALUE: 29536403Ssklower * Determine the proper maximum transmission unit, i.e., MTU, to use, given 29636403Ssklower * a) the header size for the network protocol and the max transmission 29736403Ssklower * unit on the subnet interface, determined from the information in (isop), 29836403Ssklower * b) the max size negotiated so far (negot) 29936403Ssklower * c) the window size used by the tp connection (found in so), 30036403Ssklower * 30136403Ssklower * The result is put in the integer *size in its integer form and in 30236403Ssklower * *negot in its logarithmic form. 30336403Ssklower * 30436403Ssklower * The rules are: 30536403Ssklower * a) can only negotiate down from the value found in *negot. 30636403Ssklower * b) the MTU must be < the windowsize, 30736403Ssklower * c) If src and dest are on the same net, 30836403Ssklower * we will negotiate the closest size larger than MTU but really USE 30936403Ssklower * the actual device mtu - ll hdr sizes. 31036403Ssklower * otherwise we negotiate the closest size smaller than MTU - ll hdr sizes. 31136403Ssklower */ 31236403Ssklower 31336403Ssklower void 31436403Ssklower tpclnp_mtu(so, isop, size, negot ) 31536403Ssklower struct socket *so; 31636403Ssklower struct isopcb *isop; 31736403Ssklower int *size; 31836403Ssklower u_char *negot; 31936403Ssklower { 32039230Ssklower struct ifnet *ifp = 0; 32139230Ssklower struct iso_ifaddr *ia = 0; 32236403Ssklower register int i; 32336403Ssklower int windowsize = so->so_rcv.sb_hiwat; 32448738Ssklower int clnp_size, mtu; 32536403Ssklower int sizeismtu = 0; 32639230Ssklower register struct rtentry *rt = isop->isop_route.ro_rt; 32736403Ssklower 32836403Ssklower IFDEBUG(D_CONN) 32936403Ssklower printf("tpclnp_mtu(0x%x,0x%x,0x%x,0x%x)\n", so, isop, size, negot); 33036403Ssklower ENDDEBUG 33136403Ssklower IFTRACE(D_CONN) 33236403Ssklower tptrace(TPPTmisc, "ENTER GET MTU: size negot \n",*size, *negot, 0, 0); 33336403Ssklower ENDTRACE 33436403Ssklower 33536403Ssklower *size = 1 << *negot; 33636403Ssklower 33736403Ssklower if( *size > windowsize ) { 33836403Ssklower *size = windowsize; 33936403Ssklower } 34036403Ssklower 34139230Ssklower if (rt == 0 || (rt->rt_flags & RTF_UP == 0) || 34239230Ssklower (ia = (struct iso_ifaddr *)rt->rt_ifa) == 0 || 34339230Ssklower (ifp = ia->ia_ifp) == 0) { 34439230Ssklower IFDEBUG(D_CONN) 34539230Ssklower printf("tpclnp_mtu routing abort rt=0x%x ia=0x%x ifp=0x%x\n", 34639230Ssklower rt, ia, ifp) 34739230Ssklower ENDDEBUG 34836403Ssklower return; 34939230Ssklower } 35036403Ssklower 35148738Ssklower 35248738Ssklower 35336403Ssklower /* TODO - make this indirect off the socket structure to the 35436403Ssklower * network layer to get headersize 35536403Ssklower */ 35648738Ssklower clnp_size = sizeof(struct clnp_fixed) + sizeof(struct clnp_segment) + 35748738Ssklower 2 * sizeof(struct iso_addr); 35848738Ssklower mtu = SN_MTU(ifp, rt) - clnp_size; 35948738Ssklower if(*size > mtu) { 36048738Ssklower *size = mtu; 36136403Ssklower sizeismtu = 1; 36236403Ssklower } 36337469Ssklower /* have to transform size to the log2 of size */ 36447279Ssklower for(i=TP_MIN_TPDUSIZE; (i<=TP_MAX_TPDUSIZE && ((1<<i) <= *size)) ; i++) 36537469Ssklower ; 36637469Ssklower i--; 36737469Ssklower 36836403Ssklower IFTRACE(D_CONN) 36936403Ssklower tptrace(TPPTmisc, "GET MTU MID: tpcb size negot i \n", 37036403Ssklower *size, *negot, i, 0); 37136403Ssklower ENDTRACE 37236403Ssklower 37339926Ssklower *size = 1<<i; 37436403Ssklower *negot = i; 37536403Ssklower 37636403Ssklower IFDEBUG(D_CONN) 37736403Ssklower printf("GET MTU RETURNS: ifp %s size 0x%x negot 0x%x\n", 37836403Ssklower ifp->if_name, *size, *negot); 37936403Ssklower ENDDEBUG 38036403Ssklower IFTRACE(D_CONN) 38136403Ssklower tptrace(TPPTmisc, "EXIT GET MTU: tpcb size negot \n", 38236403Ssklower *size, *negot, 0, 0); 38336403Ssklower ENDTRACE 38436403Ssklower } 38536403Ssklower 38636403Ssklower 38736403Ssklower /* 38836403Ssklower * CALLED FROM: 38936403Ssklower * tp_emit() 39036403Ssklower * FUNCTION and ARGUMENTS: 39136403Ssklower * Take a packet(m0) from tp and package it so that clnp will accept it. 39236403Ssklower * This means prepending space for the clnp header and filling in a few 39336403Ssklower * of the fields. 39436403Ssklower * inp is the isopcb structure; datalen is the length of the data in the 39536403Ssklower * mbuf string m0. 39636403Ssklower * RETURN VALUE: 39736403Ssklower * whatever (E*) is returned form the net layer output routine. 39836403Ssklower */ 39936403Ssklower 40036403Ssklower int 40136403Ssklower tpclnp_output(isop, m0, datalen, nochksum) 40236403Ssklower struct isopcb *isop; 40336403Ssklower struct mbuf *m0; 40436403Ssklower int datalen; 40536403Ssklower int nochksum; 40636403Ssklower { 40737469Ssklower register struct mbuf *m = m0; 40836403Ssklower IncStat(ts_tpdu_sent); 40936403Ssklower 41036403Ssklower IFDEBUG(D_TPISO) 41136403Ssklower struct tpdu *hdr = mtod(m0, struct tpdu *); 41236403Ssklower 41336403Ssklower printf( 41436403Ssklower "abt to call clnp_output: datalen 0x%x, hdr.li 0x%x, hdr.dutype 0x%x nocsum x%x dst addr:\n", 41536403Ssklower datalen, 41636403Ssklower (int)hdr->tpdu_li, (int)hdr->tpdu_type, nochksum); 41737469Ssklower dump_isoaddr(isop->isop_faddr); 41836403Ssklower printf("\nsrc addr:\n"); 41937469Ssklower dump_isoaddr(isop->isop_laddr); 42036403Ssklower dump_mbuf(m0, "at tpclnp_output"); 42136403Ssklower ENDDEBUG 42236403Ssklower 42336403Ssklower return 42438841Ssklower clnp_output(m0, isop, datalen, /* flags */nochksum ? CLNP_NO_CKSUM : 0); 42536403Ssklower } 42636403Ssklower 42736403Ssklower /* 42836403Ssklower * CALLED FROM: 42936403Ssklower * tp_error_emit() 43036403Ssklower * FUNCTION and ARGUMENTS: 43136403Ssklower * This is a copy of tpclnp_output that takes the addresses 43236403Ssklower * instead of a pcb. It's used by the tp_error_emit, when we 43336403Ssklower * don't have an iso_pcb with which to call the normal output rtn. 43436403Ssklower * RETURN VALUE: 43536403Ssklower * ENOBUFS or 43636403Ssklower * whatever (E*) is returned form the net layer output routine. 43736403Ssklower */ 43836403Ssklower 43936403Ssklower int 44036403Ssklower tpclnp_output_dg(laddr, faddr, m0, datalen, ro, nochksum) 44136403Ssklower struct iso_addr *laddr, *faddr; 44236403Ssklower struct mbuf *m0; 44336403Ssklower int datalen; 44436403Ssklower struct route *ro; 44536403Ssklower int nochksum; 44636403Ssklower { 44736403Ssklower struct isopcb tmppcb; 44836403Ssklower int err; 44936403Ssklower int flags; 45037469Ssklower register struct mbuf *m = m0; 45136403Ssklower 45236403Ssklower IFDEBUG(D_TPISO) 45336403Ssklower printf("tpclnp_output_dg datalen 0x%x m0 0x%x\n", datalen, m0); 45436403Ssklower ENDDEBUG 45536403Ssklower 45636403Ssklower /* 45736403Ssklower * Fill in minimal portion of isopcb so that clnp can send the 45836403Ssklower * packet. 45936403Ssklower */ 46036403Ssklower bzero((caddr_t)&tmppcb, sizeof(tmppcb)); 46137469Ssklower tmppcb.isop_laddr = &tmppcb.isop_sladdr; 46237469Ssklower tmppcb.isop_laddr->siso_addr = *laddr; 46337469Ssklower tmppcb.isop_faddr = &tmppcb.isop_sfaddr; 46437469Ssklower tmppcb.isop_faddr->siso_addr = *faddr; 46536403Ssklower 46636403Ssklower IFDEBUG(D_TPISO) 46736403Ssklower printf("tpclnp_output_dg faddr: \n"); 46837469Ssklower dump_isoaddr(&tmppcb.isop_sfaddr); 46936403Ssklower printf("\ntpclnp_output_dg laddr: \n"); 47037469Ssklower dump_isoaddr(&tmppcb.isop_sladdr); 47136403Ssklower printf("\n"); 47236403Ssklower ENDDEBUG 47336403Ssklower 47436403Ssklower /* 47536403Ssklower * Do not use packet cache since this is a one shot error packet 47636403Ssklower */ 47736403Ssklower flags = (CLNP_NOCACHE|(nochksum?CLNP_NO_CKSUM:0)); 47836403Ssklower 47936403Ssklower IncStat(ts_tpdu_sent); 48036403Ssklower 48138841Ssklower err = clnp_output(m0, &tmppcb, datalen, flags); 48236403Ssklower 48336403Ssklower /* 48436403Ssklower * Free route allocated by clnp (if the route was indeed allocated) 48536403Ssklower */ 48636403Ssklower if (tmppcb.isop_route.ro_rt) 48736403Ssklower RTFREE(tmppcb.isop_route.ro_rt); 48836403Ssklower 48936403Ssklower return(err); 49036403Ssklower } 49136403Ssklower /* 49236403Ssklower * CALLED FROM: 49336403Ssklower * clnp's input routine, indirectly through the protosw. 49436403Ssklower * FUNCTION and ARGUMENTS: 49536403Ssklower * Take a packet (m) from clnp, strip off the clnp header and give it to tp 49636403Ssklower * No return value. 49736403Ssklower */ 49836403Ssklower ProtoHook 49939927Ssklower tpclnp_input(m, src, dst, clnp_len, ce_bit) 50039926Ssklower register struct mbuf *m; 50139926Ssklower struct sockaddr_iso *src, *dst; 50239927Ssklower int clnp_len, ce_bit; 50336403Ssklower { 50436403Ssklower int s = splnet(); 50537469Ssklower struct mbuf *tp_inputprep(); 50639926Ssklower int tp_input(), cltp_input(), (*input)() = tp_input; 50736403Ssklower 50836403Ssklower IncStat(ts_pkt_rcvd); 50936403Ssklower 51036403Ssklower IFDEBUG(D_TPINPUT) 51136403Ssklower printf("tpclnp_input: m 0x%x clnp_len 0x%x\n", m, clnp_len); 51236403Ssklower dump_mbuf(m, "at tpclnp_input"); 51336403Ssklower ENDDEBUG 51436403Ssklower /* 51536403Ssklower * CLNP gives us an mbuf chain WITH the clnp header pulled up, 51636403Ssklower * and the length of the clnp header. 51736403Ssklower * First, strip off the Clnp header. leave the mbuf there for the 51836403Ssklower * pullup that follows. 51936403Ssklower */ 52036403Ssklower 52136403Ssklower m->m_len -= clnp_len; 52237469Ssklower m->m_data += clnp_len; 52336403Ssklower 52437469Ssklower m = tp_inputprep(m); 52539926Ssklower if (m == 0) 52639926Ssklower return 0; 52739926Ssklower if (mtod(m, u_char *)[1] == UD_TPDU_type) 52839926Ssklower input = cltp_input; 52936403Ssklower 53036403Ssklower IFDEBUG(D_TPINPUT) 53136403Ssklower dump_mbuf(m, "after tpclnp_input both pullups"); 53236403Ssklower ENDDEBUG 53336403Ssklower 53436403Ssklower IFDEBUG(D_TPISO) 53539926Ssklower printf("calling %sinput : src 0x%x, dst 0x%x, src addr:\n", 53639926Ssklower (input == tp_input ? "tp_" : "clts_"), src, dst); 53739926Ssklower dump_isoaddr(src); 53836403Ssklower printf(" dst addr:\n"); 53939926Ssklower dump_isoaddr(dst); 54036403Ssklower ENDDEBUG 54136403Ssklower 54239926Ssklower (void) (*input)(m, (struct sockaddr *)src, (struct sockaddr *)dst, 54339927Ssklower 0, tpclnp_output_dg, ce_bit); 54436403Ssklower 54536403Ssklower IFDEBUG(D_QUENCH) 54636403Ssklower { 54736403Ssklower if(time.tv_usec & 0x4 && time.tv_usec & 0x40) { 54836403Ssklower printf("tpclnp_input: FAKING %s\n", 54936403Ssklower tp_stat.ts_pkt_rcvd & 0x1?"QUENCH":"QUENCH2"); 55036403Ssklower if(tp_stat.ts_pkt_rcvd & 0x1) { 55136403Ssklower tpclnp_ctlinput(PRC_QUENCH, &src); 55236403Ssklower } else { 55336403Ssklower tpclnp_ctlinput(PRC_QUENCH2, &src); 55436403Ssklower } 55536403Ssklower } 55636403Ssklower } 55736403Ssklower ENDDEBUG 55836403Ssklower 55936403Ssklower splx(s); 56036403Ssklower return 0; 56136403Ssklower } 56236403Ssklower 56336403Ssklower ProtoHook 56436403Ssklower iso_rtchange() 56536403Ssklower { 56636403Ssklower return 0; 56736403Ssklower } 56836403Ssklower 56936403Ssklower /* 57036403Ssklower * CALLED FROM: 57136403Ssklower * tpclnp_ctlinput() 57236403Ssklower * FUNCTION and ARGUMENTS: 57336403Ssklower * find the tpcb pointer and pass it to tp_quench 57436403Ssklower */ 57536403Ssklower void 57636403Ssklower tpiso_decbit(isop) 57736403Ssklower struct isopcb *isop; 57836403Ssklower { 57937469Ssklower tp_quench((struct tp_pcb *)isop->isop_socket->so_tpcb, PRC_QUENCH2); 58036403Ssklower } 58136403Ssklower /* 58236403Ssklower * CALLED FROM: 58336403Ssklower * tpclnp_ctlinput() 58436403Ssklower * FUNCTION and ARGUMENTS: 58536403Ssklower * find the tpcb pointer and pass it to tp_quench 58636403Ssklower */ 58736403Ssklower void 58836403Ssklower tpiso_quench(isop) 58936403Ssklower struct isopcb *isop; 59036403Ssklower { 59137469Ssklower tp_quench((struct tp_pcb *)isop->isop_socket->so_tpcb, PRC_QUENCH); 59236403Ssklower } 59336403Ssklower 59436403Ssklower /* 59536403Ssklower * CALLED FROM: 59636403Ssklower * The network layer through the protosw table. 59736403Ssklower * FUNCTION and ARGUMENTS: 59836403Ssklower * When clnp an ICMP-like msg this gets called. 59936403Ssklower * It either returns an error status to the user or 60036403Ssklower * it causes all connections on this address to be aborted 60136403Ssklower * by calling the appropriate xx_notify() routine. 60236403Ssklower * (cmd) is the type of ICMP error. 60336403Ssklower * (siso) is the address of the guy who sent the ER CLNPDU 60436403Ssklower */ 60536403Ssklower ProtoHook 60636403Ssklower tpclnp_ctlinput(cmd, siso) 60736403Ssklower int cmd; 60836403Ssklower struct sockaddr_iso *siso; 60936403Ssklower { 61036403Ssklower extern u_char inetctlerrmap[]; 61136403Ssklower extern ProtoHook tpiso_abort(); 61236403Ssklower extern ProtoHook iso_rtchange(); 61336403Ssklower extern ProtoHook tpiso_reset(); 61437469Ssklower void iso_pcbnotify(); 61536403Ssklower 61636403Ssklower IFDEBUG(D_TPINPUT) 61739926Ssklower printf("tpclnp_ctlinput1: cmd 0x%x addr: \n", cmd); 61839926Ssklower dump_isoaddr(siso); 61936403Ssklower ENDDEBUG 62036403Ssklower 62136403Ssklower if (cmd < 0 || cmd > PRC_NCMDS) 62236403Ssklower return 0; 62339926Ssklower if (siso->siso_family != AF_ISO) 62439926Ssklower return 0; 62536403Ssklower switch (cmd) { 62636403Ssklower 62736403Ssklower case PRC_QUENCH2: 62839926Ssklower iso_pcbnotify(&tp_isopcb, siso, 0, (int (*)())tpiso_decbit); 62936403Ssklower break; 63036403Ssklower 63136403Ssklower case PRC_QUENCH: 63239926Ssklower iso_pcbnotify(&tp_isopcb, siso, 0, (int (*)())tpiso_quench); 63336403Ssklower break; 63436403Ssklower 63536403Ssklower case PRC_TIMXCEED_REASS: 63636403Ssklower case PRC_ROUTEDEAD: 63739926Ssklower iso_pcbnotify(&tp_isopcb, siso, 0, tpiso_reset); 63836403Ssklower break; 63936403Ssklower 64036403Ssklower case PRC_HOSTUNREACH: 64136403Ssklower case PRC_UNREACH_NET: 64236403Ssklower case PRC_IFDOWN: 64336403Ssklower case PRC_HOSTDEAD: 64439926Ssklower iso_pcbnotify(&tp_isopcb, siso, 64536403Ssklower (int)inetctlerrmap[cmd], iso_rtchange); 64636403Ssklower break; 64736403Ssklower 64836403Ssklower default: 64936403Ssklower /* 65036403Ssklower case PRC_MSGSIZE: 65136403Ssklower case PRC_UNREACH_HOST: 65236403Ssklower case PRC_UNREACH_PROTOCOL: 65336403Ssklower case PRC_UNREACH_PORT: 65436403Ssklower case PRC_UNREACH_NEEDFRAG: 65536403Ssklower case PRC_UNREACH_SRCFAIL: 65636403Ssklower case PRC_REDIRECT_NET: 65736403Ssklower case PRC_REDIRECT_HOST: 65836403Ssklower case PRC_REDIRECT_TOSNET: 65936403Ssklower case PRC_REDIRECT_TOSHOST: 66036403Ssklower case PRC_TIMXCEED_INTRANS: 66136403Ssklower case PRC_PARAMPROB: 66236403Ssklower */ 66339926Ssklower iso_pcbnotify(&tp_isopcb, siso, (int)inetctlerrmap[cmd], tpiso_abort); 66436403Ssklower break; 66536403Ssklower } 66636403Ssklower return 0; 66736403Ssklower } 66839926Ssklower /* 66939926Ssklower * XXX - Variant which is called by clnp_er.c with an isoaddr rather 67039926Ssklower * than a sockaddr_iso. 67139926Ssklower */ 67236403Ssklower 67339926Ssklower static struct sockaddr_iso siso = {sizeof(siso), AF_ISO}; 67439926Ssklower tpclnp_ctlinput1(cmd, isoa) 67539926Ssklower int cmd; 67639926Ssklower struct iso_addr *isoa; 67739926Ssklower { 67839926Ssklower bzero((caddr_t)&siso.siso_addr, sizeof(siso.siso_addr)); 67939926Ssklower bcopy((caddr_t)isoa, (caddr_t)&siso.siso_addr, isoa->isoa_len); 68039926Ssklower tpclnp_ctlinput(cmd, &siso); 68139926Ssklower } 68239926Ssklower 68336403Ssklower /* 68436403Ssklower * These next 2 routines are 68536403Ssklower * CALLED FROM: 68636403Ssklower * xxx_notify() from tp_ctlinput() when 68736403Ssklower * net level gets some ICMP-equiv. type event. 68836403Ssklower * FUNCTION and ARGUMENTS: 68936403Ssklower * Cause the connection to be aborted with some sort of error 69036403Ssklower * reason indicating that the network layer caused the abort. 69136403Ssklower * Fakes an ER TPDU so we can go through the driver. 69236403Ssklower * abort always aborts the TP connection. 69336403Ssklower * reset may or may not, depending on the TP class that's in use. 69436403Ssklower */ 69536403Ssklower ProtoHook 69636403Ssklower tpiso_abort(isop) 69736403Ssklower struct isopcb *isop; 69836403Ssklower { 69936403Ssklower struct tp_event e; 70036403Ssklower 70136403Ssklower IFDEBUG(D_CONN) 70236403Ssklower printf("tpiso_abort 0x%x\n", isop); 70336403Ssklower ENDDEBUG 70436403Ssklower e.ev_number = ER_TPDU; 70536403Ssklower e.ATTR(ER_TPDU).e_reason = ECONNABORTED; 70636403Ssklower return tp_driver((struct tp_pcb *)isop->isop_socket->so_tpcb, &e); 70736403Ssklower } 70836403Ssklower 70936403Ssklower ProtoHook 71036403Ssklower tpiso_reset(isop) 71136403Ssklower struct isopcb *isop; 71236403Ssklower { 71336403Ssklower struct tp_event e; 71436403Ssklower 71536403Ssklower e.ev_number = T_NETRESET; 71636403Ssklower return tp_driver((struct tp_pcb *)isop->isop_socket->so_tpcb, &e); 71736403Ssklower 71836403Ssklower } 71936403Ssklower 72036403Ssklower #endif ISO 721