changeset 3291:a0d6d28506cf

6504195 IPv6 doesn't send up self-generated ICMP6_PACKET_TOO_BIG to tunnels. 6504199 tun does a lot of freeb(ipsec_mp) where ipsec_mp is 0xdeadbeef.
author danmcd
date Wed, 20 Dec 2006 03:52:51 -0800
parents 256464cbb73c
children f1a92dc5bc08
files usr/src/uts/common/inet/ip/ip6.c usr/src/uts/common/inet/ip/tun.c
diffstat 2 files changed, 23 insertions(+), 54 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/uts/common/inet/ip/ip6.c	Tue Dec 19 23:13:06 2006 -0800
+++ b/usr/src/uts/common/inet/ip/ip6.c	Wed Dec 20 03:52:51 2006 -0800
@@ -273,7 +273,6 @@
 static boolean_t	ip_source_routed_v6(ip6_t *, mblk_t *);
 static void	ip_wput_ire_v6(queue_t *, mblk_t *, ire_t *, int, int,
     conn_t *, int, int, int, zoneid_t);
-static boolean_t ip_ulp_cando_pkt2big(int);
 
 void ip_rput_v6(queue_t *, mblk_t *);
 static void ip_wput_v6(queue_t *, mblk_t *);
@@ -1113,8 +1112,8 @@
 			 * the IPsec overhead.
 			 */
 			if (ii != NULL)
-				icmp6->icmp6_mtu = htons(
-				    ntohs(icmp6->icmp6_mtu) -
+				icmp6->icmp6_mtu = htonl(
+				    ntohl(icmp6->icmp6_mtu) -
 					ipsec_in_extra_length(first_mp));
 		} else {
 			/*
@@ -11437,7 +11436,7 @@
 			int extra_len = ipsec_out_extra_length(first_mp);
 
 			if (ntohs(ip6h->ip6_plen) + IPV6_HDR_LEN + extra_len >
-			    max_frag && ip_ulp_cando_pkt2big(nexthdr)) {
+			    max_frag) {
 				/*
 				 * IPsec headers will push the packet over the
 				 * MTU limit.  Issue an ICMPv6 Packet Too Big
@@ -12951,23 +12950,6 @@
 }
 
 /*
- * See if the upper-level protocol indicated by 'proto' will be able
- * to do something with an ICMP_FRAGMENTATION_NEEDED (IPv4) or
- * ICMP6_PACKET_TOO_BIG (IPv6).
- */
-static boolean_t
-ip_ulp_cando_pkt2big(int proto)
-{
-	/*
-	 * For now, only TCP can handle this.
-	 * Tunnels may be able to also, but since tun isn't working over
-	 * IPv6 yet, don't worry about it for now.
-	 */
-	return (proto == IPPROTO_TCP);
-}
-
-
-/*
  * Propagate a multicast group membership operation (join/leave) (*fn) on
  * all interfaces crossed by the related multirt routes.
  * The call is considered successful if the operation succeeds
--- a/usr/src/uts/common/inet/ip/tun.c	Tue Dec 19 23:13:06 2006 -0800
+++ b/usr/src/uts/common/inet/ip/tun.c	Wed Dec 20 03:52:51 2006 -0800
@@ -3018,6 +3018,7 @@
 			atomic_add_32(&atp->tun_InErrors, 1);
 			goto drop;
 		}
+		ipsec_mp = NULL;
 		if (data_mp != orig_mp) {
 			/* mp has changed, reset appropriate pointers */
 
@@ -3051,6 +3052,7 @@
 			atomic_add_32(&atp->tun_InErrors, 1);
 			goto drop;
 		}
