📄 ip6_mroute.c
字号:
bzero((caddr_t)n6expire, sizeof(n6expire));
pim6 = 0;/* used for stubbing out/in pim stuff */
#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
#ifdef MRT6DEBUG
if (mrt6debug)
log(LOG_DEBUG, "ip6_mrouter_init\n");
#endif
return 0;
}
/*
* Disable multicast routing
*/
int
ip6_mrouter_done()
{
mifi_t mifi;
int i;
struct ifnet *ifp;
struct in6_ifreq ifr;
struct mf6c *rt;
struct rtdetq *rte;
int s;
#ifdef __NetBSD__
s = splsoftnet();
#else
s = splnet();
#endif
/*
* For each phyint in use, disable promiscuous reception of all IPv6
* multicasts.
*/
#ifdef INET
#ifdef MROUTING
/*
* If there is still IPv4 multicast routing daemon,
* we remain interfaces to receive all muliticasted packets.
* XXX: there may be an interface in which the IPv4 multicast
* daemon is not interested...
*/
if (!ip_mrouter)
#endif
#endif
{
for (mifi = 0; mifi < nummifs; mifi++) {
if (mif6table[mifi].m6_ifp &&
!(mif6table[mifi].m6_flags & MIFF_REGISTER)) {
ifr.ifr_addr.sin6_family = AF_INET6;
ifr.ifr_addr.sin6_addr= in6addr_any;
ifp = mif6table[mifi].m6_ifp;
(*ifp->if_ioctl)(ifp, SIOCDELMULTI,
(caddr_t)&ifr);
}
}
}
#ifdef notyet
bzero((caddr_t)qtable, sizeof(qtable));
bzero((caddr_t)tbftable, sizeof(tbftable));
#endif
bzero((caddr_t)mif6table, sizeof(mif6table));
nummifs = 0;
pim6 = 0; /* used to stub out/in pim specific code */
#if defined(__NetBSD__) || (defined(__FreeBSD__) && __FreeBSD__ >= 3)
callout_stop(&expire_upcalls_ch);
#elif defined(__OpenBSD__)
timeout_del(&expire_upcalls_ch);
#else
untimeout(expire_upcalls, (caddr_t)NULL);
#endif
/*
* Free all multicast forwarding cache entries.
*/
for (i = 0; i < MF6CTBLSIZ; i++) {
rt = mf6ctable[i];
while (rt) {
struct mf6c *frt;
for (rte = rt->mf6c_stall; rte != NULL; ) {
struct rtdetq *n = rte->next;
m_free(rte->m);
free(rte, M_MRTABLE);
rte = n;
}
frt = rt;
rt = rt->mf6c_next;
free(frt, M_MRTABLE);
}
}
bzero((caddr_t)mf6ctable, sizeof(mf6ctable));
/*
* Reset de-encapsulation cache
*/
reg_mif_num = -1;
ip6_mrouter = NULL;
ip6_mrouter_ver = 0;
splx(s);
#ifdef MRT6DEBUG
if (mrt6debug)
log(LOG_DEBUG, "ip6_mrouter_done\n");
#endif
return 0;
}
static struct sockaddr_in6 sin6 = { sizeof(sin6), AF_INET6 };
/*
* Add a mif to the mif table
*/
static int
add_m6if(mifcp)
struct mif6ctl *mifcp;
{
struct mif6 *mifp;
struct ifnet *ifp;
#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
struct in6_ifreq ifr;
#endif
int error, s;
#ifdef notyet
struct tbf *m_tbf = tbftable + mifcp->mif6c_mifi;
#endif
if (mifcp->mif6c_mifi >= MAXMIFS)
return EINVAL;
mifp = mif6table + mifcp->mif6c_mifi;
if (mifp->m6_ifp)
return EADDRINUSE; /* XXX: is it appropriate? */
if (mifcp->mif6c_pifi == 0 || mifcp->mif6c_pifi > if_index)
return ENXIO;
/*
* XXX: some OSes can remove ifp and clear ifindex2ifnet[id]
* even for id between 0 and if_index.
*/
#if defined(__FreeBSD__) && __FreeBSD__ >= 5
ifp = ifnet_byindex(mifcp->mif6c_pifi);
#else
ifp = ifindex2ifnet[mifcp->mif6c_pifi];
#endif
if (ifp == NULL)
return ENXIO;
if (mifcp->mif6c_flags & MIFF_REGISTER) {
if (reg_mif_num == (mifi_t)-1) {
#if defined(__NetBSD__) || defined(__OpenBSD__)
strcpy(multicast_register_if.if_xname,
"register_mif"); /* XXX */
#else
multicast_register_if.if_name = "register_mif";
#endif
multicast_register_if.if_flags |= IFF_LOOPBACK;
multicast_register_if.if_index = mifcp->mif6c_mifi;
reg_mif_num = mifcp->mif6c_mifi;
}
ifp = &multicast_register_if;
} /* if REGISTER */
else {
/* Make sure the interface supports multicast */
if ((ifp->if_flags & IFF_MULTICAST) == 0)
return EOPNOTSUPP;
#ifdef __NetBSD__
s = splsoftnet();
#else
s = splnet();
#endif
#if (defined(__FreeBSD__) && __FreeBSD__ >= 3)
error = if_allmulti(ifp, 1);
#else
/*
* Enable promiscuous reception of all IPv6 multicasts
* from the interface.
*/
ifr.ifr_addr.sin6_family = AF_INET6;
ifr.ifr_addr.sin6_addr = in6addr_any;
error = (*ifp->if_ioctl)(ifp, SIOCADDMULTI, (caddr_t)&ifr);
#endif
splx(s);
if (error)
return error;
}
#ifdef __NetBSD__
s = splsoftnet();
#else
s = splnet();
#endif
mifp->m6_flags = mifcp->mif6c_flags;
mifp->m6_ifp = ifp;
#ifdef notyet
/* scaling up here allows division by 1024 in critical code */
mifp->m6_rate_limit = mifcp->mif6c_rate_limit * 1024 / 1000;
#endif
/* initialize per mif pkt counters */
mifp->m6_pkt_in = 0;
mifp->m6_pkt_out = 0;
mifp->m6_bytes_in = 0;
mifp->m6_bytes_out = 0;
splx(s);
/* Adjust nummifs up if the mifi is higher than nummifs */
if (nummifs <= mifcp->mif6c_mifi)
nummifs = mifcp->mif6c_mifi + 1;
#ifdef MRT6DEBUG
if (mrt6debug)
log(LOG_DEBUG,
"add_mif #%d, phyint %s%d\n",
mifcp->mif6c_mifi,
ifp->if_name, ifp->if_unit);
#endif
return 0;
}
/*
* Delete a mif from the mif table
*/
static int
del_m6if(mifip)
mifi_t *mifip;
{
struct mif6 *mifp = mif6table + *mifip;
mifi_t mifi;
struct ifnet *ifp;
#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
struct in6_ifreq ifr;
#endif
int s;
if (*mifip >= nummifs)
return EINVAL;
if (mifp->m6_ifp == NULL)
return EINVAL;
#ifdef __NetBSD__
s = splsoftnet();
#else
s = splnet();
#endif
if (!(mifp->m6_flags & MIFF_REGISTER)) {
/*
* XXX: what if there is yet IPv4 multicast daemon
* using the interface?
*/
ifp = mifp->m6_ifp;
#if (defined(__FreeBSD__) && __FreeBSD__ >= 3)
if_allmulti(ifp, 0);
#else
ifr.ifr_addr.sin6_family = AF_INET6;
ifr.ifr_addr.sin6_addr = in6addr_any;
(*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)&ifr);
#endif
}
#ifdef notyet
bzero((caddr_t)qtable[*mifip], sizeof(qtable[*mifip]));
bzero((caddr_t)mifp->m6_tbf, sizeof(*(mifp->m6_tbf)));
#endif
bzero((caddr_t)mifp, sizeof (*mifp));
/* Adjust nummifs down */
for (mifi = nummifs; mifi > 0; mifi--)
if (mif6table[mifi - 1].m6_ifp)
break;
nummifs = mifi;
splx(s);
#ifdef MRT6DEBUG
if (mrt6debug)
log(LOG_DEBUG, "del_m6if %d, nummifs %d\n", *mifip, nummifs);
#endif
return 0;
}
/*
* Add an mfc entry
*/
static int
add_m6fc(mfccp)
struct mf6cctl *mfccp;
{
struct mf6c *rt;
u_long hash;
struct rtdetq *rte;
u_short nstl;
int s;
MF6CFIND(mfccp->mf6cc_origin.sin6_addr,
mfccp->mf6cc_mcastgrp.sin6_addr, rt);
/* If an entry already exists, just update the fields */
if (rt) {
#ifdef MRT6DEBUG
if (mrt6debug & DEBUG_MFC)
log(LOG_DEBUG,"add_m6fc update o %s g %s p %x\n",
ip6_sprintf(&mfccp->mf6cc_origin.sin6_addr),
ip6_sprintf(&mfccp->mf6cc_mcastgrp.sin6_addr),
mfccp->mf6cc_parent);
#endif
#ifdef __NetBSD__
s = splsoftnet();
#else
s = splnet();
#endif
rt->mf6c_parent = mfccp->mf6cc_parent;
rt->mf6c_ifset = mfccp->mf6cc_ifset;
splx(s);
return 0;
}
/*
* Find the entry for which the upcall was made and update
*/
#ifdef __NetBSD__
s = splsoftnet();
#else
s = splnet();
#endif
hash = MF6CHASH(mfccp->mf6cc_origin.sin6_addr,
mfccp->mf6cc_mcastgrp.sin6_addr);
for (rt = mf6ctable[hash], nstl = 0; rt; rt = rt->mf6c_next) {
if (IN6_ARE_ADDR_EQUAL(&rt->mf6c_origin.sin6_addr,
&mfccp->mf6cc_origin.sin6_addr) &&
IN6_ARE_ADDR_EQUAL(&rt->mf6c_mcastgrp.sin6_addr,
&mfccp->mf6cc_mcastgrp.sin6_addr) &&
(rt->mf6c_stall != NULL)) {
if (nstl++)
log(LOG_ERR,
"add_m6fc: %s o %s g %s p %x dbx %p\n",
"multiple kernel entries",
ip6_sprintf(&mfccp->mf6cc_origin.sin6_addr),
ip6_sprintf(&mfccp->mf6cc_mcastgrp.sin6_addr),
mfccp->mf6cc_parent, rt->mf6c_stall);
#ifdef MRT6DEBUG
if (mrt6debug & DEBUG_MFC)
log(LOG_DEBUG,
"add_m6fc o %s g %s p %x dbg %x\n",
ip6_sprintf(&mfccp->mf6cc_origin.sin6_addr),
ip6_sprintf(&mfccp->mf6cc_mcastgrp.sin6_addr),
mfccp->mf6cc_parent, rt->mf6c_stall);
#endif
rt->mf6c_origin = mfccp->mf6cc_origin;
rt->mf6c_mcastgrp = mfccp->mf6cc_mcastgrp;
rt->mf6c_parent = mfccp->mf6cc_parent;
rt->mf6c_ifset = mfccp->mf6cc_ifset;
/* initialize pkt counters per src-grp */
rt->mf6c_pkt_cnt = 0;
rt->mf6c_byte_cnt = 0;
rt->mf6c_wrong_if = 0;
rt->mf6c_expire = 0; /* Don't clean this guy up */
n6expire[hash]--;
/* free packets Qed at the end of this entry */
for (rte = rt->mf6c_stall; rte != NULL; ) {
struct rtdetq *n = rte->next;
ip6_mdq(rte->m, rte->ifp, rt);
m_freem(rte->m);
#ifdef UPCALL_TIMING
collate(&(rte->t));
#endif /* UPCALL_TIMING */
free(rte, M_MRTABLE);
rte = n;
}
rt->mf6c_stall = NULL;
}
}
/*
* It is possible that an entry is being inserted without an upcall
*/
if (nstl == 0) {
#ifdef MRT6DEBUG
if (mrt6debug & DEBUG_MFC)
log(LOG_DEBUG,
"add_m6fc no upcall h %d o %s g %s p %x\n",
hash,
ip6_sprintf(&mfccp->mf6cc_origin.sin6_addr),
ip6_sprintf(&mfccp->mf6cc_mcastgrp.sin6_addr),
mfccp->mf6cc_parent);
#endif
for (rt = mf6ctable[hash]; rt; rt = rt->mf6c_next) {
if (IN6_ARE_ADDR_EQUAL(&rt->mf6c_origin.sin6_addr,
&mfccp->mf6cc_origin.sin6_addr)&&
IN6_ARE_ADDR_EQUAL(&rt->mf6c_mcastgrp.sin6_addr,
&mfccp->mf6cc_mcastgrp.sin6_addr)) {
rt->mf6c_origin = mfccp->mf6cc_origin;
rt->mf6c_mcastgrp = mfccp->mf6cc_mcastgrp;
rt->mf6c_parent = mfccp->mf6cc_parent;
rt->mf6c_ifset = mfccp->mf6cc_ifset;
/* initialize pkt counters per src-grp */
rt->mf6c_pkt_cnt = 0;
rt->mf6c_byte_cnt = 0;
rt->mf6c_wrong_if = 0;
if (rt->mf6c_expire)
n6expire[hash]--;
rt->mf6c_expire = 0;
}
}
if (rt == NULL) {
/* no upcall, so make a new entry */
rt = (struct mf6c *)malloc(sizeof(*rt), M_MRTABLE,
M_NOWAIT);
if (rt == NULL) {
splx(s);
return ENOBUFS;
}
/* insert new entry at head of hash chain */
rt->mf6c_origin = mfccp->mf6cc_origin;
rt->mf6c_mcastgrp = mfccp->mf6cc_mcastgrp;
rt->mf6c_parent = mfccp->mf6cc_parent;
rt->mf6c_ifset = mfccp->mf6cc_ifset;
/* initialize pkt counters per src-grp */
rt->mf6c_pkt_cnt = 0;
rt->mf6c_byte_cnt = 0;
rt->mf6c_wrong_if = 0;
rt->mf6c_expire = 0;
rt->mf6c_stall = NULL;
/* link into table */
rt->mf6c_next = mf6ctable[hash];
mf6ctable[hash] = rt;
}
}
splx(s);
return 0;
}
#ifdef UPCALL_TIMING
/*
* collect delay statistics on the upcalls
*/
static void
collate(t)
struct timeval *t;
{
u_long d;
struct timeval tp;
u_long delta;
GET_TIME(tp);
if (TV_LT(*t, tp))
{
TV_DELTA(tp, *t, delta);
d = delta >> 10;
if (d > UPCALL_MAX)
d = UPCALL_MAX;
++upcall_data[d];
}
}
#endif /* UPCALL_TIMING */
/*
* Delete an mfc entry
*/
static int
del_m6fc(mfccp)
struct mf6cctl *mfccp;
{
struct sockaddr_in6 origin;
struct sockaddr_in6 mcastgrp;
struct mf6c *rt;
struct mf6c **nptr;
u_long hash;
int s;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -