summaryrefslogtreecommitdiffstats
path: root/sys/netinet6/ipv6_icmp.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netinet6/ipv6_icmp.c')
-rw-r--r--sys/netinet6/ipv6_icmp.c1086
1 files changed, 0 insertions, 1086 deletions
diff --git a/sys/netinet6/ipv6_icmp.c b/sys/netinet6/ipv6_icmp.c
deleted file mode 100644
index 01424305243..00000000000
--- a/sys/netinet6/ipv6_icmp.c
+++ /dev/null
@@ -1,1086 +0,0 @@
-/*
-%%% copyright-nrl-95
-This software is Copyright 1995-1998 by Randall Atkinson, Ronald Lee,
-Daniel McDonald, Bao Phan, and Chris Winters. All Rights Reserved. All
-rights under this copyright have been assigned to the US Naval Research
-Laboratory (NRL). The NRL Copyright Notice and License Agreement Version
-1.1 (January 17, 1995) applies to this software.
-You should have received a copy of the license with this software. If you
-didn't get a copy, you may request one from <license@ipv6.nrl.navy.mil>.
-
-*/
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/malloc.h>
-#include <sys/mbuf.h>
-#include <sys/protosw.h>
-#include <sys/socket.h>
-#include <sys/socketvar.h>
-#include <sys/time.h>
-#include <sys/kernel.h>
-
-#include <net/if.h>
-#include <net/route.h>
-
-#include <netinet/in.h>
-#include <netinet/in_systm.h>
-#include <netinet/ip.h>
-#include <netinet/in_pcb.h>
-
-#include <netinet6/in6_var.h>
-#include <netinet6/ipv6.h>
-#include <netinet6/ipv6_var.h>
-#include <netinet6/ipv6_icmp.h>
-#include <netinet6/icmpv6_var.h>
-
-#if __OpenBSD__
-#undef IPSEC
-#ifdef NRL_IPSEC
-#define IPSEC 1
-#endif /* NRL_IPSEC */
-#endif /* __OpenBSD__ */
-
-#ifdef IPSEC
-#include <sys/osdep.h>
-#include <net/netproc.h>
-#include <net/netproc_var.h>
-
-extern struct netproc_security fixedencrypt;
-extern struct netproc_auth fixedauth;
-#endif /* IPSEC */
-
-#if __FreeBSD__
-#include <sys/sysctl.h>
-#endif /* __FreeBSD__ */
-
-#ifdef DEBUG_NRL
-#include <sys/debug.h>
-#else /* DEBUG_NRL */
-#if __OpenBSD__
-#include <netinet6/debug.h>
-#else /* __OpenBSD__ */
-#include <sys/debug.h>
-#endif /* __OpenBSD__ */
-#endif /* DEBUG_NRL */
-
-/*
- * Globals.
- */
-
-static struct sockaddr_in6 icmpsrc = { sizeof (struct sockaddr_in6),
- AF_INET6 };
-static struct sockaddr_in6 icmpdst = { sizeof (struct sockaddr_in6),
- AF_INET6 };
-struct icmpv6stat icmpv6stat;
-
-/*
- * External globals.
- */
-
-extern struct in6_ifaddr *in6_ifaddr;
-extern u_char ipv6_protox[];
-extern struct protosw inet6sw[];
-
-/*
- * Functions and macros (and one global that needs to be near the function).
- */
-
-uint8_t ipv6_saved_routing[384]; /* If a routing header has been processed,
- then it will have been bcopy()d into
- this buffer. If not, the first byte
- will be set to zero (which would be
- a nexthdr of hop-by-hop, and is not
- valid). */
-
-struct mbuf *ipv6_srcrt __P((void));
-void ipv6_icmp_reflect __P((struct mbuf *, int));
-void update_pathmtu __P((struct in6_addr *, uint32_t));
-
-/* This is broken as of getting rid of hdrindex and the mbuf structure it
- creates. While this needs to be fixed, it's a Real Shame that source
- route reflection couldn't be reimplemented for this release... - cmetz */
-#if 0
-/*----------------------------------------------------------------------
- * Reverse a saved IPv6 source route, for possible use on replies.
- ----------------------------------------------------------------------*/
-
-struct mbuf *ipv6_srcrt()
-{
- struct ipv6_srcroute0 *sr, *osr = (struct ipv6_srcroute0 *)ipv6_saved_routing;
- struct in6_addr *sra, *osra;
- struct mbuf *srm;
- int i, j;
-
- if (!osr->i6sr_nexthdr)
- return NULL;
- if (osr->i6sr_type)
- return NULL;
- if (!(srm = m_get(M_DONTWAIT, MT_DATA)))
- return NULL;
-
- sr = mtod(srm, struct ipv6_srcroute0 *);
- bzero(sr, sizeof(struct ipv6_srcroute0));
- sr->i6sr_nexthdr = IPPROTO_ICMPV6;
- sr->i6sr_len = osr->i6sr_len;
- j = sr->i6sr_left = sr->i6sr_len/2;
-/* We probably should reverse the bit mask, but it's painful, and defaulting
- to loose source routing might be preferable anyway. */
- sra = (struct in6_addr *)((caddr_t)sr + sizeof(struct ipv6_srcroute0));
- osra = (struct in6_addr *)((caddr_t)osr + sizeof(struct ipv6_srcroute0));
- srm->m_len = sizeof(struct ipv6_srcroute0) + sizeof(struct in6_addr) * j;
- for (i = 0; i < sr->i6sr_len/2; sra[i++] = osra[j--]);
- return srm;
-}
-#endif /* 0 */
-
-/*----------------------------------------------------------------------
- * Reflect an IPv6 ICMP packet back to the source.
- ----------------------------------------------------------------------*/
-
-void
-ipv6_icmp_reflect(m, extra)
- struct mbuf *m;
- int extra;
-{
- struct in6_addr tmp;
- struct ipv6 *ipv6;
- struct in6_ifaddr *i6a;
- struct ipv6_icmp *icmp;
-#if 0
- struct mbuf *routing = NULL;
-#endif /* 0 */
-#ifdef IPSEC
- struct socket *socket, fake;
-#endif /* IPSEC */
-
- /*
- * Hmmm, we potentially have authentication, routing, and hop-by-hop
- * headers behind this. OUCH. For now, however, assume only IPv6
- * header, followed by ICMP.
- */
-
- DP(FINISHED, extra, d);
-
- ipv6 = mtod(m, struct ipv6 *);
- icmp = (struct ipv6_icmp *)(mtod(m, caddr_t) + extra);
-
- tmp = ipv6->ipv6_dst;
- ipv6->ipv6_dst = ipv6->ipv6_src;
-
- /*
- * If the incoming packet was addressed directly to us,
- * use dst as the src for the reply. Otherwise (multicast
- * or anonymous), use the address which corresponds
- * to the incoming interface.
- */
-
- for (i6a = in6_ifaddr; i6a; i6a = i6a->i6a_next)
- {
- /* Find first (non-local if possible) address for
- source usage. If multiple locals, use last one found. */
-
- if (IN6_ARE_ADDR_EQUAL(&tmp, &I6A_SIN(i6a)->sin6_addr))
- break;
- }
- icmpdst.sin6_addr = tmp;
-
- if (i6a == NULL && m->m_pkthdr.rcvif != NULL)
- i6a = (struct in6_ifaddr *)ifaof_ifpforaddr((struct sockaddr *)&icmpdst,
- m->m_pkthdr.rcvif);
-
- if (i6a == NULL)
- {
- /* Want globally-routable if I can help it. */
- i6a = in6_ifaddr;
- }
-
- ipv6->ipv6_src = I6A_SIN(i6a)->sin6_addr;
-
- ipv6->ipv6_nexthdr = IPPROTO_ICMPV6;
-
- if (extra > sizeof(struct ipv6)) {
- DP(FINISHED, extra, 08x);
- DP(FINISHED, m->m_pkthdr.len, 08x);
- ipv6_stripoptions(m, extra);
- DP(FINISHED, m->m_pkthdr.len, 08x);
- extra = sizeof(struct ipv6);
-#if 0
- if ((routing = ipv6_srcrt())) {
- ipv6->ipv6_nexthdr = IPPROTO_ROUTING;
- mtod(routing, struct ipv6_srcroute0 *)->i6sr_nexthdr = IPPROTO_ICMPV6;
- routing->m_next = m->m_next;
- m->m_next = routing;
- extra += routing->m_len;
- } else
- DPRINTF(IDL_ERROR, ("icmp_reflect() got options but can't strip them\n"));
-#endif /* 0 */
- }
-
- m->m_flags &= ~(M_BCAST|M_MCAST);
-
- DP(FINISHED, m->m_pkthdr.len, d);
-
- /* For errors, anything over the 576 byte mark we discard. */
- if (!(ICMPV6_INFOTYPE(icmp->icmp_type)))
- if (m->m_pkthdr.len > ICMPV6_MAXLEN)
- m_adj(m, -(m->m_pkthdr.len - ICMPV6_MAXLEN));
-
- DP(FINISHED, m->m_pkthdr.len - extra, d);
-
- icmp->icmp_cksum = 0;
- DPRINTF(IDL_EVENT,("ipv6_icmp_reflect() calling in6_cksum().\n"));
- icmp->icmp_cksum = in6_cksum(m,IPPROTO_ICMPV6, m->m_pkthdr.len - extra,
- extra);
- DP(FINISHED, icmp->icmp_cksum, 04x);
-
- ipv6->ipv6_hoplimit = 255;
- /* Version 6, priority 12 (info) or 15 (error), flow zero */
- ipv6->ipv6_versfl = htonl(((6) << 28) |
- ((ICMPV6_INFOTYPE(icmp->icmp_type) ? 12 : 15) << 24));
-
-#if 0 /* def IPSEC */
- /*
- * Packet sent should be authenticated/encrypted if responding to
- * received packet that was authenticated/encrypted.
- */
- if (m->m_flags & (M_AUTHENTIC | M_DECRYPTED)) {
- struct netproc_requestandstate *r;
-
- bzero(&fake, sizeof(struct socket));
-
- if (netproc_alloc(&fake)) {
- DPRINTF(ERROR, ("icmp_send: netproc_alloc failed\n"));
- m_freem(m);
- return;
- }
-
- r = &((struct netproc_socketdata *)fake.so_netproc)->requests[0];
- r->requestlen = ((m->m_flags & M_AUTHENTIC) ?
- sizeof(struct netproc_auth) : 0) +
- ((m->m_flags & M_DECRYPTED) ?
- sizeof(struct netproc_security) : 0);
- if (!(r->request = OSDEP_MALLOC(r->requestlen))) {
- DPRINTF(ERROR, ("icmp_send: malloc(%d) failed\n",
- r->requestlen));
- netproc_free(&fake);
- m_freem(m);
- return;
- }
-
- {
- void *p = r->request;
-
- if (m->m_flags & M_AUTHENTIC) {
- memcpy(p, &fixedauth, sizeof(struct netproc_auth));
- p += sizeof(fixedauth);
- }
- if (m->m_flags & M_DECRYPTED)
- memcpy(p, &fixedencrypt, sizeof(struct netproc_security));
- }
-
- socket = &fake;
- } else
- socket = NULL;
-#endif /* IPSEC */
-
- icmpv6stat.icps_outhist[icmp->icmp_type]++;
-
-#ifdef IPSEC
- ipv6_output(m, NULL, IPV6_RAWOUTPUT, NULL, NULL, socket);
-
- if (socket)
- netproc_free(socket);
-#else /* IPSEC */
- ipv6_output(m, NULL, IPV6_RAWOUTPUT, NULL, NULL, NULL);
-#endif /* IPSEC */
-}
-
-/*----------------------------------------------------------------------
- * Given a bad packet (badpack), generate an ICMP error packet in response.
- * We assume that ipv6_preparse() has been run over badpack.
- *
- * Add rate-limiting code to this function, on a timer basis.
- * (i.e. if t(current) - t(lastsent) < limit, then don't send a message.
- ----------------------------------------------------------------------*/
-
-void
-ipv6_icmp_error(badpack, type, code, paramptr)
- struct mbuf *badpack;
- int type,code;
- uint32_t paramptr;
-{
- struct ipv6 *oipv6;
- int divpoint = sizeof(struct ipv6);
- struct ipv6_icmp *icmp;
- struct mbuf *outgoing;
-
- if ((badpack->m_flags & M_MCAST) /*&& type != ICMPV6_TOOBIG */) {
- m_freem(badpack);
- return;
- }
-
- /*if (type != ICMPV6_REDIRECT)*/
- icmpv6stat.icps_error++;
-
- /*
- * Since MTU and max ICMP packet size is less than a cluster (so far...)
- * pull the offending packet into a single cluster.
- *
- * If option-stripping becomes required, here might be the place to do it.
- * (The current design decision is to not strip options. Besides, one of
- * the callers of this function is ipv6_hop(), which does hop-by-hop
- * option processing.)
- */
-
- oipv6 = mtod(badpack,struct ipv6 *);
-
- DDO(GROSSEVENT,printf("oipv6 (0x%lx) is:\n",(unsigned long)oipv6);dump_ipv6(oipv6));
-
- DP(FINISHED, badpack->m_pkthdr.len, d);
-
- /*
- * Get a new cluster mbuf for ICMP error message. Since IPv6 ICMP messages
- * have a length limit that should be less than MCLBYTES, one cluster should
- * work nicely.
- */
-
- if (!(outgoing = m_gethdr(M_DONTWAIT,MT_HEADER))) {
- m_freem(badpack);
- return;
- };
-
- MCLGET(outgoing, M_DONTWAIT);
- if (!(outgoing->m_flags & M_EXT)) {
- m_freem(badpack);
- m_free(outgoing);
- return;
- };
-
- outgoing->m_len = sizeof(struct ipv6) + ICMPV6_MINLEN;
- bcopy(oipv6, mtod(outgoing, caddr_t), sizeof(struct ipv6));
- icmp = (struct ipv6_icmp *)(mtod(outgoing, caddr_t) + sizeof(struct ipv6));
-
- {
- int i = badpack->m_pkthdr.len;
-
- if (i > ICMPV6_MAXLEN - sizeof(struct ipv6) - sizeof(struct icmpv6hdr))
- i = ICMPV6_MAXLEN - sizeof(struct ipv6) - sizeof(struct icmpv6hdr);
-
- outgoing->m_len += i;
- /* Copies are expensive, but linear buffers are nice. Luckily, the data
- is bounded, short, and ICMP errors aren't that performance critical. */
- m_copydata(badpack, 0, i, mtod(outgoing, caddr_t) +
- sizeof(struct ipv6) + sizeof(struct icmpv6hdr));
- }
-
- /* Need rcvif to do source address selection later */
- outgoing->m_pkthdr.rcvif = badpack->m_pkthdr.rcvif;
-
- outgoing->m_pkthdr.len = outgoing->m_len;
-
-#if 0 /* defined(IPSEC) || defined(NRL_IPSEC) */
- /*
- * Copy over the DECRYPTED and AUTHENTIC flag.
- * NB: If the inbound packet was sent to us in an authenticated
- * or encrypted tunnel, these flags are cleared when we get here.
- * We don't have a way to preserve tunnel state at the moment.
- * This is a hole we need to fix soon.
- */
- outgoing->m_flags |= badpack->m_flags & (M_DECRYPTED | M_AUTHENTIC);
- DDO(IDL_ERROR,if (outgoing->m_flags & M_AUTHENTIC) printf("icmpv6_error processing authentic pkt\n"));
- DDO(IDL_ERROR,if (outgoing->m_flags & M_DECRYPTED) printf("icmpv6_error processing encrypted pkt\n"));
-#endif /* defined(IPSEC) || defined(NRL_IPSEC) */
-
- m_freem(badpack);
-
- icmp->icmp_type = type;
- icmp->icmp_code = code;
- icmp->icmp_unused = 0;
- if (type == ICMPV6_PARAMPROB || type == ICMPV6_TOOBIG)
- icmp->icmp_paramptr = htonl(paramptr);
-
- ipv6_icmp_reflect(outgoing, divpoint);
-}
-
-/*----------------------------------------------------------------------
- * Update path MTU for an IPv6 destination. This function may have to go
- * scan for TCP control blocks and give them hints to scale down.
- * There is a small denial-of-service attack if MTU messages are
- * unauthenticated. I can lower MTU to 576.
- ----------------------------------------------------------------------*/
-
-void
-update_pathmtu(dst, newmtu)
- struct in6_addr *dst;
- uint32_t newmtu; /* ntohl()'ed by caller. */
-{
- int s = splnet();
- struct rtentry *rt;
- struct sockaddr_in6 sin6;
-
- DDO(IDL_EVENT,printf("Entering update_pathmtu with:\n");\
- dump_in6_addr(dst);printf("And newmtu of %d.\n",(unsigned int)newmtu));
-
- if (IN6_IS_ADDR_MULTICAST(dst))
- {
- /* Multicast MTU Discovery not yet implemented */
- DPRINTF(IDL_ERROR, ("Multicast MTU too big message.\n"));
- splx(s);
- return;
- }
-
- sin6.sin6_family = AF_INET6;
- sin6.sin6_len = sizeof(struct sockaddr_in6);
- sin6.sin6_addr = *dst;
-
- /*
- * Since I'm doing a rtalloc, no need to zero-out the port and flowlabel.
- */
-#ifdef __FreeBSD__
- if ((rt = rtalloc1((struct sockaddr *)&sin6,0,0UL)) != NULL)
-#else /* __FreeBSD__ */
- if ((rt = rtalloc1((struct sockaddr *)&sin6,0)) != NULL)
-#endif /* __FreeBSD__ */
- {
- if (rt->rt_flags & RTF_HOST) {
- if (rt->rt_rmx.rmx_mtu < newmtu) {
- DPRINTF(IDL_ERROR,
- ("DANGER: New MTU message is LARGER than current MTU.\n"));
- };
-
- rt->rt_rmx.rmx_mtu = newmtu; /* This should be enough for HLP's to
- know MTU has changed, IMHO. */
- rt->rt_refcnt--;
- } else {
- DPRINTF(IDL_ERROR,
- ("Got path MTU message for non-cloned destination route.\n"));
- }
- /*
- * Find all active tcp connections, and indicate they need path MTU
- * updating as well.
- *
- * Also, find RTF_TUNNEL routes that point to this updated route,
- * because they need their path MTU lowered. Perhaps decapsulating
- * the message, and sending TOOBIG messages back.
- */
- }
-
- splx(s);
- return;
-}
-
-/*----------------------------------------------------------------------
- * ICMPv6 input routine. Handles inbound ICMPv6 packets, including
- * direct handling of some packets.
- ----------------------------------------------------------------------*/
-
-void
-ipv6_icmp_input(incoming, extra)
- register struct mbuf *incoming;
- int extra;
-{
- struct ipv6_icmp *icmp;
- struct ipv6 *ipv6;
- int icmplen,code;
- void (*ctlfunc) __P((int, struct sockaddr *, struct ipv6 *, struct mbuf *));
-
- /*
- * Q: Any address validity checks beyond those in ipv6_input()?
- */
-
- DPRINTF(FINISHED, ("ipv6_icmp_input -- pkthdr.len = %d, extra = %d\n",
- incoming->m_pkthdr.len, extra));
-
- DDO(FINISHED, dump_mbuf_tcpdump(incoming));
-
- icmplen = incoming->m_pkthdr.len - extra;
- if (icmplen < ICMPV6_MINLEN)
- {
- /* Not enough for full ICMP packet. */
- icmpv6stat.icps_tooshort++;
- m_freem(incoming);
- return;
- }
-
- if (incoming->m_len < extra + ICMPV6_MINLEN)
- if (!(incoming = m_pullup2(incoming, extra + ICMPV6_MINLEN)))
- return;
-
- DDO(FINISHED, dump_mbuf_tcpdump(incoming));
-
- ipv6 = mtod(incoming, struct ipv6 *);
- icmp = (struct ipv6_icmp *)(mtod(incoming, caddr_t) + extra);
-
- /*
- * Verify checksum with IPv6 header at the top of this chain.
- */
-
- DPRINTF(IDL_EVENT,("ipv6_icmp_input() calling in6_cksum().\n"));
- DPRINTF(IDL_EVENT,("icmplen = %d\n", icmplen));
- {
- unsigned int cksum;
-
- if ((cksum = in6_cksum(incoming, IPPROTO_ICMPV6, icmplen, extra)))
- {
- DPRINTF(IDL_ERROR,("ipv6_icmp_input() -- checksum returned %08x.\n", cksum));
- m_freem(incoming);
- icmpv6stat.icps_checksum++;
- return;
- }
- }
-
-#ifdef IPSEC
- /* Perform input-side policy check. Drop packet if policy says to drop it. */
- {
- struct sockaddr_in6 srcsa, dstsa;
-
- bzero(&srcsa, sizeof(struct sockaddr_in6));
- srcsa.sin6_family = AF_INET6;
- srcsa.sin6_len = sizeof(struct sockaddr_in6);
- srcsa.sin6_addr = ipv6->ipv6_src;
-
- bzero(&dstsa, sizeof(struct sockaddr_in6));
- dstsa.sin6_family = AF_INET6;
- dstsa.sin6_len = sizeof(struct sockaddr_in6);
- dstsa.sin6_addr = ipv6->ipv6_dst;
-
- /* XXX - state arg should NOT be NULL, it should be the netproc state
- carried up the stack - cmetz */
- if (netproc_inputpolicy(NULL, (struct sockaddr *)&srcsa,
- (struct sockaddr *)&dstsa, IPPROTO_ICMPV6,
- incoming, NULL, NULL)) {
- m_freem(incoming);
- return;
- }
- }
-#endif /* IPSEC */
-
- code = icmp->icmp_code;
- DPRINTF(IDL_EVENT, ("icmp->icmp_type = %d\n", icmp->icmp_type));
-
- if (icmp->icmp_type < ICMPV6_MAXTYPE + 1)
- {
- icmpv6stat.icps_inhist[icmp->icmp_type]++;
-
- /*
- * Deal with the appropriate ICMPv6 message type/code.
- */
- switch(icmp->icmp_type)
- {
- case ICMPV6_ECHO:
- icmp->icmp_type = ICMPV6_ECHOREPLY;
- icmpv6stat.icps_reflect++;
- ipv6_icmp_reflect(incoming, extra);
- return;
- case ICMPV6_UNREACH:
- /*
- * The pair of <type,code> should map into a PRC_*
- * value such that I don't have to rewrite in_pcb.c.
- */
- switch (code)
- {
- case ICMPV6_UNREACH_NOROUTE:
- code = PRC_UNREACH_NET;
- break;
- case ICMPV6_UNREACH_ADMIN:
- /* Subject to change */
- code = PRC_UNREACH_HOST;
- break;
- case ICMPV6_UNREACH_NOTNEIGHBOR:
- /* Subject to change */
- code = PRC_UNREACH_HOST;
- break;
- case ICMPV6_UNREACH_ADDRESS:
- code = PRC_HOSTDEAD;
- break;
- case ICMPV6_UNREACH_PORT:
- code = PRC_UNREACH_PORT;
- break;
- default:
- goto badcode;
- }
- goto deliver;
- break;
- case ICMPV6_TIMXCEED:
- if (code >1)
- goto badcode;
- code += PRC_TIMXCEED_INTRANS;
- goto deliver;
-
- case ICMPV6_PARAMPROB:
- if (code >2)
- goto badcode;
- code = PRC_PARAMPROB;
-
- case ICMPV6_TOOBIG:
- deliver:
- /*
- * Problem with datagram, advice HLP's.
- */
- DPRINTF(IDL_EVENT, ("delivering\n"));
- if (icmplen < ICMPV6_HLPMINLEN)
- {
- icmpv6stat.icps_badlen++;
- m_freem(incoming);
- return;
- }
-
- /* May want to pullup more than this */
- if (!(incoming = m_pullup2(incoming, extra + ICMPV6_HLPMINLEN)))
- return;
-
- /*
- * If cannot determine HLP, discard packet.
- *
- * For now, I assume that ICMP messages will be generated such that
- * the enclosed header contains only IPv6+<HLP header>. This is not
- * a good assumption to make in light of all sorts of options between
- * IPv6 and the relevant place to deliver this message.
- */
- {
- struct ipv6 *ipv6 = (struct ipv6 *)(mtod(incoming, caddr_t) + extra + ICMPV6_MINLEN);
- icmpsrc.sin6_addr = ipv6->ipv6_dst;
-
- if (icmp->icmp_type == ICMPV6_TOOBIG)
- {
- update_pathmtu(&ipv6->ipv6_dst,htonl(icmp->icmp_nexthopmtu));
- /* If I want to deliver to HLP, remove the break, and
- set code accordingly. */
- break;
- }
- DPRINTF(IDL_EVENT, ("Finding control function for %d\n",
- ipv6->ipv6_nexthdr));
- if ((ctlfunc = (void *)inet6sw[ipv6_protox[ipv6->ipv6_nexthdr]].pr_ctlinput)) {
- DPRINTF(IDL_EVENT, ("Calling control function for %d\n",
- ipv6->ipv6_nexthdr));
- (*ctlfunc)(code, (struct sockaddr *)&icmpsrc, ipv6,incoming);
- }
- }
- break;
-
- badcode:
- DPRINTF(IDL_EVENT, ("Bad code!\n"));
- icmpv6stat.icps_badcode++;
- break;
-
- /*
- * IPv6 multicast group messages.
- */
- case ICMPV6_GRPQUERY:
- case ICMPV6_GRPREPORT:
- case ICMPV6_GRPTERM:
- break;
-
- /*
- * IPv6 discovery messages.
- */
- case ICMPV6_ROUTERSOL:
- ipv6_routersol_input(incoming, extra);
- break;
- case ICMPV6_ROUTERADV:
- ipv6_routeradv_input(incoming, extra);
- break;
- case ICMPV6_NEIGHBORSOL:
- ipv6_neighborsol_input(incoming, extra);
- break;
- case ICMPV6_NEIGHBORADV:
- ipv6_neighboradv_input(incoming, extra);
- break;
- case ICMPV6_REDIRECT:
- ipv6_redirect_input(incoming, extra);
- break;
- default:
- /* Allow delivery to raw socket. */
- break;
- }
- }
- DPRINTF(IDL_EVENT, ("Delivering ICMPv6 to raw socket\n"));
- DP(FINISHED, incoming->m_pkthdr.len, d);
-
- ripv6_input(incoming, extra); /* Deliver to raw socket. */
-}
-
-
-/*
- * The following functions attempt to address ICMP deficiencies in IPv6.
- * Mostly these are part of a hack to keep the user-level program from
- * computing checksums. :-P
- */
-
-/*----------------------------------------------------------------------
- * This function should never be called.
- ----------------------------------------------------------------------*/
-
-int
-ipv6_icmp_output(m, so, dst)
- struct mbuf *m;
- struct socket *so;
- struct in6_addr *dst;
-{
- DPRINTF(IDL_ERROR,
- ("ipv6_icmp_output() was called and shouldn't have been.\n"));
-
- return ripv6_output(m,so,dst,NULL);
-}
-
-#if !__FreeBSD__
-/*----------------------------------------------------------------------
- * Prepend IPv6 header, and compute IPv6 checksum for PRU_SEND, otherwise,
- * redirect call to ripv6_usrreq().
- ----------------------------------------------------------------------*/
-int
-#if __NetBSD__
-ipv6_icmp_usrreq(so, req, m, nam, control, p)
-#else /* __NetBSD__ */
-ipv6_icmp_usrreq(so, req, m, nam, control)
-#endif /* __NetBSD__ */
- struct socket *so;
- int req;
- struct mbuf *m, *nam, *control;
-#if __NetBSD__
- struct proc *p;
-#endif /* __NetBSD__ */
-{
- register struct inpcb *inp = sotoinpcb(so);
-
- DPRINTF(IDL_EVENT,("Entering ipv6_icmp_usrreq(), req == %d\n",req));
-
- /*
- * If not sending, or sending with the header included (which IMHO means
- * the user filled in the src & dest on his/her own), do normal raw
- * IPv6 user request.
- */
-
- DPRINTF(IDL_EVENT,("Before check for ripv6_usrreq().\n"));
- if (req != PRU_SEND || inp->inp_flags & INP_HDRINCL)
-#if __NetBSD__
- return ripv6_usrreq(so,req,m,nam,control,p);
-#else /* __NetBSD__ */
- return ripv6_usrreq(so,req,m,nam,control);
-#endif /* __NetBSD__ */
-
- {
- struct sockaddr *sa;
-
- if (nam)
- sa = mtod(nam, struct sockaddr *);
- else
- sa = NULL;
-
-#if __NetBSD__
- return ipv6_icmp_send(so, req, m, sa, control, p);
-#else /* __NetBSD__ */
- return ipv6_icmp_send(so, req, m, sa, control, NULL);
-#endif /* __NetBSD__ */
- };
-}
-#endif /* !__FreeBSD__ */
-
-int ipv6_icmp_send(struct socket *so, int req, struct mbuf *m,
- struct sockaddr *addr, struct mbuf *control,
- struct proc *p)
-{
- register struct inpcb *inp = sotoinpcb(so);
- register struct ipv6 *ipv6;
- register struct ipv6_icmp *icp;
- struct in6_addr *dst;
- int tflags = 0, len, rc;
- struct in6_ifaddr *i6a;
-
- /*
- * redundant check, but necessary since we don't know if we are coming from
- * icmp_usrreq or not.
- */
- if (inp->inp_flags & INP_HDRINCL)
-#if __NetBSD__ || __FreeBSD__
- return ripv6_usrreq_send(so, req, m, addr, control, p);
-#else /* __NetBSD__ || __FreeBSD__ */
- return ripv6_usrreq_send(so, req, m, addr, control);
-#endif /* __NetBSD__ || __FreeBSD__ */
-
- if (in6_ifaddr == NULL)
- {
- m_freem(m);
- return EADDRNOTAVAIL;
- }
- len = m->m_pkthdr.len;
-
- /*
- * If we get here, req == PRU_SEND and flags do not have INP_HDRINCL set.
- * What that means in English is that a user process is sending an ICMPv6
- * datagram without constructing an IPv6 header.
- * We will construct an IPv6 header, fill it in completely, THEN COMPUTE
- * THE ICMPv6 CHECKSUM and tell ipv6_output() that we are raw.
- */
-
- if (so->so_state & SS_ISCONNECTED)
- {
- if (addr)
- {
- m_freem(m);
- return EISCONN;
- }
- dst = &(inp->inp_faddr6);
- i6a = (struct in6_ifaddr *)inp->inp_route6.ro_rt->rt_ifa;
- }
- else /* Not connected */
- {
- if (addr == NULL)
- {
- m_freem(m);
- return ENOTCONN;
- }
- DPRINTF(GROSSEVENT,("Sockaddr in nam is:\n"));
- DDO(GROSSEVENT,dump_smart_sockaddr(addr));
- dst = &(((struct sockaddr_in6 *) addr)->sin6_addr);
- inp->inp_route6.ro_dst = *((struct sockaddr_in6 *)addr);
- DPRINTF(EVENT,("In icmpv6_usrreq, Route is:\n"));
- DDO(EVENT, dump_rtentry(inp->inp_route6.ro_rt));
- if (so->so_options & SO_DONTROUTE)
- {
-#define ifatoi6a(x) ((struct in6_ifaddr *)x)
- if ((i6a =
- ifatoi6a(ifa_ifwithdstaddr((struct sockaddr *)addr))) == 0
- &&
- (i6a =
- ifatoi6a(ifa_ifwithnet((struct sockaddr *)addr))) == 0)
- {
- m_freem(m);
- return ENETUNREACH;
- }
- inp->inp_route.ro_rt = NULL;
- }
- else
- {
- struct route *ro = &inp->inp_route;
-
- /*
- * If there is no route, consider sending out a neighbor advert
- * across all the nodes. This is like the ipv6_onlink_query()
- * call in ipv6_output.c.
- */
- if (ro->ro_rt == NULL)
- rtalloc(ro);
- if (ro->ro_rt == NULL)
- {
- /*
- * No route of any kind, so spray neighbor solicits out all
- * interfaces, unless it's a multicast address.
- */
- DPRINTF(IDL_FINISHED,("Icmpv6 spraying neigbor solicits.\n"));
- if (IN6_IS_ADDR_MULTICAST(dst))
- {
- /*
- * Select source address for multicast, for now
- * return an error.
- */
- m_freem(m);
- return ENETUNREACH;
- }
- ipv6_onlink_query((struct sockaddr_in6 *)&ro->ro_dst);
- rtalloc(ro);
- }
- if (ro->ro_rt == NULL)
- {
- m_freem(m);
- return ENETUNREACH;
- }
- DPRINTF(IDL_EVENT,("Route after ipv6_onlink_query:\n"));
- DDO(IDL_EVENT,dump_route(ro));
- DDO(IDL_EVENT,if (ro) dump_rtentry(ro->ro_rt));
- if (ro->ro_rt->rt_ifa == NULL)
- {
- /*
- * We have a route where we don't quite know which interface
- * the neighbor belongs to yet. If I get here, I know that this
- * route is not pre-allocated (such as done by in6_pcbconnect()),
- * because those pre-allocators will do the same
- * ipv6_onlink_query() and ipv6_verify_onlink() in advance.
- *
- * I can therefore free the route, and get it again.
- */
- int error;
-
- DPRINTF(IDL_EVENT,("Okay...rt_ifa==NULL!\n"));
- RTFREE(ro->ro_rt);
- ro->ro_rt = NULL;
- switch (error = ipv6_verify_onlink((struct sockaddr_in6 *)&ro->ro_dst))
- {
- case 0:
- break;
- case -1:
- error = ENETUNREACH;
- default:
- m_freem(m);
- return error;
- }
- rtalloc((struct route *)ro);
- if (ro->ro_rt == NULL || ro->ro_rt->rt_ifa == NULL)
- panic("Oops3, I'm forgetting something after verify_onlink().");
- DPRINTF(IDL_EVENT,("Route after ipv6_verify_onlink:\n"));
- DDO(IDL_EVENT,dump_route(ro));
- DDO(IDL_EVENT,if (ro) dump_rtentry(ro->ro_rt));
- }
-
- i6a = (struct in6_ifaddr *)ro->ro_rt->rt_ifa;
- DPRINTF(IDL_EVENT,("Okay we got an interface for ipv6_icmp:\n"));
- DDO(IDL_EVENT,dump_ifa((struct ifaddr *)i6a));
- }
-
- if (IN6_IS_ADDR_MULTICAST(dst) && inp->inp_moptions6 &&
- inp->inp_moptions6->i6mo_multicast_ifp &&
- inp->inp_moptions6->i6mo_multicast_ifp != i6a->i6a_ifp)
- {
- struct ifaddr *ifa;
-
-#if __FreeBSD__
- for (ifa = inp->inp_moptions6->i6mo_multicast_ifp->if_addrhead.tqh_first;
- ifa != NULL; ifa = ifa->ifa_link.tqe_next)
-#else /* __FreeBSD__ */
-#if __NetBSD__ || __OpenBSD__
- for (ifa = inp->inp_moptions6->i6mo_multicast_ifp->if_addrlist.tqh_first;
- ifa != NULL; ifa = ifa->ifa_list.tqe_next)
-#else /* __NetBSD__ || __OpenBSD__ */
- for (ifa = inp->inp_moptions6->i6mo_multicast_ifp->if_addrlist;
- ifa != NULL; ifa = ifa->ifa_next)
-#endif /* __NetBSD__ || __OpenBSD__ */
-#endif /* __FreeBSD__ */
- if (ifa->ifa_addr->sa_family == AF_INET6)
- {
- i6a = (struct in6_ifaddr *)ifa;
- break;
- }
- if (ifa == NULL)
- {
- DPRINTF(IDL_ERROR,("mcast inconsitency in icmp PRU_SEND.\n"));
- }
- }
- }
-
- /*
- * If PCB has options hanging off of it, insert them here.
- */
-
- DPRINTF(GROSSEVENT,("ipv6_icmp_usrreq(): dst is "));
- DDO(GROSSEVENT,dump_in6_addr(dst));
-
- M_PREPEND(m,sizeof(struct ipv6),M_WAIT);
- if (m == NULL)
- panic("M_PREPEND died in ipv6_icmp_usrreq().");
-
- DPRINTF(EVENT,("Before m_pullup() for %d bytes.\n",\
- sizeof(struct ipv6) + ICMPV6_MINLEN));
- if ((m = m_pullup(m,sizeof(struct ipv6) + ICMPV6_MINLEN)) == NULL)
- {
- DPRINTF(IDL_ERROR,("m_pullup in ipv6_icmp_usrreq() failed.\n"));
- return ENOBUFS; /* Any better ideas? */
- }
-
- ipv6 = mtod(m,struct ipv6 *);
- ipv6->ipv6_length = len;
- ipv6->ipv6_nexthdr = IPPROTO_ICMPV6;
- ipv6->ipv6_hoplimit = 255;
- ipv6->ipv6_dst = *dst;
- ipv6->ipv6_versfl = htonl(0x60000000); /* Plus flow label stuff. */
- /*
- * i6a pointer should be checked here.
- */
- ipv6->ipv6_src = i6a->i6a_addr.sin6_addr;
-
- icp = (struct ipv6_icmp *)(m->m_data + sizeof(struct ipv6));
- if (!(sotoinpcb(so)->inp_csumoffset))
- sotoinpcb(so)->inp_csumoffset = 2;
-
- DPRINTF(GROSSEVENT,("ipv6_icmp_usrreq(): Headers are\n"));
- DDO(GROSSEVENT,dump_ipv6(ipv6));
- DDO(GROSSEVENT,dump_ipv6_icmp(icp));
-
- /*
- * After this comment block you'd probably insert options,
- * and adjust lengths accordingly.
- */
-
- /*
- * Temporarily tweak INP_HDRINCL to fool ripv6_output(). I still don't
- * know how a user who sets INP_HDRINCL for real will prepare ICMP packets.
- * Also, set up data structures for callback routine in ipv6_output().
- */
-
- if (!(sotoinpcb(so)->inp_flags & INP_HDRINCL))
- {
- sotoinpcb(so)->inp_flags |= INP_HDRINCL;
- tflags = 1;
- }
- rc = ripv6_output(m,so,dst,control);
- if (!(so->so_state & SS_ISCONNECTED) && !(so->so_options & SO_DONTROUTE))
- {
- RTFREE(inp->inp_route.ro_rt);
- inp->inp_route.ro_rt = NULL;
- }
- if (tflags)
- sotoinpcb(so)->inp_flags &= ~INP_HDRINCL;
-
- return rc;
-}
-
-#if __FreeBSD__
-#if __GNUC__ && __GNUC__ >= 2 && __OPTIMIZE__ && !__FreeBSD__
-#define MAYBEINLINE __inline__
-#else /* __GNUC__ && __GNUC__ >= 2 && __OPTIMIZE__ && !__FreeBSD__ */
-#define MAYBEINLINE
-#endif /* __GNUC__ && __GNUC__ >= 2 && __OPTIMIZE__ && !__FreeBSD__ */
-
-#if 0
-MAYBEINLINE int ripv6_usrreq_attach(struct socket *, int , struct proc *);
-MAYBEINLINE int ripv6_usrreq_detach(struct socket *);
-MAYBEINLINE int ripv6_usrreq_abort(struct socket *);
-MAYBEINLINE int ripv6_usrreq_bind(struct socket *, struct sockaddr *, struct proc *);
-MAYBEINLINE int ripv6_usrreq_connect(struct socket *, struct sockaddr *, struct proc *);
-MAYBEINLINE int ripv6_usrreq_shutdown(struct socket *so);
-MAYBEINLINE int ripv6_usrreq_control(struct socket *, u_long, caddr_t,
- struct ifnet *, struct proc *);
-MAYBEINLINE int ripv6_usrreq_sense(struct socket *, struct stat *);
-MAYBEINLINE int ripv6_usrreq_sockaddr(struct socket *, struct sockaddr **);
-MAYBEINLINE int ripv6_usrreq_peeraddr(struct socket *, struct sockaddr **);
-#endif /* 0 */
-
-struct pr_usrreqs ipv6_icmp_usrreqs = {
- ripv6_usrreq_abort, pru_accept_notsupp, ripv6_usrreq_attach,
- ripv6_usrreq_bind, ripv6_usrreq_connect, pru_connect2_notsupp,
- ripv6_usrreq_control, ripv6_usrreq_detach, ripv6_usrreq_detach,
- pru_listen_notsupp, ripv6_usrreq_peeraddr, pru_rcvd_notsupp,
- pru_rcvoob_notsupp, ipv6_icmp_send, ripv6_usrreq_sense,
- ripv6_usrreq_shutdown, ripv6_usrreq_sockaddr, sosend, soreceive, sopoll
-};
-#endif /* __FreeBSD__ */
-
-int *icmpv6_sysvars[] = ICMPV6CTL_VARS;
-
-#if __FreeBSD__
-SYSCTL_STRUCT(_net_inet_icmpv6, ICMPV6CTL_STATS, icmpv6stat, CTLFLAG_RD, &icmpv6stat, icmpv6stat, "");
-#else /* __FreeBSD__ */
-int
-ipv6_icmp_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
- int *name;
- u_int namelen;
- void *oldp;
- size_t *oldlenp;
- void *newp;
- size_t newlen;
-{
- if (name[0] >= ICMPV6CTL_MAXID)
- return (EOPNOTSUPP);
- switch (name[0]) {
-#if defined(_BSDI_VERSION) && (_BSDI_VERSION >= 199802)
- case ICMPV6CTL_STATS:
- return sysctl_rdtrunc(oldp, oldlenp, newp, &icmpv6stat, sizeof(icmpv6stat));
- default:
- return (sysctl_int_arr(icmpv6_sysvars, name, namelen, oldp, oldlenp, newp, newlen));
-#else /* defined(_BSDI_VERSION) && (_BSDI_VERSION >= 199802) */
- default:
- return EOPNOTSUPP;
-#endif /* defined(_BSDI_VERSION) && (_BSDI_VERSION >= 199802) */
- }
-};
-#endif /* __FreeBSD__ */