Cleanup sctp_send_initiate() and sctp_send_initiate_ack() to be

in sync as much as possible. This simplifies upcoming changes.
This commit is contained in:
Michael Tuexen 2014-08-01 12:42:37 +00:00
parent 835b36e211
commit ce11b8429b
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=269376
6 changed files with 219 additions and 269 deletions

View File

@ -82,12 +82,6 @@ struct sctp_supported_addr_param {
uint16_t addr_type[2]; /* array of supported address types */
} SCTP_PACKED;
/* ECN parameter */
struct sctp_ecn_supported_param {
struct sctp_paramhdr ph;/* type=SCTP_ECN_CAPABLE */
} SCTP_PACKED;
/* heartbeat info parameter */
struct sctp_heartbeat_info_param {
struct sctp_paramhdr ph;

View File

@ -2505,7 +2505,7 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length,
SCTP_BUF_LEN(merr) = sizeof(*phd);
SCTP_BUF_NEXT(merr) = SCTP_M_COPYM(m, *offset, chk_length, M_NOWAIT);
if (SCTP_BUF_NEXT(merr)) {
if (sctp_pad_lastmbuf(SCTP_BUF_NEXT(merr), SCTP_SIZE32(chk_length) - chk_length, NULL)) {
if (sctp_pad_lastmbuf(SCTP_BUF_NEXT(merr), SCTP_SIZE32(chk_length) - chk_length, NULL) == NULL) {
sctp_m_freem(merr);
} else {
sctp_queue_op_err(stcb, merr);

View File

@ -5484,7 +5484,7 @@ __attribute__((noinline))
SCTP_BUF_LEN(mm) = sizeof(*phd);
SCTP_BUF_NEXT(mm) = SCTP_M_COPYM(m, *offset, chk_length, M_NOWAIT);
if (SCTP_BUF_NEXT(mm)) {
if (sctp_pad_lastmbuf(SCTP_BUF_NEXT(mm), SCTP_SIZE32(chk_length) - chk_length, NULL)) {
if (sctp_pad_lastmbuf(SCTP_BUF_NEXT(mm), SCTP_SIZE32(chk_length) - chk_length, NULL) == NULL) {
sctp_m_freem(mm);
} else {
#ifdef SCTP_MBUF_LOGGING

View File

@ -4700,7 +4700,7 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked
#endif
)
{
struct mbuf *m;
struct mbuf *m, *m_last;
struct sctp_nets *net;
struct sctp_init_chunk *init;
struct sctp_supported_addr_param *sup_addr;
@ -4775,80 +4775,17 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked
init->init.num_inbound_streams = htons(stcb->asoc.max_inbound_streams);
init->init.initial_tsn = htonl(stcb->asoc.init_seq_number);
if (stcb->asoc.scope.ipv4_addr_legal || stcb->asoc.scope.ipv6_addr_legal) {
uint8_t i;
parameter_len = (uint16_t) sizeof(struct sctp_paramhdr);
if (stcb->asoc.scope.ipv4_addr_legal) {
parameter_len += (uint16_t) sizeof(uint16_t);
}
if (stcb->asoc.scope.ipv6_addr_legal) {
parameter_len += (uint16_t) sizeof(uint16_t);
}
sup_addr = (struct sctp_supported_addr_param *)(mtod(m, caddr_t)+chunk_len);
sup_addr->ph.param_type = htons(SCTP_SUPPORTED_ADDRTYPE);
sup_addr->ph.param_length = htons(parameter_len);
i = 0;
if (stcb->asoc.scope.ipv4_addr_legal) {
sup_addr->addr_type[i++] = htons(SCTP_IPV4_ADDRESS);
}
if (stcb->asoc.scope.ipv6_addr_legal) {
sup_addr->addr_type[i++] = htons(SCTP_IPV6_ADDRESS);
}
padding_len = 4 - 2 * i;
chunk_len += parameter_len;
}
/* Adaptation layer indication parameter */
if (inp->sctp_ep.adaptation_layer_indicator_provided) {
if (padding_len > 0) {
memset(mtod(m, caddr_t)+chunk_len, 0, padding_len);
chunk_len += padding_len;
padding_len = 0;
}
parameter_len = (uint16_t) sizeof(struct sctp_adaptation_layer_indication);
ali = (struct sctp_adaptation_layer_indication *)(mtod(m, caddr_t)+chunk_len);
ali->ph.param_type = htons(SCTP_ULP_ADAPTATION);
ali->ph.param_length = htons(parameter_len);
ali->indication = ntohl(inp->sctp_ep.adaptation_layer_indicator);
chunk_len += parameter_len;
}
if (SCTP_BASE_SYSCTL(sctp_inits_include_nat_friendly)) {
/* Add NAT friendly parameter. */
if (padding_len > 0) {
memset(mtod(m, caddr_t)+chunk_len, 0, padding_len);
chunk_len += padding_len;
padding_len = 0;
}
parameter_len = (uint16_t) sizeof(struct sctp_paramhdr);
ph = (struct sctp_paramhdr *)(mtod(m, caddr_t)+chunk_len);
ph->param_type = htons(SCTP_HAS_NAT_SUPPORT);
ph->param_length = htons(parameter_len);
chunk_len += parameter_len;
}
/* now any cookie time extensions */
if (stcb->asoc.cookie_preserve_req) {
struct sctp_cookie_perserve_param *cookie_preserve;
if (padding_len > 0) {
memset(mtod(m, caddr_t)+chunk_len, 0, padding_len);
chunk_len += padding_len;
padding_len = 0;
}
parameter_len = (uint16_t) sizeof(struct sctp_cookie_perserve_param);
cookie_preserve = (struct sctp_cookie_perserve_param *)(mtod(m, caddr_t)+chunk_len);
cookie_preserve->ph.param_type = htons(SCTP_COOKIE_PRESERVE);
cookie_preserve->ph.param_length = htons(parameter_len);
cookie_preserve->time = htonl(stcb->asoc.cookie_preserve_req);
stcb->asoc.cookie_preserve_req = 0;
ali->indication = htonl(inp->sctp_ep.adaptation_layer_indicator);
chunk_len += parameter_len;
}
/* ECN parameter */
if (stcb->asoc.ecn_allowed == 1) {
if (padding_len > 0) {
memset(mtod(m, caddr_t)+chunk_len, 0, padding_len);
chunk_len += padding_len;
padding_len = 0;
}
parameter_len = (uint16_t) sizeof(struct sctp_paramhdr);
ph = (struct sctp_paramhdr *)(mtod(m, caddr_t)+chunk_len);
ph->param_type = htons(SCTP_ECN_CAPABLE);
@ -4856,21 +4793,24 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked
chunk_len += parameter_len;
}
/* And now tell the peer we do support PR-SCTP. */
if (padding_len > 0) {
memset(mtod(m, caddr_t)+chunk_len, 0, padding_len);
chunk_len += padding_len;
padding_len = 0;
}
parameter_len = (uint16_t) sizeof(struct sctp_paramhdr);
ph = (struct sctp_paramhdr *)(mtod(m, caddr_t)+chunk_len);
ph->param_type = htons(SCTP_PRSCTP_SUPPORTED);
ph->param_length = htons(parameter_len);
chunk_len += parameter_len;
/* And now tell the peer we do all the extensions */
/* Add NAT friendly parameter. */
if (SCTP_BASE_SYSCTL(sctp_inits_include_nat_friendly)) {
parameter_len = (uint16_t) sizeof(struct sctp_paramhdr);
ph = (struct sctp_paramhdr *)(mtod(m, caddr_t)+chunk_len);
ph->param_type = htons(SCTP_HAS_NAT_SUPPORT);
ph->param_length = htons(parameter_len);
chunk_len += parameter_len;
}
/* And now tell the peer which extensions we support */
num_ext = 0;
pr_supported = (struct sctp_supported_chunk_types_param *)(mtod(m, caddr_t)+chunk_len);
pr_supported->ph.param_type = htons(SCTP_SUPPORTED_CHUNK_EXT);
num_ext = 0;
pr_supported->chunk_types[num_ext++] = SCTP_ASCONF;
pr_supported->chunk_types[num_ext++] = SCTP_ASCONF_ACK;
pr_supported->chunk_types[num_ext++] = SCTP_FORWARD_CUM_TSN;
@ -4943,8 +4883,52 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked
chunk_len += parameter_len;
}
}
SCTP_BUF_LEN(m) = chunk_len;
/* now any cookie time extensions */
if (stcb->asoc.cookie_preserve_req) {
struct sctp_cookie_perserve_param *cookie_preserve;
if (padding_len > 0) {
memset(mtod(m, caddr_t)+chunk_len, 0, padding_len);
chunk_len += padding_len;
padding_len = 0;
}
parameter_len = (uint16_t) sizeof(struct sctp_cookie_perserve_param);
cookie_preserve = (struct sctp_cookie_perserve_param *)(mtod(m, caddr_t)+chunk_len);
cookie_preserve->ph.param_type = htons(SCTP_COOKIE_PRESERVE);
cookie_preserve->ph.param_length = htons(parameter_len);
cookie_preserve->time = htonl(stcb->asoc.cookie_preserve_req);
stcb->asoc.cookie_preserve_req = 0;
chunk_len += parameter_len;
}
if (stcb->asoc.scope.ipv4_addr_legal || stcb->asoc.scope.ipv6_addr_legal) {
uint8_t i;
if (padding_len > 0) {
memset(mtod(m, caddr_t)+chunk_len, 0, padding_len);
chunk_len += padding_len;
padding_len = 0;
}
parameter_len = (uint16_t) sizeof(struct sctp_paramhdr);
if (stcb->asoc.scope.ipv4_addr_legal) {
parameter_len += (uint16_t) sizeof(uint16_t);
}
if (stcb->asoc.scope.ipv6_addr_legal) {
parameter_len += (uint16_t) sizeof(uint16_t);
}
sup_addr = (struct sctp_supported_addr_param *)(mtod(m, caddr_t)+chunk_len);
sup_addr->ph.param_type = htons(SCTP_SUPPORTED_ADDRTYPE);
sup_addr->ph.param_length = htons(parameter_len);
i = 0;
if (stcb->asoc.scope.ipv4_addr_legal) {
sup_addr->addr_type[i++] = htons(SCTP_IPV4_ADDRESS);
}
if (stcb->asoc.scope.ipv6_addr_legal) {
sup_addr->addr_type[i++] = htons(SCTP_IPV6_ADDRESS);
}
padding_len = 4 - 2 * i;
chunk_len += parameter_len;
}
SCTP_BUF_LEN(m) = chunk_len;
/* now the addresses */
/*
* To optimize this we could put the scoping stuff into a structure
@ -4952,18 +4936,13 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked
* we could just sifa in the address within the stcb. But for now
* this is a quick hack to get the address stuff teased apart.
*/
sctp_add_addresses_to_i_ia(inp, stcb, &stcb->asoc.scope, m, cnt_inits_to, &padding_len, &chunk_len);
m_last = sctp_add_addresses_to_i_ia(inp, stcb, &stcb->asoc.scope,
m, cnt_inits_to,
&padding_len, &chunk_len);
init->ch.chunk_length = htons(chunk_len);
if (padding_len > 0) {
struct mbuf *m_at, *mp_last;
mp_last = NULL;
for (m_at = m; m_at; m_at = SCTP_BUF_NEXT(m_at)) {
if (SCTP_BUF_NEXT(m_at) == NULL)
mp_last = m_at;
}
if ((mp_last == NULL) || sctp_add_pad_tombuf(mp_last, padding_len)) {
if (sctp_add_pad_tombuf(m_last, padding_len) == NULL) {
sctp_m_freem(m);
return;
}
@ -5100,7 +5079,6 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt,
*nat_friendly = 1;
/* fall through */
case SCTP_PRSCTP_SUPPORTED:
if (padded_size != sizeof(struct sctp_paramhdr)) {
SCTPDBG(SCTP_DEBUG_OUTPUT1, "Invalid size - error prsctp/nat support %d\n", plen);
goto invalid_size;
@ -5108,7 +5086,7 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt,
at += padded_size;
break;
case SCTP_ECN_CAPABLE:
if (padded_size != sizeof(struct sctp_ecn_supported_param)) {
if (padded_size != sizeof(struct sctp_paramhdr)) {
SCTPDBG(SCTP_DEBUG_OUTPUT1, "Invalid size - error ecn %d\n", plen);
goto invalid_size;
}
@ -5493,13 +5471,13 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
uint32_t vrf_id, uint16_t port, int hold_inp_lock)
{
struct sctp_association *asoc;
struct mbuf *m, *m_at, *m_tmp, *m_cookie, *op_err, *mp_last;
struct mbuf *m, *m_tmp, *m_last, *m_cookie, *op_err;
struct sctp_init_ack_chunk *initack;
struct sctp_adaptation_layer_indication *ali;
struct sctp_ecn_supported_param *ecn;
struct sctp_prsctp_supported_param *prsctp;
struct sctp_supported_chunk_types_param *pr_supported;
struct sctp_paramhdr *ph;
union sctp_sockstore *over_addr;
struct sctp_scoping scp;
#ifdef INET
struct sockaddr_in *dst4 = (struct sockaddr_in *)dst;
@ -5519,18 +5497,16 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
uint8_t *signature = NULL;
int cnt_inits_to = 0;
uint16_t his_limit, i_want;
int abort_flag, padval;
int num_ext;
int p_len;
int abort_flag;
int nat_friendly = 0;
struct socket *so;
uint16_t num_ext, chunk_len, padding_len, parameter_len;
if (stcb) {
asoc = &stcb->asoc;
} else {
asoc = NULL;
}
mp_last = NULL;
if ((asoc != NULL) &&
(SCTP_GET_STATE(asoc) != SCTP_STATE_COOKIE_WAIT) &&
(sctp_are_there_new_addresses(asoc, init_pkt, offset, src))) {
@ -5573,7 +5549,8 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
sctp_m_freem(op_err);
return;
}
SCTP_BUF_LEN(m) = sizeof(struct sctp_init_chunk);
chunk_len = (uint16_t) sizeof(struct sctp_init_ack_chunk);
padding_len = 0;
/*
* We might not overwrite the identification[] completely and on
@ -5897,161 +5874,156 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
/* adaptation layer indication parameter */
if (inp->sctp_ep.adaptation_layer_indicator_provided) {
ali = (struct sctp_adaptation_layer_indication *)((caddr_t)initack + sizeof(*initack));
parameter_len = (uint16_t) sizeof(struct sctp_adaptation_layer_indication);
ali = (struct sctp_adaptation_layer_indication *)(mtod(m, caddr_t)+chunk_len);
ali->ph.param_type = htons(SCTP_ULP_ADAPTATION);
ali->ph.param_length = htons(sizeof(*ali));
ali->indication = ntohl(inp->sctp_ep.adaptation_layer_indicator);
SCTP_BUF_LEN(m) += sizeof(*ali);
ecn = (struct sctp_ecn_supported_param *)((caddr_t)ali + sizeof(*ali));
} else {
ecn = (struct sctp_ecn_supported_param *)((caddr_t)initack + sizeof(*initack));
ali->ph.param_length = htons(parameter_len);
ali->indication = htonl(inp->sctp_ep.adaptation_layer_indicator);
chunk_len += parameter_len;
}
/* ECN parameter */
if (((asoc != NULL) && (asoc->ecn_allowed == 1)) ||
(inp->sctp_ecn_enable == 1)) {
ecn->ph.param_type = htons(SCTP_ECN_CAPABLE);
ecn->ph.param_length = htons(sizeof(*ecn));
SCTP_BUF_LEN(m) += sizeof(*ecn);
prsctp = (struct sctp_prsctp_supported_param *)((caddr_t)ecn +
sizeof(*ecn));
} else {
prsctp = (struct sctp_prsctp_supported_param *)((caddr_t)ecn);
((asoc == NULL) && (inp->sctp_ecn_enable == 1))) {
parameter_len = (uint16_t) sizeof(struct sctp_paramhdr);
ph = (struct sctp_paramhdr *)(mtod(m, caddr_t)+chunk_len);
ph->param_type = htons(SCTP_ECN_CAPABLE);
ph->param_length = htons(parameter_len);
chunk_len += parameter_len;
}
/* And now tell the peer we do pr-sctp */
prsctp->ph.param_type = htons(SCTP_PRSCTP_SUPPORTED);
prsctp->ph.param_length = htons(sizeof(*prsctp));
SCTP_BUF_LEN(m) += sizeof(*prsctp);
if (nat_friendly) {
/* Add NAT friendly parameter */
struct sctp_paramhdr *ph;
/* And now tell the peer we do pr-sctp */
parameter_len = (uint16_t) sizeof(struct sctp_paramhdr);
ph = (struct sctp_paramhdr *)(mtod(m, caddr_t)+chunk_len);
ph->param_type = htons(SCTP_PRSCTP_SUPPORTED);
ph->param_length = htons(parameter_len);
chunk_len += parameter_len;
ph = (struct sctp_paramhdr *)(mtod(m, caddr_t)+SCTP_BUF_LEN(m));
/* Add NAT friendly parameter */
if (nat_friendly) {
parameter_len = (uint16_t) sizeof(struct sctp_paramhdr);
ph = (struct sctp_paramhdr *)(mtod(m, caddr_t)+chunk_len);
ph->param_type = htons(SCTP_HAS_NAT_SUPPORT);
ph->param_length = htons(sizeof(struct sctp_paramhdr));
SCTP_BUF_LEN(m) += sizeof(struct sctp_paramhdr);
chunk_len += sizeof(struct sctp_paramhdr);
}
/* And now tell the peer we do all the extensions */
pr_supported = (struct sctp_supported_chunk_types_param *)(mtod(m, caddr_t)+SCTP_BUF_LEN(m));
pr_supported->ph.param_type = htons(SCTP_SUPPORTED_CHUNK_EXT);
/* And now tell the peer which extensions we support */
num_ext = 0;
pr_supported = (struct sctp_supported_chunk_types_param *)(mtod(m, caddr_t)+chunk_len);
pr_supported->ph.param_type = htons(SCTP_SUPPORTED_CHUNK_EXT);
pr_supported->chunk_types[num_ext++] = SCTP_ASCONF;
pr_supported->chunk_types[num_ext++] = SCTP_ASCONF_ACK;
pr_supported->chunk_types[num_ext++] = SCTP_FORWARD_CUM_TSN;
pr_supported->chunk_types[num_ext++] = SCTP_PACKET_DROPPED;
pr_supported->chunk_types[num_ext++] = SCTP_STREAM_RESET;
if (!SCTP_BASE_SYSCTL(sctp_auth_disable))
if (!SCTP_BASE_SYSCTL(sctp_auth_disable)) {
pr_supported->chunk_types[num_ext++] = SCTP_AUTHENTICATION;
if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off))
}
if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off)) {
pr_supported->chunk_types[num_ext++] = SCTP_NR_SELECTIVE_ACK;
p_len = sizeof(*pr_supported) + num_ext;
pr_supported->ph.param_length = htons(p_len);
bzero((caddr_t)pr_supported + p_len, SCTP_SIZE32(p_len) - p_len);
SCTP_BUF_LEN(m) += SCTP_SIZE32(p_len);
}
parameter_len = (uint16_t) sizeof(struct sctp_supported_chunk_types_param) + num_ext;
pr_supported->ph.param_length = htons(parameter_len);
padding_len = SCTP_SIZE32(parameter_len) - parameter_len;
chunk_len += parameter_len;
/* add authentication parameters */
if (!SCTP_BASE_SYSCTL(sctp_auth_disable)) {
struct sctp_auth_random *randp;
struct sctp_auth_hmac_algo *hmacs;
struct sctp_auth_chunk_list *chunks;
uint16_t random_len;
if (padding_len > 0) {
memset(mtod(m, caddr_t)+chunk_len, 0, padding_len);
chunk_len += padding_len;
padding_len = 0;
}
/* generate and add RANDOM parameter */
random_len = SCTP_AUTH_RANDOM_SIZE_DEFAULT;
randp = (struct sctp_auth_random *)(mtod(m, caddr_t)+SCTP_BUF_LEN(m));
randp = (struct sctp_auth_random *)(mtod(m, caddr_t)+chunk_len);
parameter_len = (uint16_t) sizeof(struct sctp_auth_random) +
SCTP_AUTH_RANDOM_SIZE_DEFAULT;
randp->ph.param_type = htons(SCTP_RANDOM);
p_len = sizeof(*randp) + random_len;
randp->ph.param_length = htons(p_len);
SCTP_READ_RANDOM(randp->random_data, random_len);
/* zero out any padding required */
bzero((caddr_t)randp + p_len, SCTP_SIZE32(p_len) - p_len);
SCTP_BUF_LEN(m) += SCTP_SIZE32(p_len);
randp->ph.param_length = htons(parameter_len);
SCTP_READ_RANDOM(randp->random_data, SCTP_AUTH_RANDOM_SIZE_DEFAULT);
padding_len = SCTP_SIZE32(parameter_len) - parameter_len;
chunk_len += parameter_len;
if (padding_len > 0) {
memset(mtod(m, caddr_t)+chunk_len, 0, padding_len);
chunk_len += padding_len;
padding_len = 0;
}
/* add HMAC_ALGO parameter */
hmacs = (struct sctp_auth_hmac_algo *)(mtod(m, caddr_t)+SCTP_BUF_LEN(m));
p_len = sctp_serialize_hmaclist(inp->sctp_ep.local_hmacs,
hmacs = (struct sctp_auth_hmac_algo *)(mtod(m, caddr_t)+chunk_len);
parameter_len = (uint16_t) sizeof(struct sctp_auth_hmac_algo) +
sctp_serialize_hmaclist(inp->sctp_ep.local_hmacs,
(uint8_t *) hmacs->hmac_ids);
if (p_len > 0) {
p_len += sizeof(*hmacs);
hmacs->ph.param_type = htons(SCTP_HMAC_LIST);
hmacs->ph.param_length = htons(p_len);
/* zero out any padding required */
bzero((caddr_t)hmacs + p_len, SCTP_SIZE32(p_len) - p_len);
SCTP_BUF_LEN(m) += SCTP_SIZE32(p_len);
hmacs->ph.param_type = htons(SCTP_HMAC_LIST);
hmacs->ph.param_length = htons(parameter_len);
padding_len = SCTP_SIZE32(parameter_len) - parameter_len;
chunk_len += parameter_len;
if (padding_len > 0) {
memset(mtod(m, caddr_t)+chunk_len, 0, padding_len);
chunk_len += padding_len;
padding_len = 0;
}
/* add CHUNKS parameter */
chunks = (struct sctp_auth_chunk_list *)(mtod(m, caddr_t)+SCTP_BUF_LEN(m));
p_len = sctp_serialize_auth_chunks(inp->sctp_ep.local_auth_chunks,
chunks = (struct sctp_auth_chunk_list *)(mtod(m, caddr_t)+chunk_len);
parameter_len = (uint16_t) sizeof(struct sctp_auth_chunk_list) +
sctp_serialize_auth_chunks(inp->sctp_ep.local_auth_chunks,
chunks->chunk_types);
if (p_len > 0) {
p_len += sizeof(*chunks);
chunks->ph.param_type = htons(SCTP_CHUNK_LIST);
chunks->ph.param_length = htons(p_len);
/* zero out any padding required */
bzero((caddr_t)chunks + p_len, SCTP_SIZE32(p_len) - p_len);
SCTP_BUF_LEN(m) += SCTP_SIZE32(p_len);
}
chunks->ph.param_type = htons(SCTP_CHUNK_LIST);
chunks->ph.param_length = htons(parameter_len);
padding_len = SCTP_SIZE32(parameter_len) - parameter_len;
chunk_len += parameter_len;
}
m_at = m;
SCTP_BUF_LEN(m) = chunk_len;
m_last = m;
/* now the addresses */
{
struct sctp_scoping scp;
/*
* To optimize this we could put the scoping stuff into a
* structure and remove the individual uint8's from the stc
* structure. Then we could just sifa in the address within
* the stc.. but for now this is a quick hack to get the
* address stuff teased apart.
*/
scp.ipv4_addr_legal = stc.ipv4_addr_legal;
scp.ipv6_addr_legal = stc.ipv6_addr_legal;
scp.loopback_scope = stc.loopback_scope;
scp.ipv4_local_scope = stc.ipv4_scope;
scp.local_scope = stc.local_scope;
scp.site_scope = stc.site_scope;
m_at = sctp_add_addresses_to_i_ia(inp, stcb, &scp, m_at, cnt_inits_to, NULL, NULL);
/*
* To optimize this we could put the scoping stuff into a structure
* and remove the individual uint8's from the stc structure. Then we
* could just sifa in the address within the stc.. but for now this
* is a quick hack to get the address stuff teased apart.
*/
scp.ipv4_addr_legal = stc.ipv4_addr_legal;
scp.ipv6_addr_legal = stc.ipv6_addr_legal;
scp.loopback_scope = stc.loopback_scope;
scp.ipv4_local_scope = stc.ipv4_scope;
scp.local_scope = stc.local_scope;
scp.site_scope = stc.site_scope;
m_last = sctp_add_addresses_to_i_ia(inp, stcb, &scp, m_last,
cnt_inits_to,
&padding_len, &chunk_len);
/* padding_len can only be positive, if no addresses have been added */
if (padding_len > 0) {
memset(mtod(m, caddr_t)+chunk_len, 0, padding_len);
chunk_len += padding_len;
SCTP_BUF_LEN(m) += padding_len;
padding_len = 0;
}
/* tack on the operational error if present */
if (op_err) {
struct mbuf *ol;
int llen;
llen = 0;
ol = op_err;
while (ol) {
llen += SCTP_BUF_LEN(ol);
ol = SCTP_BUF_NEXT(ol);
parameter_len = 0;
for (m_tmp = op_err; m_tmp != NULL; m_tmp = SCTP_BUF_NEXT(m_tmp)) {
parameter_len += SCTP_BUF_LEN(m_tmp);
}
if (llen % 4) {
/* must add a pad to the param */
uint32_t cpthis = 0;
int padlen;
padlen = 4 - (llen % 4);
m_copyback(op_err, llen, padlen, (caddr_t)&cpthis);
}
while (SCTP_BUF_NEXT(m_at) != NULL) {
m_at = SCTP_BUF_NEXT(m_at);
}
SCTP_BUF_NEXT(m_at) = op_err;
while (SCTP_BUF_NEXT(m_at) != NULL) {
m_at = SCTP_BUF_NEXT(m_at);
padding_len = SCTP_SIZE32(parameter_len) - parameter_len;
SCTP_BUF_NEXT(m_last) = op_err;
while (SCTP_BUF_NEXT(m_last) != NULL) {
m_last = SCTP_BUF_NEXT(m_last);
}
chunk_len += parameter_len;
}
/* pre-calulate the size and update pkt header and chunk header */
p_len = 0;
for (m_tmp = m; m_tmp; m_tmp = SCTP_BUF_NEXT(m_tmp)) {
p_len += SCTP_BUF_LEN(m_tmp);
if (SCTP_BUF_NEXT(m_tmp) == NULL) {
/* m_tmp should now point to last one */
break;
if (padding_len > 0) {
m_last = sctp_add_pad_tombuf(m_last, padding_len);
if (m_last == NULL) {
/* Houston we have a problem, no space */
sctp_m_freem(m);
return;
}
chunk_len += padding_len;
padding_len = 0;
}
/* Now we must build a cookie */
m_cookie = sctp_add_cookie(init_pkt, offset, m, 0, &stc, &signature);
if (m_cookie == NULL) {
@ -6060,21 +6032,22 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
return;
}
/* Now append the cookie to the end and update the space/size */
SCTP_BUF_NEXT(m_tmp) = m_cookie;
for (m_tmp = m_cookie; m_tmp; m_tmp = SCTP_BUF_NEXT(m_tmp)) {
p_len += SCTP_BUF_LEN(m_tmp);
SCTP_BUF_NEXT(m_last) = m_cookie;
parameter_len = 0;
for (m_tmp = m_cookie; m_tmp != NULL; m_tmp = SCTP_BUF_NEXT(m_tmp)) {
parameter_len += SCTP_BUF_LEN(m_tmp);
if (SCTP_BUF_NEXT(m_tmp) == NULL) {
/* m_tmp should now point to last one */
mp_last = m_tmp;
break;
m_last = m_tmp;
}
}
padding_len = SCTP_SIZE32(parameter_len) - parameter_len;
chunk_len += parameter_len;
/*
* Place in the size, but we don't include the last pad (if any) in
* the INIT-ACK.
*/
initack->ch.chunk_length = htons(p_len);
initack->ch.chunk_length = htons(chunk_len);
/*
* Time to sign the cookie, we don't sign over the cookie signature
@ -6088,11 +6061,8 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
* We sifa 0 here to NOT set IP_DF if its IPv4, we ignore the return
* here since the timer will drive a retranmission.
*/
padval = p_len % 4;
if ((padval) && (mp_last)) {
/* see my previous comments on mp_last */
if (sctp_add_pad_tombuf(mp_last, (4 - padval))) {
/* Houston we have a problem, no space */
if (padding_len > 0) {
if (sctp_add_pad_tombuf(m_last, padding_len) == NULL) {
sctp_m_freem(m);
return;
}
@ -7582,12 +7552,10 @@ sctp_move_to_outqueue(struct sctp_tcb *stcb,
int pads;
pads = SCTP_SIZE32(chk->book_size) - chk->send_size;
if (sctp_pad_lastmbuf(chk->data, pads, chk->last_mbuf) == 0) {
chk->pad_inplace = 1;
}
if ((lm = SCTP_BUF_NEXT(chk->last_mbuf)) != NULL) {
/* pad added an mbuf */
lm = sctp_pad_lastmbuf(chk->data, pads, chk->last_mbuf);
if (lm != NULL) {
chk->last_mbuf = lm;
chk->pad_inplace = 1;
}
chk->send_size += pads;
}
@ -10900,7 +10868,8 @@ sctp_send_abort_tcb(struct sctp_tcb *stcb, struct mbuf *operr, int so_locked
abort->ch.chunk_length = htons(chunk_len);
/* Add padding, if necessary. */
if (padding_len > 0) {
if ((m_last == NULL) || sctp_add_pad_tombuf(m_last, padding_len)) {
if ((m_last == NULL) ||
(sctp_add_pad_tombuf(m_last, padding_len) == NULL)) {
sctp_m_freem(m_out);
return;
}
@ -11000,7 +10969,7 @@ sctp_send_resp_msg(struct sockaddr *src, struct sockaddr *dst,
padding_len = 4 - padding_len;
}
if (padding_len != 0) {
if (sctp_add_pad_tombuf(m_last, padding_len)) {
if (sctp_add_pad_tombuf(m_last, padding_len) == NULL) {
sctp_m_freem(cause);
return;
}

View File

@ -2516,58 +2516,44 @@ sctp_get_next_param(struct mbuf *m,
}
int
struct mbuf *
sctp_add_pad_tombuf(struct mbuf *m, int padlen)
{
/*
* add padlen bytes of 0 filled padding to the end of the mbuf. If
* padlen is > 3 this routine will fail.
*/
uint8_t *dp;
int i;
struct mbuf *m_last;
caddr_t dp;
if (padlen > 3) {
SCTP_LTRACE_ERR_RET_PKT(m, NULL, NULL, NULL, SCTP_FROM_SCTPUTIL, ENOBUFS);
return (ENOBUFS);
return (NULL);
}
if (padlen <= M_TRAILINGSPACE(m)) {
/*
* The easy way. We hope the majority of the time we hit
* here :)
*/
dp = (uint8_t *) (mtod(m, caddr_t)+SCTP_BUF_LEN(m));
SCTP_BUF_LEN(m) += padlen;
m_last = m;
} else {
/* Hard way we must grow the mbuf */
struct mbuf *tmp;
tmp = sctp_get_mbuf_for_msg(padlen, 0, M_NOWAIT, 1, MT_DATA);
if (tmp == NULL) {
/* Out of space GAK! we are in big trouble. */
SCTP_LTRACE_ERR_RET_PKT(m, NULL, NULL, NULL, SCTP_FROM_SCTPUTIL, ENOBUFS);
return (ENOBUFS);
/* Hard way we must grow the mbuf chain */
m_last = sctp_get_mbuf_for_msg(padlen, 0, M_NOWAIT, 1, MT_DATA);
if (m_last == NULL) {
return (NULL);
}
/* setup and insert in middle */
SCTP_BUF_LEN(tmp) = padlen;
SCTP_BUF_NEXT(tmp) = NULL;
SCTP_BUF_NEXT(m) = tmp;
dp = mtod(tmp, uint8_t *);
SCTP_BUF_LEN(m_last) = 0;
SCTP_BUF_NEXT(m_last) = NULL;
SCTP_BUF_NEXT(m) = m_last;
}
/* zero out the pad */
for (i = 0; i < padlen; i++) {
*dp = 0;
dp++;
}
return (0);
dp = mtod(m_last, caddr_t)+SCTP_BUF_LEN(m_last);
SCTP_BUF_LEN(m_last) += padlen;
memset(dp, 0, padlen);
return (m_last);
}
int
struct mbuf *
sctp_pad_lastmbuf(struct mbuf *m, int padval, struct mbuf *last_mbuf)
{
/* find the last mbuf in chain and pad it */
struct mbuf *m_at;
if (last_mbuf) {
if (last_mbuf != NULL) {
return (sctp_add_pad_tombuf(last_mbuf, padval));
} else {
for (m_at = m; m_at; m_at = SCTP_BUF_NEXT(m_at)) {
@ -2576,8 +2562,7 @@ sctp_pad_lastmbuf(struct mbuf *m, int padval, struct mbuf *last_mbuf)
}
}
}
SCTP_LTRACE_ERR_RET_PKT(m, NULL, NULL, NULL, SCTP_FROM_SCTPUTIL, EFAULT);
return (EFAULT);
return (NULL);
}
static void

View File

@ -147,9 +147,11 @@ struct sctp_paramhdr *
sctp_get_next_param(struct mbuf *, int,
struct sctp_paramhdr *, int);
int sctp_add_pad_tombuf(struct mbuf *, int);
struct mbuf *
sctp_add_pad_tombuf(struct mbuf *, int);
int sctp_pad_lastmbuf(struct mbuf *, int, struct mbuf *);
struct mbuf *
sctp_pad_lastmbuf(struct mbuf *, int, struct mbuf *);
void
sctp_ulp_notify(uint32_t, struct sctp_tcb *, uint32_t, void *, int