/* * Copyright (c) 1984, 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)ns_error.c 8.1 (Berkeley) 6/10/93 * $FreeBSD: src/sys/netns/ns_error.c,v 1.9 1999/08/28 00:49:49 peter Exp $ * $DragonFly: src/sys/netproto/ns/ns_error.c,v 1.9 2004/06/03 13:34:37 joerg Exp $ */ #include #include #include #include #include #include #include #include #include #include "ns.h" #include "ns_pcb.h" #include "idp.h" #include "ns_error.h" extern int idpcksum; /* from ns_input.c */ extern int idpchsum; /* from ns_input.c */ extern void spp_ctlinput( int, caddr_t); /* from spp_usrreq.c XXX */ struct ns_errstat ns_errstat; #ifdef lint #define NS_ERRPRINTFS 1 #endif #ifdef NS_ERRPRINTFS /* * NS_ERR routines: error generation, receive packet processing, and * routines to turnaround packets back to the originator. */ int ns_errprintfs = 0; #endif int ns_err_x(c) int c; { u_short *w, *lim, *base = ns_errstat.ns_es_codes; u_short x = c; /* * zero is a legit error code, handle specially */ if (x == 0) return (0); lim = base + NS_ERR_MAX - 1; for (w = base + 1; w < lim; w++) { if (*w == 0) *w = x; if (*w == x) break; } return (w - base); } /* * Generate an error packet of type error * in response to bad packet. */ void ns_error(om, type, param) struct mbuf *om; int type; int param; { struct ns_epidp *ep; struct mbuf *m; struct idp *nip; struct idp *oip = mtod(om, struct idp *); /* * If this packet was sent to the echo port, * and nobody was there, just echo it. * (Yes, this is a wart!) */ if (type == NS_ERR_NOSOCK && oip->idp_dna.x_port == htons(2) && (type = ns_echo(om))==0) return; #ifdef NS_ERRPRINTFS if (ns_errprintfs) printf("ns_err_error(%x, %d, %d)\n", oip, type, param); #endif /* * Don't Generate error packets in response to multicasts. */ if (oip->idp_dna.x_host.c_host[0] & 1) goto freeit; ns_errstat.ns_es_error++; /* * Make sure that the old IDP packet had 30 bytes of data to return; * if not, don't bother. Also don't EVER error if the old * packet protocol was NS_ERR. */ if (oip->idp_len < sizeof(struct idp)) { ns_errstat.ns_es_oldshort++; goto freeit; } if (oip->idp_pt == NSPROTO_ERROR) { ns_errstat.ns_es_oldns_err++; goto freeit; } /* * First, formulate ns_err message */ m = m_gethdr(MB_DONTWAIT, MT_HEADER); if (m == NULL) goto freeit; m->m_len = sizeof(*ep); MH_ALIGN(m, m->m_len); ep = mtod(m, struct ns_epidp *); if ((u_int)type > NS_ERR_TOO_BIG) panic("ns_err_error"); ns_errstat.ns_es_outhist[ns_err_x(type)]++; ep->ns_ep_errp.ns_err_num = htons((u_short)type); ep->ns_ep_errp.ns_err_param = htons((u_short)param); bcopy((caddr_t)oip, (caddr_t)&ep->ns_ep_errp.ns_err_idp, 42); nip = &ep->ns_ep_idp; nip->idp_len = sizeof(*ep); nip->idp_len = htons((u_short)nip->idp_len); nip->idp_pt = NSPROTO_ERROR; nip->idp_tc = 0; nip->idp_dna = oip->idp_sna; nip->idp_sna = oip->idp_dna; if (idpcksum) { nip->idp_sum = 0; nip->idp_sum = ns_cksum(m, sizeof(*ep)); } else nip->idp_sum = 0xffff; (void) ns_output(m, (struct route *)0, 0); freeit: m_freem(om); } void ns_printhost(p) struct ns_addr *p; { printf("", p->x_net.s_net[0], p->x_net.s_net[1], p->x_host.s_host[0], p->x_host.s_host[1], p->x_host.s_host[2], p->x_port); } /* * Process a received NS_ERR message. */ void ns_err_input(m) struct mbuf *m; { struct ns_errp *ep; #ifdef NS_ERRPRINTFS struct ns_epidp *epidp = mtod(m, struct ns_epidp *); #endif int i; int type, code, param; /* * Locate ns_err structure in mbuf, and check * that not corrupted and of at least minimum length. */ #ifdef NS_ERRPRINTFS if (ns_errprintfs) { printf("ns_err_input from "); ns_printhost(&epidp->ns_ep_idp.idp_sna); printf("len %d\n", ntohs(epidp->ns_ep_idp.idp_len)); } #endif i = sizeof (struct ns_epidp); if (((m->m_flags & M_EXT) || m->m_len < i) && (m = m_pullup(m, i)) == 0) { ns_errstat.ns_es_tooshort++; return; } ep = &(mtod(m, struct ns_epidp *)->ns_ep_errp); type = ntohs(ep->ns_err_num); param = ntohs(ep->ns_err_param); ns_errstat.ns_es_inhist[ns_err_x(type)]++; #ifdef NS_ERRPRINTFS /* * Message type specific processing. */ if (ns_errprintfs) printf("ns_err_input, type %d param %d\n", type, param); #endif if (type >= NS_ERR_TOO_BIG) { goto badcode; } ns_errstat.ns_es_outhist[ns_err_x(type)]++; switch (type) { case NS_ERR_UNREACH_HOST: code = PRC_UNREACH_NET; goto deliver; case NS_ERR_TOO_OLD: code = PRC_TIMXCEED_INTRANS; goto deliver; case NS_ERR_TOO_BIG: code = PRC_MSGSIZE; goto deliver; case NS_ERR_FULLUP: code = PRC_QUENCH; goto deliver; case NS_ERR_NOSOCK: code = PRC_UNREACH_PORT; goto deliver; case NS_ERR_UNSPEC_T: case NS_ERR_BADSUM_T: case NS_ERR_BADSUM: case NS_ERR_UNSPEC: code = PRC_PARAMPROB; goto deliver; deliver: /* * Problem with datagram; advise higher level routines. */ #ifdef NS_ERRPRINTFS if (ns_errprintfs) printf("deliver to protocol %d\n", ep->ns_err_idp.idp_pt); #endif switch(ep->ns_err_idp.idp_pt) { case NSPROTO_SPP: spp_ctlinput(code, (caddr_t)ep); break; default: idp_ctlinput(code, (caddr_t)ep); } goto freeit; default: badcode: ns_errstat.ns_es_badcode++; goto freeit; } freeit: m_freem(m); } int ns_echo(m) struct mbuf *m; { struct idp *idp = mtod(m, struct idp *); struct echo { struct idp ec_idp; u_short ec_op; /* Operation, 1 = request, 2 = reply */ } *ec = (struct echo *)idp; struct ns_addr temp; if (idp->idp_pt!=NSPROTO_ECHO) return(NS_ERR_NOSOCK); if (ec->ec_op!=htons(1)) return(NS_ERR_UNSPEC); ec->ec_op = htons(2); temp = idp->idp_dna; idp->idp_dna = idp->idp_sna; idp->idp_sna = temp; if (idp->idp_sum != 0xffff) { idp->idp_sum = 0; idp->idp_sum = ns_cksum(m, (int)(((ntohs(idp->idp_len) - 1)|1)+1)); } (void) ns_output(m, (struct route *)0, NS_FORWARDING); return(0); }