+		ipsec_mp = NULL;
 		if (data_mp != orig_mp) {
 			/* mp has changed, reset appropriate pointers */
 			/* v6src should still be a valid and relevant ptr */
@@ -3147,6 +3149,8 @@
 		if (!pullupmsg(data_mp, hdrlen + pullup_len)) {
 			atomic_add_32(&atp->tun_InErrors, 1);
 			atomic_add_32(&atp->tun_InDiscard, 1);
+			if (ipsec_mp != NULL)
+				freeb(ipsec_mp);
 			goto drop;
 		}
 		iph = (ipha_t *)data_mp->b_rptr;
@@ -3162,10 +3166,10 @@
 		ASSERT(IN6_ARE_ADDR_EQUAL(&v4mapped_dst, &atp->tun_laddr) &&
 		    IN6_ARE_ADDR_EQUAL(&v4mapped_src, &atp->tun_faddr));
 
+		/* NOTE:  ipsec_tun_inbound() always frees ipsec_mp. */
 		if (!ipsec_tun_inbound(ipsec_mp, &data_mp, atp->tun_itp,
 			inner_iph, NULL, iph, NULL, 0)) {
 			data_mp = NULL;
-			ipsec_mp = NULL;
 			atomic_add_32(&atp->tun_InErrors, 1);
 			goto drop;
 		}
@@ -3195,10 +3199,10 @@
 		ip6h = (ip6_t *)data_mp->b_rptr;
 		ASSERT(IPH_HDR_VERSION(ip6h) == IPV6_VERSION);
 
+		/* NOTE:  ipsec_tun_inbound() always frees ipsec_mp. */
 		if (!ipsec_tun_inbound(ipsec_mp, &data_mp, atp->tun_itp, NULL,
 			ip6h, iph, NULL, 0)) {
 			data_mp = NULL;
-			ipsec_mp = NULL;
 			atomic_add_32(&atp->tun_InErrors, 1);
 			goto drop;
 		}
@@ -3426,8 +3430,6 @@
 	TUN_PUTMSG_CHAIN_STATS(q, data_mp, nmp, &atp->tun_HCInOctets);
 	return (0);
 drop:
-	if (ipsec_mp != NULL)
-		freeb(ipsec_mp);
 	tun_freemsg_chain(data_mp, NULL);
 	return (0);
 }
@@ -3578,7 +3580,8 @@
 	 * us to receive it.  We now have to use inner policy to see if
 	 * we want to percolate it up (like conn_t's are checked).
 	 *
-	 * Use -outer_hlen to indicate this is an ICMP packet.
+	 * Use -outer_hlen to indicate this is an ICMP packet.  And
+	 * ipsec_tun_inbound() always frees ipsec_mp.
 	 */
 	if (!ipsec_tun_inbound(ipsec_mp, &mp, atp->tun_itp, inner_ipha, NULL,
 		outer_ipha, NULL, -outer_hlen)) {
@@ -3602,8 +3605,6 @@
 				tun0dbg(("icmp_ricmp_err_v4_v4: invalid " \
 				    "icmp mtu\n"));
 				atomic_add_32(&atp->tun_InErrors, 1);
-				if (ipsec_mp != NULL)
-					freeb(ipsec_mp);
 				freemsg(mp);
 				return;
 			}
@@ -3657,8 +3658,6 @@
 			break;
 		default:
 			atomic_add_32(&atp->tun_InErrors, 1);
-			if (ipsec_mp != NULL)
-				freeb(ipsec_mp);
 			freemsg(mp);
 			return;
 		}
@@ -3674,8 +3673,6 @@
 			tun0dbg(("icmp_ricmp_err_v4_v4: ICMP_PARAM_PROBLEM " \
 			    "too short\n"));
 			atomic_add_32(&atp->tun_InErrors, 1);
-			if (ipsec_mp != NULL)
-				freeb(ipsec_mp);
 			freemsg(mp);
 			return;
 		}
@@ -3685,8 +3682,6 @@
 		break;
 	default:
 		atomic_add_32(&atp->tun_InErrors, 1);
-		if (ipsec_mp != NULL)
-			freeb(ipsec_mp);
 		freemsg(mp);
 		return;
 	}
