Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 10 Feb 2012 22:54:58 +0000 (UTC)
From:      Michael Tuexen <tuexen@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org
Subject:   svn commit: r231460 - stable/8/sys/netinet
Message-ID:  <201202102254.q1AMswqv099892@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: tuexen
Date: Fri Feb 10 22:54:58 2012
New Revision: 231460
URL: http://svn.freebsd.org/changeset/base/231460

Log:
  MFC r225549:
  Fix the handling of the flowlabel and DSCP value in the SCTP_PEER_ADDR_PARAMS
  socket option.
  Honor the net.inet6.ip6.auto_flowlabel sysctl setting.

Modified:
  stable/8/sys/netinet/sctp_output.c
  stable/8/sys/netinet/sctp_pcb.c
  stable/8/sys/netinet/sctp_pcb.h
  stable/8/sys/netinet/sctp_structs.h
  stable/8/sys/netinet/sctp_usrreq.c
  stable/8/sys/netinet/sctputil.c
Directory Properties:
  stable/8/sys/   (props changed)
  stable/8/sys/amd64/include/xen/   (props changed)
  stable/8/sys/boot/   (props changed)
  stable/8/sys/cddl/contrib/opensolaris/   (props changed)
  stable/8/sys/contrib/dev/acpica/   (props changed)
  stable/8/sys/contrib/pf/   (props changed)
  stable/8/sys/dev/e1000/   (props changed)

