ip6_mroute.c
来自「eCos操作系统源码」· C语言 代码 · 共 2,032 行 · 第 1/4 页
C
2,032 行
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 intsocket_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. */intip6_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 voidexpire_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 intip6_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 + =
减小字号Ctrl + -
显示快捷键?