@@ -3740,7 +3735,8 @@
 	 * us to receive it.  We now have to use inner policy to see if
 	 * we want to percolate it up (like conn_t's are checked).
 	 *
-	 * Use -outer_hlen to indicate this is an ICMP packet.
+	 * Use -outer_hlen to indicate this is an ICMP packet.  And
+	 * ipsec_tun_inbound() always frees ipsec_mp.
 	 */
 	if (!ipsec_tun_inbound(ipsec_mp, &mp, atp->tun_itp, ipha, NULL, NULL,
 		ip6, -outer_hlen))
@@ -3807,8 +3803,6 @@
 		}
 
 		if (found != B_TRUE) {
-			if (ipsec_mp != NULL)
-				freeb(ipsec_mp);
 			freemsg(mp);
 			return;
 		}
@@ -3832,13 +3826,16 @@
 		if (ipha->ipha_fragment_offset_and_flags & IPH_DF) {
 			icmp.icmph_type = ICMP_DEST_UNREACHABLE;
 			icmp.icmph_code = ICMP_FRAGMENTATION_NEEDED;
-			icmp.icmph_du_mtu = htonl(mtu);
+			/*
+			 * NOTE - htons() because ICMP (for IPv4) uses a
+			 * uint16_t here.
+			 */
+			icmp.icmph_du_mtu = htons(mtu);
+			icmp.icmph_du_zero = 0;
 		}
 		break;
 	}
 	default:
-		if (ipsec_mp != NULL)
-			freeb(ipsec_mp);
 		freemsg(mp);
 		return;
 	}
@@ -3893,7 +3890,8 @@
 	 * us to receive it.  We now have to use inner policy to see if
 	 * we want to percolate it up (like conn_t's are checked).
 	 *
-	 * Use -outer_hlen to indicate this is an ICMP packet.
+	 * Use -outer_hlen to indicate this is an ICMP packet.  And
+	 * ipsec_tun_inbound() always frees ipsec_mp.
 	 */
 	if (!ipsec_tun_inbound(ipsec_mp, &mp, atp->tun_itp, NULL, inner_ip6,
 		NULL, ip6, -outer_hlen))
@@ -3960,8 +3958,6 @@
 		}
 
 		if (found != B_TRUE) {
-			if (ipsec_mp != NULL)
-				freeb(ipsec_mp);
 			freemsg(mp);
 			return;	/* case */
 		}
@@ -3991,8 +3987,6 @@
 		break;
 	}
 	default:
-		if (ipsec_mp != NULL)
-			freeb(ipsec_mp);
 		freemsg(mp);
 		return;
 	}
@@ -4103,7 +4097,8 @@
 	 * us to receive it.  We now have to use inner policy to see if
 	 * we want to percolate it up (like conn_t's are checked).
 	 *
-	 * Use -outer_hlen to indicate this is an ICMP packet.
+	 * Use -outer_hlen to indicate this is an ICMP packet.  And
+	 * ipsec_tun_inbound() always frees ipsec_mp.
 	 */
 	if (!ipsec_tun_inbound(ipsec_mp, &mp, atp->tun_itp, NULL, ip6h,
 		outer_ipha, NULL, -outer_hlen))
@@ -4126,8 +4121,6 @@
 				tun0dbg(("icmp_ricmp_err_v6_v4: invalid " \
 				    "icmp mtu\n"));
 				atomic_add_32(&atp->tun_InErrors, 1);
-				if (ipsec_mp != NULL)
-					freeb(ipsec_mp);
 				freemsg(mp);
 				return;
 			}
@@ -4195,8 +4188,6 @@
 			break;
 		default:
 			atomic_add_32(&atp->tun_InErrors, 1);
-			if (ipsec_mp != NULL)
-				freeb(ipsec_mp);
 			freemsg(mp);
 			return;
 		}
@@ -4212,8 +4203,6 @@
 			tun0dbg(("icmp_ricmp_err_v6_v4: ICMP_PARAM_PROBLEM " \
 			    "too short\n"));
 			atomic_add_32(&atp->tun_InErrors, 1);
-			if (ipsec_mp != NULL)
-				freeb(ipsec_mp);
 			freemsg(mp);
 			return;
 		}
@@ -4224,8 +4213,6 @@
 
 	default:
 		atomic_add_32(&atp->tun_InErrors, 1);
-		if (ipsec_mp != NULL)
-			freeb(ipsec_mp);
 		freemsg(mp);
 		return;
 	}