PATCH: SK110-018 CHANGES: sys/netinet/ip_mroute.c SUMMARY: This patch fixes a problem in the IP multicast forwarding code (option MROUTING) that causes crashes if a multicast packet was forwarded on a local interface and on a tunnel using encapsulation. INSTALLATION: cd /sys # your local kernel source tree patch -p < this_file # then rebuild your kernel per the instructions in the release notes =================================================================== RCS file: netinet/RCS/ip_mroute.c,v retrieving revision 1.4 diff -c -r1.4 netinet/ip_mroute.c *** 1.4 1994/01/30 02:21:14 --- netinet/ip_mroute.c 1994/09/02 16:14:13 *************** *** 1,4 **** ! /* BSDI $Id: ip_mroute.c,v 1.4 1994/01/30 02:21:14 karels Exp $ */ /* * Copyright (c) 1989 Stephen Deering --- 1,4 ---- ! /* BSDI $Id: ip_mroute.c,v 1.5 1994/09/02 16:14:13 karels Exp $ */ /* * Copyright (c) 1989 Stephen Deering *************** *** 841,849 **** --- 841,858 ---- register struct mbuf *mb_copy; register struct ip_moptions *imo; register int error; + int hlen = ip->ip_hl << 2; struct ip_moptions simo; + /* + * Make a new reference to the packet; make sure that + * the IP header is actually copied, not just referenced, + * so that modifications to this copy are not made + * to the original when we call ip_output. + */ mb_copy = m_copy(m, 0, M_COPYALL); + if (mb_copy) + mb_copy = m_pullup(mb_copy, hlen); if (mb_copy == NULL) return; *************** *** 864,869 **** --- 873,879 ---- { register struct mbuf *mb_copy, *mb_opts; register struct ip *ip_copy; + int hlen = ip->ip_hl << 2; register int error; register u_char *cp; *************** *** 879,913 **** mb_copy = m_copy(m, 0, M_COPYALL); if (mb_copy == NULL) return; - ip_copy = mtod(mb_copy, struct ip *); - ip_copy->ip_ttl--; - ip_copy->ip_dst = vifp->v_rmt_addr; /* remote tunnel end-point */ - /* - * Adjust the ip header length to account for the tunnel options. - */ - ip_copy->ip_hl += TUNNEL_LEN >> 2; - ip_copy->ip_len += TUNNEL_LEN; MGETHDR(mb_opts, M_DONTWAIT, MT_HEADER); if (mb_opts == NULL) { m_freem(mb_copy); return; } /* ! * 'Delete' the base ip header from the mb_copy chain */ ! mb_copy->m_len -= IP_HDR_LEN; ! mb_copy->m_data += IP_HDR_LEN; /* * Make mb_opts be the new head of the packet chain. - * Any options of the packet were left in the old packet chain head */ mb_opts->m_next = mb_copy; ! mb_opts->m_len = IP_HDR_LEN + TUNNEL_LEN; mb_opts->m_data += MSIZE - mb_opts->m_len; /* ! * Copy the base ip header from the mb_copy chain to the new head mbuf */ ! bcopy((caddr_t)ip_copy, mtod(mb_opts, caddr_t), IP_HDR_LEN); /* * Add the NOP and LSRR after the base ip header */ --- 889,923 ---- mb_copy = m_copy(m, 0, M_COPYALL); if (mb_copy == NULL) return; MGETHDR(mb_opts, M_DONTWAIT, MT_HEADER); if (mb_opts == NULL) { m_freem(mb_copy); return; } /* ! * 'Delete' the ip header from the mb_copy chain */ ! mb_copy->m_len -= hlen; ! mb_copy->m_data += hlen; /* * Make mb_opts be the new head of the packet chain. */ mb_opts->m_next = mb_copy; ! mb_opts->m_len = hlen + TUNNEL_LEN; mb_opts->m_data += MSIZE - mb_opts->m_len; + mb_opts->m_pkthdr.len = mb_copy->m_pkthdr.len + TUNNEL_LEN; + /* + * Copy the ip header from the mb_copy chain to the new head mbuf + */ + bcopy((caddr_t)ip_copy, mtod(mb_opts, caddr_t), hlen); + ip_copy = mtod(mb_opts, struct ip *); + ip_copy->ip_ttl--; + ip_copy->ip_dst = vifp->v_rmt_addr; /* remote tunnel end-point */ /* ! * Adjust the ip header length to account for the tunnel options. */ ! ip_copy->ip_hl += TUNNEL_LEN >> 2; ! ip_copy->ip_len += TUNNEL_LEN; /* * Add the NOP and LSRR after the base ip header */ *************** *** 953,958 **** --- 963,969 ---- mb_copy = m_pullup(mb_copy, i); if (mb_copy == NULL) return; + mb_copy->m_pkthdr.len = len + sizeof(multicast_encap_iphdr); /* * fill in the encapsulating IP header.