📄 ip6_mroute.c
字号:
origin = mfccp->mf6cc_origin;
mcastgrp = mfccp->mf6cc_mcastgrp;
hash = MF6CHASH(origin.sin6_addr, mcastgrp.sin6_addr);
#ifdef MRT6DEBUG
if (mrt6debug & DEBUG_MFC)
log(LOG_DEBUG,"del_m6fc orig %s mcastgrp %s\n",
ip6_sprintf(&origin.sin6_addr),
ip6_sprintf(&mcastgrp.sin6_addr));
#endif
#ifdef __NetBSD__
s = splsoftnet();
#else
s = splnet();
#endif
nptr = &mf6ctable[hash];
while ((rt = *nptr) != NULL) {
if (IN6_ARE_ADDR_EQUAL(&origin.sin6_addr,
&rt->mf6c_origin.sin6_addr) &&
IN6_ARE_ADDR_EQUAL(&mcastgrp.sin6_addr,
&rt->mf6c_mcastgrp.sin6_addr) &&
rt->mf6c_stall == NULL)
break;
nptr = &rt->mf6c_next;
}
if (rt == NULL) {
splx(s);
return EADDRNOTAVAIL;
}
*nptr = rt->mf6c_next;
free(rt, M_MRTABLE);
splx(s);
return 0;
}
static int
socket_send(s, mm, src)
struct socket *s;
struct mbuf *mm;
struct sockaddr_in6 *src;
{
if (s) {
if (sbappendaddr(&s->so_rcv,
(struct sockaddr *)src,
mm, (struct mbuf *)0) != 0) {
sorwakeup(s);
return 0;
}
}
m_freem(mm);
return -1;
}
/*
* IPv6 multicast forwarding function. This function assumes that the packet
* pointed to by "ip6" has arrived on (or is about to be sent to) the interface
* pointed to by "ifp", and the packet is to be relayed to other networks
* that have members of the packet's destination IPv6 multicast group.
*
* The packet is returned unscathed to the caller, unless it is
* erroneous, in which case a non-zero return value tells the caller to
* discard it.
*/
int
ip6_mforward(ip6, ifp, m)
struct ip6_hdr *ip6;
struct ifnet *ifp;
struct mbuf *m;
{
struct mf6c *rt;
struct mif6 *mifp;
struct mbuf *mm;
int s;
mifi_t mifi;
#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
long time_second = time.tv_sec;
#endif
#ifdef MRT6DEBUG
if (mrt6debug & DEBUG_FORWARD)
log(LOG_DEBUG, "ip6_mforward: src %s, dst %s, ifindex %d\n",
ip6_sprintf(&ip6->ip6_src), ip6_sprintf(&ip6->ip6_dst),
ifp->if_index);
#endif
/*
* Don't forward a packet with Hop limit of zero or one,
* or a packet destined to a local-only group.
*/
if (ip6->ip6_hlim <= 1 || IN6_IS_ADDR_MC_INTFACELOCAL(&ip6->ip6_dst) ||
IN6_IS_ADDR_MC_LINKLOCAL(&ip6->ip6_dst))
return 0;
ip6->ip6_hlim--;
/*
* Source address check: do not forward packets with unspecified
* source. It was discussed in July 2000, on ipngwg mailing list.
* This is rather more serious than unicast cases, because some
* MLD packets can be sent with the unspecified source address
* (although such packets must normally set 1 to the hop limit field).
*/
if (IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) {
ip6stat.ip6s_cantforward++;
if (ip6_log_time + ip6_log_interval < time_second) {
ip6_log_time = time_second;
log(LOG_DEBUG,
"cannot forward "
"from %s to %s nxt %d received on %s\n",
ip6_sprintf(&ip6->ip6_src),
ip6_sprintf(&ip6->ip6_dst),
ip6->ip6_nxt,
m->m_pkthdr.rcvif ?
if_name(m->m_pkthdr.rcvif) : "?");
}
return 0;
}
/*
* Determine forwarding mifs from the forwarding cache table
*/
#ifdef __NetBSD__
s = splsoftnet();
#else
s = splnet();
#endif
MF6CFIND(ip6->ip6_src, ip6->ip6_dst, rt);
/* Entry exists, so forward if necessary */
if (rt) {
splx(s);
return (ip6_mdq(m, ifp, rt));
} else {
/*
* If we don't have a route for packet's origin,
* Make a copy of the packet &
* send message to routing daemon
*/
struct mbuf *mb0;
struct rtdetq *rte;
u_long hash;
/* int i, npkts;*/
#ifdef UPCALL_TIMING
struct timeval tp;
GET_TIME(tp);
#endif /* UPCALL_TIMING */
mrt6stat.mrt6s_no_route++;
#ifdef MRT6DEBUG
if (mrt6debug & (DEBUG_FORWARD | DEBUG_MFC))
log(LOG_DEBUG, "ip6_mforward: no rte s %s g %s\n",
ip6_sprintf(&ip6->ip6_src),
ip6_sprintf(&ip6->ip6_dst));
#endif
/*
* Allocate mbufs early so that we don't do extra work if we
* are just going to fail anyway.
*/
rte = (struct rtdetq *)malloc(sizeof(*rte), M_MRTABLE,
M_NOWAIT);
if (rte == NULL) {
splx(s);
return ENOBUFS;
}
mb0 = m_copy(m, 0, M_COPYALL);
/*
* Pullup packet header if needed before storing it,
* as other references may modify it in the meantime.
*/
if (mb0 &&
(M_HASCL(mb0) || mb0->m_len < sizeof(struct ip6_hdr)))
mb0 = m_pullup(mb0, sizeof(struct ip6_hdr));
if (mb0 == NULL) {
free(rte, M_MRTABLE);
splx(s);
return ENOBUFS;
}
/* is there an upcall waiting for this packet? */
hash = MF6CHASH(ip6->ip6_src, ip6->ip6_dst);
for (rt = mf6ctable[hash]; rt; rt = rt->mf6c_next) {
if (IN6_ARE_ADDR_EQUAL(&ip6->ip6_src,
&rt->mf6c_origin.sin6_addr) &&
IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst,
&rt->mf6c_mcastgrp.sin6_addr) &&
(rt->mf6c_stall != NULL))
break;
}
if (rt == NULL) {
struct mrt6msg *im;
#ifdef MRT6_OINIT
struct omrt6msg *oim;
#endif
/* no upcall, so make a new entry */
rt = (struct mf6c *)malloc(sizeof(*rt), M_MRTABLE,
M_NOWAIT);
if (rt == NULL) {
free(rte, M_MRTABLE);
m_freem(mb0);
splx(s);
return ENOBUFS;
}
/*
* Make a copy of the header to send to the user
* level process
*/
mm = m_copy(mb0, 0, sizeof(struct ip6_hdr));
if (mm == NULL) {
free(rte, M_MRTABLE);
m_freem(mb0);
free(rt, M_MRTABLE);
splx(s);
return ENOBUFS;
}
/*
* Send message to routing daemon
*/
sin6.sin6_addr = ip6->ip6_src;
im = NULL;
#ifdef MRT6_OINIT
oim = NULL;
#endif
switch (ip6_mrouter_ver) {
#ifdef MRT6_OINIT
case MRT6_OINIT:
oim = mtod(mm, struct omrt6msg *);
oim->im6_msgtype = MRT6MSG_NOCACHE;
oim->im6_mbz = 0;
break;
#endif
case MRT6_INIT:
im = mtod(mm, struct mrt6msg *);
im->im6_msgtype = MRT6MSG_NOCACHE;
im->im6_mbz = 0;
break;
default:
free(rte, M_MRTABLE);
m_freem(mb0);
free(rt, M_MRTABLE);
splx(s);
return EINVAL;
}
#ifdef MRT6DEBUG
if (mrt6debug & DEBUG_FORWARD)
log(LOG_DEBUG,
"getting the iif info in the kernel\n");
#endif
for (mifp = mif6table, mifi = 0;
mifi < nummifs && mifp->m6_ifp != ifp;
mifp++, mifi++)
;
switch (ip6_mrouter_ver) {
#ifdef MRT6_OINIT
case MRT6_OINIT:
oim->im6_mif = mifi;
break;
#endif
case MRT6_INIT:
im->im6_mif = mifi;
break;
}
if (socket_send(ip6_mrouter, mm, &sin6) < 0) {
log(LOG_WARNING, "ip6_mforward: ip6_mrouter "
"socket queue full\n");
mrt6stat.mrt6s_upq_sockfull++;
free(rte, M_MRTABLE);
m_freem(mb0);
free(rt, M_MRTABLE);
splx(s);
return ENOBUFS;
}
mrt6stat.mrt6s_upcalls++;
/* insert new entry at head of hash chain */
bzero(rt, sizeof(*rt));
rt->mf6c_origin.sin6_family = AF_INET6;
rt->mf6c_origin.sin6_len = sizeof(struct sockaddr_in6);
rt->mf6c_origin.sin6_addr = ip6->ip6_src;
rt->mf6c_mcastgrp.sin6_family = AF_INET6;
rt->mf6c_mcastgrp.sin6_len = sizeof(struct sockaddr_in6);
rt->mf6c_mcastgrp.sin6_addr = ip6->ip6_dst;
rt->mf6c_expire = UPCALL_EXPIRE;
n6expire[hash]++;
rt->mf6c_parent = MF6C_INCOMPLETE_PARENT;
/* link into table */
rt->mf6c_next = mf6ctable[hash];
mf6ctable[hash] = rt;
/* Add this entry to the end of the queue */
rt->mf6c_stall = rte;
} else {
/* determine if q has overflowed */
struct rtdetq **p;
int npkts = 0;
for (p = &rt->mf6c_stall; *p != NULL; p = &(*p)->next)
if (++npkts > MAX_UPQ6) {
mrt6stat.mrt6s_upq_ovflw++;
free(rte, M_MRTABLE);
m_freem(mb0);
splx(s);
return 0;
}
/* Add this entry to the end of the queue */
*p = rte;
}
rte->next = NULL;
rte->m = mb0;
rte->ifp = ifp;
#ifdef UPCALL_TIMING
rte->t = tp;
#endif /* UPCALL_TIMING */
splx(s);
return 0;
}
}
/*
* Clean up cache entries if upcalls are not serviced
* Call from the Slow Timeout mechanism, every half second.
*/
static void
expire_upcalls(unused)
void *unused;
{
struct rtdetq *rte;
struct mf6c *mfc, **nptr;
int i;
int s;
#ifdef __NetBSD__
s = splsoftnet();
#else
s = splnet();
#endif
for (i = 0; i < MF6CTBLSIZ; i++) {
if (n6expire[i] == 0)
continue;
nptr = &mf6ctable[i];
while ((mfc = *nptr) != NULL) {
rte = mfc->mf6c_stall;
/*
* Skip real cache entries
* Make sure it wasn't marked to not expire (shouldn't happen)
* If it expires now
*/
if (rte != NULL &&
mfc->mf6c_expire != 0 &&
--mfc->mf6c_expire == 0) {
#ifdef MRT6DEBUG
if (mrt6debug & DEBUG_EXPIRE)
log(LOG_DEBUG, "expire_upcalls: expiring (%s %s)\n",
ip6_sprintf(&mfc->mf6c_origin.sin6_addr),
ip6_sprintf(&mfc->mf6c_mcastgrp.sin6_addr));
#endif
/*
* drop all the packets
* free the mbuf with the pkt, if, timing info
*/
do {
struct rtdetq *n = rte->next;
m_freem(rte->m);
free(rte, M_MRTABLE);
rte = n;
} while (rte != NULL);
mrt6stat.mrt6s_cache_cleanups++;
n6expire[i]--;
*nptr = mfc->mf6c_next;
free(mfc, M_MRTABLE);
} else {
nptr = &mfc->mf6c_next;
}
}
}
splx(s);
#if defined(__NetBSD__) || (defined(__FreeBSD__) && __FreeBSD__ >= 3)
callout_reset(&expire_upcalls_ch, EXPIRE_TIMEOUT,
expire_upcalls, NULL);
#elif defined(__OpenBSD__)
timeout_set(&expire_upcalls_ch, expire_upcalls, NULL);
timeout_add(&expire_upcalls_ch, EXPIRE_TIMEOUT);
#else
timeout(expire_upcalls, (caddr_t)NULL, EXPIRE_TIMEOUT);
#endif
}
/*
* Packet forwarding routine once entry in the cache is made
*/
static int
ip6_mdq(m, ifp, rt)
struct mbuf *m;
struct ifnet *ifp;
struct mf6c *rt;
{
struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
mifi_t mifi, iif;
struct mif6 *mifp;
int plen = m->m_pkthdr.len;
/*
* Macro to send packet on mif. Since RSVP packets don't get counted on
* input, they shouldn't get counted on output, so statistics keeping is
* seperate.
*/
#define MC6_SEND(ip6, mifp, m) do { \ if ((mifp)->m6_flags & MIFF_REGISTER) \ register_send((ip6), (mifp), (m)); \ else \ phyint_send((ip6), (mifp), (m)); \} while (0)
/*
* Don't forward if it didn't arrive from the parent mif
* for its origin.
*/
mifi = rt->mf6c_parent;
if ((mifi >= nummifs) || (mif6table[mifi].m6_ifp != ifp)) {
/* came in the wrong interface */
#ifdef MRT6DEBUG
if (mrt6debug & DEBUG_FORWARD)
log(LOG_DEBUG,
"wrong if: ifid %d mifi %d mififid %x\n",
ifp->if_index, mifi,
mif6table[mifi].m6_ifp->if_index);
#endif
mrt6stat.mrt6s_wrong_if++;
rt->mf6c_wrong_if++;
/*
* If we are doing PIM processing, and we are forwarding
* packets on this interface, send a message to the
* routing daemon.
*/
/* have to make sure this is a valid mif */
if (mifi < nummifs && mif6table[mifi].m6_ifp)
if (pim6 && (m->m_flags & M_LOOP) == 0) {
/*
* Check the M_LOOP flag to avoid an
* unnecessary PIM assert.
* XXX: M_LOOP is an ad-hoc hack...
*/
static struct sockaddr_in6 sin6 =
{ sizeof(sin6), AF_INET6 };
struct mbuf *mm;
struct mrt6msg *im;
#ifdef MRT6_OINIT
struct omrt6msg *oim;
#endif
mm = m_copy(m, 0, sizeof(struct ip6_hdr));
if (mm &&
(M_HASCL(mm) ||
mm->m_len < sizeof(struct ip6_hdr)))
mm = m_pullup(mm, sizeof(struct ip6_hdr));
if (mm == NULL)
return ENOBUFS;
#ifdef MRT6_OINIT
oim = NULL;
#endif
im = NULL;
switch (ip6_mrouter_ver) {
#ifdef MRT6_OINIT
case MRT6_OINIT:
oim = mtod(mm, struct omrt6msg *);
oim->im6_msgtype = MRT6MSG_WRONGMIF;
oim->im6_mbz = 0;
break;
#endif
case MRT6_INIT:
im = mtod(mm, struct mrt6msg *);
im->im6_msgtype = MRT6MSG_WRONGMIF;
im->im6_mbz = 0;
break;
default:
m_freem(mm);
return EINVAL;
}
for (mifp = mif6table, iif = 0;
iif < nummifs && mifp &&
mifp->m6_ifp != ifp;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -