usr/src/uts/common/inet/ip/ip_multi.c
changeset 741 40027a3621ac
parent 0 68f95e015346
child 1676 37f4a3e2bd99
--- a/usr/src/uts/common/inet/ip/ip_multi.c	Sat Oct 22 11:06:40 2005 -0700
+++ b/usr/src/uts/common/inet/ip/ip_multi.c	Sat Oct 22 22:50:14 2005 -0700
@@ -65,6 +65,7 @@
 #include <inet/ipsec_impl.h>
 #include <inet/sctp_ip.h>
 #include <inet/ip_listutils.h>
+#include <inet/udp_impl.h>
 
 #include <netinet/igmp.h>
 
@@ -1186,14 +1187,39 @@
 ip_multicast_loopback(queue_t *q, ill_t *ill, mblk_t *mp_orig, int fanout_flags,
     zoneid_t zoneid)
 {
-	mblk_t		*mp;
-	mblk_t		*ipsec_mp;
-
-	/* TODO this could use dup'ed messages except for the IP header. */
-	mp = ip_copymsg(mp_orig);
+	mblk_t	*mp;
+	mblk_t	*ipsec_mp;
+
+	if (DB_TYPE(mp_orig) == M_DATA &&
+	    ((ipha_t *)mp_orig->b_rptr)->ipha_protocol == IPPROTO_UDP) {
+		uint_t hdrsz;
+
+		hdrsz = IPH_HDR_LENGTH((ipha_t *)mp_orig->b_rptr) +
+		    sizeof (udpha_t);
+		ASSERT(MBLKL(mp_orig) >= hdrsz);
+
+		if (((mp = allocb(hdrsz, BPRI_MED)) != NULL) &&
+		    (mp_orig = dupmsg(mp_orig)) != NULL) {
+			bcopy(mp_orig->b_rptr, mp->b_rptr, hdrsz);
+			mp->b_wptr += hdrsz;
+			mp->b_cont = mp_orig;
+			mp_orig->b_rptr += hdrsz;
+			if (MBLKL(mp_orig) == 0) {
+				mp->b_cont = mp_orig->b_cont;
+				mp_orig->b_cont = NULL;
+				freeb(mp_orig);
+			}
+		} else if (mp != NULL) {
+			freeb(mp);
+			mp = NULL;
+		}
+	} else {
+		mp = ip_copymsg(mp_orig);
+	}
+
 	if (mp == NULL)
 		return;
-	if (mp->b_datap->db_type == M_CTL) {
+	if (DB_TYPE(mp) == M_CTL) {
 		ipsec_mp = mp;
 		mp = mp->b_cont;
 	} else {
@@ -2553,7 +2579,7 @@
 	zoneid = connp->conn_zoneid;
 
 	/* don't allow multicast operations on a tcp conn */
-	if (IS_TCP_CONN(connp))
+	if (IPCL_IS_TCP(connp))
 		return (ENOPROTOOPT);
 
 	if (cmd == SIOCSIPMSFILTER || cmd == SIOCGIPMSFILTER) {