6201425 setting IPV6_UNICAST_HOPS on SCTP socket doesn't do anything
6201431 IPV6_UNICAST_HOPS steps on IPV6_MULTICAST_HOPS' toes
6290936 Solaris 10 IPv6 traceroute does not increment the Hop limit
6292943 IPV6_HOPLIMIT is not a socket option
6327929 CurHopLimit in IPv6 Router Advertisement shouldn't affect multicast packets
diff --git a/usr/src/uts/common/inet/ip.h b/usr/src/uts/common/inet/ip.h
index c499914..9caf225 100644
--- a/usr/src/uts/common/inet/ip.h
+++ b/usr/src/uts/common/inet/ip.h
@@ -2393,8 +2393,9 @@
uint_t ipp_sticky_ignored; /* sticky fields to ignore */
uint_t ipp_ifindex; /* pktinfo ifindex */
in6_addr_t ipp_addr; /* pktinfo src/dst addr */
- uint_t ipp_hoplimit;
- uint_t ipp_multi_hoplimit;
+ uint_t ipp_unicast_hops; /* IPV6_UNICAST_HOPS */
+ uint_t ipp_multicast_hops; /* IPV6_MULTICAST_HOPS */
+ uint_t ipp_hoplimit; /* IPV6_HOPLIMIT */
uint_t ipp_hopoptslen;
uint_t ipp_rtdstoptslen;
uint_t ipp_rthdrlen;
@@ -2448,13 +2449,14 @@
#define IPPF_TCLASS 0x1000
#define IPPF_DONTFRAG 0x2000
-#define IPPF_USE_MIN_MTU 0x4000
-#define IPPF_MULTI_HOPLIMIT 0x8000
+#define IPPF_USE_MIN_MTU 0x04000
+#define IPPF_MULTICAST_HOPS 0x08000
+#define IPPF_UNICAST_HOPS 0x10000
#define IPPF_HAS_IP6I \
(IPPF_IFINDEX|IPPF_ADDR|IPPF_NEXTHOP|IPPF_SCOPE_ID| \
IPPF_NO_CKSUM|IPPF_RAW_CKSUM|IPPF_HOPLIMIT|IPPF_DONTFRAG| \
- IPPF_USE_MIN_MTU|IPPF_MULTI_HOPLIMIT)
+ IPPF_USE_MIN_MTU|IPPF_MULTICAST_HOPS|IPPF_UNICAST_HOPS)
#define TCP_PORTS_OFFSET 0
#define UDP_PORTS_OFFSET 0
diff --git a/usr/src/uts/common/inet/ip/icmp.c b/usr/src/uts/common/inet/ip/icmp.c
index 6783ee6..9c3863b 100644
--- a/usr/src/uts/common/inet/ip/icmp.c
+++ b/usr/src/uts/common/inet/ip/icmp.c
@@ -1694,12 +1694,6 @@
pkti->ipi6_addr = ipv6_all_zeros;
return (sizeof (struct in6_pktinfo));
}
- case IPV6_HOPLIMIT:
- if (ipp->ipp_fields & IPPF_HOPLIMIT)
- *i1 = ipp->ipp_hoplimit;
- else
- *i1 = -1; /* Not set */
- break;
case IPV6_NEXTHOP: {
sin6_t *sin6 = (sin6_t *)ptr;
@@ -2130,15 +2124,15 @@
}
if (!checkonly) {
if (*i1 == -1) {
- icmp->icmp_ttl = ipp->ipp_hoplimit =
+ icmp->icmp_ttl = ipp->ipp_unicast_hops =
icmp_ipv6_hoplimit;
- ipp->ipp_fields &= ~IPPF_HOPLIMIT;
+ ipp->ipp_fields &= ~IPPF_UNICAST_HOPS;
/* Pass modified value to IP. */
*i1 = ipp->ipp_hoplimit;
} else {
- icmp->icmp_ttl = ipp->ipp_hoplimit =
+ icmp->icmp_ttl = ipp->ipp_unicast_hops =
(uint8_t)*i1;
- ipp->ipp_fields |= IPPF_HOPLIMIT;
+ ipp->ipp_fields |= IPPF_UNICAST_HOPS;
}
/* Rebuild the header template */
error = icmp_build_hdrs(q, icmp);
@@ -2157,22 +2151,16 @@
if (!checkonly) {
if (*i1 == -1) {
icmp->icmp_multicast_ttl =
- ipp->ipp_multi_hoplimit =
+ ipp->ipp_multicast_hops =
IP_DEFAULT_MULTICAST_TTL;
- ipp->ipp_fields &= ~IPPF_MULTI_HOPLIMIT;
+ ipp->ipp_fields &= ~IPPF_MULTICAST_HOPS;
/* Pass modified value to IP. */
- *i1 = ipp->ipp_multi_hoplimit;
+ *i1 = icmp->icmp_multicast_ttl;
} else {
icmp->icmp_multicast_ttl =
- ipp->ipp_multi_hoplimit =
+ ipp->ipp_multicast_hops =
(uint8_t)*i1;
- ipp->ipp_fields |= IPPF_MULTI_HOPLIMIT;
- }
- /* Rebuild the header template */
- error = icmp_build_hdrs(q, icmp);
- if (error != 0) {
- *outlenp = 0;
- return (error);
+ ipp->ipp_fields |= IPPF_MULTICAST_HOPS;
}
}
break;
@@ -2322,6 +2310,9 @@
}
break;
case IPV6_HOPLIMIT:
+ /* This option can only be used as ancillary data. */
+ if (sticky)
+ return (EINVAL);
if (inlen != 0 && inlen != sizeof (int))
return (EINVAL);
if (checkonly)
@@ -2339,11 +2330,6 @@
ipp->ipp_hoplimit = *i1;
ipp->ipp_fields |= IPPF_HOPLIMIT;
}
- if (sticky) {
- error = icmp_build_hdrs(q, icmp);
- if (error != 0)
- return (error);
- }
break;
case IPV6_TCLASS:
/*
@@ -2727,15 +2713,6 @@
if (!(ipp->ipp_fields & IPPF_ADDR))
ip6h->ip6_src = icmp->icmp_v6src;
- /*
- * If IPV6_HOPLIMIT was set in ipp, use that value.
- * For sticky options, if it does not exist use
- * the value in the icmp structure.
- * All this as per RFC 2922.
- */
- if (!(ipp->ipp_fields & IPPF_HOPLIMIT))
- ip6h->ip6_hops = icmp->icmp_ttl;
-
/* Try to get everything in a single mblk */
if (hdrs_len > icmp->icmp_max_hdr_len) {
icmp->icmp_max_hdr_len = hdrs_len;
@@ -4247,13 +4224,21 @@
}
}
- if (!(ignore & IPPF_HOPLIMIT)) {
- if (ipp->ipp_fields & IPPF_HOPLIMIT) {
- option_exists |= IPPF_HOPLIMIT;
- } else if (icmp->icmp_sticky_ipp.ipp_fields & IPPF_HOPLIMIT) {
- option_exists |= IPPF_HOPLIMIT;
- is_sticky |= IPPF_HOPLIMIT;
- }
+ if (!(ignore & IPPF_HOPLIMIT) && (ipp->ipp_fields & IPPF_HOPLIMIT))
+ option_exists |= IPPF_HOPLIMIT;
+ /* IPV6_HOPLIMIT can never be sticky */
+ ASSERT(!(icmp->icmp_sticky_ipp.ipp_fields & IPPF_HOPLIMIT));
+
+ if (!(ignore & IPPF_UNICAST_HOPS) &&
+ (icmp->icmp_sticky_ipp.ipp_fields & IPPF_UNICAST_HOPS)) {
+ option_exists |= IPPF_UNICAST_HOPS;
+ is_sticky |= IPPF_UNICAST_HOPS;
+ }
+
+ if (!(ignore & IPPF_MULTICAST_HOPS) &&
+ (icmp->icmp_sticky_ipp.ipp_fields & IPPF_MULTICAST_HOPS)) {
+ option_exists |= IPPF_MULTICAST_HOPS;
+ is_sticky |= IPPF_MULTICAST_HOPS;
}
if (icmp->icmp_sticky_ipp.ipp_fields & IPPF_NO_CKSUM) {
@@ -4373,15 +4358,19 @@
ip6h->ip6_vcf = IPV6_DEFAULT_VERS_AND_FLOW;
bzero(&ip6h->ip6_src, sizeof (ip6h->ip6_src));
+ /* Set the hoplimit of the outgoing packet. */
if (option_exists & IPPF_HOPLIMIT) {
- tipp = ANCIL_OR_STICKY_PTR(IPPF_HOPLIMIT);
- ip6h->ip6_hops = tipp->ipp_hoplimit;
- } else if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr) &&
- (icmp->icmp_sticky_ipp.ipp_fields & IPPF_MULTI_HOPLIMIT)) {
- ip6h->ip6_hops = icmp->icmp_multicast_ttl;
+ /* IPV6_HOPLIMIT ancillary data overrides all other settings. */
+ ip6h->ip6_hops = ipp->ipp_hoplimit;
ip6i->ip6i_flags |= IP6I_HOPLIMIT;
+ } else if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
+ ip6h->ip6_hops = icmp->icmp_multicast_ttl;
+ if (option_exists & IPPF_MULTICAST_HOPS)
+ ip6i->ip6i_flags |= IP6I_HOPLIMIT;
} else {
ip6h->ip6_hops = icmp->icmp_ttl;
+ if (option_exists & IPPF_UNICAST_HOPS)
+ ip6i->ip6i_flags |= IP6I_HOPLIMIT;
}
if (option_exists & IPPF_ADDR) {
diff --git a/usr/src/uts/common/inet/ip/ip6.c b/usr/src/uts/common/inet/ip/ip6.c
index 2f84c39..d701d17 100644
--- a/usr/src/uts/common/inet/ip/ip6.c
+++ b/usr/src/uts/common/inet/ip/ip6.c
@@ -10263,12 +10263,14 @@
/*
* If the sender didn't supply the hop limit and there is a default
- * hop limit associated with the output interface, we use that.
- * Interface specific hop limits as set via the SIOCSLIFLNKINFO
- * ioctl.
+ * unicast hop limit associated with the output interface, we use
+ * that if the packet is unicast. Interface specific unicast hop
+ * limits as set via the SIOCSLIFLNKINFO ioctl.
*/
- if (!(flags & IP6I_HOPLIMIT) && ill->ill_max_hops != 0)
+ if (ill->ill_max_hops != 0 && !(flags & IP6I_HOPLIMIT) &&
+ !(IN6_IS_ADDR_MULTICAST(&ip6h->ip6_dst))) {
ip6h->ip6_hops = ill->ill_max_hops;
+ }
if (ire->ire_type == IRE_LOCAL && ire->ire_zoneid != zoneid) {
/*
@@ -11724,8 +11726,8 @@
&ipp->ipp_addr));
ip6i->ip6i_flags |= IP6I_VERIFY_SRC;
}
- if (ipp->ipp_fields & IPPF_HOPLIMIT) {
- ip6i->ip6i_hops = ip6h->ip6_hops = ipp->ipp_hoplimit;
+ if (ipp->ipp_fields & IPPF_UNICAST_HOPS) {
+ ip6h->ip6_hops = ipp->ipp_unicast_hops;
/*
* We need to set this flag so that IP doesn't
* rewrite the IPv6 header's hoplimit with the
diff --git a/usr/src/uts/common/inet/sctp/sctp_common.c b/usr/src/uts/common/inet/sctp/sctp_common.c
index d8fcc22..7b1a73c 100644
--- a/usr/src/uts/common/inet/sctp/sctp_common.c
+++ b/usr/src/uts/common/inet/sctp/sctp_common.c
@@ -422,6 +422,12 @@
iph->ipha_length = htons(sum);
} else {
ip6h = (ip6_t *)mp->b_rptr;
+ /*
+ * If an ip6i_t is present, the real IPv6 header
+ * immediately follows.
+ */
+ if (ip6h->ip6_nxt == IPPROTO_RAW)
+ ip6h = (ip6_t *)&ip6h[1];
ip6h->ip6_plen = htons(sum - ((char *)&sctp->sctp_ip6h[1] -
sctp->sctp_iphc6));
}
@@ -904,14 +910,12 @@
ip6_pkt_t *ipp = &sctp->sctp_sticky_ipp;
in6_addr_t src;
in6_addr_t dst;
- uint8_t hoplimit;
/*
* save the existing sctp header and source/dest IP addresses
*/
bcopy(sctp->sctp_sctph6, buf, sizeof (sctp_hdr_t));
src = sctp->sctp_ip6h->ip6_src;
dst = sctp->sctp_ip6h->ip6_dst;
- hoplimit = sctp->sctp_ip6h->ip6_hops;
hdrs_len = ip_total_hdrs_len_v6(ipp) + SCTP_MAX_HDR_LENGTH;
ASSERT(hdrs_len != 0);
if (hdrs_len > sctp->sctp_iphc6_len) {
@@ -948,20 +952,11 @@
sctp->sctp_ip6h->ip6_src = src;
sctp->sctp_ip6h->ip6_dst = dst;
/*
- * If IPV6_HOPLIMIT was set in ipp, use that value.
- * For sticky options, if it does not exist use
- * the default/saved value (which was set in ip_build_hdrs_v6())
- * All this as per RFC 2922.
+ * If the hoplimit was not set by ip_build_hdrs_v6(), we need to
+ * set it to the default value for SCTP.
*/
- if (!(ipp->ipp_fields & IPPF_HOPLIMIT))
- sctp->sctp_ip6h->ip6_hops = hoplimit;
- /*
- * Set the IPv6 header payload length.
- * If there's an ip6i_t included, don't count it in the length.
- */
- sctp->sctp_ip6h->ip6_plen = sctp->sctp_hdr6_len - IPV6_HDR_LEN;
- if (ipp->ipp_fields & IPPF_HAS_IP6I)
- sctp->sctp_ip6h->ip6_plen -= sizeof (ip6i_t);
+ if (!(ipp->ipp_fields & IPPF_UNICAST_HOPS))
+ sctp->sctp_ip6h->ip6_hops = sctp_ipv6_hoplimit;
/*
* If we're setting extension headers after a connection
* has been established, and if we have a routing header
diff --git a/usr/src/uts/common/inet/sctp/sctp_opt_data.c b/usr/src/uts/common/inet/sctp/sctp_opt_data.c
index a335a90..b283ab3 100644
--- a/usr/src/uts/common/inet/sctp/sctp_opt_data.c
+++ b/usr/src/uts/common/inet/sctp/sctp_opt_data.c
@@ -1122,12 +1122,6 @@
*optlen = sizeof (struct in6_pktinfo);
break;
}
- case IPV6_HOPLIMIT:
- if (ipp->ipp_fields & IPPF_HOPLIMIT)
- *i1 = ipp->ipp_hoplimit;
- else
- *i1 = -1; /* Not set */
- break; /* goto sizeof (int) option return */
case IPV6_NEXTHOP: {
sin6_t *sin6;
@@ -1515,10 +1509,14 @@
retval = EINVAL;
break;
}
- if (*i1 == -1)
- sctp->sctp_ip6h->ip6_hops = sctp_ipv6_hoplimit;
- else
- sctp->sctp_ip6h->ip6_hops = (uint8_t)*i1;
+ if (*i1 == -1) {
+ ipp->ipp_unicast_hops = sctp_ipv6_hoplimit;
+ ipp->ipp_fields &= ~IPPF_UNICAST_HOPS;
+ } else {
+ ipp->ipp_unicast_hops = (uint8_t)*i1;
+ ipp->ipp_fields |= IPPF_UNICAST_HOPS;
+ }
+ retval = sctp_build_hdrs(sctp);
break;
case IPV6_UNSPEC_SRC:
if (inlen < sizeof (int32_t)) {
@@ -1635,26 +1633,6 @@
}
retval = sctp_build_hdrs(sctp);
break;
- case IPV6_HOPLIMIT:
- if (inlen != 0 && inlen != sizeof (int)) {
- retval = EINVAL;
- break;
- }
- if (inlen == 0) {
- ipp->ipp_fields &= ~IPPF_HOPLIMIT;
- } else {
- if (*i1 > 255 || *i1 < -1) {
- retval = EINVAL;
- break;
- }
- if (*i1 == -1)
- ipp->ipp_hoplimit = sctp_ipv6_hoplimit;
- else
- ipp->ipp_hoplimit = *i1;
- ipp->ipp_fields |= IPPF_HOPLIMIT;
- }
- retval = sctp_build_hdrs(sctp);
- break;
case IPV6_NEXTHOP: {
struct sockaddr_in6 *sin6;
diff --git a/usr/src/uts/common/inet/tcp/tcp.c b/usr/src/uts/common/inet/tcp/tcp.c
index 7ed6170..8c651d1 100644
--- a/usr/src/uts/common/inet/tcp/tcp.c
+++ b/usr/src/uts/common/inet/tcp/tcp.c
@@ -10220,12 +10220,6 @@
pkti->ipi6_addr = ipv6_all_zeros;
return (sizeof (struct in6_pktinfo));
}
- case IPV6_HOPLIMIT:
- if (ipp->ipp_fields & IPPF_HOPLIMIT)
- *i1 = ipp->ipp_hoplimit;
- else
- *i1 = -1; /* Not set */
- break; /* goto sizeof (int) option return */
case IPV6_TCLASS:
if (ipp->ipp_fields & IPPF_TCLASS)
*i1 = ipp->ipp_tclass;
@@ -10722,16 +10716,20 @@
if (!checkonly) {
if (*i1 == -1) {
tcp->tcp_ip6h->ip6_hops =
- ipp->ipp_hoplimit =
+ ipp->ipp_unicast_hops =
(uint8_t)tcp_ipv6_hoplimit;
- ipp->ipp_fields &= ~IPPF_HOPLIMIT;
+ ipp->ipp_fields &= ~IPPF_UNICAST_HOPS;
/* Pass modified value to IP. */
*i1 = tcp->tcp_ip6h->ip6_hops;
} else {
tcp->tcp_ip6h->ip6_hops =
- ipp->ipp_hoplimit = (uint8_t)*i1;
- ipp->ipp_fields |= IPPF_HOPLIMIT;
+ ipp->ipp_unicast_hops =
+ (uint8_t)*i1;
+ ipp->ipp_fields |= IPPF_UNICAST_HOPS;
}
+ reterr = tcp_build_hdrs(q, tcp);
+ if (reterr != 0)
+ return (reterr);
}
break;
case IPV6_BOUND_IF:
@@ -10877,33 +10875,6 @@
if (reterr != 0)
return (reterr);
break;
- case IPV6_HOPLIMIT:
- if (inlen != 0 && inlen != sizeof (int))
- return (EINVAL);
- if (checkonly)
- break;
-
- if (inlen == 0) {
- ipp->ipp_fields &= ~IPPF_HOPLIMIT;
- tcp->tcp_ip6_hops =
- (uint8_t)tcp_ipv6_hoplimit;
- } else {
- if (*i1 > 255 || *i1 < -1)
- return (EINVAL);
- if (*i1 == -1) {
- ipp->ipp_hoplimit = tcp_ipv6_hoplimit;
- *i1 = tcp_ipv6_hoplimit;
- } else {
- ipp->ipp_hoplimit = *i1;
- }
- ipp->ipp_fields |= IPPF_HOPLIMIT;
- tcp->tcp_ip6_hops =
- ipp->ipp_hoplimit;
- }
- reterr = tcp_build_hdrs(q, tcp);
- if (reterr != 0)
- return (reterr);
- break;
case IPV6_TCLASS:
if (inlen != 0 && inlen != sizeof (int))
return (EINVAL);
@@ -11175,7 +11146,6 @@
char buf[TCP_MAX_HDR_LENGTH];
ip6_pkt_t *ipp = &tcp->tcp_sticky_ipp;
in6_addr_t src, dst;
- uint8_t hops;
/*
* save the existing tcp header and source/dest IP addresses
@@ -11183,7 +11153,6 @@
bcopy(tcp->tcp_tcph, buf, tcp->tcp_tcp_hdr_len);
src = tcp->tcp_ip6h->ip6_src;
dst = tcp->tcp_ip6h->ip6_dst;
- hops = tcp->tcp_ip6h->ip6_hops;
hdrs_len = ip_total_hdrs_len_v6(ipp) + TCP_MAX_HDR_LENGTH;
ASSERT(hdrs_len != 0);
if (hdrs_len > tcp->tcp_iphc_len) {
@@ -11230,20 +11199,13 @@
tcp->tcp_ip6h->ip6_dst = dst;
/*
- * If the hop limit was not set by ip_build_hdrs_v6(), restore
- * the saved value.
+ * If the hop limit was not set by ip_build_hdrs_v6(), set it to
+ * the default value for TCP.
*/
- if (!(ipp->ipp_fields & IPPF_HOPLIMIT))
- tcp->tcp_ip6h->ip6_hops = hops;
+ if (!(ipp->ipp_fields & IPPF_UNICAST_HOPS))
+ tcp->tcp_ip6h->ip6_hops = tcp_ipv6_hoplimit;
/*
- * Set the IPv6 header payload length.
- * If there's an ip6i_t included, don't count it in the length.
- */
- tcp->tcp_ip6h->ip6_plen = tcp->tcp_hdr_len - IPV6_HDR_LEN;
- if (ipp->ipp_fields & IPPF_HAS_IP6I)
- tcp->tcp_ip6h->ip6_plen -= sizeof (ip6i_t);
- /*
* If we're setting extension headers after a connection
* has been established, and if we have a routing header
* among the extension headers, call ip_massage_options_v6 to
diff --git a/usr/src/uts/common/inet/tcp/tcp_opt_data.c b/usr/src/uts/common/inet/tcp/tcp_opt_data.c
index 2f1d9d3..d0ab3d8 100644
--- a/usr/src/uts/common/inet/tcp/tcp_opt_data.c
+++ b/usr/src/uts/common/inet/tcp/tcp_opt_data.c
@@ -149,9 +149,6 @@
{ IPV6_PKTINFO, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP,
(OP_PASSNEXT|OP_NODEFAULT|OP_VARLEN),
sizeof (struct in6_pktinfo), -1 /* not initialized */ },
-{ IPV6_HOPLIMIT, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP,
- (OP_PASSNEXT|OP_NODEFAULT),
- sizeof (int), -1 /* not initialized */ },
{ IPV6_NEXTHOP, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP,
(OP_PASSNEXT|OP_NODEFAULT),
sizeof (sin6_t), -1 /* not initialized */ },
diff --git a/usr/src/uts/common/inet/udp/udp.c b/usr/src/uts/common/inet/udp/udp.c
index 9f31e3a..5bed5bf 100644
--- a/usr/src/uts/common/inet/udp/udp.c
+++ b/usr/src/uts/common/inet/udp/udp.c
@@ -2455,12 +2455,6 @@
pkti->ipi6_addr = ipv6_all_zeros;
return (sizeof (struct in6_pktinfo));
}
- case IPV6_HOPLIMIT:
- if (ipp->ipp_fields & IPPF_HOPLIMIT)
- *i1 = ipp->ipp_hoplimit;
- else
- *i1 = -1; /* Not set */
- break; /* goto sizeof (int) option return */
case IPV6_TCLASS:
if (ipp->ipp_fields & IPPF_TCLASS)
*i1 = ipp->ipp_tclass;
@@ -2807,15 +2801,15 @@
}
if (!checkonly) {
if (*i1 == -1) {
- udp->udp_ttl = ipp->ipp_hoplimit =
+ udp->udp_ttl = ipp->ipp_unicast_hops =
udp_ipv6_hoplimit;
- ipp->ipp_fields &= ~IPPF_HOPLIMIT;
+ ipp->ipp_fields &= ~IPPF_UNICAST_HOPS;
/* Pass modified value to IP. */
*i1 = udp->udp_ttl;
} else {
- udp->udp_ttl = ipp->ipp_hoplimit =
+ udp->udp_ttl = ipp->ipp_unicast_hops =
(uint8_t)*i1;
- ipp->ipp_fields |= IPPF_HOPLIMIT;
+ ipp->ipp_fields |= IPPF_UNICAST_HOPS;
}
/* Rebuild the header template */
error = udp_build_hdrs(q, udp);
@@ -2834,22 +2828,16 @@
if (!checkonly) {
if (*i1 == -1) {
udp->udp_multicast_ttl =
- ipp->ipp_multi_hoplimit =
+ ipp->ipp_multicast_hops =
IP_DEFAULT_MULTICAST_TTL;
- ipp->ipp_fields &= ~IPPF_MULTI_HOPLIMIT;
+ ipp->ipp_fields &= ~IPPF_MULTICAST_HOPS;
/* Pass modified value to IP. */
*i1 = udp->udp_multicast_ttl;
} else {
udp->udp_multicast_ttl =
- ipp->ipp_multi_hoplimit =
+ ipp->ipp_multicast_hops =
(uint8_t)*i1;
- ipp->ipp_fields |= IPPF_MULTI_HOPLIMIT;
- }
- /* Rebuild the header template */
- error = udp_build_hdrs(q, udp);
- if (error != 0) {
- *outlenp = 0;
- return (error);
+ ipp->ipp_fields |= IPPF_MULTICAST_HOPS;
}
}
break;
@@ -2967,6 +2955,8 @@
}
break;
case IPV6_HOPLIMIT:
+ if (sticky)
+ return (EINVAL);
if (inlen != 0 && inlen != sizeof (int))
return (EINVAL);
if (checkonly)
@@ -2984,11 +2974,6 @@
ipp->ipp_hoplimit = *i1;
ipp->ipp_fields |= IPPF_HOPLIMIT;
}
- if (sticky) {
- error = udp_build_hdrs(q, udp);
- if (error != 0)
- return (error);
- }
break;
case IPV6_TCLASS:
if (inlen != 0 && inlen != sizeof (int))
@@ -3326,15 +3311,6 @@
if (!(ipp->ipp_fields & IPPF_ADDR))
ip6h->ip6_src = udp->udp_v6src;
- /*
- * If IPV6_HOPLIMIT was set in ipp, use that value.
- * For sticky options, if it does not exist use
- * the value in the udp structure.
- * All this as per RFC 2922.
- */
- if (!(ipp->ipp_fields & IPPF_HOPLIMIT))
- ip6h->ip6_hops = udp->udp_ttl;
-
udpha = (udpha_t *)(udp->udp_sticky_hdrs + hdrs_len - UDPH_SIZE);
udpha->uha_src_port = udp->udp_port;
@@ -5505,13 +5481,21 @@
}
}
- if (!(ignore & IPPF_HOPLIMIT)) {
- if (ipp->ipp_fields & IPPF_HOPLIMIT) {
- option_exists |= IPPF_HOPLIMIT;
- } else if (udp->udp_sticky_ipp.ipp_fields & IPPF_HOPLIMIT) {
- option_exists |= IPPF_HOPLIMIT;
- is_sticky |= IPPF_HOPLIMIT;
- }
+ if (!(ignore & IPPF_HOPLIMIT) && (ipp->ipp_fields & IPPF_HOPLIMIT))
+ option_exists |= IPPF_HOPLIMIT;
+ /* IPV6_HOPLIMIT can never be sticky */
+ ASSERT(!(udp->udp_sticky_ipp.ipp_fields & IPPF_HOPLIMIT));
+
+ if (!(ignore & IPPF_UNICAST_HOPS) &&
+ (udp->udp_sticky_ipp.ipp_fields & IPPF_UNICAST_HOPS)) {
+ option_exists |= IPPF_UNICAST_HOPS;
+ is_sticky |= IPPF_UNICAST_HOPS;
+ }
+
+ if (!(ignore & IPPF_MULTICAST_HOPS) &&
+ (udp->udp_sticky_ipp.ipp_fields & IPPF_MULTICAST_HOPS)) {
+ option_exists |= IPPF_MULTICAST_HOPS;
+ is_sticky |= IPPF_MULTICAST_HOPS;
}
if (!(ignore & IPPF_TCLASS)) {
@@ -5611,15 +5595,19 @@
ip6h->ip6_vcf = IPV6_DEFAULT_VERS_AND_FLOW;
bzero(&ip6h->ip6_src, sizeof (ip6h->ip6_src));
+ /* Set the hoplimit of the outgoing packet. */
if (option_exists & IPPF_HOPLIMIT) {
- tipp = ANCIL_OR_STICKY_PTR(IPPF_HOPLIMIT);
- ip6h->ip6_hops = tipp->ipp_hoplimit;
- } else if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr) &&
- (udp->udp_sticky_ipp.ipp_fields & IPPF_MULTI_HOPLIMIT)) {
- ip6h->ip6_hops = udp->udp_multicast_ttl;
+ /* IPV6_HOPLIMIT ancillary data overrides all other settings. */
+ ip6h->ip6_hops = ipp->ipp_hoplimit;
ip6i->ip6i_flags |= IP6I_HOPLIMIT;
+ } else if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
+ ip6h->ip6_hops = udp->udp_multicast_ttl;
+ if (option_exists & IPPF_MULTICAST_HOPS)
+ ip6i->ip6i_flags |= IP6I_HOPLIMIT;
} else {
ip6h->ip6_hops = udp->udp_ttl;
+ if (option_exists & IPPF_UNICAST_HOPS)
+ ip6i->ip6i_flags |= IP6I_HOPLIMIT;
}
if (option_exists & IPPF_ADDR) {