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.
This commit is contained in:
parent
a4de89de11
commit
58bdb69150
@ -3904,6 +3904,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
|
||||
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_inpcb *inp,
|
||||
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_inpcb *inp,
|
||||
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_inpcb *inp,
|
||||
|
||||
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_inpcb *inp,
|
||||
#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_inpcb *inp,
|
||||
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_inpcb *inp,
|
||||
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_inpcb *inp,
|
||||
} else {
|
||||
ro = (sctp_route_t *) & net->ro;
|
||||
}
|
||||
tosBottom = (((struct in6pcb *)inp)->in6p_flowinfo & 0x0c);
|
||||
if (ecn_ok) {
|
||||
tosBottom |= sctp_get_ect(stcb, chk);
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
tosBottom <<= 4;
|
||||
ip6h->ip6_flow = htonl(((tosTop << 24) | ((tosBottom | flowTop) << 16) | flowBottom));
|
||||
tos_value &= 0xfc;
|
||||
if (ecn_ok) {
|
||||
tos_value |= sctp_get_ect(stcb, chk);
|
||||
}
|
||||
flowinfo = 0x06;
|
||||
flowinfo <<= 8;
|
||||
flowinfo |= tos_value;
|
||||
flowinfo <<= 20;
|
||||
flowinfo |= flowlabel;
|
||||
ip6h->ip6_flow = htonl(flowinfo);
|
||||
if (port) {
|
||||
ip6h->ip6_nxt = IPPROTO_UDP;
|
||||
} else {
|
||||
|
@ -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, uint32_t vrf_id)
|
||||
/* 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, uint32_t vrf_id)
|
||||
*/
|
||||
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 *stcb, struct sockaddr *newaddr,
|
||||
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 {
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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 */
|
||||
/*
|
||||
|
@ -2428,15 +2428,14 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
|
||||
} 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 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
|
||||
|
||||
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 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
|
||||
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 optname, void *optval, size_t optsize,
|
||||
}
|
||||
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 optname, void *optval, size_t optsize,
|
||||
}
|
||||
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 optname, void *optval, size_t optsize,
|
||||
} 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);
|
||||
|
@ -923,16 +923,19 @@ sctp_init_asoc(struct sctp_inpcb *m, struct sctp_tcb *stcb,
|
||||
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) {
|
||||
|
Loading…
Reference in New Issue
Block a user