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 $ */ 29*40774Ssklower /* @(#)clnp_er.c 7.6 (Berkeley) 04/05/90 */ 3036368Ssklower 3136368Ssklower #ifndef lint 3236763Ssklower static char *rcsid = "$Header: /var/src/sys/netiso/RCS/clnp_er.c,v 5.1 89/02/09 16:20:18 hagens Exp $"; 3336368Ssklower #endif lint 3436368Ssklower 3537469Ssklower #include "param.h" 3637469Ssklower #include "mbuf.h" 3737469Ssklower #include "domain.h" 3837469Ssklower #include "protosw.h" 3937469Ssklower #include "socket.h" 4037469Ssklower #include "socketvar.h" 4137469Ssklower #include "errno.h" 4236368Ssklower 4336368Ssklower #include "../net/if.h" 4436368Ssklower #include "../net/route.h" 4536368Ssklower 4637469Ssklower #include "iso.h" 4737469Ssklower #include "iso_var.h" 4837469Ssklower #include "iso_pcb.h" 4939194Ssklower #define CLNP_ER_CODES 5037469Ssklower #include "clnp.h" 5137469Ssklower #include "clnp_stat.h" 5237469Ssklower #include "argo_debug.h" 5336368Ssklower 5436368Ssklower static struct clnp_fixed er_template = { 5536368Ssklower ISO8473_CLNP, /* network identifier */ 5636368Ssklower 0, /* length */ 5736368Ssklower ISO8473_V1, /* version */ 5836368Ssklower CLNP_TTL, /* ttl */ 5936368Ssklower CLNP_ER, /* type */ 6036368Ssklower 0, /* segment length */ 6136368Ssklower 0 /* checksum */ 6236368Ssklower }; 6336368Ssklower 6436368Ssklower /* 6536368Ssklower * FUNCTION: clnp_er_input 6636368Ssklower * 6736368Ssklower * PURPOSE: Process an ER pdu. 6836368Ssklower * 6936368Ssklower * RETURNS: 7036368Ssklower * 7136368Ssklower * SIDE EFFECTS: 7236368Ssklower * 7336368Ssklower * NOTES: 7436368Ssklower */ 7536368Ssklower clnp_er_input(m, src, reason) 7636368Ssklower struct mbuf *m; /* ptr to packet itself */ 7736368Ssklower struct iso_addr *src; /* ptr to src of er */ 7837469Ssklower u_char reason; /* reason code of er */ 7936368Ssklower { 8036368Ssklower int cmd = -1; 8136368Ssklower extern u_char clnp_protox[]; 8236368Ssklower 8336368Ssklower IFDEBUG(D_CTLINPUT) 8436368Ssklower printf("clnp_er_input: m x%x, src %s, reason x%x\n", m, 8536368Ssklower clnp_iso_addrp(src), reason); 8636368Ssklower ENDDEBUG 8736368Ssklower 8839194Ssklower INCSTAT(cns_er_inhist[clnp_er_index(reason)]); 8936368Ssklower switch (reason) { 9036368Ssklower case GEN_NOREAS: 9136368Ssklower case GEN_PROTOERR: 9236368Ssklower break; 9336368Ssklower case GEN_BADCSUM: 9436368Ssklower cmd = PRC_PARAMPROB; 9536368Ssklower break; 9636368Ssklower case GEN_CONGEST: 9736368Ssklower cmd = PRC_QUENCH; 9836368Ssklower break; 9936368Ssklower case GEN_HDRSYNTAX: 10036368Ssklower cmd = PRC_PARAMPROB; 10136368Ssklower break; 10236368Ssklower case GEN_SEGNEEDED: 103*40774Ssklower cmd = PRC_MSGSIZE; 10436368Ssklower break; 10536368Ssklower case GEN_INCOMPLETE: 10636368Ssklower cmd = PRC_PARAMPROB; 10736368Ssklower break; 10836368Ssklower case GEN_DUPOPT: 10936368Ssklower cmd = PRC_PARAMPROB; 11036368Ssklower break; 11136368Ssklower case ADDR_DESTUNREACH: 11236368Ssklower cmd = PRC_UNREACH_HOST; 11336368Ssklower break; 11436368Ssklower case ADDR_DESTUNKNOWN: 11536368Ssklower cmd = PRC_UNREACH_PROTOCOL; 11636368Ssklower break; 11736368Ssklower case SRCRT_UNSPECERR: 11836368Ssklower case SRCRT_SYNTAX: 11936368Ssklower case SRCRT_UNKNOWNADDR: 12036368Ssklower case SRCRT_BADPATH: 12136368Ssklower cmd = PRC_UNREACH_SRCFAIL; 12236368Ssklower break; 12336368Ssklower case TTL_EXPTRANSIT: 12436368Ssklower cmd = PRC_TIMXCEED_INTRANS; 12536368Ssklower break; 12636368Ssklower case TTL_EXPREASS: 12736368Ssklower cmd = PRC_TIMXCEED_REASS; 12836368Ssklower break; 12936368Ssklower case DISC_UNSUPPOPT: 13036368Ssklower case DISC_UNSUPPVERS: 13136368Ssklower case DISC_UNSUPPSECURE: 13236368Ssklower case DISC_UNSUPPSRCRT: 13336368Ssklower case DISC_UNSUPPRECRT: 13436368Ssklower cmd = PRC_PARAMPROB; 13536368Ssklower break; 13636368Ssklower case REASS_INTERFERE: 13736368Ssklower cmd = PRC_TIMXCEED_REASS; 13836368Ssklower break; 13936368Ssklower } 14036368Ssklower 14136763Ssklower /* 14236763Ssklower * tpclnp_ctlinput1 is called directly so that we don't 14336763Ssklower * have to build an iso_sockaddr out of src. 14436763Ssklower */ 14536368Ssklower if (cmd >= 0) 14636763Ssklower tpclnp_ctlinput1(cmd, src); 14736368Ssklower 14836368Ssklower m_freem(m); 14936368Ssklower } 15036368Ssklower 15136368Ssklower /* 15236368Ssklower * FUNCTION: clnp_discard 15336368Ssklower * 15436368Ssklower * PURPOSE: Discard a clnp datagram 15536368Ssklower * 15636368Ssklower * RETURNS: nothing 15736368Ssklower * 15836368Ssklower * SIDE EFFECTS: Will emit an ER pdu if possible 15936368Ssklower * 16036368Ssklower * NOTES: This code assumes that we have previously tried to pull 16136368Ssklower * up the header of the datagram into one mbuf. 16236368Ssklower */ 16336368Ssklower clnp_discard(m, reason) 16436368Ssklower struct mbuf *m; /* header of packet to discard */ 16536368Ssklower char reason; /* reason for discard */ 16636368Ssklower { 16736368Ssklower IFDEBUG(D_DISCARD) 16836368Ssklower printf("clnp_discard: m x%x, reason x%x\n", m, reason); 16936368Ssklower ENDDEBUG 17036368Ssklower 17136368Ssklower if (m != NULL) { 17236368Ssklower if (m->m_len >= sizeof(struct clnp_fixed)) { 17336368Ssklower register struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *); 17436368Ssklower 17537469Ssklower if (((clnp->cnf_type & CNF_TYPE) != CLNP_ER) && 17637469Ssklower (clnp->cnf_type & CNF_ERR_OK)) { 17737469Ssklower clnp_emit_er(m, reason); 17837469Ssklower return; 17936368Ssklower } 18036368Ssklower } 18136368Ssklower m_freem(m); 18236368Ssklower } 18336368Ssklower } 18436368Ssklower 18536368Ssklower /* 18636368Ssklower * FUNCTION: clnp_emit_er 18736368Ssklower * 18836368Ssklower * PURPOSE: Send an ER pdu. 18936368Ssklower * The src of the of the ER pdu is the host that is sending 19036368Ssklower * the ER (ie. us), *not* the original destination of the 19136368Ssklower * packet. 19236368Ssklower * 19336368Ssklower * RETURNS: nothing 19436368Ssklower * 19536368Ssklower * SIDE EFFECTS: 19636368Ssklower * 19736368Ssklower * NOTES: Takes responsibility for freeing mbuf passed 19836368Ssklower * This function may be called with a packet that 19936368Ssklower * was created by us; in this case, do not send 20036368Ssklower * an ER. 20136368Ssklower */ 20236368Ssklower clnp_emit_er(m, reason) 20336368Ssklower struct mbuf *m; /* header of packet to discard */ 20436368Ssklower char reason; /* reason for discard */ 20536368Ssklower { 20636368Ssklower register struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *); 20736368Ssklower register struct clnp_fixed *er; 20837469Ssklower struct route_iso route; 20936368Ssklower struct ifnet *ifp; 21036368Ssklower struct sockaddr *first_hop; 21136368Ssklower struct iso_addr src, dst, *our_addr; 21236368Ssklower caddr_t hoff, hend; 21336368Ssklower int total_len; /* total len of dg */ 21436368Ssklower struct mbuf *m0; /* contains er pdu hdr */ 21537469Ssklower struct iso_ifaddr *ia = 0; 21636368Ssklower 21736368Ssklower IFDEBUG(D_DISCARD) 21836368Ssklower printf("clnp_emit_er: m x%x, hdr len %d\n", m, clnp->cnf_hdr_len); 21936368Ssklower ENDDEBUG 22036368Ssklower 22136368Ssklower bzero((caddr_t)&route, sizeof(route)); 22236368Ssklower 22336368Ssklower /* 22436368Ssklower * If header length is incorrect, or entire header is not contained 22536368Ssklower * in this mbuf, we punt 22636368Ssklower */ 22736368Ssklower if ((clnp->cnf_hdr_len < CLNP_HDR_MIN) || 22836368Ssklower (clnp->cnf_hdr_len > CLNP_HDR_MAX) || 22936368Ssklower (clnp->cnf_hdr_len > m->m_len)) 23036368Ssklower goto bad; 23136368Ssklower 23236368Ssklower /* extract src, dest address */ 23336368Ssklower hend = (caddr_t)clnp + clnp->cnf_hdr_len; 23436368Ssklower hoff = (caddr_t)clnp + sizeof(struct clnp_fixed); 23536368Ssklower CLNP_EXTRACT_ADDR(dst, hoff, hend); 23636368Ssklower if (hoff == (caddr_t)0) { 23736368Ssklower goto bad; 23836368Ssklower } 23936368Ssklower CLNP_EXTRACT_ADDR(src, hoff, hend); 24036368Ssklower if (hoff == (caddr_t)0) { 24136368Ssklower goto bad; 24236368Ssklower } 24336368Ssklower 24436368Ssklower /* 24536368Ssklower * Do not send ER if we generated the packet. 24636368Ssklower */ 24736368Ssklower if (clnp_ours(&src)) 24836368Ssklower goto bad; 24936368Ssklower 25036368Ssklower /* 25136368Ssklower * Trim mbuf to hold only the header. 25236368Ssklower * This mbuf will be the 'data' of the er pdu 25336368Ssklower */ 25436368Ssklower if (m->m_next != NULL) { 25536368Ssklower m_freem(m->m_next); 25636368Ssklower m->m_next = NULL; 25736368Ssklower } 25836368Ssklower 25936368Ssklower if (m->m_len > clnp->cnf_hdr_len) 26037469Ssklower m_adj(m, (int)-(m->m_len - (int)clnp->cnf_hdr_len)); 26136368Ssklower 26236368Ssklower /* route er pdu: note we send pkt to src of original packet */ 26337469Ssklower if (clnp_route(&src, &route, /* flags */0, &first_hop, &ia) != 0) 26436368Ssklower goto bad; 26536368Ssklower 26636368Ssklower /* compute our address based upon firsthop/ifp */ 26737469Ssklower if (ia) 26837469Ssklower our_addr = &ia->ia_addr.siso_addr; 26937469Ssklower else 27037469Ssklower goto bad; 27137469Ssklower ifp = ia->ia_ifp; 27236368Ssklower 27336368Ssklower IFDEBUG(D_DISCARD) 27436368Ssklower printf("clnp_emit_er: to %s", clnp_iso_addrp(&src)); 27536368Ssklower printf(" from %s\n", clnp_iso_addrp(our_addr)); 27636368Ssklower ENDDEBUG 27736368Ssklower 27836368Ssklower IFDEBUG(D_DISCARD) 27936368Ssklower printf("clnp_emit_er: packet routed to %s\n", 28036368Ssklower clnp_iso_addrp(&((struct sockaddr_iso *)first_hop)->siso_addr)); 28136368Ssklower ENDDEBUG 28236368Ssklower 28336368Ssklower /* allocate mbuf for er pdu header: punt on no space */ 28436368Ssklower MGET(m0, M_DONTWAIT, MT_HEADER); 28536368Ssklower if (m0 == 0) 28636368Ssklower goto bad; 28736368Ssklower 28836368Ssklower m0->m_next = m; 28936368Ssklower er = mtod(m0, struct clnp_fixed *); 29036368Ssklower *er = er_template; 29136368Ssklower 29236368Ssklower /* setup src/dst on er pdu */ 29336368Ssklower /* NOTE REVERSAL OF SRC/DST */ 29436368Ssklower hoff = (caddr_t)er + sizeof(struct clnp_fixed); 29537469Ssklower CLNP_INSERT_ADDR(hoff, src); 29637469Ssklower CLNP_INSERT_ADDR(hoff, *our_addr); 29736368Ssklower 29836368Ssklower /* 29936368Ssklower * TODO: if complete src rt was specified, then reverse path, and 30036368Ssklower * copy into er as option. 30136368Ssklower */ 30236368Ssklower 30336368Ssklower /* add er option */ 30436368Ssklower *hoff++ = CLNPOVAL_ERREAS; /* code */ 30536368Ssklower *hoff++ = 2; /* length */ 30636368Ssklower *hoff++ = reason; /* discard reason */ 30736368Ssklower *hoff++ = 0; /* error localization = not specified */ 30836368Ssklower 30936368Ssklower /* set length */ 31036368Ssklower er->cnf_hdr_len = m0->m_len = (u_char)(hoff - (caddr_t)er); 31136368Ssklower total_len = m0->m_len + m->m_len; 31236368Ssklower HTOC(er->cnf_seglen_msb, er->cnf_seglen_lsb, total_len); 31336368Ssklower 31436368Ssklower /* compute checksum (on header only) */ 31536368Ssklower iso_gen_csum(m0, CLNP_CKSUM_OFF, (int)er->cnf_hdr_len); 31636368Ssklower 31736368Ssklower /* trim packet if too large for interface */ 31836368Ssklower if (total_len > ifp->if_mtu) 31936368Ssklower m_adj(m0, -(total_len - ifp->if_mtu)); 32036368Ssklower 32136368Ssklower /* send packet */ 32239194Ssklower INCSTAT(cns_er_outhist[clnp_er_index(reason)]); 323*40774Ssklower (void) (*ifp->if_output)(ifp, m0, first_hop, route.ro_rt); 32436368Ssklower goto done; 32536368Ssklower 32636368Ssklower bad: 32736368Ssklower m_freem(m); 32836368Ssklower 32936368Ssklower done: 33036368Ssklower /* free route if it is a temp */ 33136368Ssklower if (route.ro_rt != NULL) 33236368Ssklower RTFREE(route.ro_rt); 33336368Ssklower } 33439194Ssklower 33539194Ssklower clnp_er_index(p) 33639194Ssklower u_char p; 33739194Ssklower { 33839194Ssklower register u_char *cp = clnp_er_codes + CLNP_ERRORS; 33939194Ssklower while (cp > clnp_er_codes) { 34039194Ssklower cp--; 34139194Ssklower if (*cp == p) 34239194Ssklower return (cp - clnp_er_codes); 34339194Ssklower } 34439194Ssklower return (CLNP_ERRORS + 1); 34539194Ssklower } 346