ip6_mroute.c
来自「eCos操作系统源码」· C语言 代码 · 共 2,032 行 · 第 1/4 页
C
2,032 行
mifp++, iif++) ; switch (ip6_mrouter_ver) {#ifdef MRT6_OINIT case MRT6_OINIT: oim->im6_mif = iif; sin6.sin6_addr = oim->im6_src; break;#endif case MRT6_INIT: im->im6_mif = iif; sin6.sin6_addr = im->im6_src; break; } mrt6stat.mrt6s_upcalls++; if (socket_send(ip6_mrouter, mm, &sin6) < 0) {#ifdef MRT6DEBUG if (mrt6debug) log(LOG_WARNING, "mdq, ip6_mrouter socket queue full\n");#endif ++mrt6stat.mrt6s_upq_sockfull; return ENOBUFS; } /* if socket Q full */ } /* if PIM */ return 0; } /* if wrong iif */ /* If I sourced this packet, it counts as output, else it was input. */ if (m->m_pkthdr.rcvif == NULL) { /* XXX: is rcvif really NULL when output?? */ mif6table[mifi].m6_pkt_out++; mif6table[mifi].m6_bytes_out += plen; } else { mif6table[mifi].m6_pkt_in++; mif6table[mifi].m6_bytes_in += plen; } rt->mf6c_pkt_cnt++; rt->mf6c_byte_cnt += plen; /* * For each mif, forward a copy of the packet if there are group * members downstream on the interface. */ for (mifp = mif6table, mifi = 0; mifi < nummifs; mifp++, mifi++) if (IF_ISSET(mifi, &rt->mf6c_ifset)) { int64_t dscopein, sscopein, dscopeout, sscopeout; /* * check if the outgoing packet is going to break * a scope boundary. * XXX For packets through PIM register tunnel * interface, we believe a routing daemon. */ if ((mif6table[rt->mf6c_parent].m6_flags & MIFF_REGISTER) == 0 && (mif6table[mifi].m6_flags & MIFF_REGISTER) == 0) { if ((dscopein = in6_addr2zoneid(ifp, &ip6->ip6_dst)) < 0 || (dscopeout = in6_addr2zoneid(mif6table[mifi].m6_ifp, &ip6->ip6_dst)) < 0 || (sscopein = in6_addr2zoneid(ifp, &ip6->ip6_src)) < 0 || (sscopeout = in6_addr2zoneid(mif6table[mifi].m6_ifp, &ip6->ip6_src)) < 0 || dscopein != dscopeout || sscopein != sscopeout) { ip6stat.ip6s_badscope++; continue; } } mifp->m6_pkt_out++; mifp->m6_bytes_out += plen; MC6_SEND(ip6, mifp, m); } return 0;}static voidphyint_send(ip6, mifp, m) struct ip6_hdr *ip6; struct mif6 *mifp; struct mbuf *m;{ struct mbuf *mb_copy; struct ifnet *ifp = mifp->m6_ifp; int error = 0;#ifdef __NetBSD__ int s = splsoftnet(); /* needs to protect static "ro" below. */#else int s = splnet(); /* needs to protect static "ro" below. */#endif#ifdef NEW_STRUCT_ROUTE static struct route ro;#else static struct route_in6 ro;#endif struct in6_multi *in6m; struct sockaddr_in6 *dst6; /* * Make a new reference to the packet; make sure that * the IPv6 header is actually copied, not just referenced, * so that ip6_output() only scribbles on the copy. */ mb_copy = m_copy(m, 0, M_COPYALL); if (mb_copy && (M_HASCL(mb_copy) || mb_copy->m_len < sizeof(struct ip6_hdr))) mb_copy = m_pullup(mb_copy, sizeof(struct ip6_hdr)); if (mb_copy == NULL) { splx(s); return; } /* set MCAST flag to the outgoing packet */ mb_copy->m_flags |= M_MCAST; /* * If we sourced the packet, call ip6_output since we may devide * the packet into fragments when the packet is too big for the * outgoing interface. * Otherwise, we can simply send the packet to the interface * sending queue. */ if (m->m_pkthdr.rcvif == NULL) { struct ip6_moptions im6o; im6o.im6o_multicast_ifp = ifp; /* XXX: ip6_output will override ip6->ip6_hlim */ im6o.im6o_multicast_hlim = ip6->ip6_hlim; im6o.im6o_multicast_loop = 1; error = ip6_output(mb_copy, NULL, &ro, IPV6_FORWARDING, &im6o, NULL);#ifdef MRT6DEBUG if (mrt6debug & DEBUG_XMIT) log(LOG_DEBUG, "phyint_send on mif %d err %d\n", mifp - mif6table, error);#endif splx(s); return; } /* * If we belong to the destination multicast group * on the outgoing interface, loop back a copy. */ dst6 = (struct sockaddr_in6 *)&ro.ro_dst; IN6_LOOKUP_MULTI(ip6->ip6_dst, ifp, in6m); if (in6m != NULL) { dst6->sin6_len = sizeof(struct sockaddr_in6); dst6->sin6_family = AF_INET6; dst6->sin6_addr = ip6->ip6_dst; ip6_mloopback(ifp, m, (struct sockaddr_in6 *)&ro.ro_dst); } /* * Put the packet into the sending queue of the outgoing interface * if it would fit in the MTU of the interface. */ if (mb_copy->m_pkthdr.len < ifp->if_mtu || ifp->if_mtu < IPV6_MMTU) { dst6->sin6_len = sizeof(struct sockaddr_in6); dst6->sin6_family = AF_INET6; dst6->sin6_addr = ip6->ip6_dst; /* * We just call if_output instead of nd6_output here, since * we need no ND for a multicast forwarded packet...right? */ error = (*ifp->if_output)(ifp, mb_copy, (struct sockaddr *)&ro.ro_dst, NULL);#ifdef MRT6DEBUG if (mrt6debug & DEBUG_XMIT) log(LOG_DEBUG, "phyint_send on mif %d err %d\n", mifp - mif6table, error);#endif } else {#ifdef MULTICAST_PMTUD icmp6_error(mb_copy, ICMP6_PACKET_TOO_BIG, 0, ifp->if_mtu);#else#ifdef MRT6DEBUG if (mrt6debug & DEBUG_XMIT) log(LOG_DEBUG, "phyint_send: packet too big on %s o %s g %s" " size %d(discarded)\n", if_name(ifp), ip6_sprintf(&ip6->ip6_src), ip6_sprintf(&ip6->ip6_dst), mb_copy->m_pkthdr.len);#endif /* MRT6DEBUG */ m_freem(mb_copy); /* simply discard the packet */#endif } splx(s);}static intregister_send(ip6, mif, m) struct ip6_hdr *ip6; struct mif6 *mif; struct mbuf *m;{ struct mbuf *mm; int i, len = m->m_pkthdr.len; static struct sockaddr_in6 sin6 = { sizeof(sin6), AF_INET6 }; struct mrt6msg *im6;#ifdef MRT6DEBUG if (mrt6debug) log(LOG_DEBUG, "** IPv6 register_send **\n src %s dst %s\n", ip6_sprintf(&ip6->ip6_src), ip6_sprintf(&ip6->ip6_dst));#endif ++pim6stat.pim6s_snd_registers; /* Make a copy of the packet to send to the user level process */ MGETHDR(mm, M_DONTWAIT, MT_HEADER); if (mm == NULL) return ENOBUFS; mm->m_pkthdr.rcvif = NULL; mm->m_data += max_linkhdr; mm->m_len = sizeof(struct ip6_hdr); if ((mm->m_next = m_copy(m, 0, M_COPYALL)) == NULL) { m_freem(mm); return ENOBUFS; } i = MHLEN - M_LEADINGSPACE(mm); if (i > len) i = len; mm = m_pullup(mm, i); if (mm == NULL){ m_freem(mm); return ENOBUFS; }/* TODO: check it! */ mm->m_pkthdr.len = len + sizeof(struct ip6_hdr); /* * Send message to routing daemon */ sin6.sin6_addr = ip6->ip6_src; im6 = mtod(mm, struct mrt6msg *); im6->im6_msgtype = MRT6MSG_WHOLEPKT; im6->im6_mbz = 0; im6->im6_mif = mif - mif6table; /* iif info is not given for reg. encap.n */ mrt6stat.mrt6s_upcalls++; if (socket_send(ip6_mrouter, mm, &sin6) < 0) {#ifdef MRT6DEBUG if (mrt6debug) log(LOG_WARNING, "register_send: ip6_mrouter socket queue full\n");#endif ++mrt6stat.mrt6s_upq_sockfull; return ENOBUFS; } return 0;}/* * PIM sparse mode hook * Receives the pim control messages, and passes them up to the listening * socket, using rip6_input. * The only message processed is the REGISTER pim message; the pim header * is stripped off, and the inner packet is passed to register_mforward. */intpim6_input(mp, offp, proto) struct mbuf **mp; int *offp, proto;{ struct pim *pim; /* pointer to a pim struct */ struct ip6_hdr *ip6; int pimlen; struct mbuf *m = *mp; int minlen; int off = *offp; ++pim6stat.pim6s_rcv_total; ip6 = mtod(m, struct ip6_hdr *); pimlen = m->m_pkthdr.len - *offp; /* * Validate lengths */ if (pimlen < PIM_MINLEN) { ++pim6stat.pim6s_rcv_tooshort;#ifdef MRT6DEBUG if (mrt6debug & DEBUG_PIM) log(LOG_DEBUG,"pim6_input: PIM packet too short\n");#endif m_freem(m); return(IPPROTO_DONE); } /* * if the packet is at least as big as a REGISTER, go ahead * and grab the PIM REGISTER header size, to avoid another * possible m_pullup() later. * * PIM_MINLEN == pimhdr + u_int32 == 8 * PIM6_REG_MINLEN == pimhdr + reghdr + eip6hdr == 4 + 4 + 40 */ minlen = (pimlen >= PIM6_REG_MINLEN) ? PIM6_REG_MINLEN : PIM_MINLEN; /* * Make sure that the IP6 and PIM headers in contiguous memory, and * possibly the PIM REGISTER header */#ifndef PULLDOWN_TEST IP6_EXTHDR_CHECK(m, off, minlen, IPPROTO_DONE); /* adjust pointer */ ip6 = mtod(m, struct ip6_hdr *); /* adjust mbuf to point to the PIM header */ pim = (struct pim *)((caddr_t)ip6 + off);#else IP6_EXTHDR_GET(pim, struct pim *, m, off, minlen); if (pim == NULL) { pim6stat.pim6s_rcv_tooshort++; return IPPROTO_DONE; }#endif#define PIM6_CHECKSUM#ifdef PIM6_CHECKSUM { int cksumlen; /* * Validate checksum. * If PIM REGISTER, exclude the data packet */ if (pim->pim_type == PIM_REGISTER) cksumlen = PIM_MINLEN; else cksumlen = pimlen; if (in6_cksum(m, IPPROTO_PIM, off, cksumlen)) { ++pim6stat.pim6s_rcv_badsum;#ifdef MRT6DEBUG if (mrt6debug & DEBUG_PIM) log(LOG_DEBUG, "pim6_input: invalid checksum\n");#endif m_freem(m); return(IPPROTO_DONE); } }#endif /* PIM_CHECKSUM */ /* PIM version check */ if (pim->pim_ver != PIM_VERSION) { ++pim6stat.pim6s_rcv_badversion;#ifdef MRT6DEBUG log(LOG_ERR, "pim6_input: incorrect version %d, expecting %d\n", pim->pim_ver, PIM_VERSION);#endif m_freem(m); return(IPPROTO_DONE); } if (pim->pim_type == PIM_REGISTER) { /* * since this is a REGISTER, we'll make a copy of the register * headers ip6+pim+u_int32_t+encap_ip6, to be passed up to the * routing daemon. */ static struct sockaddr_in6 dst = { sizeof(dst), AF_INET6 }; struct mbuf *mcp; struct ip6_hdr *eip6; u_int32_t *reghdr; int rc; ++pim6stat.pim6s_rcv_registers; if ((reg_mif_num >= nummifs) || (reg_mif_num == (mifi_t) -1)) {#ifdef MRT6DEBUG if (mrt6debug & DEBUG_PIM) log(LOG_DEBUG, "pim6_input: register mif not set: %d\n", reg_mif_num);#endif m_freem(m); return(IPPROTO_DONE); } reghdr = (u_int32_t *)(pim + 1); if ((ntohl(*reghdr) & PIM_NULL_REGISTER)) goto pim6_input_to_daemon; /* * Validate length */ if (pimlen < PIM6_REG_MINLEN) { ++pim6stat.pim6s_rcv_tooshort; ++pim6stat.pim6s_rcv_badregisters;#ifdef MRT6DEBUG log(LOG_ERR, "pim6_input: register packet size too " "small %d from %s\n", pimlen, ip6_sprintf(&ip6->ip6_src));#endif m_freem(m); return(IPPROTO_DONE); } eip6 = (struct ip6_hdr *) (reghdr + 1);#ifdef MRT6DEBUG if (mrt6debug & DEBUG_PIM) log(LOG_DEBUG, "pim6_input[register], eip6: %s -> %s, " "eip6 plen %d\n", ip6_sprintf(&eip6->ip6_src), ip6_sprintf(&eip6->ip6_dst), ntohs(eip6->ip6_plen));#endif /* verify the version number of the inner packet */ if ((eip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) { ++pim6stat.pim6s_rcv_badregisters;#ifdef MRT6DEBUG log(LOG_DEBUG, "pim6_input: invalid IP version (%d) " "of the inner packet\n", (eip6->ip6_vfc & IPV6_VERSION));#endif m_freem(m); return(IPPROTO_NONE); } /* verify the inner packet is destined to a mcast group */ if (!IN6_IS_ADDR_MULTICAST(&eip6->ip6_dst)) { ++pim6stat.pim6s_rcv_badregisters;#ifdef MRT6DEBUG if (mrt6debug & DEBUG_PIM) log(LOG_DEBUG, "pim6_input: inner packet of register " "is not multicast %s\n", ip6_sprintf(&eip6->ip6_dst));#endif m_freem(m); return(IPPROTO_DONE); } /* * make a copy of the whole header to pass to the daemon later. */ mcp = m_copy(m, 0, off + PIM6_REG_MINLEN); if (mcp == NULL) {#ifdef MRT6DEBUG log(LOG_ERR, "pim6_input: pim register: " "could not copy register head\n");#endif m_freem(m); return(IPPROTO_DONE); } /* * forward the inner ip6 packet; point m_data at the inner ip6. */ m_adj(m, off + PIM_MINLEN);#ifdef MRT6DEBUG if (mrt6debug & DEBUG_PIM) { log(LOG_DEBUG, "pim6_input: forwarding decapsulated register: " "src %s, dst %s, mif %d\n", ip6_sprintf(&eip6->ip6_src), ip6_sprintf(&eip6->ip6_dst), reg_mif_num); }#endif#if defined(__FreeBSD__) && __FreeBSD__ >= 3#if (__FreeBSD_version >= 410000) rc = if_simloop(mif6table[reg_mif_num].m6_ifp, m, dst.sin6_family, (int)NULL);#else rc = if_simloop(mif6table[reg_mif_num].m6_ifp, m, (struct sockaddr *) &dst, NULL);#endif#else rc = looutput(mif6table[reg_mif_num].m6_ifp, m, (struct sockaddr *) &dst, (struct rtentry *) NULL);#endif /* prepare the register head to send to the mrouting daemon */ m = mcp; } /* * Pass the PIM message up to the daemon; if it is a register message * pass the 'head' only up to the daemon. This includes the * encapsulator ip6 header, pim header, register header and the * encapsulated ip6 header. */ pim6_input_to_daemon: rip6_input(&m, offp, proto); return(IPPROTO_DONE);}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?