Modified: stable/8/sys/netinet/sctp_output.c
==============================================================================
--- stable/8/sys/netinet/sctp_output.c	Fri Feb 10 22:52:08 2012	(r231459)
+++ stable/8/sys/netinet/sctp_output.c	Fri Feb 10 22:54:58 2012	(r231460)
@@ -3904,6 +3904,7 @@ sctp_lowlevel_chunk_output(struct sctp_i
 	uint32_t vrf_id;
 	sctp_route_t *ro = NULL;
 	struct udphdr *udp = NULL;
+	uint8_t tos_value;
 
 #if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
 	struct socket *so = NULL;
@@ -3925,13 +3926,20 @@ sctp_lowlevel_chunk_output(struct sctp_i
 	if ((auth != NULL) && (stcb != NULL)) {
 		sctp_fill_hmac_digest_m(m, auth_offset, auth, stcb, auth_keyid);
 	}
+	if (net) {
+		tos_value = net->dscp;
+	} else if (stcb) {
+		tos_value = stcb->asoc.default_dscp;
+	} else {
+		tos_value = inp->sctp_ep.default_dscp;
+	}
+
 	switch (to->sa_family) {
 #ifdef INET
 	case AF_INET:
 		{
 			struct ip *ip = NULL;
 			sctp_route_t iproute;
-			uint8_t tos_value;
 			int len;
 
 			len = sizeof(struct ip) + sizeof(struct sctphdr);
@@ -3966,11 +3974,18 @@ sctp_lowlevel_chunk_output(struct sctp_i
 			ip = mtod(m, struct ip *);
 			ip->ip_v = IPVERSION;
 			ip->ip_hl = (sizeof(struct ip) >> 2);
-			if (net) {
-				tos_value = net->dscp;
-			} else {
+			if (tos_value == 0) {
+				/*
+				 * This means especially, that it is not set
+				 * at the SCTP layer. So use the value from
+				 * the IP layer.
+				 */
 				tos_value = inp->ip_inp.inp.inp_ip_tos;
 			}
+			tos_value &= 0xfc;
+			if (ecn_ok) {
+				tos_value |= sctp_get_ect(stcb, chk);
+			}
 			if ((nofragment_flag) && (port == 0)) {
 				ip->ip_off = IP_DF;
 			} else
@@ -3981,10 +3996,7 @@ sctp_lowlevel_chunk_output(struct sctp_i
 
 			ip->ip_ttl = inp->ip_inp.inp.inp_ip_ttl;
 			ip->ip_len = packet_length;
-			ip->ip_tos = tos_value & 0xfc;
-			if (ecn_ok) {
-				ip->ip_tos |= sctp_get_ect(stcb, chk);
-			}
+			ip->ip_tos = tos_value;
 			if (port) {
 				ip->ip_p = IPPROTO_UDP;
 			} else {
@@ -4189,13 +4201,10 @@ sctp_lowlevel_chunk_output(struct sctp_i
 #ifdef INET6
 	case AF_INET6:
 		{
-			uint32_t flowlabel;
+			uint32_t flowlabel, flowinfo;
 			struct ip6_hdr *ip6h;
 			struct route_in6 ip6route;
 			struct ifnet *ifp;
-			u_char flowTop;
-			uint16_t flowBottom;
-			u_char tosBottom, tosTop;
 			struct sockaddr_in6 *sin6, tmp, *lsa6, lsa6_tmp;
 			int prev_scope = 0;
 			struct sockaddr_in6 lsa6_storage;
@@ -4203,12 +4212,22 @@ sctp_lowlevel_chunk_output(struct sctp_i
 			u_short prev_port = 0;
 			int len;
 
-			if (net != NULL) {
+			if (net) {
 				flowlabel = net->flowlabel;
+			} else if (stcb) {
+				flowlabel = stcb->asoc.default_flowlabel;
 			} else {
-				flowlabel = ((struct in6pcb *)inp)->in6p_flowinfo;
+				flowlabel = inp->sctp_ep.default_flowlabel;
 			}
-
+			if (flowlabel == 0) {
+				/*
+				 * This means especially, that it is not set
+				 * at the SCTP layer. So use the value from
+				 * the IP layer.
+				 */
+				flowlabel = ntohl(((struct in6pcb *)inp)->in6p_flowinfo);
+			}
+			flowlabel &= 0x000fffff;
 			len = sizeof(struct ip6_hdr) + sizeof(struct sctphdr);
 			if (port) {
 				len += sizeof(struct udphdr);
@@ -4240,13 +4259,6 @@ sctp_lowlevel_chunk_output(struct sctp_i
 			packet_length = sctp_calculate_len(m);
 
 			ip6h = mtod(m, struct ip6_hdr *);
-			/*
-			 * We assume here that inp_flow is in host byte
-			 * order within the TCB!
-			 */
-			flowBottom = flowlabel & 0x0000ffff;
-			flowTop = ((flowlabel & 0x000f0000) >> 16);
-			tosTop = (((flowlabel & 0xf0) >> 4) | IPV6_VERSION);
 			/* protect *sin6 from overwrite */
 			sin6 = (struct sockaddr_in6 *)to;
 			tmp = *sin6;
@@ -4264,12 +4276,28 @@ sctp_lowlevel_chunk_output(struct sctp_i
 			} else {
 				ro = (sctp_route_t *) & net->ro;
 			}
-			tosBottom = (((struct in6pcb *)inp)->in6p_flowinfo & 0x0c);
+			/*
+			 * We assume here that inp_flow is in host byte
+			 * order within the TCB!
+			 */
+			if (tos_value == 0) {
+				/*
+				 * This means especially, that it is not set
+				 * at the SCTP layer. So use the value from
+				 * the IP layer.
+				 */
+				tos_value = (ntohl(((struct in6pcb *)inp)->in6p_flowinfo) >> 20) & 0xff;
+			}
+			tos_value &= 0xfc;
 			if (ecn_ok) {
-				tosBottom |= sctp_get_ect(stcb, chk);
+				tos_value |= sctp_get_ect(stcb, chk);
 			}
-			tosBottom <<= 4;
-			ip6h->ip6_flow = htonl(((tosTop << 24) | ((tosBottom | flowTop) << 16) | flowBottom));
+			flowinfo = 0x06;
+			flowinfo <<= 8;
+			flowinfo |= tos_value;
+			flowinfo <<= 20;
+			flowinfo |= flowlabel;
+			ip6h->ip6_flow = htonl(flowinfo);
 			if (port) {
 				ip6h->ip6_nxt = IPPROTO_UDP;
 			} else {

Modified: stable/8/sys/netinet/sctp_pcb.c
==============================================================================
--- stable/8/sys/netinet/sctp_pcb.c	Fri Feb 10 22:52:08 2012	(r231459)
+++ stable/8/sys/netinet/sctp_pcb.c	Fri Feb 10 22:54:58 2012	(r231460)
@@ -49,6 +49,9 @@ __FBSDID("$FreeBSD$");
 #include <netinet/sctp_bsd_addr.h>
 #include <netinet/sctp_dtrace_define.h>
 #include <netinet/udp.h>
+#ifdef INET6
+#include <netinet6/ip6_var.h>
+#endif
 #include <sys/sched.h>
 #include <sys/smp.h>
 #include <sys/unistd.h>
@@ -2503,6 +2506,11 @@ sctp_inpcb_alloc(struct socket *so, uint
 	/* setup socket pointers */
 	inp->sctp_socket = so;
 	inp->ip_inp.inp.inp_socket = so;
+#ifdef INET6
+	if (MODULE_GLOBAL(ip6_auto_flowlabel)) {
+		inp->ip_inp.inp.inp_flags |= IN6P_AUTOFLOWLABEL;
+	}
+#endif
 	inp->sctp_associd_counter = 1;
 	inp->partial_delivery_point = SCTP_SB_LIMIT_RCV(so) >> SCTP_PARTIAL_DELIVERY_SHIFT;
 	inp->sctp_frag_point = SCTP_DEFAULT_MAXSEGMENT;
@@ -2668,6 +2676,10 @@ sctp_inpcb_alloc(struct socket *so, uint
 	 */
 	m->local_hmacs = sctp_default_supported_hmaclist();
 	m->local_auth_chunks = sctp_alloc_chunklist();
+	m->default_dscp = 0;
+#ifdef INET6
+	m->default_flowlabel = 0;
+#endif
 	sctp_auth_set_default_chunks(m->local_auth_chunks);
 	LIST_INIT(&m->shared_keys);
 	/* add default NULL key as key id 0 */
@@ -4015,7 +4027,9 @@ sctp_add_remote_addr(struct sctp_tcb *st
 		net->port = 0;
 	}
 	net->dscp = stcb->asoc.default_dscp;
+#ifdef INET6
 	net->flowlabel = stcb->asoc.default_flowlabel;
+#endif
 	if (sctp_is_feature_on(stcb->sctp_ep, SCTP_PCB_FLAGS_DONOT_HEARTBEAT)) {
 		net->dest_state |= SCTP_ADDR_NOHB;
 	} else {

Modified: stable/8/sys/netinet/sctp_pcb.h
==============================================================================
--- stable/8/sys/netinet/sctp_pcb.h	Fri Feb 10 22:52:08 2012	(r231459)
+++ stable/8/sys/netinet/sctp_pcb.h	Fri Feb 10 22:54:58 2012	(r231460)
@@ -322,6 +322,10 @@ struct sctp_pcb {
 	uint32_t store_at;
 	uint32_t max_burst;
 	uint32_t fr_max_burst;
+#ifdef INET6
+	uint32_t default_flowlabel;
+#endif
+	uint8_t default_dscp;
 	char current_secret_number;
 	char last_secret_number;
 };

Modified: stable/8/sys/netinet/sctp_structs.h
==============================================================================
--- stable/8/sys/netinet/sctp_structs.h	Fri Feb 10 22:52:08 2012	(r231459)
+++ stable/8/sys/netinet/sctp_structs.h	Fri Feb 10 22:54:58 2012	(r231460)
@@ -321,7 +321,9 @@ struct sctp_nets {
 	uint32_t fast_recovery_tsn;
 	uint32_t heartbeat_random1;
 	uint32_t heartbeat_random2;
+#ifdef INET6
 	uint32_t flowlabel;
+#endif
 	uint8_t dscp;
 
 	struct timeval start_time;	/* time when this net was created */
@@ -987,7 +989,9 @@ struct sctp_association {
 	uint32_t sb_send_resv;	/* amount reserved on a send */
 	uint32_t my_rwnd_control_len;	/* shadow of sb_mbcnt used for rwnd
 					 * control */
+#ifdef INET6
 	uint32_t default_flowlabel;
+#endif
 	uint32_t pr_sctp_cnt;
 	int ctrl_queue_cnt;	/* could be removed  REM - NO IT CAN'T!! RRS */
 	/*

Modified: stable/8/sys/netinet/sctp_usrreq.c
==============================================================================
--- stable/8/sys/netinet/sctp_usrreq.c	Fri Feb 10 22:52:08 2012	(r231459)
+++ stable/8/sys/netinet/sctp_usrreq.c	Fri Feb 10 22:54:58 2012	(r231460)
@@ -2417,15 +2417,14 @@ flags_out:
 					} else {
 						paddrp->spp_flags |= SPP_PMTUD_DISABLE;
 					}
-#ifdef INET
-					if (net->ro._l_addr.sin.sin_family == AF_INET) {
-						paddrp->spp_dscp = net->dscp;
+					if (net->dscp & 0x01) {
+						paddrp->spp_dscp = net->dscp >> 2;
 						paddrp->spp_flags |= SPP_DSCP;
 					}
-#endif
 #ifdef INET6
-					if (net->ro._l_addr.sin6.sin6_family == AF_INET6) {
-						paddrp->spp_ipv6_flowlabel = net->flowlabel;
+					if ((net->ro._l_addr.sa.sa_family == AF_INET6) &&
+					    (net->flowlabel & 0x80000000)) {
+						paddrp->spp_ipv6_flowlabel = net->flowlabel & 0x000fffff;
 						paddrp->spp_flags |= SPP_IPV6_FLOWLABEL;
 					}
 #endif
@@ -2438,13 +2437,15 @@ flags_out:
 
 					paddrp->spp_pathmaxrxt = stcb->asoc.def_net_failure;
 					paddrp->spp_pathmtu = sctp_get_frag_point(stcb, &stcb->asoc);
-#ifdef INET
-					paddrp->spp_dscp = stcb->asoc.default_dscp & 0x000000fc;
-					paddrp->spp_flags |= SPP_DSCP;
-#endif
+					if (stcb->asoc.default_dscp & 0x01) {
+						paddrp->spp_dscp = stcb->asoc.default_dscp >> 2;
+						paddrp->spp_flags |= SPP_DSCP;
+					}
 #ifdef INET6
-					paddrp->spp_ipv6_flowlabel = stcb->asoc.default_flowlabel;
-					paddrp->spp_flags |= SPP_IPV6_FLOWLABEL;
+					if (stcb->asoc.default_flowlabel & 0x80000000) {
+						paddrp->spp_ipv6_flowlabel = stcb->asoc.default_flowlabel & 0x000fffff;
+						paddrp->spp_flags |= SPP_IPV6_FLOWLABEL;
+					}
 #endif
 					/* default settings should be these */
 					if (sctp_is_feature_on(stcb->sctp_ep, SCTP_PCB_FLAGS_DONOT_HEARTBEAT)) {
@@ -2474,13 +2475,14 @@ flags_out:
 					paddrp->spp_hbinterval = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT]);
 					paddrp->spp_assoc_id = SCTP_FUTURE_ASSOC;
 					/* get inp's default */
-#ifdef INET
-					paddrp->spp_dscp = inp->ip_inp.inp.inp_ip_tos;
-					paddrp->spp_flags |= SPP_DSCP;
-#endif
+					if (inp->sctp_ep.default_dscp & 0x01) {
+						paddrp->spp_dscp = inp->sctp_ep.default_dscp >> 2;
+						paddrp->spp_flags |= SPP_DSCP;
+					}
 #ifdef INET6
-					if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
-						paddrp->spp_ipv6_flowlabel = ((struct in6pcb *)inp)->in6p_flowinfo;
+					if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
+					    (inp->sctp_ep.default_flowlabel & 0x80000000)) {
+						paddrp->spp_ipv6_flowlabel = inp->sctp_ep.default_flowlabel & 0x000fffff;
 						paddrp->spp_flags |= SPP_IPV6_FLOWLABEL;
 					}
 #endif
@@ -4651,17 +4653,15 @@ sctp_setopt(struct socket *so, int optna
 						}
 						net->failure_threshold = paddrp->spp_pathmaxrxt;
 					}
-#ifdef INET
 					if (paddrp->spp_flags & SPP_DSCP) {
-						if (net->ro._l_addr.sin.sin_family == AF_INET) {
-							net->dscp = paddrp->spp_dscp & 0xfc;
-						}
+						net->dscp = paddrp->spp_dscp << 2;
+						net->dscp |= 0x01;
 					}
-#endif
 #ifdef INET6
 					if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) {
-						if (net->ro._l_addr.sin6.sin6_family == AF_INET6) {
+						if (net->ro._l_addr.sa.sa_family == AF_INET6) {
 							net->flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff;
+							net->flowlabel |= 0x80000000;
 						}
 					}
 #endif
@@ -4752,16 +4752,24 @@ sctp_setopt(struct socket *so, int optna
 					}
 					if (paddrp->spp_flags & SPP_DSCP) {
 						TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
-							net->dscp = paddrp->spp_dscp & 0x000000fc;
+							net->dscp = paddrp->spp_dscp << 2;
+							net->dscp |= 0x01;
 						}
-						stcb->asoc.default_dscp = paddrp->spp_dscp & 0x000000fc;
+						stcb->asoc.default_dscp = paddrp->spp_dscp << 2;
+						stcb->asoc.default_dscp |= 0x01;
 					}
+#ifdef INET6
 					if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) {
 						TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
-							net->flowlabel = paddrp->spp_ipv6_flowlabel;
+							if (net->ro._l_addr.sa.sa_family == AF_INET6) {
+								net->flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff;
+								net->flowlabel |= 0x80000000;
+							}
 						}
-						stcb->asoc.default_flowlabel = paddrp->spp_ipv6_flowlabel;
+						stcb->asoc.default_flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff;
+						stcb->asoc.default_flowlabel |= 0x80000000;
 					}
+#endif
 				}
 				SCTP_TCB_UNLOCK(stcb);
 			} else {
@@ -4795,6 +4803,18 @@ sctp_setopt(struct socket *so, int optna
 					} else if (paddrp->spp_flags & SPP_HB_DISABLE) {
 						sctp_feature_on(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT);
 					}
+					if (paddrp->spp_flags & SPP_DSCP) {
+						inp->sctp_ep.default_dscp = paddrp->spp_dscp << 2;
+						inp->sctp_ep.default_dscp |= 0x01;
+					}
+#ifdef INET6
+					if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) {
+						if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
+							inp->sctp_ep.default_flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff;
+							inp->sctp_ep.default_flowlabel |= 0x80000000;
+						}
+					}
+#endif
 					SCTP_INP_WUNLOCK(inp);
 				} else {
 					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);

Modified: stable/8/sys/netinet/sctputil.c
==============================================================================
--- stable/8/sys/netinet/sctputil.c	Fri Feb 10 22:52:08 2012	(r231459)
+++ stable/8/sys/netinet/sctputil.c	Fri Feb 10 22:54:58 2012	(r231460)
@@ -923,16 +923,19 @@ sctp_init_asoc(struct sctp_inpcb *m, str
 	asoc->sctp_cmt_pf = (uint8_t) 0;
 	asoc->sctp_frag_point = m->sctp_frag_point;
 	asoc->sctp_features = m->sctp_features;
-#ifdef INET
-	asoc->default_dscp = m->ip_inp.inp.inp_ip_tos;
-#else
-	asoc->default_dscp = 0;
-#endif
-
+	asoc->default_dscp = m->sctp_ep.default_dscp;
 #ifdef INET6
-	asoc->default_flowlabel = ((struct in6pcb *)m)->in6p_flowinfo;
-#else
-	asoc->default_flowlabel = 0;
+	if (m->sctp_ep.default_flowlabel) {
+		asoc->default_flowlabel = m->sctp_ep.default_flowlabel;
+	} else {
+		if (m->ip_inp.inp.inp_flags & IN6P_AUTOFLOWLABEL) {
+			asoc->default_flowlabel = sctp_select_initial_TSN(&m->sctp_ep);
+			asoc->default_flowlabel &= 0x000fffff;
+			asoc->default_flowlabel |= 0x80000000;
+		} else {
+			asoc->default_flowlabel = 0;
+		}
+	}
 #endif
 	asoc->sb_send_resv = 0;
 	if (override_tag) {



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201202102254.q1AMswqv099892>