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 29*37469Ssklower * $Header: /var/src/sys/netiso/RCS/tp_iso.c,v 5.1 89/02/09 16:20:51 hagens Exp $ 30*37469Ssklower * $Source: /var/src/sys/netiso/RCS/tp_iso.c,v $ 3136403Ssklower * 3236403Ssklower * Here is where you find the iso-dependent code. We've tried 3336403Ssklower * keep all net-level and (primarily) address-family-dependent stuff 3436403Ssklower * out of the tp source, and everthing here is reached indirectly 3536403Ssklower * through a switch table (struct nl_protosw *) tpcb->tp_nlproto 3636403Ssklower * (see tp_pcb.c). 3736403Ssklower * The routines here are: 3836403Ssklower * iso_getsufx: gets transport suffix out of an isopcb structure. 3936403Ssklower * iso_putsufx: put transport suffix into an isopcb structure. 4036403Ssklower * iso_putnetaddr: put a whole net addr into an isopcb. 4136403Ssklower * iso_getnetaddr: get a whole net addr from an isopcb. 4236403Ssklower * iso_recycle_suffix: clear suffix for reuse in isopcb 4336403Ssklower * tpclnp_ctlinput: handle ER CNLPdu : icmp-like stuff 4436403Ssklower * tpclnp_mtu: figure out what size tpdu to use 4536403Ssklower * tpclnp_input: take a pkt from clnp, strip off its clnp header, 4636403Ssklower * give to tp 4736403Ssklower * tpclnp_output_dg: package a pkt for clnp given 2 addresses & some data 4836403Ssklower * tpclnp_output: package a pkt for clnp given an isopcb & some data 4936403Ssklower */ 5036403Ssklower 5136403Ssklower #ifndef lint 52*37469Ssklower static char *rcsid = "$Header: /var/src/sys/netiso/RCS/tp_iso.c,v 5.1 89/02/09 16:20:51 hagens Exp $"; 5336403Ssklower #endif lint 5436403Ssklower 5536403Ssklower #ifdef ISO 5636403Ssklower 57*37469Ssklower #include "param.h" 58*37469Ssklower #include "socket.h" 59*37469Ssklower #include "socketvar.h" 60*37469Ssklower #include "domain.h" 61*37469Ssklower #include "malloc.h" 62*37469Ssklower #include "mbuf.h" 63*37469Ssklower #include "errno.h" 64*37469Ssklower #include "time.h" 65*37469Ssklower #include "protosw.h" 66*37469Ssklower 6736403Ssklower #include "../net/if.h" 6836403Ssklower #include "../net/route.h" 6936403Ssklower 70*37469Ssklower #include "argo_debug.h" 71*37469Ssklower #include "tp_param.h" 72*37469Ssklower #include "tp_stat.h" 73*37469Ssklower #include "tp_pcb.h" 74*37469Ssklower #include "tp_trace.h" 75*37469Ssklower #include "tp_stat.h" 76*37469Ssklower #include "tp_tpdu.h" 77*37469Ssklower #include "tp_clnp.h" 7836403Ssklower 7936403Ssklower /* 8036403Ssklower * CALLED FROM: 8136403Ssklower * pr_usrreq() on PRU_BIND, PRU_CONNECT, PRU_ACCEPT, and PRU_PEERADDR 82*37469Ssklower * FUNCTION, ARGUMENTS: 8336403Ssklower * The argument (which) takes the value TP_LOCAL or TP_FOREIGN. 8436403Ssklower */ 8536403Ssklower 86*37469Ssklower iso_getsufx(isop, lenp, data_out, which) 8736403Ssklower struct isopcb *isop; 88*37469Ssklower u_short *lenp; 89*37469Ssklower caddr_t data_out; 9036403Ssklower int which; 9136403Ssklower { 92*37469Ssklower register struct sockaddr_iso *addr = 0; 93*37469Ssklower 9436403Ssklower switch (which) { 9536403Ssklower case TP_LOCAL: 96*37469Ssklower addr = isop->isop_laddr; 97*37469Ssklower break; 9836403Ssklower 9936403Ssklower case TP_FOREIGN: 100*37469Ssklower addr = isop->isop_faddr; 10136403Ssklower } 102*37469Ssklower if (addr) 103*37469Ssklower bcopy(TSEL(addr), data_out, (*lenp = addr->siso_tsuffixlen)); 10436403Ssklower } 10536403Ssklower 10636403Ssklower /* CALLED FROM: 10736403Ssklower * tp_newsocket(); i.e., when a connection is being established by an 10836403Ssklower * incoming CR_TPDU. 10936403Ssklower * 11036403Ssklower * FUNCTION, ARGUMENTS: 11136403Ssklower * Put a transport suffix (found in name) into an isopcb structure (isop). 11236403Ssklower * The argument (which) takes the value TP_LOCAL or TP_FOREIGN. 11336403Ssklower */ 11436403Ssklower void 115*37469Ssklower iso_putsufx(isop, sufxloc, sufxlen, which) 11636403Ssklower struct isopcb *isop; 117*37469Ssklower caddr_t sufxloc; 118*37469Ssklower int sufxlen, which; 11936403Ssklower { 120*37469Ssklower struct sockaddr_iso **dst, *backup; 121*37469Ssklower register struct sockaddr_iso *addr; 122*37469Ssklower struct mbuf *m; 123*37469Ssklower int len; 124*37469Ssklower 12536403Ssklower switch (which) { 126*37469Ssklower default: 127*37469Ssklower return; 128*37469Ssklower 12936403Ssklower case TP_LOCAL: 130*37469Ssklower dst = &isop->isop_laddr; 131*37469Ssklower backup = &isop->isop_sladdr; 13236403Ssklower break; 133*37469Ssklower 13436403Ssklower case TP_FOREIGN: 135*37469Ssklower dst = &isop->isop_faddr; 136*37469Ssklower backup = &isop->isop_sfaddr; 13736403Ssklower } 138*37469Ssklower if ((addr = *dst) == 0) { 139*37469Ssklower addr = *dst = backup; 140*37469Ssklower addr->siso_nlen = 0; 141*37469Ssklower addr->siso_ssuffixlen = 0; 142*37469Ssklower printf("iso_putsufx on un-initialized isopcb\n"); 143*37469Ssklower } 144*37469Ssklower len = sufxlen + addr->siso_nlen + 145*37469Ssklower (sizeof(struct sockaddr_iso) - sizeof(struct iso_addr)); 146*37469Ssklower if (addr == backup) { 147*37469Ssklower if (len > sizeof(isop->isop_sladdr)) { 148*37469Ssklower m = m_getclr(M_DONTWAIT, MT_SONAME); 149*37469Ssklower if (m == 0) 150*37469Ssklower return; 151*37469Ssklower addr = *dst = mtod(m, struct sockaddr_iso *); 152*37469Ssklower *addr = *backup; 153*37469Ssklower m->m_len = len; 154*37469Ssklower } 155*37469Ssklower } else 156*37469Ssklower dtom(addr)->m_len = len; 157*37469Ssklower bcopy(sufxloc, TSEL(addr), sufxlen); 158*37469Ssklower addr->siso_tsuffixlen = sufxlen; 159*37469Ssklower addr->siso_len = len; 16036403Ssklower } 16136403Ssklower 16236403Ssklower /* 16336403Ssklower * CALLED FROM: 16436403Ssklower * tp.trans whenever we go into REFWAIT state. 16536403Ssklower * FUNCTION and ARGUMENT: 16636403Ssklower * Called when a ref is frozen, to allow the suffix to be reused. 16736403Ssklower * (isop) is the net level pcb. This really shouldn't have to be 16836403Ssklower * done in a NET level pcb but... for the internet world that just 16936403Ssklower * the way it is done in BSD... 17036403Ssklower * The alternative is to have the port unusable until the reference 17136403Ssklower * timer goes off. 17236403Ssklower */ 17336403Ssklower void 17436403Ssklower iso_recycle_tsuffix(isop) 17536403Ssklower struct isopcb *isop; 17636403Ssklower { 177*37469Ssklower isop->isop_laddr->siso_tsuffixlen = isop->isop_faddr->siso_tsuffixlen = 0; 17836403Ssklower } 17936403Ssklower 18036403Ssklower /* 18136403Ssklower * CALLED FROM: 18236403Ssklower * tp_newsocket(); i.e., when a connection is being established by an 18336403Ssklower * incoming CR_TPDU. 18436403Ssklower * 18536403Ssklower * FUNCTION and ARGUMENTS: 18636403Ssklower * Copy a whole net addr from a struct sockaddr (name). 18736403Ssklower * into an isopcb (isop). 18836403Ssklower * The argument (which) takes values TP_LOCAL or TP_FOREIGN 18936403Ssklower */ 19036403Ssklower void 19136403Ssklower iso_putnetaddr(isop, name, which) 19236403Ssklower register struct isopcb *isop; 19336403Ssklower struct sockaddr_iso *name; 19436403Ssklower int which; 19536403Ssklower { 196*37469Ssklower struct sockaddr_iso **sisop, *backup; 197*37469Ssklower register struct sockaddr_iso *siso; 198*37469Ssklower 19936403Ssklower switch (which) { 20036403Ssklower case TP_LOCAL: 201*37469Ssklower sisop = &isop->isop_laddr; 202*37469Ssklower backup = &isop->isop_sladdr; 20336403Ssklower break; 20436403Ssklower case TP_FOREIGN: 205*37469Ssklower sisop = &isop->isop_faddr; 206*37469Ssklower backup = &isop->isop_sfaddr; 20736403Ssklower } 208*37469Ssklower siso = ((*sisop == 0) ? (*sisop = backup) : *sisop); 209*37469Ssklower IFDEBUG(D_TPISO) 210*37469Ssklower printf("ISO_PUTNETADDR\n"); 211*37469Ssklower dump_isoaddr(isop->isop_faddr); 212*37469Ssklower ENDDEBUG 213*37469Ssklower siso->siso_addr = name->siso_addr; 21436403Ssklower } 21536403Ssklower 21636403Ssklower /* 21736403Ssklower * CALLED FROM: 21836403Ssklower * pr_usrreq() PRU_SOCKADDR, PRU_ACCEPT, PRU_PEERADDR 21936403Ssklower * FUNCTION and ARGUMENTS: 22036403Ssklower * Copy a whole net addr from an isopcb (isop) into 22136403Ssklower * a struct sockaddr (name). 22236403Ssklower * The argument (which) takes values TP_LOCAL or TP_FOREIGN. 22336403Ssklower */ 22436403Ssklower 22536403Ssklower void 22636403Ssklower iso_getnetaddr( isop, name, which) 22736403Ssklower struct isopcb *isop; 228*37469Ssklower struct mbuf *name; 22936403Ssklower int which; 23036403Ssklower { 231*37469Ssklower struct sockaddr_iso *siso = 232*37469Ssklower (which == TP_LOCAL ? isop->isop_laddr : isop->isop_faddr); 233*37469Ssklower if (siso) 234*37469Ssklower bcopy((caddr_t)siso, mtod(name, caddr_t), 235*37469Ssklower (unsigned)(name->m_len = siso->siso_len)); 236*37469Ssklower else 237*37469Ssklower name->m_len = 0; 23836403Ssklower } 23936403Ssklower 24036403Ssklower /* 24136403Ssklower * CALLED FROM: 24236403Ssklower * tp_input() on incoming CR, CC, and pr_usrreq() for PRU_CONNECT 24336403Ssklower * FUNCTION, ARGUMENTS, SIDE EFFECTS and RETURN VALUE: 24436403Ssklower * Determine the proper maximum transmission unit, i.e., MTU, to use, given 24536403Ssklower * a) the header size for the network protocol and the max transmission 24636403Ssklower * unit on the subnet interface, determined from the information in (isop), 24736403Ssklower * b) the max size negotiated so far (negot) 24836403Ssklower * c) the window size used by the tp connection (found in so), 24936403Ssklower * 25036403Ssklower * The result is put in the integer *size in its integer form and in 25136403Ssklower * *negot in its logarithmic form. 25236403Ssklower * 25336403Ssklower * The rules are: 25436403Ssklower * a) can only negotiate down from the value found in *negot. 25536403Ssklower * b) the MTU must be < the windowsize, 25636403Ssklower * c) If src and dest are on the same net, 25736403Ssklower * we will negotiate the closest size larger than MTU but really USE 25836403Ssklower * the actual device mtu - ll hdr sizes. 25936403Ssklower * otherwise we negotiate the closest size smaller than MTU - ll hdr sizes. 26036403Ssklower */ 26136403Ssklower 26236403Ssklower void 26336403Ssklower tpclnp_mtu(so, isop, size, negot ) 26436403Ssklower struct socket *so; 26536403Ssklower struct isopcb *isop; 26636403Ssklower int *size; 26736403Ssklower u_char *negot; 26836403Ssklower { 26936403Ssklower struct ifnet *ifp; 270*37469Ssklower struct iso_ifaddr *ia; 27136403Ssklower register int i; 27236403Ssklower int windowsize = so->so_rcv.sb_hiwat; 27336403Ssklower int clnp_size; 27436403Ssklower int sizeismtu = 0; 27536403Ssklower 276*37469Ssklower struct iso_ifaddr *iso_routeifa(); 27736403Ssklower 27836403Ssklower IFDEBUG(D_CONN) 27936403Ssklower printf("tpclnp_mtu(0x%x,0x%x,0x%x,0x%x)\n", so, isop, size, negot); 28036403Ssklower ENDDEBUG 28136403Ssklower IFTRACE(D_CONN) 28236403Ssklower tptrace(TPPTmisc, "ENTER GET MTU: size negot \n",*size, *negot, 0, 0); 28336403Ssklower ENDTRACE 28436403Ssklower 28536403Ssklower *size = 1 << *negot; 28636403Ssklower 28736403Ssklower if( *size > windowsize ) { 28836403Ssklower *size = windowsize; 28936403Ssklower } 29036403Ssklower 291*37469Ssklower if (((ia = iso_routeifa(isop->isop_faddr)) == 0) 292*37469Ssklower || (ifp = ia->ia_ifp) == 0) 29336403Ssklower return; 29436403Ssklower 29536403Ssklower /* TODO - make this indirect off the socket structure to the 29636403Ssklower * network layer to get headersize 29736403Ssklower */ 298*37469Ssklower if (isop->isop_laddr) 299*37469Ssklower clnp_size = clnp_hdrsize(isop->isop_laddr->siso_addr.isoa_len); 300*37469Ssklower else 301*37469Ssklower clnp_size = 20; 30236403Ssklower 30336403Ssklower if(*size > ifp->if_mtu - clnp_size) { 30436403Ssklower *size = ifp->if_mtu - clnp_size; 30536403Ssklower sizeismtu = 1; 30636403Ssklower } 307*37469Ssklower /* have to transform size to the log2 of size */ 308*37469Ssklower for(i=TP_MIN_TPDUSIZE; (i<TP_MAX_TPDUSIZE && ((1<<i) <= *size)) ; i++) 309*37469Ssklower ; 310*37469Ssklower i--; 311*37469Ssklower 31236403Ssklower IFTRACE(D_CONN) 31336403Ssklower tptrace(TPPTmisc, "GET MTU MID: tpcb size negot i \n", 31436403Ssklower *size, *negot, i, 0); 31536403Ssklower ENDTRACE 31636403Ssklower 31736403Ssklower /* are we on the same LAN? if so, negotiate one tpdu size larger, 31836403Ssklower * and actually send the real mtu size 31936403Ssklower */ 320*37469Ssklower if (iso_localifa(isop->isop_faddr)) { 32136403Ssklower i++; 32236403Ssklower } else { 32336403Ssklower *size = 1<<i; 32436403Ssklower } 32536403Ssklower *negot = i; 32636403Ssklower 32736403Ssklower IFDEBUG(D_CONN) 32836403Ssklower printf("GET MTU RETURNS: ifp %s size 0x%x negot 0x%x\n", 32936403Ssklower ifp->if_name, *size, *negot); 33036403Ssklower ENDDEBUG 33136403Ssklower IFTRACE(D_CONN) 33236403Ssklower tptrace(TPPTmisc, "EXIT GET MTU: tpcb size negot \n", 33336403Ssklower *size, *negot, 0, 0); 33436403Ssklower ENDTRACE 33536403Ssklower } 33636403Ssklower 33736403Ssklower 33836403Ssklower /* 33936403Ssklower * CALLED FROM: 34036403Ssklower * tp_emit() 34136403Ssklower * FUNCTION and ARGUMENTS: 34236403Ssklower * Take a packet(m0) from tp and package it so that clnp will accept it. 34336403Ssklower * This means prepending space for the clnp header and filling in a few 34436403Ssklower * of the fields. 34536403Ssklower * inp is the isopcb structure; datalen is the length of the data in the 34636403Ssklower * mbuf string m0. 34736403Ssklower * RETURN VALUE: 34836403Ssklower * whatever (E*) is returned form the net layer output routine. 34936403Ssklower */ 35036403Ssklower 35136403Ssklower int 35236403Ssklower tpclnp_output(isop, m0, datalen, nochksum) 35336403Ssklower struct isopcb *isop; 35436403Ssklower struct mbuf *m0; 35536403Ssklower int datalen; 35636403Ssklower int nochksum; 35736403Ssklower { 358*37469Ssklower register struct mbuf *m = m0; 35936403Ssklower IncStat(ts_tpdu_sent); 36036403Ssklower 36136403Ssklower IFDEBUG(D_TPISO) 36236403Ssklower struct tpdu *hdr = mtod(m0, struct tpdu *); 36336403Ssklower 36436403Ssklower printf( 36536403Ssklower "abt to call clnp_output: datalen 0x%x, hdr.li 0x%x, hdr.dutype 0x%x nocsum x%x dst addr:\n", 36636403Ssklower datalen, 36736403Ssklower (int)hdr->tpdu_li, (int)hdr->tpdu_type, nochksum); 368*37469Ssklower dump_isoaddr(isop->isop_faddr); 36936403Ssklower printf("\nsrc addr:\n"); 370*37469Ssklower dump_isoaddr(isop->isop_laddr); 37136403Ssklower dump_mbuf(m0, "at tpclnp_output"); 37236403Ssklower ENDDEBUG 373*37469Ssklower if ((m->m_flags & M_PKTHDR) == 0) { 374*37469Ssklower IFDEBUG(D_TPISO) 375*37469Ssklower printf("tpclnp_output: non headered mbuf"); 376*37469Ssklower ENDDEBUG 377*37469Ssklower MGETHDR(m, M_DONTWAIT, MT_DATA); 378*37469Ssklower if (m == 0) { 379*37469Ssklower m_freem(m0); 380*37469Ssklower return ENOBUFS; 381*37469Ssklower } 382*37469Ssklower m->m_next = m0; 383*37469Ssklower m->m_len = 0; 384*37469Ssklower m->m_pkthdr.len = datalen; 385*37469Ssklower m0 = m; 386*37469Ssklower } 38736403Ssklower 38836403Ssklower return 389*37469Ssklower clnp_output(m0, isop, /* flags */nochksum ? CLNP_NO_CKSUM : 0); 39036403Ssklower } 39136403Ssklower 39236403Ssklower /* 39336403Ssklower * CALLED FROM: 39436403Ssklower * tp_error_emit() 39536403Ssklower * FUNCTION and ARGUMENTS: 39636403Ssklower * This is a copy of tpclnp_output that takes the addresses 39736403Ssklower * instead of a pcb. It's used by the tp_error_emit, when we 39836403Ssklower * don't have an iso_pcb with which to call the normal output rtn. 39936403Ssklower * RETURN VALUE: 40036403Ssklower * ENOBUFS or 40136403Ssklower * whatever (E*) is returned form the net layer output routine. 40236403Ssklower */ 40336403Ssklower 40436403Ssklower int 40536403Ssklower tpclnp_output_dg(laddr, faddr, m0, datalen, ro, nochksum) 40636403Ssklower struct iso_addr *laddr, *faddr; 40736403Ssklower struct mbuf *m0; 40836403Ssklower int datalen; 40936403Ssklower struct route *ro; 41036403Ssklower int nochksum; 41136403Ssklower { 41236403Ssklower struct isopcb tmppcb; 41336403Ssklower int err; 41436403Ssklower int flags; 415*37469Ssklower register struct mbuf *m = m0; 41636403Ssklower 41736403Ssklower IFDEBUG(D_TPISO) 41836403Ssklower printf("tpclnp_output_dg datalen 0x%x m0 0x%x\n", datalen, m0); 41936403Ssklower ENDDEBUG 42036403Ssklower 42136403Ssklower /* 42236403Ssklower * Fill in minimal portion of isopcb so that clnp can send the 42336403Ssklower * packet. 42436403Ssklower */ 42536403Ssklower bzero((caddr_t)&tmppcb, sizeof(tmppcb)); 426*37469Ssklower tmppcb.isop_laddr = &tmppcb.isop_sladdr; 427*37469Ssklower tmppcb.isop_laddr->siso_addr = *laddr; 428*37469Ssklower tmppcb.isop_faddr = &tmppcb.isop_sfaddr; 429*37469Ssklower tmppcb.isop_faddr->siso_addr = *faddr; 43036403Ssklower 43136403Ssklower IFDEBUG(D_TPISO) 43236403Ssklower printf("tpclnp_output_dg faddr: \n"); 433*37469Ssklower dump_isoaddr(&tmppcb.isop_sfaddr); 43436403Ssklower printf("\ntpclnp_output_dg laddr: \n"); 435*37469Ssklower dump_isoaddr(&tmppcb.isop_sladdr); 43636403Ssklower printf("\n"); 43736403Ssklower ENDDEBUG 43836403Ssklower 43936403Ssklower /* 44036403Ssklower * Do not use packet cache since this is a one shot error packet 44136403Ssklower */ 44236403Ssklower flags = (CLNP_NOCACHE|(nochksum?CLNP_NO_CKSUM:0)); 44336403Ssklower 44436403Ssklower IncStat(ts_tpdu_sent); 44536403Ssklower 446*37469Ssklower if ((m->m_flags & M_PKTHDR) == 0) { 447*37469Ssklower printf("tpclnp_output: non headered mbuf"); 448*37469Ssklower MGETHDR(m, M_DONTWAIT, MT_DATA); 449*37469Ssklower if (m == 0) { 450*37469Ssklower m_freem(m0); 451*37469Ssklower return ENOBUFS; 452*37469Ssklower } 453*37469Ssklower m->m_next = m0; 454*37469Ssklower m->m_len = 0; 455*37469Ssklower m->m_pkthdr.len = datalen; 456*37469Ssklower m0 = m; 457*37469Ssklower } 458*37469Ssklower err = clnp_output(m0, &tmppcb, flags); 45936403Ssklower 46036403Ssklower /* 46136403Ssklower * Free route allocated by clnp (if the route was indeed allocated) 46236403Ssklower */ 46336403Ssklower if (tmppcb.isop_route.ro_rt) 46436403Ssklower RTFREE(tmppcb.isop_route.ro_rt); 46536403Ssklower 46636403Ssklower return(err); 46736403Ssklower } 468*37469Ssklower extern struct sockaddr_iso blank_siso; 46936403Ssklower /* 47036403Ssklower * CALLED FROM: 47136403Ssklower * clnp's input routine, indirectly through the protosw. 47236403Ssklower * FUNCTION and ARGUMENTS: 47336403Ssklower * Take a packet (m) from clnp, strip off the clnp header and give it to tp 47436403Ssklower * No return value. 47536403Ssklower */ 47636403Ssklower ProtoHook 47736403Ssklower tpclnp_input(m, faddr, laddr, clnp_len) 47836403Ssklower struct mbuf *m; 47936403Ssklower struct iso_addr *faddr, *laddr; 48036403Ssklower int clnp_len; 48136403Ssklower { 48236403Ssklower struct sockaddr_iso src, dst; 48336403Ssklower int s = splnet(); 484*37469Ssklower struct mbuf *tp_inputprep(); 48536403Ssklower 48636403Ssklower IncStat(ts_pkt_rcvd); 48736403Ssklower 48836403Ssklower IFDEBUG(D_TPINPUT) 48936403Ssklower printf("tpclnp_input: m 0x%x clnp_len 0x%x\n", m, clnp_len); 49036403Ssklower dump_mbuf(m, "at tpclnp_input"); 49136403Ssklower ENDDEBUG 49236403Ssklower /* 49336403Ssklower * CLNP gives us an mbuf chain WITH the clnp header pulled up, 49436403Ssklower * and the length of the clnp header. 49536403Ssklower * First, strip off the Clnp header. leave the mbuf there for the 49636403Ssklower * pullup that follows. 49736403Ssklower */ 49836403Ssklower 49936403Ssklower m->m_len -= clnp_len; 500*37469Ssklower m->m_data += clnp_len; 50136403Ssklower 502*37469Ssklower m = tp_inputprep(m); 50336403Ssklower 50436403Ssklower IFDEBUG(D_TPINPUT) 50536403Ssklower dump_mbuf(m, "after tpclnp_input both pullups"); 50636403Ssklower ENDDEBUG 50736403Ssklower 508*37469Ssklower src = blank_siso; dst = blank_siso; 509*37469Ssklower bcopy((caddr_t)faddr, (caddr_t)&src.siso_addr, 1 + faddr->isoa_len); 510*37469Ssklower bcopy((caddr_t)laddr, (caddr_t)&dst.siso_addr, 1 + laddr->isoa_len); 51136403Ssklower 51236403Ssklower IFDEBUG(D_TPISO) 51336403Ssklower printf("calling tp_input: &src 0x%x &dst 0x%x, src addr:\n", 51436403Ssklower &src, &dst); 51536403Ssklower printf(" dst addr:\n"); 51636403Ssklower dump_isoaddr(&src); 51736403Ssklower dump_isoaddr(&dst); 51836403Ssklower ENDDEBUG 51936403Ssklower 520*37469Ssklower (void) tp_input(m, (struct sockaddr *)&src, (struct sockaddr *)&dst, 521*37469Ssklower 0, tpclnp_output_dg); 52236403Ssklower 52336403Ssklower IFDEBUG(D_QUENCH) 52436403Ssklower { 52536403Ssklower if(time.tv_usec & 0x4 && time.tv_usec & 0x40) { 52636403Ssklower printf("tpclnp_input: FAKING %s\n", 52736403Ssklower tp_stat.ts_pkt_rcvd & 0x1?"QUENCH":"QUENCH2"); 52836403Ssklower if(tp_stat.ts_pkt_rcvd & 0x1) { 52936403Ssklower tpclnp_ctlinput(PRC_QUENCH, &src); 53036403Ssklower } else { 53136403Ssklower tpclnp_ctlinput(PRC_QUENCH2, &src); 53236403Ssklower } 53336403Ssklower } 53436403Ssklower } 53536403Ssklower ENDDEBUG 53636403Ssklower 53736403Ssklower splx(s); 53836403Ssklower return 0; 53936403Ssklower } 54036403Ssklower 54136403Ssklower ProtoHook 54236403Ssklower iso_rtchange() 54336403Ssklower { 54436403Ssklower return 0; 54536403Ssklower } 54636403Ssklower 54736403Ssklower /* 54836403Ssklower * CALLED FROM: 54936403Ssklower * tpclnp_ctlinput() 55036403Ssklower * FUNCTION and ARGUMENTS: 55136403Ssklower * find the tpcb pointer and pass it to tp_quench 55236403Ssklower */ 55336403Ssklower void 55436403Ssklower tpiso_decbit(isop) 55536403Ssklower struct isopcb *isop; 55636403Ssklower { 557*37469Ssklower tp_quench((struct tp_pcb *)isop->isop_socket->so_tpcb, PRC_QUENCH2); 55836403Ssklower } 55936403Ssklower /* 56036403Ssklower * CALLED FROM: 56136403Ssklower * tpclnp_ctlinput() 56236403Ssklower * FUNCTION and ARGUMENTS: 56336403Ssklower * find the tpcb pointer and pass it to tp_quench 56436403Ssklower */ 56536403Ssklower void 56636403Ssklower tpiso_quench(isop) 56736403Ssklower struct isopcb *isop; 56836403Ssklower { 569*37469Ssklower tp_quench((struct tp_pcb *)isop->isop_socket->so_tpcb, PRC_QUENCH); 57036403Ssklower } 57136403Ssklower 57236403Ssklower /* 57336403Ssklower * CALLED FROM: 57436403Ssklower * The network layer through the protosw table. 57536403Ssklower * FUNCTION and ARGUMENTS: 57636403Ssklower * When clnp an ICMP-like msg this gets called. 57736403Ssklower * It either returns an error status to the user or 57836403Ssklower * it causes all connections on this address to be aborted 57936403Ssklower * by calling the appropriate xx_notify() routine. 58036403Ssklower * (cmd) is the type of ICMP error. 58136403Ssklower * (siso) is the address of the guy who sent the ER CLNPDU 58236403Ssklower */ 58336403Ssklower ProtoHook 58436403Ssklower tpclnp_ctlinput(cmd, siso) 58536403Ssklower int cmd; 58636403Ssklower struct sockaddr_iso *siso; 58736403Ssklower { 588*37469Ssklower return tpclnp_ctlinput1(cmd, &siso->siso_addr); 589*37469Ssklower } 590*37469Ssklower 591*37469Ssklower /* 592*37469Ssklower * Entry to ctlinput with argument of an iso_addr rather than a sockaddr 593*37469Ssklower */ 594*37469Ssklower ProtoHook 595*37469Ssklower tpclnp_ctlinput1(cmd, isoa) 596*37469Ssklower int cmd; 597*37469Ssklower struct iso_addr *isoa; 598*37469Ssklower { 59936403Ssklower extern u_char inetctlerrmap[]; 60036403Ssklower extern ProtoHook tpiso_abort(); 60136403Ssklower extern ProtoHook iso_rtchange(); 60236403Ssklower extern ProtoHook tpiso_reset(); 603*37469Ssklower void iso_pcbnotify(); 60436403Ssklower 60536403Ssklower IFDEBUG(D_TPINPUT) 606*37469Ssklower printf("tpclnp_ctlinput1: cmd 0x%x addr: %s\n", cmd, 607*37469Ssklower clnp_iso_addrp(isoa)); 60836403Ssklower ENDDEBUG 60936403Ssklower 61036403Ssklower if (cmd < 0 || cmd > PRC_NCMDS) 61136403Ssklower return 0; 61236403Ssklower switch (cmd) { 61336403Ssklower 61436403Ssklower case PRC_QUENCH2: 615*37469Ssklower iso_pcbnotify(&tp_isopcb, isoa, 0, (int (*)())tpiso_decbit); 61636403Ssklower break; 61736403Ssklower 61836403Ssklower case PRC_QUENCH: 619*37469Ssklower iso_pcbnotify(&tp_isopcb, isoa, 0, (int (*)())tpiso_quench); 62036403Ssklower break; 62136403Ssklower 62236403Ssklower case PRC_TIMXCEED_REASS: 62336403Ssklower case PRC_ROUTEDEAD: 624*37469Ssklower iso_pcbnotify(&tp_isopcb, isoa, 0, tpiso_reset); 62536403Ssklower break; 62636403Ssklower 62736403Ssklower case PRC_HOSTUNREACH: 62836403Ssklower case PRC_UNREACH_NET: 62936403Ssklower case PRC_IFDOWN: 63036403Ssklower case PRC_HOSTDEAD: 631*37469Ssklower iso_pcbnotify(&tp_isopcb, isoa, 63236403Ssklower (int)inetctlerrmap[cmd], iso_rtchange); 63336403Ssklower break; 63436403Ssklower 63536403Ssklower default: 63636403Ssklower /* 63736403Ssklower case PRC_MSGSIZE: 63836403Ssklower case PRC_UNREACH_HOST: 63936403Ssklower case PRC_UNREACH_PROTOCOL: 64036403Ssklower case PRC_UNREACH_PORT: 64136403Ssklower case PRC_UNREACH_NEEDFRAG: 64236403Ssklower case PRC_UNREACH_SRCFAIL: 64336403Ssklower case PRC_REDIRECT_NET: 64436403Ssklower case PRC_REDIRECT_HOST: 64536403Ssklower case PRC_REDIRECT_TOSNET: 64636403Ssklower case PRC_REDIRECT_TOSHOST: 64736403Ssklower case PRC_TIMXCEED_INTRANS: 64836403Ssklower case PRC_PARAMPROB: 64936403Ssklower */ 650*37469Ssklower iso_pcbnotify(&tp_isopcb, isoa, (int)inetctlerrmap[cmd], tpiso_abort); 65136403Ssklower break; 65236403Ssklower } 65336403Ssklower return 0; 65436403Ssklower } 65536403Ssklower 65636403Ssklower /* 65736403Ssklower * These next 2 routines are 65836403Ssklower * CALLED FROM: 65936403Ssklower * xxx_notify() from tp_ctlinput() when 66036403Ssklower * net level gets some ICMP-equiv. type event. 66136403Ssklower * FUNCTION and ARGUMENTS: 66236403Ssklower * Cause the connection to be aborted with some sort of error 66336403Ssklower * reason indicating that the network layer caused the abort. 66436403Ssklower * Fakes an ER TPDU so we can go through the driver. 66536403Ssklower * abort always aborts the TP connection. 66636403Ssklower * reset may or may not, depending on the TP class that's in use. 66736403Ssklower */ 66836403Ssklower ProtoHook 66936403Ssklower tpiso_abort(isop) 67036403Ssklower struct isopcb *isop; 67136403Ssklower { 67236403Ssklower struct tp_event e; 67336403Ssklower 67436403Ssklower IFDEBUG(D_CONN) 67536403Ssklower printf("tpiso_abort 0x%x\n", isop); 67636403Ssklower ENDDEBUG 67736403Ssklower e.ev_number = ER_TPDU; 67836403Ssklower e.ATTR(ER_TPDU).e_reason = ECONNABORTED; 67936403Ssklower return tp_driver((struct tp_pcb *)isop->isop_socket->so_tpcb, &e); 68036403Ssklower } 68136403Ssklower 68236403Ssklower ProtoHook 68336403Ssklower tpiso_reset(isop) 68436403Ssklower struct isopcb *isop; 68536403Ssklower { 68636403Ssklower struct tp_event e; 68736403Ssklower 68836403Ssklower e.ev_number = T_NETRESET; 68936403Ssklower return tp_driver((struct tp_pcb *)isop->isop_socket->so_tpcb, &e); 69036403Ssklower 69136403Ssklower } 69236403Ssklower 69336403Ssklower #endif ISO 694