136368Ssklower /*********************************************************** 236368Ssklower Copyright IBM Corporation 1987 336368Ssklower 436368Ssklower All Rights Reserved 536368Ssklower 636368Ssklower Permission to use, copy, modify, and distribute this software and its 736368Ssklower documentation for any purpose and without fee is hereby granted, 836368Ssklower provided that the above copyright notice appear in all copies and that 936368Ssklower both that copyright notice and this permission notice appear in 1036368Ssklower supporting documentation, and that the name of IBM not be 1136368Ssklower used in advertising or publicity pertaining to distribution of the 1236368Ssklower software without specific, written prior permission. 1336368Ssklower 1436368Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 1536368Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 1636368Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 1736368Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 1836368Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 1936368Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 2036368Ssklower SOFTWARE. 2136368Ssklower 2236368Ssklower ******************************************************************/ 2336368Ssklower 2436368Ssklower /* 2536368Ssklower * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison 2636368Ssklower */ 2736763Ssklower /* $Header: /var/src/sys/netiso/RCS/clnp_er.c,v 5.1 89/02/09 16:20:18 hagens Exp $ */ 2836763Ssklower /* $Source: /var/src/sys/netiso/RCS/clnp_er.c,v $ */ 2936368Ssklower 3036368Ssklower #ifndef lint 3136763Ssklower static char *rcsid = "$Header: /var/src/sys/netiso/RCS/clnp_er.c,v 5.1 89/02/09 16:20:18 hagens Exp $"; 3236368Ssklower #endif lint 3336368Ssklower 3436368Ssklower #ifdef ISO 3536368Ssklower 36*37469Ssklower #include "types.h" 37*37469Ssklower #include "param.h" 38*37469Ssklower #include "mbuf.h" 39*37469Ssklower #include "domain.h" 40*37469Ssklower #include "protosw.h" 41*37469Ssklower #include "socket.h" 42*37469Ssklower #include "socketvar.h" 43*37469Ssklower #include "errno.h" 4436368Ssklower 4536368Ssklower #include "../net/if.h" 4636368Ssklower #include "../net/route.h" 4736368Ssklower 48*37469Ssklower #include "iso.h" 49*37469Ssklower #include "iso_var.h" 50*37469Ssklower #include "iso_pcb.h" 51*37469Ssklower #include "clnp.h" 52*37469Ssklower #include "clnp_stat.h" 53*37469Ssklower #include "argo_debug.h" 5436368Ssklower 5536368Ssklower static struct clnp_fixed er_template = { 5636368Ssklower ISO8473_CLNP, /* network identifier */ 5736368Ssklower 0, /* length */ 5836368Ssklower ISO8473_V1, /* version */ 5936368Ssklower CLNP_TTL, /* ttl */ 6036368Ssklower CLNP_ER, /* type */ 6136368Ssklower 0, /* segment length */ 6236368Ssklower 0 /* checksum */ 6336368Ssklower }; 6436368Ssklower 6536368Ssklower /* 6636368Ssklower * FUNCTION: clnp_er_input 6736368Ssklower * 6836368Ssklower * PURPOSE: Process an ER pdu. 6936368Ssklower * 7036368Ssklower * RETURNS: 7136368Ssklower * 7236368Ssklower * SIDE EFFECTS: 7336368Ssklower * 7436368Ssklower * NOTES: 7536368Ssklower */ 7636368Ssklower clnp_er_input(m, src, reason) 7736368Ssklower struct mbuf *m; /* ptr to packet itself */ 7836368Ssklower struct iso_addr *src; /* ptr to src of er */ 79*37469Ssklower u_char reason; /* reason code of er */ 8036368Ssklower { 8136368Ssklower int cmd = -1; 8236368Ssklower extern u_char clnp_protox[]; 8336368Ssklower 8436368Ssklower IFDEBUG(D_CTLINPUT) 8536368Ssklower printf("clnp_er_input: m x%x, src %s, reason x%x\n", m, 8636368Ssklower clnp_iso_addrp(src), reason); 8736368Ssklower ENDDEBUG 8836368Ssklower 8936368Ssklower INCSTAT(cns_errcvd); 9036368Ssklower 9136368Ssklower switch (reason) { 9236368Ssklower case GEN_NOREAS: 9336368Ssklower case GEN_PROTOERR: 9436368Ssklower INCSTAT(er_protoerr); 9536368Ssklower break; 9636368Ssklower case GEN_BADCSUM: 9736368Ssklower cmd = PRC_PARAMPROB; 9836368Ssklower INCSTAT(er_badcsum); 9936368Ssklower break; 10036368Ssklower case GEN_CONGEST: 10136368Ssklower cmd = PRC_QUENCH; 10236368Ssklower INCSTAT(er_congest); 10336368Ssklower break; 10436368Ssklower case GEN_HDRSYNTAX: 10536368Ssklower cmd = PRC_PARAMPROB; 10636368Ssklower INCSTAT(er_protoerr); 10736368Ssklower break; 10836368Ssklower case GEN_SEGNEEDED: 10936368Ssklower cmd = PRC_UNREACH_NEEDFRAG; 11036368Ssklower INCSTAT(er_segneeded); 11136368Ssklower break; 11236368Ssklower case GEN_INCOMPLETE: 11336368Ssklower cmd = PRC_PARAMPROB; 11436368Ssklower INCSTAT(er_reassfail); 11536368Ssklower break; 11636368Ssklower case GEN_DUPOPT: 11736368Ssklower cmd = PRC_PARAMPROB; 11836368Ssklower INCSTAT(er_protoerr); 11936368Ssklower break; 12036368Ssklower case ADDR_DESTUNREACH: 12136368Ssklower cmd = PRC_UNREACH_HOST; 12236368Ssklower INCSTAT(er_dstunreach); 12336368Ssklower break; 12436368Ssklower case ADDR_DESTUNKNOWN: 12536368Ssklower cmd = PRC_UNREACH_PROTOCOL; 12636368Ssklower INCSTAT(er_dstunreach); 12736368Ssklower break; 12836368Ssklower case SRCRT_UNSPECERR: 12936368Ssklower case SRCRT_SYNTAX: 13036368Ssklower case SRCRT_UNKNOWNADDR: 13136368Ssklower case SRCRT_BADPATH: 13236368Ssklower cmd = PRC_UNREACH_SRCFAIL; 13336368Ssklower INCSTAT(er_srcrterr); 13436368Ssklower break; 13536368Ssklower case TTL_EXPTRANSIT: 13636368Ssklower cmd = PRC_TIMXCEED_INTRANS; 13736368Ssklower INCSTAT(er_ttlexpired); 13836368Ssklower break; 13936368Ssklower case TTL_EXPREASS: 14036368Ssklower cmd = PRC_TIMXCEED_REASS; 14136368Ssklower INCSTAT(er_ttlexpired); 14236368Ssklower break; 14336368Ssklower case DISC_UNSUPPOPT: 14436368Ssklower case DISC_UNSUPPVERS: 14536368Ssklower case DISC_UNSUPPSECURE: 14636368Ssklower case DISC_UNSUPPSRCRT: 14736368Ssklower case DISC_UNSUPPRECRT: 14836368Ssklower cmd = PRC_PARAMPROB; 14936368Ssklower INCSTAT(er_unsupported); 15036368Ssklower break; 15136368Ssklower case REASS_INTERFERE: 15236368Ssklower cmd = PRC_TIMXCEED_REASS; 15336368Ssklower INCSTAT(er_reassfail); 15436368Ssklower break; 15536368Ssklower } 15636368Ssklower 15736763Ssklower /* 15836763Ssklower * tpclnp_ctlinput1 is called directly so that we don't 15936763Ssklower * have to build an iso_sockaddr out of src. 16036763Ssklower */ 16136368Ssklower if (cmd >= 0) 16236763Ssklower tpclnp_ctlinput1(cmd, src); 16336368Ssklower 16436368Ssklower m_freem(m); 16536368Ssklower } 16636368Ssklower 16736368Ssklower /* 16836368Ssklower * FUNCTION: clnp_discard 16936368Ssklower * 17036368Ssklower * PURPOSE: Discard a clnp datagram 17136368Ssklower * 17236368Ssklower * RETURNS: nothing 17336368Ssklower * 17436368Ssklower * SIDE EFFECTS: Will emit an ER pdu if possible 17536368Ssklower * 17636368Ssklower * NOTES: This code assumes that we have previously tried to pull 17736368Ssklower * up the header of the datagram into one mbuf. 17836368Ssklower */ 17936368Ssklower clnp_discard(m, reason) 18036368Ssklower struct mbuf *m; /* header of packet to discard */ 18136368Ssklower char reason; /* reason for discard */ 18236368Ssklower { 18336368Ssklower IFDEBUG(D_DISCARD) 18436368Ssklower printf("clnp_discard: m x%x, reason x%x\n", m, reason); 18536368Ssklower ENDDEBUG 18636368Ssklower 18736368Ssklower if (m != NULL) { 18836368Ssklower if (m->m_len >= sizeof(struct clnp_fixed)) { 18936368Ssklower register struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *); 19036368Ssklower 191*37469Ssklower if (((clnp->cnf_type & CNF_TYPE) != CLNP_ER) && 192*37469Ssklower (clnp->cnf_type & CNF_ERR_OK)) { 193*37469Ssklower clnp_emit_er(m, reason); 194*37469Ssklower return; 19536368Ssklower } 19636368Ssklower } 19736368Ssklower m_freem(m); 19836368Ssklower } 19936368Ssklower } 20036368Ssklower 20136368Ssklower /* 20236368Ssklower * FUNCTION: clnp_emit_er 20336368Ssklower * 20436368Ssklower * PURPOSE: Send an ER pdu. 20536368Ssklower * The src of the of the ER pdu is the host that is sending 20636368Ssklower * the ER (ie. us), *not* the original destination of the 20736368Ssklower * packet. 20836368Ssklower * 20936368Ssklower * RETURNS: nothing 21036368Ssklower * 21136368Ssklower * SIDE EFFECTS: 21236368Ssklower * 21336368Ssklower * NOTES: Takes responsibility for freeing mbuf passed 21436368Ssklower * This function may be called with a packet that 21536368Ssklower * was created by us; in this case, do not send 21636368Ssklower * an ER. 21736368Ssklower */ 21836368Ssklower clnp_emit_er(m, reason) 21936368Ssklower struct mbuf *m; /* header of packet to discard */ 22036368Ssklower char reason; /* reason for discard */ 22136368Ssklower { 22236368Ssklower register struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *); 22336368Ssklower register struct clnp_fixed *er; 224*37469Ssklower struct route_iso route; 22536368Ssklower struct ifnet *ifp; 22636368Ssklower struct sockaddr *first_hop; 22736368Ssklower struct iso_addr src, dst, *our_addr; 22836368Ssklower caddr_t hoff, hend; 22936368Ssklower int total_len; /* total len of dg */ 23036368Ssklower struct mbuf *m0; /* contains er pdu hdr */ 231*37469Ssklower struct iso_ifaddr *ia = 0; 23236368Ssklower 23336368Ssklower IFDEBUG(D_DISCARD) 23436368Ssklower printf("clnp_emit_er: m x%x, hdr len %d\n", m, clnp->cnf_hdr_len); 23536368Ssklower ENDDEBUG 23636368Ssklower 23736368Ssklower bzero((caddr_t)&route, sizeof(route)); 23836368Ssklower 23936368Ssklower /* 24036368Ssklower * If header length is incorrect, or entire header is not contained 24136368Ssklower * in this mbuf, we punt 24236368Ssklower */ 24336368Ssklower if ((clnp->cnf_hdr_len < CLNP_HDR_MIN) || 24436368Ssklower (clnp->cnf_hdr_len > CLNP_HDR_MAX) || 24536368Ssklower (clnp->cnf_hdr_len > m->m_len)) 24636368Ssklower goto bad; 24736368Ssklower 24836368Ssklower /* extract src, dest address */ 24936368Ssklower hend = (caddr_t)clnp + clnp->cnf_hdr_len; 25036368Ssklower hoff = (caddr_t)clnp + sizeof(struct clnp_fixed); 25136368Ssklower CLNP_EXTRACT_ADDR(dst, hoff, hend); 25236368Ssklower if (hoff == (caddr_t)0) { 25336368Ssklower goto bad; 25436368Ssklower } 25536368Ssklower CLNP_EXTRACT_ADDR(src, hoff, hend); 25636368Ssklower if (hoff == (caddr_t)0) { 25736368Ssklower goto bad; 25836368Ssklower } 25936368Ssklower 26036368Ssklower /* 26136368Ssklower * Do not send ER if we generated the packet. 26236368Ssklower */ 26336368Ssklower if (clnp_ours(&src)) 26436368Ssklower goto bad; 26536368Ssklower 26636368Ssklower /* 26736368Ssklower * Trim mbuf to hold only the header. 26836368Ssklower * This mbuf will be the 'data' of the er pdu 26936368Ssklower */ 27036368Ssklower if (m->m_next != NULL) { 27136368Ssklower m_freem(m->m_next); 27236368Ssklower m->m_next = NULL; 27336368Ssklower } 27436368Ssklower 27536368Ssklower if (m->m_len > clnp->cnf_hdr_len) 276*37469Ssklower m_adj(m, (int)-(m->m_len - (int)clnp->cnf_hdr_len)); 27736368Ssklower 27836368Ssklower /* route er pdu: note we send pkt to src of original packet */ 279*37469Ssklower if (clnp_route(&src, &route, /* flags */0, &first_hop, &ia) != 0) 28036368Ssklower goto bad; 28136368Ssklower 28236368Ssklower /* compute our address based upon firsthop/ifp */ 283*37469Ssklower if (ia) 284*37469Ssklower our_addr = &ia->ia_addr.siso_addr; 285*37469Ssklower else 286*37469Ssklower goto bad; 287*37469Ssklower ifp = ia->ia_ifp; 28836368Ssklower 28936368Ssklower IFDEBUG(D_DISCARD) 29036368Ssklower printf("clnp_emit_er: to %s", clnp_iso_addrp(&src)); 29136368Ssklower printf(" from %s\n", clnp_iso_addrp(our_addr)); 29236368Ssklower ENDDEBUG 29336368Ssklower 29436368Ssklower IFDEBUG(D_DISCARD) 29536368Ssklower printf("clnp_emit_er: packet routed to %s\n", 29636368Ssklower clnp_iso_addrp(&((struct sockaddr_iso *)first_hop)->siso_addr)); 29736368Ssklower ENDDEBUG 29836368Ssklower 29936368Ssklower /* allocate mbuf for er pdu header: punt on no space */ 30036368Ssklower MGET(m0, M_DONTWAIT, MT_HEADER); 30136368Ssklower if (m0 == 0) 30236368Ssklower goto bad; 30336368Ssklower 30436368Ssklower m0->m_next = m; 30536368Ssklower er = mtod(m0, struct clnp_fixed *); 30636368Ssklower *er = er_template; 30736368Ssklower 30836368Ssklower /* setup src/dst on er pdu */ 30936368Ssklower /* NOTE REVERSAL OF SRC/DST */ 31036368Ssklower hoff = (caddr_t)er + sizeof(struct clnp_fixed); 311*37469Ssklower CLNP_INSERT_ADDR(hoff, src); 312*37469Ssklower CLNP_INSERT_ADDR(hoff, *our_addr); 31336368Ssklower 31436368Ssklower /* 31536368Ssklower * TODO: if complete src rt was specified, then reverse path, and 31636368Ssklower * copy into er as option. 31736368Ssklower */ 31836368Ssklower 31936368Ssklower /* add er option */ 32036368Ssklower *hoff++ = CLNPOVAL_ERREAS; /* code */ 32136368Ssklower *hoff++ = 2; /* length */ 32236368Ssklower *hoff++ = reason; /* discard reason */ 32336368Ssklower *hoff++ = 0; /* error localization = not specified */ 32436368Ssklower 32536368Ssklower /* set length */ 32636368Ssklower er->cnf_hdr_len = m0->m_len = (u_char)(hoff - (caddr_t)er); 32736368Ssklower total_len = m0->m_len + m->m_len; 32836368Ssklower HTOC(er->cnf_seglen_msb, er->cnf_seglen_lsb, total_len); 32936368Ssklower 33036368Ssklower /* compute checksum (on header only) */ 33136368Ssklower iso_gen_csum(m0, CLNP_CKSUM_OFF, (int)er->cnf_hdr_len); 33236368Ssklower 33336368Ssklower /* trim packet if too large for interface */ 33436368Ssklower if (total_len > ifp->if_mtu) 33536368Ssklower m_adj(m0, -(total_len - ifp->if_mtu)); 33636368Ssklower 33736368Ssklower /* send packet */ 33836368Ssklower (void) (*ifp->if_output)(ifp, m0, first_hop); 33936368Ssklower goto done; 34036368Ssklower 34136368Ssklower bad: 34236368Ssklower m_freem(m); 34336368Ssklower 34436368Ssklower done: 34536368Ssklower /* free route if it is a temp */ 34636368Ssklower if (route.ro_rt != NULL) 34736368Ssklower RTFREE(route.ro_rt); 34836368Ssklower } 34936368Ssklower #endif ISO 350