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) {
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to