From owner-svn-src-all@FreeBSD.ORG Wed Sep 14 08:15:22 2011 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 33150106564A; Wed, 14 Sep 2011 08:15:22 +0000 (UTC) (envelope-from tuexen@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 220FE8FC08; Wed, 14 Sep 2011 08:15:22 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.4/8.14.4) with ESMTP id p8E8FMnv017541; Wed, 14 Sep 2011 08:15:22 GMT (envelope-from tuexen@svn.freebsd.org) Received: (from tuexen@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id p8E8FLdG017534; Wed, 14 Sep 2011 08:15:21 GMT (envelope-from tuexen@svn.freebsd.org) Message-Id: <201109140815.p8E8FLdG017534@svn.freebsd.org> From: Michael Tuexen Date: Wed, 14 Sep 2011 08:15:21 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r225549 - head/sys/netinet X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 14 Sep 2011 08:15:22 -0000 Author: tuexen Date: Wed Sep 14 08:15:21 2011 New Revision: 225549 URL: http://svn.freebsd.org/changeset/base/225549 Log: 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. Approved by: re (bz) MFC after: 1 month. Modified: head/sys/netinet/sctp_output.c head/sys/netinet/sctp_pcb.c head/sys/netinet/sctp_pcb.h head/sys/netinet/sctp_structs.h head/sys/netinet/sctp_usrreq.c head/sys/netinet/sctputil.c Modified: head/sys/netinet/sctp_output.c ============================================================================== --- head/sys/netinet/sctp_output.c Wed Sep 14 07:56:25 2011 (r225548) +++ head/sys/netinet/sctp_output.c Wed Sep 14 08:15:21 2011 (r225549) @@ -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: head/sys/netinet/sctp_pcb.c ============================================================================== --- head/sys/netinet/sctp_pcb.c Wed Sep 14 07:56:25 2011 (r225548) +++ head/sys/netinet/sctp_pcb.c Wed Sep 14 08:15:21 2011 (r225549) @@ -49,6 +49,9 @@ __FBSDID("$FreeBSD$"); #include #include #include +#ifdef INET6 +#include +#endif #include #include #include @@ -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: head/sys/netinet/sctp_pcb.h ============================================================================== --- head/sys/netinet/sctp_pcb.h Wed Sep 14 07:56:25 2011 (r225548) +++ head/sys/netinet/sctp_pcb.h Wed Sep 14 08:15:21 2011 (r225549) @@ -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: head/sys/netinet/sctp_structs.h ============================================================================== --- head/sys/netinet/sctp_structs.h Wed Sep 14 07:56:25 2011 (r225548) +++ head/sys/netinet/sctp_structs.h Wed Sep 14 08:15:21 2011 (r225549) @@ -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: head/sys/netinet/sctp_usrreq.c ============================================================================== --- head/sys/netinet/sctp_usrreq.c Wed Sep 14 07:56:25 2011 (r225548) +++ head/sys/netinet/sctp_usrreq.c Wed Sep 14 08:15:21 2011 (r225549) @@ -2428,15 +2428,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 @@ -2449,13 +2448,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)) { @@ -2485,13 +2486,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 @@ -4683,17 +4685,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 @@ -4784,16 +4784,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 { @@ -4827,6 +4835,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: head/sys/netinet/sctputil.c ============================================================================== --- head/sys/netinet/sctputil.c Wed Sep 14 07:56:25 2011 (r225548) +++ head/sys/netinet/sctputil.c Wed Sep 14 08:15:21 2011 (r225549) @@ -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) {